xref: /freebsd/lib/libfetch/fetch.c (revision 4ca1ab94348cfb9bf0b65b9f523e26c136a94210)
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  *	$Id$
294ca1ab94SDag-Erling Smørgrav  */
304ca1ab94SDag-Erling Smørgrav 
314ca1ab94SDag-Erling Smørgrav #include <sys/param.h>
324ca1ab94SDag-Erling Smørgrav 
334ca1ab94SDag-Erling Smørgrav #include <ctype.h>
344ca1ab94SDag-Erling Smørgrav #include <stdio.h>
354ca1ab94SDag-Erling Smørgrav #include <stdlib.h>
364ca1ab94SDag-Erling Smørgrav #include <string.h>
374ca1ab94SDag-Erling Smørgrav 
384ca1ab94SDag-Erling Smørgrav #include "fetch.h"
394ca1ab94SDag-Erling Smørgrav 
404ca1ab94SDag-Erling Smørgrav #ifndef NDEBUG
414ca1ab94SDag-Erling Smørgrav #define DEBUG(x) do x; while (0)
424ca1ab94SDag-Erling Smørgrav #else
434ca1ab94SDag-Erling Smørgrav #define DEBUG(x) do { } while (0)
444ca1ab94SDag-Erling Smørgrav #endif
454ca1ab94SDag-Erling Smørgrav 
464ca1ab94SDag-Erling Smørgrav 
474ca1ab94SDag-Erling Smørgrav /* get URL */
484ca1ab94SDag-Erling Smørgrav FILE *
494ca1ab94SDag-Erling Smørgrav fetchGetURL(char *URL, char *flags)
504ca1ab94SDag-Erling Smørgrav {
514ca1ab94SDag-Erling Smørgrav     url_t *u;
524ca1ab94SDag-Erling Smørgrav     FILE *f;
534ca1ab94SDag-Erling Smørgrav 
544ca1ab94SDag-Erling Smørgrav     /* parse URL */
554ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
564ca1ab94SDag-Erling Smørgrav 	return NULL;
574ca1ab94SDag-Erling Smørgrav 
584ca1ab94SDag-Erling Smørgrav     /* select appropriate function */
594ca1ab94SDag-Erling Smørgrav     if (strcasecmp(u->scheme, "file") == 0)
604ca1ab94SDag-Erling Smørgrav 	f = fetchGetFile(u, flags);
614ca1ab94SDag-Erling Smørgrav     else if (strcasecmp(u->scheme, "http") == 0)
624ca1ab94SDag-Erling Smørgrav 	f = fetchGetHTTP(u, flags);
634ca1ab94SDag-Erling Smørgrav     else if (strcasecmp(u->scheme, "ftp") == 0)
644ca1ab94SDag-Erling Smørgrav 	f = fetchGetFTP(u, flags);
654ca1ab94SDag-Erling Smørgrav     else f = NULL;
664ca1ab94SDag-Erling Smørgrav 
674ca1ab94SDag-Erling Smørgrav     fetchFreeURL(u);
684ca1ab94SDag-Erling Smørgrav     return f;
694ca1ab94SDag-Erling Smørgrav }
704ca1ab94SDag-Erling Smørgrav 
714ca1ab94SDag-Erling Smørgrav 
724ca1ab94SDag-Erling Smørgrav /* put URL */
734ca1ab94SDag-Erling Smørgrav FILE *
744ca1ab94SDag-Erling Smørgrav fetchPutURL(char *URL, char *flags)
754ca1ab94SDag-Erling Smørgrav {
764ca1ab94SDag-Erling Smørgrav     url_t *u;
774ca1ab94SDag-Erling Smørgrav     FILE *f;
784ca1ab94SDag-Erling Smørgrav 
794ca1ab94SDag-Erling Smørgrav     /* parse URL */
804ca1ab94SDag-Erling Smørgrav     if ((u = fetchParseURL(URL)) == NULL)
814ca1ab94SDag-Erling Smørgrav 	return NULL;
824ca1ab94SDag-Erling Smørgrav 
834ca1ab94SDag-Erling Smørgrav     /* select appropriate function */
844ca1ab94SDag-Erling Smørgrav     if (strcasecmp(u->scheme, "file") == 0)
854ca1ab94SDag-Erling Smørgrav 	f = fetchPutFile(u, flags);
864ca1ab94SDag-Erling Smørgrav     else if (strcasecmp(u->scheme, "http") == 0)
874ca1ab94SDag-Erling Smørgrav 	f = fetchPutHTTP(u, flags);
884ca1ab94SDag-Erling Smørgrav     else if (strcasecmp(u->scheme, "ftp") == 0)
894ca1ab94SDag-Erling Smørgrav 	f = fetchPutFTP(u, flags);
904ca1ab94SDag-Erling Smørgrav     else f = NULL;
914ca1ab94SDag-Erling Smørgrav 
924ca1ab94SDag-Erling Smørgrav     fetchFreeURL(u);
934ca1ab94SDag-Erling Smørgrav     return f;
944ca1ab94SDag-Erling Smørgrav }
954ca1ab94SDag-Erling Smørgrav 
964ca1ab94SDag-Erling Smørgrav /*
974ca1ab94SDag-Erling Smørgrav  * Split an URL into components. URL syntax is:
984ca1ab94SDag-Erling Smørgrav  * method:[//[user[:pwd]@]host[:port]]/[document]
994ca1ab94SDag-Erling Smørgrav  * This almost, but not quite, RFC1738 URL syntax.
1004ca1ab94SDag-Erling Smørgrav  */
1014ca1ab94SDag-Erling Smørgrav url_t *
1024ca1ab94SDag-Erling Smørgrav fetchParseURL(char *URL)
1034ca1ab94SDag-Erling Smørgrav {
1044ca1ab94SDag-Erling Smørgrav     char *p, *q;
1054ca1ab94SDag-Erling Smørgrav     url_t *u;
1064ca1ab94SDag-Erling Smørgrav     int i;
1074ca1ab94SDag-Erling Smørgrav 
1084ca1ab94SDag-Erling Smørgrav     /* allocate url_t */
1094ca1ab94SDag-Erling Smørgrav     if ((u = calloc(1, sizeof(url_t))) == NULL)
1104ca1ab94SDag-Erling Smørgrav 	return NULL;
1114ca1ab94SDag-Erling Smørgrav 
1124ca1ab94SDag-Erling Smørgrav     /* scheme name */
1134ca1ab94SDag-Erling Smørgrav     for (i = 0; *URL && (*URL != ':'); URL++)
1144ca1ab94SDag-Erling Smørgrav 	if (i < URL_SCHEMELEN)
1154ca1ab94SDag-Erling Smørgrav 	    u->scheme[i++] = *URL;
1164ca1ab94SDag-Erling Smørgrav     if (!URL[0] || (URL[1] != '/'))
1174ca1ab94SDag-Erling Smørgrav 	goto ouch;
1184ca1ab94SDag-Erling Smørgrav     else URL++;
1194ca1ab94SDag-Erling Smørgrav     if (URL[1] != '/') {
1204ca1ab94SDag-Erling Smørgrav 	p = URL;
1214ca1ab94SDag-Erling Smørgrav 	goto nohost;
1224ca1ab94SDag-Erling Smørgrav     }
1234ca1ab94SDag-Erling Smørgrav     else URL += 2;
1244ca1ab94SDag-Erling Smørgrav 
1254ca1ab94SDag-Erling Smørgrav     p = strpbrk(URL, "/@");
1264ca1ab94SDag-Erling Smørgrav     if (*p == '@') {
1274ca1ab94SDag-Erling Smørgrav 	/* username */
1284ca1ab94SDag-Erling Smørgrav 	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
1294ca1ab94SDag-Erling Smørgrav 	    if (i < URL_USERLEN)
1304ca1ab94SDag-Erling Smørgrav 		u->user[i++] = *q;
1314ca1ab94SDag-Erling Smørgrav 
1324ca1ab94SDag-Erling Smørgrav 	/* password */
1334ca1ab94SDag-Erling Smørgrav 	if (*q == ':')
1344ca1ab94SDag-Erling Smørgrav 	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
1354ca1ab94SDag-Erling Smørgrav 		if (i < URL_PWDLEN)
1364ca1ab94SDag-Erling Smørgrav 		    u->pwd[i++] = *q;
1374ca1ab94SDag-Erling Smørgrav 
1384ca1ab94SDag-Erling Smørgrav 	p++;
1394ca1ab94SDag-Erling Smørgrav     } else p = URL;
1404ca1ab94SDag-Erling Smørgrav 
1414ca1ab94SDag-Erling Smørgrav     /* hostname */
1424ca1ab94SDag-Erling Smørgrav     for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
1434ca1ab94SDag-Erling Smørgrav 	if (i < MAXHOSTNAMELEN)
1444ca1ab94SDag-Erling Smørgrav 	    u->host[i++] = *p;
1454ca1ab94SDag-Erling Smørgrav 
1464ca1ab94SDag-Erling Smørgrav     /* port */
1474ca1ab94SDag-Erling Smørgrav     if (*p == ':') {
1484ca1ab94SDag-Erling Smørgrav 	for (q = ++p; *q && (*q != '/'); q++)
1494ca1ab94SDag-Erling Smørgrav 	    if (isdigit(*q))
1504ca1ab94SDag-Erling Smørgrav 		u->port = u->port * 10 + (*q - '0');
1514ca1ab94SDag-Erling Smørgrav 	    else return 0; /* invalid port */
1524ca1ab94SDag-Erling Smørgrav 	while (*p && (*p != '/'))
1534ca1ab94SDag-Erling Smørgrav 	    p++;
1544ca1ab94SDag-Erling Smørgrav     }
1554ca1ab94SDag-Erling Smørgrav 
1564ca1ab94SDag-Erling Smørgrav nohost:
1574ca1ab94SDag-Erling Smørgrav     /* document */
1584ca1ab94SDag-Erling Smørgrav     if (*p)
1594ca1ab94SDag-Erling Smørgrav 	u->doc = strdup(p);
1604ca1ab94SDag-Erling Smørgrav     u->doc = strdup(*p ? p : "/");
1614ca1ab94SDag-Erling Smørgrav     if (!u->doc)
1624ca1ab94SDag-Erling Smørgrav 	goto ouch;
1634ca1ab94SDag-Erling Smørgrav 
1644ca1ab94SDag-Erling Smørgrav     DEBUG(fprintf(stderr,
1654ca1ab94SDag-Erling Smørgrav 		  "scheme:   [\033[1m%s\033[m]\n"
1664ca1ab94SDag-Erling Smørgrav 		  "user:     [\033[1m%s\033[m]\n"
1674ca1ab94SDag-Erling Smørgrav 		  "password: [\033[1m%s\033[m]\n"
1684ca1ab94SDag-Erling Smørgrav 		  "host:     [\033[1m%s\033[m]\n"
1694ca1ab94SDag-Erling Smørgrav 		  "port:     [\033[1m%d\033[m]\n"
1704ca1ab94SDag-Erling Smørgrav 		  "document: [\033[1m%s\033[m]\n",
1714ca1ab94SDag-Erling Smørgrav 		  u->scheme, u->user, u->pwd,
1724ca1ab94SDag-Erling Smørgrav 		  u->host, u->port, u->doc));
1734ca1ab94SDag-Erling Smørgrav 
1744ca1ab94SDag-Erling Smørgrav     return u;
1754ca1ab94SDag-Erling Smørgrav 
1764ca1ab94SDag-Erling Smørgrav ouch:
1774ca1ab94SDag-Erling Smørgrav     free(u);
1784ca1ab94SDag-Erling Smørgrav     return NULL;
1794ca1ab94SDag-Erling Smørgrav }
1804ca1ab94SDag-Erling Smørgrav 
1814ca1ab94SDag-Erling Smørgrav void
1824ca1ab94SDag-Erling Smørgrav fetchFreeURL(url_t *u)
1834ca1ab94SDag-Erling Smørgrav {
1844ca1ab94SDag-Erling Smørgrav     if (u) {
1854ca1ab94SDag-Erling Smørgrav 	if (u->doc)
1864ca1ab94SDag-Erling Smørgrav 	    free(u->doc);
1874ca1ab94SDag-Erling Smørgrav 	free(u);
1884ca1ab94SDag-Erling Smørgrav     }
1894ca1ab94SDag-Erling Smørgrav }
190