fetch.c revision 41862
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.6 1998/11/06 22:14:08 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 43int 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 54static 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 */ 68FILE * 69fetchGet(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 */ 87FILE * 88fetchPut(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 */ 106int 107fetchStat(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 * Attempt to parse the given URL; if successful, call fetchGet(). 123 */ 124FILE * 125fetchGetURL(char *URL, char *flags) 126{ 127 struct url *u; 128 FILE *f; 129 130 if ((u = fetchParseURL(URL)) == NULL) 131 return NULL; 132 133 f = fetchGet(u, flags); 134 135 free(u); 136 return f; 137} 138 139 140/* 141 * Attempt to parse the given URL; if successful, call fetchPut(). 142 */ 143FILE * 144fetchPutURL(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 = fetchPut(u, flags); 153 154 free(u); 155 return f; 156} 157 158/* 159 * Attempt to parse the given URL; if successful, call fetchStat(). 160 */ 161int 162fetchStatURL(char *URL, struct url_stat *us, char *flags) 163{ 164 struct url *u; 165 int s; 166 167 if ((u = fetchParseURL(URL)) == NULL) 168 return -1; 169 170 s = fetchStat(u, us, flags); 171 172 free(u); 173 return s; 174} 175 176/* 177 * Split an URL into components. URL syntax is: 178 * method:[//[user[:pwd]@]host[:port]]/[document] 179 * This almost, but not quite, RFC1738 URL syntax. 180 */ 181struct url * 182fetchParseURL(char *URL) 183{ 184 char *p, *q; 185 struct url *u; 186 int i; 187 188 /* allocate struct url */ 189 if ((u = calloc(1, sizeof(struct url))) == NULL) { 190 errno = ENOMEM; 191 _fetch_syserr(); 192 return NULL; 193 } 194 195 /* scheme name */ 196 for (i = 0; *URL && (*URL != ':'); URL++) 197 if (i < URL_SCHEMELEN) 198 u->scheme[i++] = *URL; 199 if (!URL[0] || (URL[1] != '/')) { 200 _url_seterr(URL_BAD_SCHEME); 201 goto ouch; 202 } 203 else URL++; 204 if (URL[1] != '/') { 205 p = URL; 206 goto nohost; 207 } 208 else URL += 2; 209 210 p = strpbrk(URL, "/@"); 211 if (p && *p == '@') { 212 /* username */ 213 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 214 if (i < URL_USERLEN) 215 u->user[i++] = *q; 216 217 /* password */ 218 if (*q == ':') 219 for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 220 if (i < URL_PWDLEN) 221 u->pwd[i++] = *q; 222 223 p++; 224 } else p = URL; 225 226 /* hostname */ 227 for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 228 if (i < MAXHOSTNAMELEN) 229 u->host[i++] = *p; 230 231 /* port */ 232 if (*p == ':') { 233 for (q = ++p; *q && (*q != '/'); q++) 234 if (isdigit(*q)) 235 u->port = u->port * 10 + (*q - '0'); 236 else { 237 /* invalid port */ 238 _url_seterr(URL_BAD_PORT); 239 goto ouch; 240 } 241 while (*p && (*p != '/')) 242 p++; 243 } 244 245nohost: 246 /* document */ 247 if (*p) { 248 struct url *t; 249 t = realloc(u, sizeof(*u)+strlen(p)-1); 250 if (t == NULL) { 251 errno = ENOMEM; 252 _fetch_syserr(); 253 goto ouch; 254 } 255 u = t; 256 strcpy(u->doc, p); 257 } else { 258 u->doc[0] = '/'; 259 u->doc[1] = 0; 260 } 261 262 DEBUG(fprintf(stderr, 263 "scheme: [\033[1m%s\033[m]\n" 264 "user: [\033[1m%s\033[m]\n" 265 "password: [\033[1m%s\033[m]\n" 266 "host: [\033[1m%s\033[m]\n" 267 "port: [\033[1m%d\033[m]\n" 268 "document: [\033[1m%s\033[m]\n", 269 u->scheme, u->user, u->pwd, 270 u->host, u->port, u->doc)); 271 272 return u; 273 274ouch: 275 free(u); 276 return NULL; 277} 278