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