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