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.7 1998/12/16 10:24:54 des Exp $ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/errno.h> 33 34 #include <ctype.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 #include "fetch.h" 40 #include "common.h" 41 42 43 int fetchLastErrCode; 44 45 46 /*** Local data **************************************************************/ 47 48 /* 49 * Error messages for parser errors 50 */ 51 #define URL_MALFORMED 1 52 #define URL_BAD_SCHEME 2 53 #define URL_BAD_PORT 3 54 static struct fetcherr _url_errlist[] = { 55 { URL_MALFORMED, FETCH_URL, "Malformed URL" }, 56 { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" }, 57 { URL_BAD_PORT, FETCH_URL, "Invalid server port" }, 58 { -1, FETCH_UNKNOWN, "Unknown parser error" } 59 }; 60 61 62 /*** Public API **************************************************************/ 63 64 /* 65 * Select the appropriate protocol for the URL scheme, and return a 66 * read-only stream connected to the document referenced by the URL. 67 */ 68 FILE * 69 fetchGet(struct url *URL, char *flags) 70 { 71 if (strcasecmp(URL->scheme, "file") == 0) 72 return fetchGetFile(URL, flags); 73 else if (strcasecmp(URL->scheme, "http") == 0) 74 return fetchGetHTTP(URL, flags); 75 else if (strcasecmp(URL->scheme, "ftp") == 0) 76 return fetchGetFTP(URL, flags); 77 else { 78 _url_seterr(URL_BAD_SCHEME); 79 return NULL; 80 } 81 } 82 83 /* 84 * Select the appropriate protocol for the URL scheme, and return a 85 * write-only stream connected to the document referenced by the URL. 86 */ 87 FILE * 88 fetchPut(struct url *URL, char *flags) 89 { 90 if (strcasecmp(URL->scheme, "file") == 0) 91 return fetchPutFile(URL, flags); 92 else if (strcasecmp(URL->scheme, "http") == 0) 93 return fetchPutHTTP(URL, flags); 94 else if (strcasecmp(URL->scheme, "ftp") == 0) 95 return fetchPutFTP(URL, flags); 96 else { 97 _url_seterr(URL_BAD_SCHEME); 98 return NULL; 99 } 100 } 101 102 /* 103 * Select the appropriate protocol for the URL scheme, and return the 104 * size of the document referenced by the URL if it exists. 105 */ 106 int 107 fetchStat(struct url *URL, struct url_stat *us, char *flags) 108 { 109 if (strcasecmp(URL->scheme, "file") == 0) 110 return fetchStatFile(URL, us, flags); 111 else if (strcasecmp(URL->scheme, "http") == 0) 112 return fetchStatHTTP(URL, us, flags); 113 else if (strcasecmp(URL->scheme, "ftp") == 0) 114 return fetchStatFTP(URL, us, flags); 115 else { 116 _url_seterr(URL_BAD_SCHEME); 117 return -1; 118 } 119 } 120 121 /* 122 * Select the appropriate protocol for the URL scheme, and return a 123 * list of files in the directory pointed to by the URL. 124 */ 125 struct url_ent * 126 fetchList(struct url *URL, char *flags) 127 { 128 if (strcasecmp(URL->scheme, "file") == 0) 129 return fetchListFile(URL, flags); 130 else if (strcasecmp(URL->scheme, "http") == 0) 131 return fetchListHTTP(URL, flags); 132 else if (strcasecmp(URL->scheme, "ftp") == 0) 133 return fetchListFTP(URL, flags); 134 else { 135 _url_seterr(URL_BAD_SCHEME); 136 return NULL; 137 } 138 } 139 140 /* 141 * Attempt to parse the given URL; if successful, call fetchGet(). 142 */ 143 FILE * 144 fetchGetURL(char *URL, char *flags) 145 { 146 struct url *u; 147 FILE *f; 148 149 if ((u = fetchParseURL(URL)) == NULL) 150 return NULL; 151 152 f = fetchGet(u, flags); 153 154 free(u); 155 return f; 156 } 157 158 159 /* 160 * Attempt to parse the given URL; if successful, call fetchPut(). 161 */ 162 FILE * 163 fetchPutURL(char *URL, char *flags) 164 { 165 struct url *u; 166 FILE *f; 167 168 if ((u = fetchParseURL(URL)) == NULL) 169 return NULL; 170 171 f = fetchPut(u, flags); 172 173 free(u); 174 return f; 175 } 176 177 /* 178 * Attempt to parse the given URL; if successful, call fetchStat(). 179 */ 180 int 181 fetchStatURL(char *URL, struct url_stat *us, char *flags) 182 { 183 struct url *u; 184 int s; 185 186 if ((u = fetchParseURL(URL)) == NULL) 187 return -1; 188 189 s = fetchStat(u, us, flags); 190 191 free(u); 192 return s; 193 } 194 195 /* 196 * Attempt to parse the given URL; if successful, call fetchList(). 197 */ 198 struct url_ent * 199 fetchListURL(char *URL, char *flags) 200 { 201 struct url *u; 202 struct url_ent *ue; 203 204 if ((u = fetchParseURL(URL)) == NULL) 205 return NULL; 206 207 ue = fetchList(u, flags); 208 209 free(u); 210 return ue; 211 } 212 213 /* 214 * Split an URL into components. URL syntax is: 215 * method:[//[user[:pwd]@]host[:port]]/[document] 216 * This almost, but not quite, RFC1738 URL syntax. 217 */ 218 struct url * 219 fetchParseURL(char *URL) 220 { 221 char *p, *q; 222 struct url *u; 223 int i; 224 225 /* allocate struct url */ 226 if ((u = calloc(1, sizeof(struct url))) == NULL) { 227 errno = ENOMEM; 228 _fetch_syserr(); 229 return NULL; 230 } 231 232 /* scheme name */ 233 for (i = 0; *URL && (*URL != ':'); URL++) 234 if (i < URL_SCHEMELEN) 235 u->scheme[i++] = *URL; 236 if (!URL[0] || (URL[1] != '/')) { 237 _url_seterr(URL_BAD_SCHEME); 238 goto ouch; 239 } 240 else URL++; 241 if (URL[1] != '/') { 242 p = URL; 243 goto nohost; 244 } 245 else URL += 2; 246 247 p = strpbrk(URL, "/@"); 248 if (p && *p == '@') { 249 /* username */ 250 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 251 if (i < URL_USERLEN) 252 u->user[i++] = *q; 253 254 /* password */ 255 if (*q == ':') 256 for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 257 if (i < URL_PWDLEN) 258 u->pwd[i++] = *q; 259 260 p++; 261 } else p = URL; 262 263 /* hostname */ 264 for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 265 if (i < MAXHOSTNAMELEN) 266 u->host[i++] = *p; 267 268 /* port */ 269 if (*p == ':') { 270 for (q = ++p; *q && (*q != '/'); q++) 271 if (isdigit(*q)) 272 u->port = u->port * 10 + (*q - '0'); 273 else { 274 /* invalid port */ 275 _url_seterr(URL_BAD_PORT); 276 goto ouch; 277 } 278 while (*p && (*p != '/')) 279 p++; 280 } 281 282 nohost: 283 /* document */ 284 if (*p) { 285 struct url *t; 286 t = realloc(u, sizeof(*u)+strlen(p)-1); 287 if (t == NULL) { 288 errno = ENOMEM; 289 _fetch_syserr(); 290 goto ouch; 291 } 292 u = t; 293 strcpy(u->doc, p); 294 } else { 295 u->doc[0] = '/'; 296 u->doc[1] = 0; 297 } 298 299 DEBUG(fprintf(stderr, 300 "scheme: [\033[1m%s\033[m]\n" 301 "user: [\033[1m%s\033[m]\n" 302 "password: [\033[1m%s\033[m]\n" 303 "host: [\033[1m%s\033[m]\n" 304 "port: [\033[1m%d\033[m]\n" 305 "document: [\033[1m%s\033[m]\n", 306 u->scheme, u->user, u->pwd, 307 u->host, u->port, u->doc)); 308 309 return u; 310 311 ouch: 312 free(u); 313 return NULL; 314 } 315