xref: /freebsd/lib/libfetch/fetch.c (revision 9a964d6a8208cca64bb33e2e06e6fdb99185bea4)
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  *
287f3dea24SPeter Wemm  * $FreeBSD$
294ca1ab94SDag-Erling Smørgrav  */
304ca1ab94SDag-Erling Smørgrav 
314ca1ab94SDag-Erling Smørgrav #include <sys/param.h>
32d8acd8dcSDag-Erling Smørgrav #include <sys/errno.h>
334ca1ab94SDag-Erling Smørgrav 
344ca1ab94SDag-Erling Smørgrav #include <ctype.h>
354ca1ab94SDag-Erling Smørgrav #include <stdio.h>
364ca1ab94SDag-Erling Smørgrav #include <stdlib.h>
374ca1ab94SDag-Erling Smørgrav #include <string.h>
384ca1ab94SDag-Erling Smørgrav 
394ca1ab94SDag-Erling Smørgrav #include "fetch.h"
40d8acd8dcSDag-Erling Smørgrav #include "common.h"
414ca1ab94SDag-Erling Smørgrav 
424ca1ab94SDag-Erling Smørgrav 
430fba3a00SDag-Erling Smørgrav int	 fetchLastErrCode;
44ba101983SDag-Erling Smørgrav char	 fetchLastErrString[MAXERRSTRING];
45fc6e9e65SDag-Erling Smørgrav int	 fetchTimeout;
460fba3a00SDag-Erling Smørgrav 
470fba3a00SDag-Erling Smørgrav 
48d8acd8dcSDag-Erling Smørgrav /*** Local data **************************************************************/
49d8acd8dcSDag-Erling Smørgrav 
50d8acd8dcSDag-Erling Smørgrav /*
51d8acd8dcSDag-Erling Smørgrav  * Error messages for parser errors
52d8acd8dcSDag-Erling Smørgrav  */
53d8acd8dcSDag-Erling Smørgrav #define URL_MALFORMED		1
54d8acd8dcSDag-Erling Smørgrav #define URL_BAD_SCHEME		2
55d8acd8dcSDag-Erling Smørgrav #define URL_BAD_PORT		3
56d8acd8dcSDag-Erling Smørgrav static struct fetcherr _url_errlist[] = {
57d8acd8dcSDag-Erling Smørgrav     { URL_MALFORMED,	FETCH_URL,	"Malformed URL" },
58d8acd8dcSDag-Erling Smørgrav     { URL_BAD_SCHEME,	FETCH_URL,	"Invalid URL scheme" },
59d8acd8dcSDag-Erling Smørgrav     { URL_BAD_PORT,	FETCH_URL,	"Invalid server port" },
60d8acd8dcSDag-Erling Smørgrav     { -1,		FETCH_UNKNOWN,	"Unknown parser error" }
61d8acd8dcSDag-Erling Smørgrav };
62d8acd8dcSDag-Erling Smørgrav 
63d8acd8dcSDag-Erling Smørgrav 
64d8acd8dcSDag-Erling Smørgrav /*** Public API **************************************************************/
654ca1ab94SDag-Erling Smørgrav 
66842a95ccSDag-Erling Smørgrav /*
67842a95ccSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
68842a95ccSDag-Erling Smørgrav  * read-only stream connected to the document referenced by the URL.
69842a95ccSDag-Erling Smørgrav  */
70ecc91352SDag-Erling Smørgrav FILE *
71d8acd8dcSDag-Erling Smørgrav fetchGet(struct url *URL, char *flags)
72ecc91352SDag-Erling Smørgrav {
73c97925adSHajimu UMEMOTO     int direct;
74c97925adSHajimu UMEMOTO 
75c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
76ecc91352SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
77ecc91352SDag-Erling Smørgrav 	return fetchGetFile(URL, flags);
78ecc91352SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
79ecc91352SDag-Erling Smørgrav 	return fetchGetHTTP(URL, flags);
80c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
81c97925adSHajimu UMEMOTO 	if (!direct &&
82c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
83c97925adSHajimu UMEMOTO 	    return fetchGetHTTP(URL, flags);
84ecc91352SDag-Erling Smørgrav 	return fetchGetFTP(URL, flags);
85c97925adSHajimu UMEMOTO     } else {
86d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
87d8acd8dcSDag-Erling Smørgrav 	return NULL;
88d8acd8dcSDag-Erling Smørgrav     }
89ecc91352SDag-Erling Smørgrav }
90ecc91352SDag-Erling Smørgrav 
91842a95ccSDag-Erling Smørgrav /*
92842a95ccSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
93842a95ccSDag-Erling Smørgrav  * write-only stream connected to the document referenced by the URL.
94842a95ccSDag-Erling Smørgrav  */
95ecc91352SDag-Erling Smørgrav FILE *
96d8acd8dcSDag-Erling Smørgrav fetchPut(struct url *URL, char *flags)
97ecc91352SDag-Erling Smørgrav {
98c97925adSHajimu UMEMOTO     int direct;
99c97925adSHajimu UMEMOTO 
100c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
101ecc91352SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
102ecc91352SDag-Erling Smørgrav 	return fetchPutFile(URL, flags);
103ecc91352SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
104ecc91352SDag-Erling Smørgrav 	return fetchPutHTTP(URL, flags);
105c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
106c97925adSHajimu UMEMOTO 	if (!direct &&
107c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
108c97925adSHajimu UMEMOTO 	    return fetchPutHTTP(URL, flags);
109ecc91352SDag-Erling Smørgrav 	return fetchPutFTP(URL, flags);
110c97925adSHajimu UMEMOTO     } else {
111d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
112d8acd8dcSDag-Erling Smørgrav 	return NULL;
113d8acd8dcSDag-Erling Smørgrav     }
114d8acd8dcSDag-Erling Smørgrav }
115d8acd8dcSDag-Erling Smørgrav 
116d8acd8dcSDag-Erling Smørgrav /*
117d8acd8dcSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return the
118d8acd8dcSDag-Erling Smørgrav  * size of the document referenced by the URL if it exists.
119d8acd8dcSDag-Erling Smørgrav  */
120d8acd8dcSDag-Erling Smørgrav int
121d8acd8dcSDag-Erling Smørgrav fetchStat(struct url *URL, struct url_stat *us, char *flags)
122d8acd8dcSDag-Erling Smørgrav {
123c97925adSHajimu UMEMOTO     int direct;
124c97925adSHajimu UMEMOTO 
125c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
126d8acd8dcSDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
127d8acd8dcSDag-Erling Smørgrav 	return fetchStatFile(URL, us, flags);
128d8acd8dcSDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
129d8acd8dcSDag-Erling Smørgrav 	return fetchStatHTTP(URL, us, flags);
130c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
131c97925adSHajimu UMEMOTO 	if (!direct &&
132c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
133c97925adSHajimu UMEMOTO 	    return fetchStatHTTP(URL, us, flags);
134d8acd8dcSDag-Erling Smørgrav 	return fetchStatFTP(URL, us, flags);
135c97925adSHajimu UMEMOTO     } else {
136d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
137d8acd8dcSDag-Erling Smørgrav 	return -1;
138d8acd8dcSDag-Erling Smørgrav     }
139ecc91352SDag-Erling Smørgrav }
140ecc91352SDag-Erling Smørgrav 
141842a95ccSDag-Erling Smørgrav /*
142ce71b736SDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
143ce71b736SDag-Erling Smørgrav  * list of files in the directory pointed to by the URL.
144ce71b736SDag-Erling Smørgrav  */
145ce71b736SDag-Erling Smørgrav struct url_ent *
146ce71b736SDag-Erling Smørgrav fetchList(struct url *URL, char *flags)
147ce71b736SDag-Erling Smørgrav {
148c97925adSHajimu UMEMOTO     int direct;
149c97925adSHajimu UMEMOTO 
150c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
151ce71b736SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
152ce71b736SDag-Erling Smørgrav 	return fetchListFile(URL, flags);
153ce71b736SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
154ce71b736SDag-Erling Smørgrav 	return fetchListHTTP(URL, flags);
155c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
156c97925adSHajimu UMEMOTO 	if (!direct &&
157c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
158c97925adSHajimu UMEMOTO 	    return fetchListHTTP(URL, flags);
159ce71b736SDag-Erling Smørgrav 	return fetchListFTP(URL, flags);
160c97925adSHajimu UMEMOTO     } else {
161ce71b736SDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
162ce71b736SDag-Erling Smørgrav 	return NULL;
163ce71b736SDag-Erling Smørgrav     }
164ce71b736SDag-Erling Smørgrav }
165ce71b736SDag-Erling Smørgrav 
166ce71b736SDag-Erling Smørgrav /*
167842a95ccSDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchGet().
168842a95ccSDag-Erling Smørgrav  */
1694ca1ab94SDag-Erling Smørgrav FILE *
1704ca1ab94SDag-Erling Smørgrav fetchGetURL(char *URL, char *flags)
1714ca1ab94SDag-Erling Smørgrav {
172d8acd8dcSDag-Erling Smørgrav     struct url *u;
1734ca1ab94SDag-Erling Smørgrav     FILE *f;
1744ca1ab94SDag-Erling Smørgrav 
1754ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
1764ca1ab94SDag-Erling Smørgrav 	return NULL;
1774ca1ab94SDag-Erling Smørgrav 
178ecc91352SDag-Erling Smørgrav     f = fetchGet(u, flags);
1794ca1ab94SDag-Erling Smørgrav 
18060245e42SDag-Erling Smørgrav     fetchFreeURL(u);
1814ca1ab94SDag-Erling Smørgrav     return f;
1824ca1ab94SDag-Erling Smørgrav }
1834ca1ab94SDag-Erling Smørgrav 
1844ca1ab94SDag-Erling Smørgrav 
185842a95ccSDag-Erling Smørgrav /*
186842a95ccSDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchPut().
187842a95ccSDag-Erling Smørgrav  */
1884ca1ab94SDag-Erling Smørgrav FILE *
1894ca1ab94SDag-Erling Smørgrav fetchPutURL(char *URL, char *flags)
1904ca1ab94SDag-Erling Smørgrav {
191d8acd8dcSDag-Erling Smørgrav     struct url *u;
1924ca1ab94SDag-Erling Smørgrav     FILE *f;
1934ca1ab94SDag-Erling Smørgrav 
1944ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
1954ca1ab94SDag-Erling Smørgrav 	return NULL;
1964ca1ab94SDag-Erling Smørgrav 
197ecc91352SDag-Erling Smørgrav     f = fetchPut(u, flags);
1984ca1ab94SDag-Erling Smørgrav 
19960245e42SDag-Erling Smørgrav     fetchFreeURL(u);
2004ca1ab94SDag-Erling Smørgrav     return f;
2014ca1ab94SDag-Erling Smørgrav }
2024ca1ab94SDag-Erling Smørgrav 
2034ca1ab94SDag-Erling Smørgrav /*
204d8acd8dcSDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchStat().
205d8acd8dcSDag-Erling Smørgrav  */
206d8acd8dcSDag-Erling Smørgrav int
207d8acd8dcSDag-Erling Smørgrav fetchStatURL(char *URL, struct url_stat *us, char *flags)
208d8acd8dcSDag-Erling Smørgrav {
209d8acd8dcSDag-Erling Smørgrav     struct url *u;
210d8acd8dcSDag-Erling Smørgrav     int s;
211d8acd8dcSDag-Erling Smørgrav 
212d8acd8dcSDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
213d8acd8dcSDag-Erling Smørgrav 	return -1;
214d8acd8dcSDag-Erling Smørgrav 
215d8acd8dcSDag-Erling Smørgrav     s = fetchStat(u, us, flags);
216d8acd8dcSDag-Erling Smørgrav 
21760245e42SDag-Erling Smørgrav     fetchFreeURL(u);
218d8acd8dcSDag-Erling Smørgrav     return s;
219d8acd8dcSDag-Erling Smørgrav }
220d8acd8dcSDag-Erling Smørgrav 
221d8acd8dcSDag-Erling Smørgrav /*
222ce71b736SDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchList().
223ce71b736SDag-Erling Smørgrav  */
224ce71b736SDag-Erling Smørgrav struct url_ent *
225ce71b736SDag-Erling Smørgrav fetchListURL(char *URL, char *flags)
226ce71b736SDag-Erling Smørgrav {
227ce71b736SDag-Erling Smørgrav     struct url *u;
228ce71b736SDag-Erling Smørgrav     struct url_ent *ue;
229ce71b736SDag-Erling Smørgrav 
230ce71b736SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
231ce71b736SDag-Erling Smørgrav 	return NULL;
232ce71b736SDag-Erling Smørgrav 
233ce71b736SDag-Erling Smørgrav     ue = fetchList(u, flags);
234ce71b736SDag-Erling Smørgrav 
23560245e42SDag-Erling Smørgrav     fetchFreeURL(u);
236ce71b736SDag-Erling Smørgrav     return ue;
237ce71b736SDag-Erling Smørgrav }
238ce71b736SDag-Erling Smørgrav 
239ce71b736SDag-Erling Smørgrav /*
2409a964d6aSDag-Erling Smørgrav  * Make a URL
2419a964d6aSDag-Erling Smørgrav  */
2429a964d6aSDag-Erling Smørgrav struct url *
2439a964d6aSDag-Erling Smørgrav fetchMakeURL(char *scheme, char *host, int port, char *doc,
2449a964d6aSDag-Erling Smørgrav     char *user, char *pwd)
2459a964d6aSDag-Erling Smørgrav {
2469a964d6aSDag-Erling Smørgrav     struct url *u;
2479a964d6aSDag-Erling Smørgrav 
2489a964d6aSDag-Erling Smørgrav     if (!scheme || (!host && !doc)) {
2499a964d6aSDag-Erling Smørgrav 	_url_seterr(URL_MALFORMED);
2509a964d6aSDag-Erling Smørgrav 	return NULL;
2519a964d6aSDag-Erling Smørgrav     }
2529a964d6aSDag-Erling Smørgrav 
2539a964d6aSDag-Erling Smørgrav     if (port < 0 || port > 65535) {
2549a964d6aSDag-Erling Smørgrav 	_url_seterr(URL_BAD_PORT);
2559a964d6aSDag-Erling Smørgrav 	return NULL;
2569a964d6aSDag-Erling Smørgrav     }
2579a964d6aSDag-Erling Smørgrav 
2589a964d6aSDag-Erling Smørgrav     /* allocate struct url */
2599a964d6aSDag-Erling Smørgrav     if ((u = calloc(1, sizeof *u)) == NULL) {
2609a964d6aSDag-Erling Smørgrav 	_fetch_syserr();
2619a964d6aSDag-Erling Smørgrav 	return NULL;
2629a964d6aSDag-Erling Smørgrav     }
2639a964d6aSDag-Erling Smørgrav 
2649a964d6aSDag-Erling Smørgrav     if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
2659a964d6aSDag-Erling Smørgrav 	_fetch_syserr();
2669a964d6aSDag-Erling Smørgrav 	free(u);
2679a964d6aSDag-Erling Smørgrav 	return NULL;
2689a964d6aSDag-Erling Smørgrav     }
2699a964d6aSDag-Erling Smørgrav 
2709a964d6aSDag-Erling Smørgrav #define seturl(x) snprintf(u->x, sizeof u->x, "%s", x)
2719a964d6aSDag-Erling Smørgrav     seturl(scheme);
2729a964d6aSDag-Erling Smørgrav     seturl(host);
2739a964d6aSDag-Erling Smørgrav     seturl(user);
2749a964d6aSDag-Erling Smørgrav     seturl(pwd);
2759a964d6aSDag-Erling Smørgrav #undef seturl
2769a964d6aSDag-Erling Smørgrav     u->port = port;
2779a964d6aSDag-Erling Smørgrav 
2789a964d6aSDag-Erling Smørgrav     return u;
2799a964d6aSDag-Erling Smørgrav }
2809a964d6aSDag-Erling Smørgrav 
2819a964d6aSDag-Erling Smørgrav /*
2824ca1ab94SDag-Erling Smørgrav  * Split an URL into components. URL syntax is:
2834ca1ab94SDag-Erling Smørgrav  * method:[//[user[:pwd]@]host[:port]]/[document]
2844ca1ab94SDag-Erling Smørgrav  * This almost, but not quite, RFC1738 URL syntax.
2854ca1ab94SDag-Erling Smørgrav  */
286d8acd8dcSDag-Erling Smørgrav struct url *
2874ca1ab94SDag-Erling Smørgrav fetchParseURL(char *URL)
2884ca1ab94SDag-Erling Smørgrav {
2894ca1ab94SDag-Erling Smørgrav     char *p, *q;
290d8acd8dcSDag-Erling Smørgrav     struct url *u;
2914ca1ab94SDag-Erling Smørgrav     int i;
2924ca1ab94SDag-Erling Smørgrav 
293d8acd8dcSDag-Erling Smørgrav     /* allocate struct url */
294807c941cSDag-Erling Smørgrav     if ((u = calloc(1, sizeof *u)) == NULL) {
295d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
2964ca1ab94SDag-Erling Smørgrav 	return NULL;
297d8acd8dcSDag-Erling Smørgrav     }
2984ca1ab94SDag-Erling Smørgrav 
2994ca1ab94SDag-Erling Smørgrav     /* scheme name */
3004ca1ab94SDag-Erling Smørgrav     for (i = 0; *URL && (*URL != ':'); URL++)
3014ca1ab94SDag-Erling Smørgrav 	if (i < URL_SCHEMELEN)
3024ca1ab94SDag-Erling Smørgrav 	    u->scheme[i++] = *URL;
303d8acd8dcSDag-Erling Smørgrav     if (!URL[0] || (URL[1] != '/')) {
304d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
3054ca1ab94SDag-Erling Smørgrav 	goto ouch;
306d8acd8dcSDag-Erling Smørgrav     }
3074ca1ab94SDag-Erling Smørgrav     else URL++;
3084ca1ab94SDag-Erling Smørgrav     if (URL[1] != '/') {
3094ca1ab94SDag-Erling Smørgrav 	p = URL;
3104ca1ab94SDag-Erling Smørgrav 	goto nohost;
3114ca1ab94SDag-Erling Smørgrav     }
3124ca1ab94SDag-Erling Smørgrav     else URL += 2;
3134ca1ab94SDag-Erling Smørgrav 
3144ca1ab94SDag-Erling Smørgrav     p = strpbrk(URL, "/@");
3150fba3a00SDag-Erling Smørgrav     if (p && *p == '@') {
3164ca1ab94SDag-Erling Smørgrav 	/* username */
3174ca1ab94SDag-Erling Smørgrav 	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
3184ca1ab94SDag-Erling Smørgrav 	    if (i < URL_USERLEN)
3194ca1ab94SDag-Erling Smørgrav 		u->user[i++] = *q;
3204ca1ab94SDag-Erling Smørgrav 
3214ca1ab94SDag-Erling Smørgrav 	/* password */
3224ca1ab94SDag-Erling Smørgrav 	if (*q == ':')
3234ca1ab94SDag-Erling Smørgrav 	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
3244ca1ab94SDag-Erling Smørgrav 		if (i < URL_PWDLEN)
3254ca1ab94SDag-Erling Smørgrav 		    u->pwd[i++] = *q;
3264ca1ab94SDag-Erling Smørgrav 
3274ca1ab94SDag-Erling Smørgrav 	p++;
3284ca1ab94SDag-Erling Smørgrav     } else p = URL;
3294ca1ab94SDag-Erling Smørgrav 
3304ca1ab94SDag-Erling Smørgrav     /* hostname */
33128c645cfSHajimu UMEMOTO #ifdef INET6
33228c645cfSHajimu UMEMOTO     if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
33328c645cfSHajimu UMEMOTO 	(*++q == '\0' || *q == '/' || *q == ':')) {
33428c645cfSHajimu UMEMOTO 	if ((i = q - p - 2) > MAXHOSTNAMELEN)
33528c645cfSHajimu UMEMOTO 	    i = MAXHOSTNAMELEN;
33628c645cfSHajimu UMEMOTO 	strncpy(u->host, ++p, i);
33728c645cfSHajimu UMEMOTO 	p = q;
33828c645cfSHajimu UMEMOTO     } else
33928c645cfSHajimu UMEMOTO #endif
3404ca1ab94SDag-Erling Smørgrav 	for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
3414ca1ab94SDag-Erling Smørgrav 	    if (i < MAXHOSTNAMELEN)
3424ca1ab94SDag-Erling Smørgrav 		u->host[i++] = *p;
3434ca1ab94SDag-Erling Smørgrav 
3444ca1ab94SDag-Erling Smørgrav     /* port */
3454ca1ab94SDag-Erling Smørgrav     if (*p == ':') {
3464ca1ab94SDag-Erling Smørgrav 	for (q = ++p; *q && (*q != '/'); q++)
3474ca1ab94SDag-Erling Smørgrav 	    if (isdigit(*q))
3484ca1ab94SDag-Erling Smørgrav 		u->port = u->port * 10 + (*q - '0');
349d8acd8dcSDag-Erling Smørgrav 	    else {
350d8acd8dcSDag-Erling Smørgrav 		/* invalid port */
351d8acd8dcSDag-Erling Smørgrav 		_url_seterr(URL_BAD_PORT);
352d8acd8dcSDag-Erling Smørgrav 		goto ouch;
353d8acd8dcSDag-Erling Smørgrav 	    }
3544ca1ab94SDag-Erling Smørgrav 	while (*p && (*p != '/'))
3554ca1ab94SDag-Erling Smørgrav 	    p++;
3564ca1ab94SDag-Erling Smørgrav     }
3574ca1ab94SDag-Erling Smørgrav 
3584ca1ab94SDag-Erling Smørgrav nohost:
3594ca1ab94SDag-Erling Smørgrav     /* document */
36060245e42SDag-Erling Smørgrav     if (!*p)
36160245e42SDag-Erling Smørgrav 	p = "/";
36260245e42SDag-Erling Smørgrav 
36360245e42SDag-Erling Smørgrav     if ((u->doc = strdup(p)) == NULL) {
364d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
3654ca1ab94SDag-Erling Smørgrav 	goto ouch;
366d8acd8dcSDag-Erling Smørgrav     }
3674ca1ab94SDag-Erling Smørgrav 
3684ca1ab94SDag-Erling Smørgrav     DEBUG(fprintf(stderr,
3694ca1ab94SDag-Erling Smørgrav 		  "scheme:   [\033[1m%s\033[m]\n"
3704ca1ab94SDag-Erling Smørgrav 		  "user:     [\033[1m%s\033[m]\n"
3714ca1ab94SDag-Erling Smørgrav 		  "password: [\033[1m%s\033[m]\n"
3724ca1ab94SDag-Erling Smørgrav 		  "host:     [\033[1m%s\033[m]\n"
3734ca1ab94SDag-Erling Smørgrav 		  "port:     [\033[1m%d\033[m]\n"
3744ca1ab94SDag-Erling Smørgrav 		  "document: [\033[1m%s\033[m]\n",
3754ca1ab94SDag-Erling Smørgrav 		  u->scheme, u->user, u->pwd,
3764ca1ab94SDag-Erling Smørgrav 		  u->host, u->port, u->doc));
3774ca1ab94SDag-Erling Smørgrav 
3784ca1ab94SDag-Erling Smørgrav     return u;
3794ca1ab94SDag-Erling Smørgrav 
3804ca1ab94SDag-Erling Smørgrav ouch:
3814ca1ab94SDag-Erling Smørgrav     free(u);
3824ca1ab94SDag-Erling Smørgrav     return NULL;
3834ca1ab94SDag-Erling Smørgrav }
38460245e42SDag-Erling Smørgrav 
38560245e42SDag-Erling Smørgrav /*
38660245e42SDag-Erling Smørgrav  * Free a URL
38760245e42SDag-Erling Smørgrav  */
38860245e42SDag-Erling Smørgrav void
38960245e42SDag-Erling Smørgrav fetchFreeURL(struct url *u)
39060245e42SDag-Erling Smørgrav {
39160245e42SDag-Erling Smørgrav     free(u->doc);
39260245e42SDag-Erling Smørgrav     free(u);
39360245e42SDag-Erling Smørgrav }
394