xref: /freebsd/lib/libfetch/fetch.c (revision ba101983d5c240f191e3f233907ebb4a6c7029f1)
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 /*
2404ca1ab94SDag-Erling Smørgrav  * Split an URL into components. URL syntax is:
2414ca1ab94SDag-Erling Smørgrav  * method:[//[user[:pwd]@]host[:port]]/[document]
2424ca1ab94SDag-Erling Smørgrav  * This almost, but not quite, RFC1738 URL syntax.
2434ca1ab94SDag-Erling Smørgrav  */
244d8acd8dcSDag-Erling Smørgrav struct url *
2454ca1ab94SDag-Erling Smørgrav fetchParseURL(char *URL)
2464ca1ab94SDag-Erling Smørgrav {
2474ca1ab94SDag-Erling Smørgrav     char *p, *q;
248d8acd8dcSDag-Erling Smørgrav     struct url *u;
2494ca1ab94SDag-Erling Smørgrav     int i;
2504ca1ab94SDag-Erling Smørgrav 
251d8acd8dcSDag-Erling Smørgrav     /* allocate struct url */
252807c941cSDag-Erling Smørgrav     if ((u = calloc(1, sizeof *u)) == NULL) {
253d8acd8dcSDag-Erling Smørgrav 	errno = ENOMEM;
254d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
2554ca1ab94SDag-Erling Smørgrav 	return NULL;
256d8acd8dcSDag-Erling Smørgrav     }
2574ca1ab94SDag-Erling Smørgrav 
2584ca1ab94SDag-Erling Smørgrav     /* scheme name */
2594ca1ab94SDag-Erling Smørgrav     for (i = 0; *URL && (*URL != ':'); URL++)
2604ca1ab94SDag-Erling Smørgrav 	if (i < URL_SCHEMELEN)
2614ca1ab94SDag-Erling Smørgrav 	    u->scheme[i++] = *URL;
262d8acd8dcSDag-Erling Smørgrav     if (!URL[0] || (URL[1] != '/')) {
263d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
2644ca1ab94SDag-Erling Smørgrav 	goto ouch;
265d8acd8dcSDag-Erling Smørgrav     }
2664ca1ab94SDag-Erling Smørgrav     else URL++;
2674ca1ab94SDag-Erling Smørgrav     if (URL[1] != '/') {
2684ca1ab94SDag-Erling Smørgrav 	p = URL;
2694ca1ab94SDag-Erling Smørgrav 	goto nohost;
2704ca1ab94SDag-Erling Smørgrav     }
2714ca1ab94SDag-Erling Smørgrav     else URL += 2;
2724ca1ab94SDag-Erling Smørgrav 
2734ca1ab94SDag-Erling Smørgrav     p = strpbrk(URL, "/@");
2740fba3a00SDag-Erling Smørgrav     if (p && *p == '@') {
2754ca1ab94SDag-Erling Smørgrav 	/* username */
2764ca1ab94SDag-Erling Smørgrav 	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
2774ca1ab94SDag-Erling Smørgrav 	    if (i < URL_USERLEN)
2784ca1ab94SDag-Erling Smørgrav 		u->user[i++] = *q;
2794ca1ab94SDag-Erling Smørgrav 
2804ca1ab94SDag-Erling Smørgrav 	/* password */
2814ca1ab94SDag-Erling Smørgrav 	if (*q == ':')
2824ca1ab94SDag-Erling Smørgrav 	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
2834ca1ab94SDag-Erling Smørgrav 		if (i < URL_PWDLEN)
2844ca1ab94SDag-Erling Smørgrav 		    u->pwd[i++] = *q;
2854ca1ab94SDag-Erling Smørgrav 
2864ca1ab94SDag-Erling Smørgrav 	p++;
2874ca1ab94SDag-Erling Smørgrav     } else p = URL;
2884ca1ab94SDag-Erling Smørgrav 
2894ca1ab94SDag-Erling Smørgrav     /* hostname */
29028c645cfSHajimu UMEMOTO #ifdef INET6
29128c645cfSHajimu UMEMOTO     if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
29228c645cfSHajimu UMEMOTO 	(*++q == '\0' || *q == '/' || *q == ':')) {
29328c645cfSHajimu UMEMOTO 	if ((i = q - p - 2) > MAXHOSTNAMELEN)
29428c645cfSHajimu UMEMOTO 	    i = MAXHOSTNAMELEN;
29528c645cfSHajimu UMEMOTO 	strncpy(u->host, ++p, i);
29628c645cfSHajimu UMEMOTO 	p = q;
29728c645cfSHajimu UMEMOTO     } else
29828c645cfSHajimu UMEMOTO #endif
2994ca1ab94SDag-Erling Smørgrav 	for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
3004ca1ab94SDag-Erling Smørgrav 	    if (i < MAXHOSTNAMELEN)
3014ca1ab94SDag-Erling Smørgrav 		u->host[i++] = *p;
3024ca1ab94SDag-Erling Smørgrav 
3034ca1ab94SDag-Erling Smørgrav     /* port */
3044ca1ab94SDag-Erling Smørgrav     if (*p == ':') {
3054ca1ab94SDag-Erling Smørgrav 	for (q = ++p; *q && (*q != '/'); q++)
3064ca1ab94SDag-Erling Smørgrav 	    if (isdigit(*q))
3074ca1ab94SDag-Erling Smørgrav 		u->port = u->port * 10 + (*q - '0');
308d8acd8dcSDag-Erling Smørgrav 	    else {
309d8acd8dcSDag-Erling Smørgrav 		/* invalid port */
310d8acd8dcSDag-Erling Smørgrav 		_url_seterr(URL_BAD_PORT);
311d8acd8dcSDag-Erling Smørgrav 		goto ouch;
312d8acd8dcSDag-Erling Smørgrav 	    }
3134ca1ab94SDag-Erling Smørgrav 	while (*p && (*p != '/'))
3144ca1ab94SDag-Erling Smørgrav 	    p++;
3154ca1ab94SDag-Erling Smørgrav     }
3164ca1ab94SDag-Erling Smørgrav 
3174ca1ab94SDag-Erling Smørgrav nohost:
3184ca1ab94SDag-Erling Smørgrav     /* document */
31960245e42SDag-Erling Smørgrav     if (!*p)
32060245e42SDag-Erling Smørgrav 	p = "/";
32160245e42SDag-Erling Smørgrav 
32260245e42SDag-Erling Smørgrav     if ((u->doc = strdup(p)) == NULL) {
323d8acd8dcSDag-Erling Smørgrav 	errno = ENOMEM;
324d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
3254ca1ab94SDag-Erling Smørgrav 	goto ouch;
326d8acd8dcSDag-Erling Smørgrav     }
3274ca1ab94SDag-Erling Smørgrav 
3284ca1ab94SDag-Erling Smørgrav     DEBUG(fprintf(stderr,
3294ca1ab94SDag-Erling Smørgrav 		  "scheme:   [\033[1m%s\033[m]\n"
3304ca1ab94SDag-Erling Smørgrav 		  "user:     [\033[1m%s\033[m]\n"
3314ca1ab94SDag-Erling Smørgrav 		  "password: [\033[1m%s\033[m]\n"
3324ca1ab94SDag-Erling Smørgrav 		  "host:     [\033[1m%s\033[m]\n"
3334ca1ab94SDag-Erling Smørgrav 		  "port:     [\033[1m%d\033[m]\n"
3344ca1ab94SDag-Erling Smørgrav 		  "document: [\033[1m%s\033[m]\n",
3354ca1ab94SDag-Erling Smørgrav 		  u->scheme, u->user, u->pwd,
3364ca1ab94SDag-Erling Smørgrav 		  u->host, u->port, u->doc));
3374ca1ab94SDag-Erling Smørgrav 
3384ca1ab94SDag-Erling Smørgrav     return u;
3394ca1ab94SDag-Erling Smørgrav 
3404ca1ab94SDag-Erling Smørgrav ouch:
3414ca1ab94SDag-Erling Smørgrav     free(u);
3424ca1ab94SDag-Erling Smørgrav     return NULL;
3434ca1ab94SDag-Erling Smørgrav }
34460245e42SDag-Erling Smørgrav 
34560245e42SDag-Erling Smørgrav /*
34660245e42SDag-Erling Smørgrav  * Free a URL
34760245e42SDag-Erling Smørgrav  */
34860245e42SDag-Erling Smørgrav void
34960245e42SDag-Erling Smørgrav fetchFreeURL(struct url *u)
35060245e42SDag-Erling Smørgrav {
35160245e42SDag-Erling Smørgrav     free(u->doc);
35260245e42SDag-Erling Smørgrav     free(u);
35360245e42SDag-Erling Smørgrav }
354