14ca1ab94SDag-Erling Smørgrav /*- 24ca1ab94SDag-Erling Smørgrav * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 34ca1ab94SDag-Erling Smørgrav * All rights reserved. 44ca1ab94SDag-Erling Smørgrav * 54ca1ab94SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 64ca1ab94SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 74ca1ab94SDag-Erling Smørgrav * are met: 84ca1ab94SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 94ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 104ca1ab94SDag-Erling Smørgrav * in this position and unchanged. 114ca1ab94SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 124ca1ab94SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 134ca1ab94SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 144ca1ab94SDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 154ca1ab94SDag-Erling Smørgrav * derived from this software without specific prior written permission 164ca1ab94SDag-Erling Smørgrav * 174ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 184ca1ab94SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 194ca1ab94SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 204ca1ab94SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 214ca1ab94SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 224ca1ab94SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234ca1ab94SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244ca1ab94SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254ca1ab94SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 264ca1ab94SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274ca1ab94SDag-Erling Smørgrav */ 284ca1ab94SDag-Erling Smørgrav 29cecb889fSMatthew Dillon #include <sys/cdefs.h> 30cecb889fSMatthew Dillon __FBSDID("$FreeBSD$"); 31cecb889fSMatthew Dillon 324ca1ab94SDag-Erling Smørgrav #include <sys/param.h> 33d8acd8dcSDag-Erling Smørgrav #include <sys/errno.h> 344ca1ab94SDag-Erling Smørgrav 354ca1ab94SDag-Erling Smørgrav #include <ctype.h> 364ca1ab94SDag-Erling Smørgrav #include <stdio.h> 374ca1ab94SDag-Erling Smørgrav #include <stdlib.h> 384ca1ab94SDag-Erling Smørgrav #include <string.h> 394ca1ab94SDag-Erling Smørgrav 404ca1ab94SDag-Erling Smørgrav #include "fetch.h" 41d8acd8dcSDag-Erling Smørgrav #include "common.h" 424ca1ab94SDag-Erling Smørgrav 436490b215SDag-Erling Smørgrav auth_t fetchAuthMethod; 440fba3a00SDag-Erling Smørgrav int fetchLastErrCode; 45ba101983SDag-Erling Smørgrav char fetchLastErrString[MAXERRSTRING]; 46fc6e9e65SDag-Erling Smørgrav int fetchTimeout; 47a1bb3f48SDag-Erling Smørgrav int fetchRestartCalls = 1; 487eb2f34dSDag-Erling Smørgrav int fetchDebug; 490fba3a00SDag-Erling Smørgrav 500fba3a00SDag-Erling Smørgrav 51d8acd8dcSDag-Erling Smørgrav /*** Local data **************************************************************/ 52d8acd8dcSDag-Erling Smørgrav 53d8acd8dcSDag-Erling Smørgrav /* 54d8acd8dcSDag-Erling Smørgrav * Error messages for parser errors 55d8acd8dcSDag-Erling Smørgrav */ 56d8acd8dcSDag-Erling Smørgrav #define URL_MALFORMED 1 57d8acd8dcSDag-Erling Smørgrav #define URL_BAD_SCHEME 2 58d8acd8dcSDag-Erling Smørgrav #define URL_BAD_PORT 3 59d8acd8dcSDag-Erling Smørgrav static struct fetcherr _url_errlist[] = { 60d8acd8dcSDag-Erling Smørgrav { URL_MALFORMED, FETCH_URL, "Malformed URL" }, 61d8acd8dcSDag-Erling Smørgrav { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" }, 62d8acd8dcSDag-Erling Smørgrav { URL_BAD_PORT, FETCH_URL, "Invalid server port" }, 63d8acd8dcSDag-Erling Smørgrav { -1, FETCH_UNKNOWN, "Unknown parser error" } 64d8acd8dcSDag-Erling Smørgrav }; 65d8acd8dcSDag-Erling Smørgrav 66d8acd8dcSDag-Erling Smørgrav 67d8acd8dcSDag-Erling Smørgrav /*** Public API **************************************************************/ 684ca1ab94SDag-Erling Smørgrav 69842a95ccSDag-Erling Smørgrav /* 70842a95ccSDag-Erling Smørgrav * Select the appropriate protocol for the URL scheme, and return a 71842a95ccSDag-Erling Smørgrav * read-only stream connected to the document referenced by the URL. 721a5faa10SDag-Erling Smørgrav * Also fill out the struct url_stat. 73842a95ccSDag-Erling Smørgrav */ 74ecc91352SDag-Erling Smørgrav FILE * 7538c7e4a6SArchie Cobbs fetchXGet(struct url *URL, struct url_stat *us, const char *flags) 76ecc91352SDag-Erling Smørgrav { 77c97925adSHajimu UMEMOTO int direct; 78c97925adSHajimu UMEMOTO 79d74a913bSDag-Erling Smørgrav direct = CHECK_FLAG('d'); 8059769ab1SDag-Erling Smørgrav if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) 81e19e6098SDag-Erling Smørgrav return (fetchXGetFile(URL, us, flags)); 82111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) 83111e2510SDag-Erling Smørgrav return (fetchXGetFTP(URL, us, flags)); 8459769ab1SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) 85e19e6098SDag-Erling Smørgrav return (fetchXGetHTTP(URL, us, flags)); 86111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) 87111e2510SDag-Erling Smørgrav return (fetchXGetHTTP(URL, us, flags)); 88d8acd8dcSDag-Erling Smørgrav _url_seterr(URL_BAD_SCHEME); 89e19e6098SDag-Erling Smørgrav return (NULL); 90d8acd8dcSDag-Erling Smørgrav } 91ecc91352SDag-Erling Smørgrav 92842a95ccSDag-Erling Smørgrav /* 93842a95ccSDag-Erling Smørgrav * Select the appropriate protocol for the URL scheme, and return a 941a5faa10SDag-Erling Smørgrav * read-only stream connected to the document referenced by the URL. 951a5faa10SDag-Erling Smørgrav */ 961a5faa10SDag-Erling Smørgrav FILE * 9738c7e4a6SArchie Cobbs fetchGet(struct url *URL, const char *flags) 981a5faa10SDag-Erling Smørgrav { 99e19e6098SDag-Erling Smørgrav return (fetchXGet(URL, NULL, flags)); 1001a5faa10SDag-Erling Smørgrav } 1011a5faa10SDag-Erling Smørgrav 1021a5faa10SDag-Erling Smørgrav /* 1031a5faa10SDag-Erling Smørgrav * Select the appropriate protocol for the URL scheme, and return a 104842a95ccSDag-Erling Smørgrav * write-only stream connected to the document referenced by the URL. 105842a95ccSDag-Erling Smørgrav */ 106ecc91352SDag-Erling Smørgrav FILE * 10738c7e4a6SArchie Cobbs fetchPut(struct url *URL, const char *flags) 108ecc91352SDag-Erling Smørgrav { 109c97925adSHajimu UMEMOTO int direct; 110c97925adSHajimu UMEMOTO 111d74a913bSDag-Erling Smørgrav direct = CHECK_FLAG('d'); 11259769ab1SDag-Erling Smørgrav if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) 113e19e6098SDag-Erling Smørgrav return (fetchPutFile(URL, flags)); 114111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) 115111e2510SDag-Erling Smørgrav return (fetchPutFTP(URL, flags)); 11659769ab1SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) 117e19e6098SDag-Erling Smørgrav return (fetchPutHTTP(URL, flags)); 118111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) 119111e2510SDag-Erling Smørgrav return (fetchPutHTTP(URL, flags)); 120d8acd8dcSDag-Erling Smørgrav _url_seterr(URL_BAD_SCHEME); 121e19e6098SDag-Erling Smørgrav return (NULL); 122d8acd8dcSDag-Erling Smørgrav } 123d8acd8dcSDag-Erling Smørgrav 124d8acd8dcSDag-Erling Smørgrav /* 125d8acd8dcSDag-Erling Smørgrav * Select the appropriate protocol for the URL scheme, and return the 126d8acd8dcSDag-Erling Smørgrav * size of the document referenced by the URL if it exists. 127d8acd8dcSDag-Erling Smørgrav */ 128d8acd8dcSDag-Erling Smørgrav int 12938c7e4a6SArchie Cobbs fetchStat(struct url *URL, struct url_stat *us, const char *flags) 130d8acd8dcSDag-Erling Smørgrav { 131c97925adSHajimu UMEMOTO int direct; 132c97925adSHajimu UMEMOTO 133d74a913bSDag-Erling Smørgrav direct = CHECK_FLAG('d'); 13459769ab1SDag-Erling Smørgrav if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) 135e19e6098SDag-Erling Smørgrav return (fetchStatFile(URL, us, flags)); 136e19e6098SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) 137e19e6098SDag-Erling Smørgrav return (fetchStatFTP(URL, us, flags)); 138111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) 139111e2510SDag-Erling Smørgrav return (fetchStatHTTP(URL, us, flags)); 140111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) 141111e2510SDag-Erling Smørgrav return (fetchStatHTTP(URL, us, flags)); 142d8acd8dcSDag-Erling Smørgrav _url_seterr(URL_BAD_SCHEME); 143e19e6098SDag-Erling Smørgrav return (-1); 144ecc91352SDag-Erling Smørgrav } 145ecc91352SDag-Erling Smørgrav 146842a95ccSDag-Erling Smørgrav /* 147ce71b736SDag-Erling Smørgrav * Select the appropriate protocol for the URL scheme, and return a 148ce71b736SDag-Erling Smørgrav * list of files in the directory pointed to by the URL. 149ce71b736SDag-Erling Smørgrav */ 150ce71b736SDag-Erling Smørgrav struct url_ent * 15138c7e4a6SArchie Cobbs fetchList(struct url *URL, const char *flags) 152ce71b736SDag-Erling Smørgrav { 153c97925adSHajimu UMEMOTO int direct; 154c97925adSHajimu UMEMOTO 155d74a913bSDag-Erling Smørgrav direct = CHECK_FLAG('d'); 15659769ab1SDag-Erling Smørgrav if (strcasecmp(URL->scheme, SCHEME_FILE) == 0) 157e19e6098SDag-Erling Smørgrav return (fetchListFile(URL, flags)); 158e19e6098SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) 159e19e6098SDag-Erling Smørgrav return (fetchListFTP(URL, flags)); 160111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0) 161111e2510SDag-Erling Smørgrav return (fetchListHTTP(URL, flags)); 162111e2510SDag-Erling Smørgrav else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0) 163111e2510SDag-Erling Smørgrav return (fetchListHTTP(URL, flags)); 164ce71b736SDag-Erling Smørgrav _url_seterr(URL_BAD_SCHEME); 165e19e6098SDag-Erling Smørgrav return (NULL); 166ce71b736SDag-Erling Smørgrav } 167ce71b736SDag-Erling Smørgrav 168ce71b736SDag-Erling Smørgrav /* 1691a5faa10SDag-Erling Smørgrav * Attempt to parse the given URL; if successful, call fetchXGet(). 170842a95ccSDag-Erling Smørgrav */ 1714ca1ab94SDag-Erling Smørgrav FILE * 17238c7e4a6SArchie Cobbs fetchXGetURL(const char *URL, struct url_stat *us, const char *flags) 1734ca1ab94SDag-Erling Smørgrav { 174d8acd8dcSDag-Erling Smørgrav struct url *u; 1754ca1ab94SDag-Erling Smørgrav FILE *f; 1764ca1ab94SDag-Erling Smørgrav 1774ca1ab94SDag-Erling Smørgrav if ((u = fetchParseURL(URL)) == NULL) 178e19e6098SDag-Erling Smørgrav return (NULL); 1794ca1ab94SDag-Erling Smørgrav 1801a5faa10SDag-Erling Smørgrav f = fetchXGet(u, us, flags); 1814ca1ab94SDag-Erling Smørgrav 18260245e42SDag-Erling Smørgrav fetchFreeURL(u); 183e19e6098SDag-Erling Smørgrav return (f); 1844ca1ab94SDag-Erling Smørgrav } 1854ca1ab94SDag-Erling Smørgrav 1861a5faa10SDag-Erling Smørgrav /* 1871a5faa10SDag-Erling Smørgrav * Attempt to parse the given URL; if successful, call fetchGet(). 1881a5faa10SDag-Erling Smørgrav */ 1891a5faa10SDag-Erling Smørgrav FILE * 19038c7e4a6SArchie Cobbs fetchGetURL(const char *URL, const char *flags) 1911a5faa10SDag-Erling Smørgrav { 192e19e6098SDag-Erling Smørgrav return (fetchXGetURL(URL, NULL, flags)); 1931a5faa10SDag-Erling Smørgrav } 1944ca1ab94SDag-Erling Smørgrav 195842a95ccSDag-Erling Smørgrav /* 196842a95ccSDag-Erling Smørgrav * Attempt to parse the given URL; if successful, call fetchPut(). 197842a95ccSDag-Erling Smørgrav */ 1984ca1ab94SDag-Erling Smørgrav FILE * 19938c7e4a6SArchie Cobbs fetchPutURL(const char *URL, const char *flags) 2004ca1ab94SDag-Erling Smørgrav { 201d8acd8dcSDag-Erling Smørgrav struct url *u; 2024ca1ab94SDag-Erling Smørgrav FILE *f; 2034ca1ab94SDag-Erling Smørgrav 2044ca1ab94SDag-Erling Smørgrav if ((u = fetchParseURL(URL)) == NULL) 205e19e6098SDag-Erling Smørgrav return (NULL); 2064ca1ab94SDag-Erling Smørgrav 207ecc91352SDag-Erling Smørgrav f = fetchPut(u, flags); 2084ca1ab94SDag-Erling Smørgrav 20960245e42SDag-Erling Smørgrav fetchFreeURL(u); 210e19e6098SDag-Erling Smørgrav return (f); 2114ca1ab94SDag-Erling Smørgrav } 2124ca1ab94SDag-Erling Smørgrav 2134ca1ab94SDag-Erling Smørgrav /* 214d8acd8dcSDag-Erling Smørgrav * Attempt to parse the given URL; if successful, call fetchStat(). 215d8acd8dcSDag-Erling Smørgrav */ 216d8acd8dcSDag-Erling Smørgrav int 21738c7e4a6SArchie Cobbs fetchStatURL(const char *URL, struct url_stat *us, const char *flags) 218d8acd8dcSDag-Erling Smørgrav { 219d8acd8dcSDag-Erling Smørgrav struct url *u; 220d8acd8dcSDag-Erling Smørgrav int s; 221d8acd8dcSDag-Erling Smørgrav 222d8acd8dcSDag-Erling Smørgrav if ((u = fetchParseURL(URL)) == NULL) 223e19e6098SDag-Erling Smørgrav return (-1); 224d8acd8dcSDag-Erling Smørgrav 225d8acd8dcSDag-Erling Smørgrav s = fetchStat(u, us, flags); 226d8acd8dcSDag-Erling Smørgrav 22760245e42SDag-Erling Smørgrav fetchFreeURL(u); 228e19e6098SDag-Erling Smørgrav return (s); 229d8acd8dcSDag-Erling Smørgrav } 230d8acd8dcSDag-Erling Smørgrav 231d8acd8dcSDag-Erling Smørgrav /* 232ce71b736SDag-Erling Smørgrav * Attempt to parse the given URL; if successful, call fetchList(). 233ce71b736SDag-Erling Smørgrav */ 234ce71b736SDag-Erling Smørgrav struct url_ent * 23538c7e4a6SArchie Cobbs fetchListURL(const char *URL, const char *flags) 236ce71b736SDag-Erling Smørgrav { 237ce71b736SDag-Erling Smørgrav struct url *u; 238ce71b736SDag-Erling Smørgrav struct url_ent *ue; 239ce71b736SDag-Erling Smørgrav 240ce71b736SDag-Erling Smørgrav if ((u = fetchParseURL(URL)) == NULL) 241e19e6098SDag-Erling Smørgrav return (NULL); 242ce71b736SDag-Erling Smørgrav 243ce71b736SDag-Erling Smørgrav ue = fetchList(u, flags); 244ce71b736SDag-Erling Smørgrav 24560245e42SDag-Erling Smørgrav fetchFreeURL(u); 246e19e6098SDag-Erling Smørgrav return (ue); 247ce71b736SDag-Erling Smørgrav } 248ce71b736SDag-Erling Smørgrav 249ce71b736SDag-Erling Smørgrav /* 2509a964d6aSDag-Erling Smørgrav * Make a URL 2519a964d6aSDag-Erling Smørgrav */ 2529a964d6aSDag-Erling Smørgrav struct url * 25338c7e4a6SArchie Cobbs fetchMakeURL(const char *scheme, const char *host, int port, const char *doc, 25438c7e4a6SArchie Cobbs const char *user, const char *pwd) 2559a964d6aSDag-Erling Smørgrav { 2569a964d6aSDag-Erling Smørgrav struct url *u; 2579a964d6aSDag-Erling Smørgrav 2589a964d6aSDag-Erling Smørgrav if (!scheme || (!host && !doc)) { 2599a964d6aSDag-Erling Smørgrav _url_seterr(URL_MALFORMED); 260e19e6098SDag-Erling Smørgrav return (NULL); 2619a964d6aSDag-Erling Smørgrav } 2629a964d6aSDag-Erling Smørgrav 2639a964d6aSDag-Erling Smørgrav if (port < 0 || port > 65535) { 2649a964d6aSDag-Erling Smørgrav _url_seterr(URL_BAD_PORT); 265e19e6098SDag-Erling Smørgrav return (NULL); 2669a964d6aSDag-Erling Smørgrav } 2679a964d6aSDag-Erling Smørgrav 2689a964d6aSDag-Erling Smørgrav /* allocate struct url */ 2699a964d6aSDag-Erling Smørgrav if ((u = calloc(1, sizeof *u)) == NULL) { 2709a964d6aSDag-Erling Smørgrav _fetch_syserr(); 271e19e6098SDag-Erling Smørgrav return (NULL); 2729a964d6aSDag-Erling Smørgrav } 2739a964d6aSDag-Erling Smørgrav 2749a964d6aSDag-Erling Smørgrav if ((u->doc = strdup(doc ? doc : "/")) == NULL) { 2759a964d6aSDag-Erling Smørgrav _fetch_syserr(); 2769a964d6aSDag-Erling Smørgrav free(u); 277e19e6098SDag-Erling Smørgrav return (NULL); 2789a964d6aSDag-Erling Smørgrav } 2799a964d6aSDag-Erling Smørgrav 2809a964d6aSDag-Erling Smørgrav #define seturl(x) snprintf(u->x, sizeof u->x, "%s", x) 2819a964d6aSDag-Erling Smørgrav seturl(scheme); 2829a964d6aSDag-Erling Smørgrav seturl(host); 2839a964d6aSDag-Erling Smørgrav seturl(user); 2849a964d6aSDag-Erling Smørgrav seturl(pwd); 2859a964d6aSDag-Erling Smørgrav #undef seturl 2869a964d6aSDag-Erling Smørgrav u->port = port; 2879a964d6aSDag-Erling Smørgrav 288e19e6098SDag-Erling Smørgrav return (u); 2899a964d6aSDag-Erling Smørgrav } 2909a964d6aSDag-Erling Smørgrav 2919a964d6aSDag-Erling Smørgrav /* 2924ca1ab94SDag-Erling Smørgrav * Split an URL into components. URL syntax is: 29359769ab1SDag-Erling Smørgrav * [method:/][/[user[:pwd]@]host[:port]/][document] 2944ca1ab94SDag-Erling Smørgrav * This almost, but not quite, RFC1738 URL syntax. 2954ca1ab94SDag-Erling Smørgrav */ 296d8acd8dcSDag-Erling Smørgrav struct url * 29738c7e4a6SArchie Cobbs fetchParseURL(const char *URL) 2984ca1ab94SDag-Erling Smørgrav { 29938c7e4a6SArchie Cobbs char *doc; 30038c7e4a6SArchie Cobbs const char *p, *q; 301d8acd8dcSDag-Erling Smørgrav struct url *u; 3024ca1ab94SDag-Erling Smørgrav int i; 3034ca1ab94SDag-Erling Smørgrav 304d8acd8dcSDag-Erling Smørgrav /* allocate struct url */ 305807c941cSDag-Erling Smørgrav if ((u = calloc(1, sizeof *u)) == NULL) { 306d8acd8dcSDag-Erling Smørgrav _fetch_syserr(); 307e19e6098SDag-Erling Smørgrav return (NULL); 308d8acd8dcSDag-Erling Smørgrav } 3094ca1ab94SDag-Erling Smørgrav 3104ca1ab94SDag-Erling Smørgrav /* scheme name */ 31159769ab1SDag-Erling Smørgrav if ((p = strstr(URL, ":/"))) { 312e19e6098SDag-Erling Smørgrav snprintf(u->scheme, URL_SCHEMELEN+1, 313e19e6098SDag-Erling Smørgrav "%.*s", (int)(p - URL), URL); 31459769ab1SDag-Erling Smørgrav URL = ++p; 31559769ab1SDag-Erling Smørgrav /* 31659769ab1SDag-Erling Smørgrav * Only one slash: no host, leave slash as part of document 31759769ab1SDag-Erling Smørgrav * Two slashes: host follows, strip slashes 31859769ab1SDag-Erling Smørgrav */ 31959769ab1SDag-Erling Smørgrav if (URL[1] == '/') 32059769ab1SDag-Erling Smørgrav URL = (p += 2); 3211ba84976SDag-Erling Smørgrav } else { 3221ba84976SDag-Erling Smørgrav p = URL; 323d8acd8dcSDag-Erling Smørgrav } 3245b2ad516SDag-Erling Smørgrav if (!*URL || *URL == '/' || *URL == '.' || 32573b3e4dfSStefan Eßer (u->scheme[0] == '\0' && 32673b3e4dfSStefan Eßer strchr(URL, '/') == NULL && strchr(URL, ':') == NULL)) 3274ca1ab94SDag-Erling Smørgrav goto nohost; 3284ca1ab94SDag-Erling Smørgrav 3294ca1ab94SDag-Erling Smørgrav p = strpbrk(URL, "/@"); 3300fba3a00SDag-Erling Smørgrav if (p && *p == '@') { 3314ca1ab94SDag-Erling Smørgrav /* username */ 3324ca1ab94SDag-Erling Smørgrav for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) 3334ca1ab94SDag-Erling Smørgrav if (i < URL_USERLEN) 3344ca1ab94SDag-Erling Smørgrav u->user[i++] = *q; 3354ca1ab94SDag-Erling Smørgrav 3364ca1ab94SDag-Erling Smørgrav /* password */ 3374ca1ab94SDag-Erling Smørgrav if (*q == ':') 3384ca1ab94SDag-Erling Smørgrav for (q++, i = 0; (*q != ':') && (*q != '@'); q++) 3394ca1ab94SDag-Erling Smørgrav if (i < URL_PWDLEN) 3404ca1ab94SDag-Erling Smørgrav u->pwd[i++] = *q; 3414ca1ab94SDag-Erling Smørgrav 3424ca1ab94SDag-Erling Smørgrav p++; 343ab39353eSDag-Erling Smørgrav } else { 344ab39353eSDag-Erling Smørgrav p = URL; 345ab39353eSDag-Erling Smørgrav } 3464ca1ab94SDag-Erling Smørgrav 3474ca1ab94SDag-Erling Smørgrav /* hostname */ 34828c645cfSHajimu UMEMOTO #ifdef INET6 34928c645cfSHajimu UMEMOTO if (*p == '[' && (q = strchr(p + 1, ']')) != NULL && 35028c645cfSHajimu UMEMOTO (*++q == '\0' || *q == '/' || *q == ':')) { 35128c645cfSHajimu UMEMOTO if ((i = q - p - 2) > MAXHOSTNAMELEN) 35228c645cfSHajimu UMEMOTO i = MAXHOSTNAMELEN; 35328c645cfSHajimu UMEMOTO strncpy(u->host, ++p, i); 35428c645cfSHajimu UMEMOTO p = q; 35528c645cfSHajimu UMEMOTO } else 35628c645cfSHajimu UMEMOTO #endif 3574ca1ab94SDag-Erling Smørgrav for (i = 0; *p && (*p != '/') && (*p != ':'); p++) 3584ca1ab94SDag-Erling Smørgrav if (i < MAXHOSTNAMELEN) 3594ca1ab94SDag-Erling Smørgrav u->host[i++] = *p; 3604ca1ab94SDag-Erling Smørgrav 3614ca1ab94SDag-Erling Smørgrav /* port */ 3624ca1ab94SDag-Erling Smørgrav if (*p == ':') { 3634ca1ab94SDag-Erling Smørgrav for (q = ++p; *q && (*q != '/'); q++) 3644ca1ab94SDag-Erling Smørgrav if (isdigit(*q)) 3654ca1ab94SDag-Erling Smørgrav u->port = u->port * 10 + (*q - '0'); 366d8acd8dcSDag-Erling Smørgrav else { 367d8acd8dcSDag-Erling Smørgrav /* invalid port */ 368d8acd8dcSDag-Erling Smørgrav _url_seterr(URL_BAD_PORT); 369d8acd8dcSDag-Erling Smørgrav goto ouch; 370d8acd8dcSDag-Erling Smørgrav } 371551858f0SDag-Erling Smørgrav p = q; 3724ca1ab94SDag-Erling Smørgrav } 3734ca1ab94SDag-Erling Smørgrav 3744ca1ab94SDag-Erling Smørgrav nohost: 3754ca1ab94SDag-Erling Smørgrav /* document */ 37660245e42SDag-Erling Smørgrav if (!*p) 37760245e42SDag-Erling Smørgrav p = "/"; 37860245e42SDag-Erling Smørgrav 379f9c2053bSDag-Erling Smørgrav if (strcasecmp(u->scheme, SCHEME_HTTP) == 0 || 380f9c2053bSDag-Erling Smørgrav strcasecmp(u->scheme, SCHEME_HTTPS) == 0) { 38123fe6d7aSDag-Erling Smørgrav const char hexnums[] = "0123456789abcdef"; 38223fe6d7aSDag-Erling Smørgrav 383f9c2053bSDag-Erling Smørgrav /* percent-escape whitespace. */ 384f9c2053bSDag-Erling Smørgrav if ((doc = malloc(strlen(p) * 3 + 1)) == NULL) { 38523fe6d7aSDag-Erling Smørgrav _fetch_syserr(); 38623fe6d7aSDag-Erling Smørgrav goto ouch; 38723fe6d7aSDag-Erling Smørgrav } 388f9c2053bSDag-Erling Smørgrav u->doc = doc; 38923fe6d7aSDag-Erling Smørgrav while (*p != '\0') { 39023fe6d7aSDag-Erling Smørgrav if (!isspace(*p)) { 39123fe6d7aSDag-Erling Smørgrav *doc++ = *p++; 39223fe6d7aSDag-Erling Smørgrav } else { 39323fe6d7aSDag-Erling Smørgrav *doc++ = '%'; 39423fe6d7aSDag-Erling Smørgrav *doc++ = hexnums[((unsigned int)*p) >> 4]; 39523fe6d7aSDag-Erling Smørgrav *doc++ = hexnums[((unsigned int)*p) & 0xf]; 39623fe6d7aSDag-Erling Smørgrav p++; 39723fe6d7aSDag-Erling Smørgrav } 39823fe6d7aSDag-Erling Smørgrav } 39923fe6d7aSDag-Erling Smørgrav *doc = '\0'; 40023fe6d7aSDag-Erling Smørgrav } else if ((u->doc = strdup(p)) == NULL) { 401d8acd8dcSDag-Erling Smørgrav _fetch_syserr(); 4024ca1ab94SDag-Erling Smørgrav goto ouch; 403d8acd8dcSDag-Erling Smørgrav } 4044ca1ab94SDag-Erling Smørgrav 4054ca1ab94SDag-Erling Smørgrav DEBUG(fprintf(stderr, 406f67efa37SDag-Erling Smørgrav "scheme: [%s]\n" 407f67efa37SDag-Erling Smørgrav "user: [%s]\n" 408f67efa37SDag-Erling Smørgrav "password: [%s]\n" 409f67efa37SDag-Erling Smørgrav "host: [%s]\n" 410f67efa37SDag-Erling Smørgrav "port: [%d]\n" 411f67efa37SDag-Erling Smørgrav "document: [%s]\n", 4124ca1ab94SDag-Erling Smørgrav u->scheme, u->user, u->pwd, 4134ca1ab94SDag-Erling Smørgrav u->host, u->port, u->doc)); 4144ca1ab94SDag-Erling Smørgrav 415e19e6098SDag-Erling Smørgrav return (u); 4164ca1ab94SDag-Erling Smørgrav 4174ca1ab94SDag-Erling Smørgrav ouch: 4184ca1ab94SDag-Erling Smørgrav free(u); 419e19e6098SDag-Erling Smørgrav return (NULL); 4204ca1ab94SDag-Erling Smørgrav } 42160245e42SDag-Erling Smørgrav 42260245e42SDag-Erling Smørgrav /* 42360245e42SDag-Erling Smørgrav * Free a URL 42460245e42SDag-Erling Smørgrav */ 42560245e42SDag-Erling Smørgrav void 42660245e42SDag-Erling Smørgrav fetchFreeURL(struct url *u) 42760245e42SDag-Erling Smørgrav { 42860245e42SDag-Erling Smørgrav free(u->doc); 42960245e42SDag-Erling Smørgrav free(u); 43060245e42SDag-Erling Smørgrav } 431