xref: /freebsd/lib/libfetch/fetch.c (revision 1a5faa1061c06e7853a16ac839f2407869246b2c)
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;
46a1bb3f48SDag-Erling Smørgrav int	 fetchRestartCalls = 1;
470fba3a00SDag-Erling Smørgrav 
480fba3a00SDag-Erling Smørgrav 
49d8acd8dcSDag-Erling Smørgrav /*** Local data **************************************************************/
50d8acd8dcSDag-Erling Smørgrav 
51d8acd8dcSDag-Erling Smørgrav /*
52d8acd8dcSDag-Erling Smørgrav  * Error messages for parser errors
53d8acd8dcSDag-Erling Smørgrav  */
54d8acd8dcSDag-Erling Smørgrav #define URL_MALFORMED		1
55d8acd8dcSDag-Erling Smørgrav #define URL_BAD_SCHEME		2
56d8acd8dcSDag-Erling Smørgrav #define URL_BAD_PORT		3
57d8acd8dcSDag-Erling Smørgrav static struct fetcherr _url_errlist[] = {
58d8acd8dcSDag-Erling Smørgrav     { URL_MALFORMED,	FETCH_URL,	"Malformed URL" },
59d8acd8dcSDag-Erling Smørgrav     { URL_BAD_SCHEME,	FETCH_URL,	"Invalid URL scheme" },
60d8acd8dcSDag-Erling Smørgrav     { URL_BAD_PORT,	FETCH_URL,	"Invalid server port" },
61d8acd8dcSDag-Erling Smørgrav     { -1,		FETCH_UNKNOWN,	"Unknown parser error" }
62d8acd8dcSDag-Erling Smørgrav };
63d8acd8dcSDag-Erling Smørgrav 
64d8acd8dcSDag-Erling Smørgrav 
65d8acd8dcSDag-Erling Smørgrav /*** Public API **************************************************************/
664ca1ab94SDag-Erling Smørgrav 
67842a95ccSDag-Erling Smørgrav /*
68842a95ccSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
69842a95ccSDag-Erling Smørgrav  * read-only stream connected to the document referenced by the URL.
701a5faa10SDag-Erling Smørgrav  * Also fill out the struct url_stat.
71842a95ccSDag-Erling Smørgrav  */
72ecc91352SDag-Erling Smørgrav FILE *
731a5faa10SDag-Erling Smørgrav fetchXGet(struct url *URL, struct url_stat *us, char *flags)
74ecc91352SDag-Erling Smørgrav {
75c97925adSHajimu UMEMOTO     int direct;
76c97925adSHajimu UMEMOTO 
77c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
78ecc91352SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
791a5faa10SDag-Erling Smørgrav 	return fetchXGetFile(URL, us, flags);
80ecc91352SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
811a5faa10SDag-Erling Smørgrav 	return fetchXGetHTTP(URL, us, flags);
82c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
83c97925adSHajimu UMEMOTO 	if (!direct &&
84c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
851a5faa10SDag-Erling Smørgrav 	    return fetchXGetHTTP(URL, us, flags);
861a5faa10SDag-Erling Smørgrav 	return fetchXGetFTP(URL, us, flags);
87c97925adSHajimu UMEMOTO     } else {
88d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
89d8acd8dcSDag-Erling Smørgrav 	return NULL;
90d8acd8dcSDag-Erling Smørgrav     }
91ecc91352SDag-Erling Smørgrav }
92ecc91352SDag-Erling Smørgrav 
93842a95ccSDag-Erling Smørgrav /*
94842a95ccSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
951a5faa10SDag-Erling Smørgrav  * read-only stream connected to the document referenced by the URL.
961a5faa10SDag-Erling Smørgrav  */
971a5faa10SDag-Erling Smørgrav FILE *
981a5faa10SDag-Erling Smørgrav fetchGet(struct url *URL, char *flags)
991a5faa10SDag-Erling Smørgrav {
1001a5faa10SDag-Erling Smørgrav     return fetchXGet(URL, NULL, flags);
1011a5faa10SDag-Erling Smørgrav }
1021a5faa10SDag-Erling Smørgrav 
1031a5faa10SDag-Erling Smørgrav /*
1041a5faa10SDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
105842a95ccSDag-Erling Smørgrav  * write-only stream connected to the document referenced by the URL.
106842a95ccSDag-Erling Smørgrav  */
107ecc91352SDag-Erling Smørgrav FILE *
108d8acd8dcSDag-Erling Smørgrav fetchPut(struct url *URL, char *flags)
109ecc91352SDag-Erling Smørgrav {
110c97925adSHajimu UMEMOTO     int direct;
111c97925adSHajimu UMEMOTO 
112c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
113ecc91352SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
114ecc91352SDag-Erling Smørgrav 	return fetchPutFile(URL, flags);
115ecc91352SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
116ecc91352SDag-Erling Smørgrav 	return fetchPutHTTP(URL, flags);
117c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
118c97925adSHajimu UMEMOTO 	if (!direct &&
119c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
120c97925adSHajimu UMEMOTO 	    return fetchPutHTTP(URL, flags);
121ecc91352SDag-Erling Smørgrav 	return fetchPutFTP(URL, flags);
122c97925adSHajimu UMEMOTO     } else {
123d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
124d8acd8dcSDag-Erling Smørgrav 	return NULL;
125d8acd8dcSDag-Erling Smørgrav     }
126d8acd8dcSDag-Erling Smørgrav }
127d8acd8dcSDag-Erling Smørgrav 
128d8acd8dcSDag-Erling Smørgrav /*
129d8acd8dcSDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return the
130d8acd8dcSDag-Erling Smørgrav  * size of the document referenced by the URL if it exists.
131d8acd8dcSDag-Erling Smørgrav  */
132d8acd8dcSDag-Erling Smørgrav int
133d8acd8dcSDag-Erling Smørgrav fetchStat(struct url *URL, struct url_stat *us, char *flags)
134d8acd8dcSDag-Erling Smørgrav {
135c97925adSHajimu UMEMOTO     int direct;
136c97925adSHajimu UMEMOTO 
137c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
138d8acd8dcSDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
139d8acd8dcSDag-Erling Smørgrav 	return fetchStatFile(URL, us, flags);
140d8acd8dcSDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
141d8acd8dcSDag-Erling Smørgrav 	return fetchStatHTTP(URL, us, flags);
142c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
143c97925adSHajimu UMEMOTO 	if (!direct &&
144c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
145c97925adSHajimu UMEMOTO 	    return fetchStatHTTP(URL, us, flags);
146d8acd8dcSDag-Erling Smørgrav 	return fetchStatFTP(URL, us, flags);
147c97925adSHajimu UMEMOTO     } else {
148d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
149d8acd8dcSDag-Erling Smørgrav 	return -1;
150d8acd8dcSDag-Erling Smørgrav     }
151ecc91352SDag-Erling Smørgrav }
152ecc91352SDag-Erling Smørgrav 
153842a95ccSDag-Erling Smørgrav /*
154ce71b736SDag-Erling Smørgrav  * Select the appropriate protocol for the URL scheme, and return a
155ce71b736SDag-Erling Smørgrav  * list of files in the directory pointed to by the URL.
156ce71b736SDag-Erling Smørgrav  */
157ce71b736SDag-Erling Smørgrav struct url_ent *
158ce71b736SDag-Erling Smørgrav fetchList(struct url *URL, char *flags)
159ce71b736SDag-Erling Smørgrav {
160c97925adSHajimu UMEMOTO     int direct;
161c97925adSHajimu UMEMOTO 
162c97925adSHajimu UMEMOTO     direct = (flags && strchr(flags, 'd'));
163ce71b736SDag-Erling Smørgrav     if (strcasecmp(URL->scheme, "file") == 0)
164ce71b736SDag-Erling Smørgrav 	return fetchListFile(URL, flags);
165ce71b736SDag-Erling Smørgrav     else if (strcasecmp(URL->scheme, "http") == 0)
166ce71b736SDag-Erling Smørgrav 	return fetchListHTTP(URL, flags);
167c97925adSHajimu UMEMOTO     else if (strcasecmp(URL->scheme, "ftp") == 0) {
168c97925adSHajimu UMEMOTO 	if (!direct &&
169c97925adSHajimu UMEMOTO 	    getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
170c97925adSHajimu UMEMOTO 	    return fetchListHTTP(URL, flags);
171ce71b736SDag-Erling Smørgrav 	return fetchListFTP(URL, flags);
172c97925adSHajimu UMEMOTO     } else {
173ce71b736SDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
174ce71b736SDag-Erling Smørgrav 	return NULL;
175ce71b736SDag-Erling Smørgrav     }
176ce71b736SDag-Erling Smørgrav }
177ce71b736SDag-Erling Smørgrav 
178ce71b736SDag-Erling Smørgrav /*
1791a5faa10SDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchXGet().
180842a95ccSDag-Erling Smørgrav  */
1814ca1ab94SDag-Erling Smørgrav FILE *
1821a5faa10SDag-Erling Smørgrav fetchXGetURL(char *URL, struct url_stat *us, char *flags)
1834ca1ab94SDag-Erling Smørgrav {
184d8acd8dcSDag-Erling Smørgrav     struct url *u;
1854ca1ab94SDag-Erling Smørgrav     FILE *f;
1864ca1ab94SDag-Erling Smørgrav 
1874ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
1884ca1ab94SDag-Erling Smørgrav 	return NULL;
1894ca1ab94SDag-Erling Smørgrav 
1901a5faa10SDag-Erling Smørgrav     f = fetchXGet(u, us, flags);
1914ca1ab94SDag-Erling Smørgrav 
19260245e42SDag-Erling Smørgrav     fetchFreeURL(u);
1934ca1ab94SDag-Erling Smørgrav     return f;
1944ca1ab94SDag-Erling Smørgrav }
1954ca1ab94SDag-Erling Smørgrav 
1961a5faa10SDag-Erling Smørgrav /*
1971a5faa10SDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchGet().
1981a5faa10SDag-Erling Smørgrav  */
1991a5faa10SDag-Erling Smørgrav FILE *
2001a5faa10SDag-Erling Smørgrav fetchGetURL(char *URL, char *flags)
2011a5faa10SDag-Erling Smørgrav {
2021a5faa10SDag-Erling Smørgrav     return fetchXGetURL(URL, NULL, flags);
2031a5faa10SDag-Erling Smørgrav }
2044ca1ab94SDag-Erling Smørgrav 
205842a95ccSDag-Erling Smørgrav /*
206842a95ccSDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchPut().
207842a95ccSDag-Erling Smørgrav  */
2084ca1ab94SDag-Erling Smørgrav FILE *
2094ca1ab94SDag-Erling Smørgrav fetchPutURL(char *URL, char *flags)
2104ca1ab94SDag-Erling Smørgrav {
211d8acd8dcSDag-Erling Smørgrav     struct url *u;
2124ca1ab94SDag-Erling Smørgrav     FILE *f;
2134ca1ab94SDag-Erling Smørgrav 
2144ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
2154ca1ab94SDag-Erling Smørgrav 	return NULL;
2164ca1ab94SDag-Erling Smørgrav 
217ecc91352SDag-Erling Smørgrav     f = fetchPut(u, flags);
2184ca1ab94SDag-Erling Smørgrav 
21960245e42SDag-Erling Smørgrav     fetchFreeURL(u);
2204ca1ab94SDag-Erling Smørgrav     return f;
2214ca1ab94SDag-Erling Smørgrav }
2224ca1ab94SDag-Erling Smørgrav 
2234ca1ab94SDag-Erling Smørgrav /*
224d8acd8dcSDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchStat().
225d8acd8dcSDag-Erling Smørgrav  */
226d8acd8dcSDag-Erling Smørgrav int
227d8acd8dcSDag-Erling Smørgrav fetchStatURL(char *URL, struct url_stat *us, char *flags)
228d8acd8dcSDag-Erling Smørgrav {
229d8acd8dcSDag-Erling Smørgrav     struct url *u;
230d8acd8dcSDag-Erling Smørgrav     int s;
231d8acd8dcSDag-Erling Smørgrav 
232d8acd8dcSDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
233d8acd8dcSDag-Erling Smørgrav 	return -1;
234d8acd8dcSDag-Erling Smørgrav 
235d8acd8dcSDag-Erling Smørgrav     s = fetchStat(u, us, flags);
236d8acd8dcSDag-Erling Smørgrav 
23760245e42SDag-Erling Smørgrav     fetchFreeURL(u);
238d8acd8dcSDag-Erling Smørgrav     return s;
239d8acd8dcSDag-Erling Smørgrav }
240d8acd8dcSDag-Erling Smørgrav 
241d8acd8dcSDag-Erling Smørgrav /*
242ce71b736SDag-Erling Smørgrav  * Attempt to parse the given URL; if successful, call fetchList().
243ce71b736SDag-Erling Smørgrav  */
244ce71b736SDag-Erling Smørgrav struct url_ent *
245ce71b736SDag-Erling Smørgrav fetchListURL(char *URL, char *flags)
246ce71b736SDag-Erling Smørgrav {
247ce71b736SDag-Erling Smørgrav     struct url *u;
248ce71b736SDag-Erling Smørgrav     struct url_ent *ue;
249ce71b736SDag-Erling Smørgrav 
250ce71b736SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
251ce71b736SDag-Erling Smørgrav 	return NULL;
252ce71b736SDag-Erling Smørgrav 
253ce71b736SDag-Erling Smørgrav     ue = fetchList(u, flags);
254ce71b736SDag-Erling Smørgrav 
25560245e42SDag-Erling Smørgrav     fetchFreeURL(u);
256ce71b736SDag-Erling Smørgrav     return ue;
257ce71b736SDag-Erling Smørgrav }
258ce71b736SDag-Erling Smørgrav 
259ce71b736SDag-Erling Smørgrav /*
2609a964d6aSDag-Erling Smørgrav  * Make a URL
2619a964d6aSDag-Erling Smørgrav  */
2629a964d6aSDag-Erling Smørgrav struct url *
2639a964d6aSDag-Erling Smørgrav fetchMakeURL(char *scheme, char *host, int port, char *doc,
2649a964d6aSDag-Erling Smørgrav     char *user, char *pwd)
2659a964d6aSDag-Erling Smørgrav {
2669a964d6aSDag-Erling Smørgrav     struct url *u;
2679a964d6aSDag-Erling Smørgrav 
2689a964d6aSDag-Erling Smørgrav     if (!scheme || (!host && !doc)) {
2699a964d6aSDag-Erling Smørgrav 	_url_seterr(URL_MALFORMED);
2709a964d6aSDag-Erling Smørgrav 	return NULL;
2719a964d6aSDag-Erling Smørgrav     }
2729a964d6aSDag-Erling Smørgrav 
2739a964d6aSDag-Erling Smørgrav     if (port < 0 || port > 65535) {
2749a964d6aSDag-Erling Smørgrav 	_url_seterr(URL_BAD_PORT);
2759a964d6aSDag-Erling Smørgrav 	return NULL;
2769a964d6aSDag-Erling Smørgrav     }
2779a964d6aSDag-Erling Smørgrav 
2789a964d6aSDag-Erling Smørgrav     /* allocate struct url */
2799a964d6aSDag-Erling Smørgrav     if ((u = calloc(1, sizeof *u)) == NULL) {
2809a964d6aSDag-Erling Smørgrav 	_fetch_syserr();
2819a964d6aSDag-Erling Smørgrav 	return NULL;
2829a964d6aSDag-Erling Smørgrav     }
2839a964d6aSDag-Erling Smørgrav 
2849a964d6aSDag-Erling Smørgrav     if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
2859a964d6aSDag-Erling Smørgrav 	_fetch_syserr();
2869a964d6aSDag-Erling Smørgrav 	free(u);
2879a964d6aSDag-Erling Smørgrav 	return NULL;
2889a964d6aSDag-Erling Smørgrav     }
2899a964d6aSDag-Erling Smørgrav 
2909a964d6aSDag-Erling Smørgrav #define seturl(x) snprintf(u->x, sizeof u->x, "%s", x)
2919a964d6aSDag-Erling Smørgrav     seturl(scheme);
2929a964d6aSDag-Erling Smørgrav     seturl(host);
2939a964d6aSDag-Erling Smørgrav     seturl(user);
2949a964d6aSDag-Erling Smørgrav     seturl(pwd);
2959a964d6aSDag-Erling Smørgrav #undef seturl
2969a964d6aSDag-Erling Smørgrav     u->port = port;
2979a964d6aSDag-Erling Smørgrav 
2989a964d6aSDag-Erling Smørgrav     return u;
2999a964d6aSDag-Erling Smørgrav }
3009a964d6aSDag-Erling Smørgrav 
3019a964d6aSDag-Erling Smørgrav /*
3024ca1ab94SDag-Erling Smørgrav  * Split an URL into components. URL syntax is:
3034ca1ab94SDag-Erling Smørgrav  * method:[//[user[:pwd]@]host[:port]]/[document]
3044ca1ab94SDag-Erling Smørgrav  * This almost, but not quite, RFC1738 URL syntax.
3054ca1ab94SDag-Erling Smørgrav  */
306d8acd8dcSDag-Erling Smørgrav struct url *
3074ca1ab94SDag-Erling Smørgrav fetchParseURL(char *URL)
3084ca1ab94SDag-Erling Smørgrav {
3094ca1ab94SDag-Erling Smørgrav     char *p, *q;
310d8acd8dcSDag-Erling Smørgrav     struct url *u;
3114ca1ab94SDag-Erling Smørgrav     int i;
3124ca1ab94SDag-Erling Smørgrav 
313d8acd8dcSDag-Erling Smørgrav     /* allocate struct url */
314807c941cSDag-Erling Smørgrav     if ((u = calloc(1, sizeof *u)) == NULL) {
315d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
3164ca1ab94SDag-Erling Smørgrav 	return NULL;
317d8acd8dcSDag-Erling Smørgrav     }
3184ca1ab94SDag-Erling Smørgrav 
3194ca1ab94SDag-Erling Smørgrav     /* scheme name */
3204ca1ab94SDag-Erling Smørgrav     for (i = 0; *URL && (*URL != ':'); URL++)
3214ca1ab94SDag-Erling Smørgrav 	if (i < URL_SCHEMELEN)
3224ca1ab94SDag-Erling Smørgrav 	    u->scheme[i++] = *URL;
323d8acd8dcSDag-Erling Smørgrav     if (!URL[0] || (URL[1] != '/')) {
324d8acd8dcSDag-Erling Smørgrav 	_url_seterr(URL_BAD_SCHEME);
3254ca1ab94SDag-Erling Smørgrav 	goto ouch;
326d8acd8dcSDag-Erling Smørgrav     }
3274ca1ab94SDag-Erling Smørgrav     else URL++;
3284ca1ab94SDag-Erling Smørgrav     if (URL[1] != '/') {
3294ca1ab94SDag-Erling Smørgrav 	p = URL;
3304ca1ab94SDag-Erling Smørgrav 	goto nohost;
3314ca1ab94SDag-Erling Smørgrav     }
3324ca1ab94SDag-Erling Smørgrav     else URL += 2;
3334ca1ab94SDag-Erling Smørgrav 
3344ca1ab94SDag-Erling Smørgrav     p = strpbrk(URL, "/@");
3350fba3a00SDag-Erling Smørgrav     if (p && *p == '@') {
3364ca1ab94SDag-Erling Smørgrav 	/* username */
3374ca1ab94SDag-Erling Smørgrav 	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
3384ca1ab94SDag-Erling Smørgrav 	    if (i < URL_USERLEN)
3394ca1ab94SDag-Erling Smørgrav 		u->user[i++] = *q;
3404ca1ab94SDag-Erling Smørgrav 
3414ca1ab94SDag-Erling Smørgrav 	/* password */
3424ca1ab94SDag-Erling Smørgrav 	if (*q == ':')
3434ca1ab94SDag-Erling Smørgrav 	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
3444ca1ab94SDag-Erling Smørgrav 		if (i < URL_PWDLEN)
3454ca1ab94SDag-Erling Smørgrav 		    u->pwd[i++] = *q;
3464ca1ab94SDag-Erling Smørgrav 
3474ca1ab94SDag-Erling Smørgrav 	p++;
3484ca1ab94SDag-Erling Smørgrav     } else p = URL;
3494ca1ab94SDag-Erling Smørgrav 
3504ca1ab94SDag-Erling Smørgrav     /* hostname */
35128c645cfSHajimu UMEMOTO #ifdef INET6
35228c645cfSHajimu UMEMOTO     if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
35328c645cfSHajimu UMEMOTO 	(*++q == '\0' || *q == '/' || *q == ':')) {
35428c645cfSHajimu UMEMOTO 	if ((i = q - p - 2) > MAXHOSTNAMELEN)
35528c645cfSHajimu UMEMOTO 	    i = MAXHOSTNAMELEN;
35628c645cfSHajimu UMEMOTO 	strncpy(u->host, ++p, i);
35728c645cfSHajimu UMEMOTO 	p = q;
35828c645cfSHajimu UMEMOTO     } else
35928c645cfSHajimu UMEMOTO #endif
3604ca1ab94SDag-Erling Smørgrav 	for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
3614ca1ab94SDag-Erling Smørgrav 	    if (i < MAXHOSTNAMELEN)
3624ca1ab94SDag-Erling Smørgrav 		u->host[i++] = *p;
3634ca1ab94SDag-Erling Smørgrav 
3644ca1ab94SDag-Erling Smørgrav     /* port */
3654ca1ab94SDag-Erling Smørgrav     if (*p == ':') {
3664ca1ab94SDag-Erling Smørgrav 	for (q = ++p; *q && (*q != '/'); q++)
3674ca1ab94SDag-Erling Smørgrav 	    if (isdigit(*q))
3684ca1ab94SDag-Erling Smørgrav 		u->port = u->port * 10 + (*q - '0');
369d8acd8dcSDag-Erling Smørgrav 	    else {
370d8acd8dcSDag-Erling Smørgrav 		/* invalid port */
371d8acd8dcSDag-Erling Smørgrav 		_url_seterr(URL_BAD_PORT);
372d8acd8dcSDag-Erling Smørgrav 		goto ouch;
373d8acd8dcSDag-Erling Smørgrav 	    }
3744ca1ab94SDag-Erling Smørgrav 	while (*p && (*p != '/'))
3754ca1ab94SDag-Erling Smørgrav 	    p++;
3764ca1ab94SDag-Erling Smørgrav     }
3774ca1ab94SDag-Erling Smørgrav 
3784ca1ab94SDag-Erling Smørgrav nohost:
3794ca1ab94SDag-Erling Smørgrav     /* document */
38060245e42SDag-Erling Smørgrav     if (!*p)
38160245e42SDag-Erling Smørgrav 	p = "/";
38260245e42SDag-Erling Smørgrav 
38360245e42SDag-Erling Smørgrav     if ((u->doc = strdup(p)) == NULL) {
384d8acd8dcSDag-Erling Smørgrav 	_fetch_syserr();
3854ca1ab94SDag-Erling Smørgrav 	goto ouch;
386d8acd8dcSDag-Erling Smørgrav     }
3874ca1ab94SDag-Erling Smørgrav 
3884ca1ab94SDag-Erling Smørgrav     DEBUG(fprintf(stderr,
3894ca1ab94SDag-Erling Smørgrav 		  "scheme:   [\033[1m%s\033[m]\n"
3904ca1ab94SDag-Erling Smørgrav 		  "user:     [\033[1m%s\033[m]\n"
3914ca1ab94SDag-Erling Smørgrav 		  "password: [\033[1m%s\033[m]\n"
3924ca1ab94SDag-Erling Smørgrav 		  "host:     [\033[1m%s\033[m]\n"
3934ca1ab94SDag-Erling Smørgrav 		  "port:     [\033[1m%d\033[m]\n"
3944ca1ab94SDag-Erling Smørgrav 		  "document: [\033[1m%s\033[m]\n",
3954ca1ab94SDag-Erling Smørgrav 		  u->scheme, u->user, u->pwd,
3964ca1ab94SDag-Erling Smørgrav 		  u->host, u->port, u->doc));
3974ca1ab94SDag-Erling Smørgrav 
3984ca1ab94SDag-Erling Smørgrav     return u;
3994ca1ab94SDag-Erling Smørgrav 
4004ca1ab94SDag-Erling Smørgrav ouch:
4014ca1ab94SDag-Erling Smørgrav     free(u);
4024ca1ab94SDag-Erling Smørgrav     return NULL;
4034ca1ab94SDag-Erling Smørgrav }
40460245e42SDag-Erling Smørgrav 
40560245e42SDag-Erling Smørgrav /*
40660245e42SDag-Erling Smørgrav  * Free a URL
40760245e42SDag-Erling Smørgrav  */
40860245e42SDag-Erling Smørgrav void
40960245e42SDag-Erling Smørgrav fetchFreeURL(struct url *u)
41060245e42SDag-Erling Smørgrav {
41160245e42SDag-Erling Smørgrav     free(u->doc);
41260245e42SDag-Erling Smørgrav     free(u);
41360245e42SDag-Erling Smørgrav }
414