fetch.c revision 38394
1/*- 2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $Id: fetch.c,v 1.3 1998/07/11 21:29:07 des Exp $ 29 */ 30 31#include <sys/param.h> 32#include <sys/types.h> 33#include <sys/socket.h> 34#include <netinet/in.h> 35 36#include <ctype.h> 37#include <netdb.h> 38#include <stdio.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unistd.h> 42 43#include "fetch.h" 44 45#ifndef NDEBUG 46#define DEBUG(x) do x; while (0) 47#else 48#define DEBUG(x) do { } while (0) 49#endif 50 51int fetchLastErrCode; 52const char *fetchLastErrText; 53 54FILE * 55fetchGet(url_t *URL, char *flags) 56{ 57 if (strcasecmp(URL->scheme, "file") == 0) 58 return fetchGetFile(URL, flags); 59 else if (strcasecmp(URL->scheme, "http") == 0) 60 return fetchGetHTTP(URL, flags); 61 else if (strcasecmp(URL->scheme, "ftp") == 0) 62 return fetchGetFTP(URL, flags); 63 else return NULL; 64 65} 66 67FILE * 68fetchPut(url_t *URL, char *flags) 69{ 70 if (strcasecmp(URL->scheme, "file") == 0) 71 return fetchPutFile(URL, flags); 72 else if (strcasecmp(URL->scheme, "http") == 0) 73 return fetchPutHTTP(URL, flags); 74 else if (strcasecmp(URL->scheme, "ftp") == 0) 75 return fetchPutFTP(URL, flags); 76 else return NULL; 77} 78 79/* get URL */ 80FILE * 81fetchGetURL(char *URL, char *flags) 82{ 83 url_t *u; 84 FILE *f; 85 86 if ((u = fetchParseURL(URL)) == NULL) 87 return NULL; 88 89 f = fetchGet(u, flags); 90 91 fetchFreeURL(u); 92 return f; 93} 94 95 96/* put URL */ 97FILE * 98fetchPutURL(char *URL, char *flags) 99{ 100 url_t *u; 101 FILE *f; 102 103 if ((u = fetchParseURL(URL)) == NULL) 104 return NULL; 105 106 f = fetchPut(u, flags); 107 108 fetchFreeURL(u); 109 return f; 110} 111 112/* 113 * Split an URL into components. URL syntax is: 114 * method:[//[user[:pwd]@]host[:port]]/[document] 115 * This almost, but not quite, RFC1738 URL syntax. 116 */ 117url_t * 118fetchParseURL(char *URL) 119{ 120 char *p, *q; 121 url_t *u; 122 int i; 123 124 /* allocate url_t */ 125 if ((u = calloc(1, sizeof(url_t))) == NULL) 126 return NULL; 127 128 /* scheme name */ 129 for (i = 0; *URL && (*URL != ':'); URL++) 130 if (i < URL_SCHEMELEN) 131 u->scheme[i++] = *URL; 132 if (!URL[0] || (URL[1] != '/')) 133 goto ouch; 134 else URL++; 135 if (URL[1] != '/') { 136 p = URL; 137 goto nohost; 138 } 139 else URL += 2; 140 141 p = strpbrk(URL, "/@"); 142 if (*p == '@') { 143 /* username */ 144 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 145 if (i < URL_USERLEN) 146 u->user[i++] = *q; 147 148 /* password */ 149 if (*q == ':') 150 for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 151 if (i < URL_PWDLEN) 152 u->pwd[i++] = *q; 153 154 p++; 155 } else p = URL; 156 157 /* hostname */ 158 for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 159 if (i < MAXHOSTNAMELEN) 160 u->host[i++] = *p; 161 162 /* port */ 163 if (*p == ':') { 164 for (q = ++p; *q && (*q != '/'); q++) 165 if (isdigit(*q)) 166 u->port = u->port * 10 + (*q - '0'); 167 else return 0; /* invalid port */ 168 while (*p && (*p != '/')) 169 p++; 170 } 171 172nohost: 173 /* document */ 174 if (*p) 175 u->doc = strdup(p); 176 u->doc = strdup(*p ? p : "/"); 177 if (!u->doc) 178 goto ouch; 179 180 DEBUG(fprintf(stderr, 181 "scheme: [\033[1m%s\033[m]\n" 182 "user: [\033[1m%s\033[m]\n" 183 "password: [\033[1m%s\033[m]\n" 184 "host: [\033[1m%s\033[m]\n" 185 "port: [\033[1m%d\033[m]\n" 186 "document: [\033[1m%s\033[m]\n", 187 u->scheme, u->user, u->pwd, 188 u->host, u->port, u->doc)); 189 190 return u; 191 192ouch: 193 free(u); 194 return NULL; 195} 196 197void 198fetchFreeURL(url_t *u) 199{ 200 if (u) { 201 if (u->doc) 202 free(u->doc); 203 free(u); 204 } 205} 206 207int 208fetchConnect(char *host, int port) 209{ 210 struct sockaddr_in sin; 211 struct hostent *he; 212 int sd; 213 214#ifndef NDEBUG 215 fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port); 216#endif 217 218 /* look up host name */ 219 if ((he = gethostbyname(host)) == NULL) 220 return -1; 221 222 /* set up socket address structure */ 223 bzero(&sin, sizeof(sin)); 224 bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); 225 sin.sin_family = he->h_addrtype; 226 sin.sin_port = htons(port); 227 228 /* try to connect */ 229 if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1) 230 return -1; 231 if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) { 232 close(sd); 233 return -1; 234 } 235 236 return sd; 237} 238