fetch.c revision 37535
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 *	$Id$
29 */
30
31#include <sys/param.h>
32
33#include <ctype.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "fetch.h"
39
40#ifndef NDEBUG
41#define DEBUG(x) do x; while (0)
42#else
43#define DEBUG(x) do { } while (0)
44#endif
45
46
47/* get URL */
48FILE *
49fetchGetURL(char *URL, char *flags)
50{
51    url_t *u;
52    FILE *f;
53
54    /* parse URL */
55    if ((u = fetchParseURL(URL)) == NULL)
56	return NULL;
57
58    /* select appropriate function */
59    if (strcasecmp(u->scheme, "file") == 0)
60	f = fetchGetFile(u, flags);
61    else if (strcasecmp(u->scheme, "http") == 0)
62	f = fetchGetHTTP(u, flags);
63    else if (strcasecmp(u->scheme, "ftp") == 0)
64	f = fetchGetFTP(u, flags);
65    else f = NULL;
66
67    fetchFreeURL(u);
68    return f;
69}
70
71
72/* put URL */
73FILE *
74fetchPutURL(char *URL, char *flags)
75{
76    url_t *u;
77    FILE *f;
78
79    /* parse URL */
80    if ((u = fetchParseURL(URL)) == NULL)
81	return NULL;
82
83    /* select appropriate function */
84    if (strcasecmp(u->scheme, "file") == 0)
85	f = fetchPutFile(u, flags);
86    else if (strcasecmp(u->scheme, "http") == 0)
87	f = fetchPutHTTP(u, flags);
88    else if (strcasecmp(u->scheme, "ftp") == 0)
89	f = fetchPutFTP(u, flags);
90    else f = NULL;
91
92    fetchFreeURL(u);
93    return f;
94}
95
96/*
97 * Split an URL into components. URL syntax is:
98 * method:[//[user[:pwd]@]host[:port]]/[document]
99 * This almost, but not quite, RFC1738 URL syntax.
100 */
101url_t *
102fetchParseURL(char *URL)
103{
104    char *p, *q;
105    url_t *u;
106    int i;
107
108    /* allocate url_t */
109    if ((u = calloc(1, sizeof(url_t))) == NULL)
110	return NULL;
111
112    /* scheme name */
113    for (i = 0; *URL && (*URL != ':'); URL++)
114	if (i < URL_SCHEMELEN)
115	    u->scheme[i++] = *URL;
116    if (!URL[0] || (URL[1] != '/'))
117	goto ouch;
118    else URL++;
119    if (URL[1] != '/') {
120	p = URL;
121	goto nohost;
122    }
123    else URL += 2;
124
125    p = strpbrk(URL, "/@");
126    if (*p == '@') {
127	/* username */
128	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
129	    if (i < URL_USERLEN)
130		u->user[i++] = *q;
131
132	/* password */
133	if (*q == ':')
134	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
135		if (i < URL_PWDLEN)
136		    u->pwd[i++] = *q;
137
138	p++;
139    } else p = URL;
140
141    /* hostname */
142    for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
143	if (i < MAXHOSTNAMELEN)
144	    u->host[i++] = *p;
145
146    /* port */
147    if (*p == ':') {
148	for (q = ++p; *q && (*q != '/'); q++)
149	    if (isdigit(*q))
150		u->port = u->port * 10 + (*q - '0');
151	    else return 0; /* invalid port */
152	while (*p && (*p != '/'))
153	    p++;
154    }
155
156nohost:
157    /* document */
158    if (*p)
159	u->doc = strdup(p);
160    u->doc = strdup(*p ? p : "/");
161    if (!u->doc)
162	goto ouch;
163
164    DEBUG(fprintf(stderr,
165		  "scheme:   [\033[1m%s\033[m]\n"
166		  "user:     [\033[1m%s\033[m]\n"
167		  "password: [\033[1m%s\033[m]\n"
168		  "host:     [\033[1m%s\033[m]\n"
169		  "port:     [\033[1m%d\033[m]\n"
170		  "document: [\033[1m%s\033[m]\n",
171		  u->scheme, u->user, u->pwd,
172		  u->host, u->port, u->doc));
173
174    return u;
175
176ouch:
177    free(u);
178    return NULL;
179}
180
181void
182fetchFreeURL(url_t *u)
183{
184    if (u) {
185	if (u->doc)
186	    free(u->doc);
187	free(u);
188    }
189}
190