Imported libfetch into the tree. It compiles, but there's still some

work to do. I especially need help with the man page.
This commit is contained in:
Dag-Erling Smørgrav 1998-07-09 16:52:44 +00:00
parent 932634cdff
commit 4ca1ab9434
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/DES/; revision=37535
11 changed files with 1375 additions and 0 deletions

44
lib/libfetch/Makefile Normal file
View File

@ -0,0 +1,44 @@
LIB= fetch
CFLAGS+= -I${.CURDIR} -Wall
SRCS= fetch.c ftp.c http.c file.c base64.c
MAN3= fetch.3
CLEANFILES+= ftperr.c httperr.c
SHLIB_MAJOR= 1
SHLIB_MINOR= 0
beforeinstall:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/fetch.h \
${DESTDIR}/usr/include
ftperr.c: ftp.errors
@echo "struct ftperr {" \ >> ${.TARGET}
@echo " const int num;" \ >> ${.TARGET}
@echo " const char *string;" \ >> ${.TARGET}
@echo "};" \ >> ${.TARGET}
@echo "static struct ftperr _ftp_errlist[] = {" \ >> ${.TARGET}
@cat ${.ALLSRC} \
| grep -v ^# \
| sort \
| while read NUM STRING; do \
echo " { $${NUM}, \"$${NUM} $${STRING}\" },"; \
done >> ${.TARGET}
@echo " { 0, \"Unknown FTP error\" }" >> ${.TARGET}
@echo "};" >> ${.TARGET}
httperr.c: http.errors
@echo "struct httperr {" \ >> ${.TARGET}
@echo " const int num;" \ >> ${.TARGET}
@echo " const char *string;" \ >> ${.TARGET}
@echo "};" \ >> ${.TARGET}
@echo "static struct httperr _http_errlist[] = {" \ >> ${.TARGET}
@cat ${.ALLSRC} \
| grep -v ^# \
| sort \
| while read NUM STRING; do \
echo " { $${NUM}, \"$${NUM} $${STRING}\" },"; \
done >> ${.TARGET}
@echo " { 0, \"Unknown HTTP error\" }" >> ${.TARGET}
@echo "};" >> ${.TARGET}
.include <bsd.lib.mk>

23
lib/libfetch/README Normal file
View File

@ -0,0 +1,23 @@
This is the new fetch(3) library, which is to replace the ftpio(3)
library and provide a new, unified backend for all fetch(1),
pkg_add(1) and sysinstall(8).
Note that this is very much work in progress. It compiles (with a few
warnings), but there is much left to be implemented. Amongst other
items:
* The man page needs work. Really. I mean it. Now.
* ftp.c is not even half-written.
* HTTP authentication doesn't work. I'm not sure if I bungled http.c
or fubared base64.c (which was ripped from MIT fetch(1)).
* The library needs a decent interface for reporting errors. I've
started on something (sending back an error code in the url_t that
was sent in) but we're Not There (tm) yet.
Comments, patches etc. of all kinds are welcome, but please don't
commit anything without talking to me first.
-- Dag-Erling C. Smørgrav (des@FreeBSD.org)

90
lib/libfetch/base64.c Normal file
View File

@ -0,0 +1,90 @@
/*-
* Copyright 1997 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: util.c,v 1.6 1998/02/20 05:08:53 jb Exp $
*/
#include <stdio.h>
/*
* Not much left of the original MIT code, but it's still derived from it
* so I'll keep their copyright. This is taken from util.c in MIT fetch.
*
* -- DES 1998/05/22
*/
/*
* Implement the `base64' encoding as described in RFC 1521.
*/
static const char base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int
fprint64(FILE *f, const unsigned char *buf)
{
int len = 0, l = 0;
unsigned int tmp;
while (buf[len])
len++;
while (len >= 3) {
tmp = buf[0] << 16 | buf[1] << 8 | buf[2];
fprintf(f, "%c%c%c%c",
base64[(tmp >> 18) & 077],
base64[(tmp >> 12) & 077],
base64[(tmp >> 6) & 077],
base64[tmp & 077]);
len -= 3;
buf += 3;
l += 4;
}
/* RFC 1521 enumerates these three possibilities... */
switch(len) {
case 2:
tmp = buf[0] << 16 | buf[1] << 8;
fprintf(f, "%c%c%c=",
base64[(tmp >> 18) & 077],
base64[(tmp >> 12) & 077],
base64[(tmp >> 6) & 077]);
l += 4;
break;
case 1:
tmp = buf[0] << 16;
fprintf(f, "%c%c==",
base64[(tmp >> 18) & 077],
base64[(tmp >> 12) & 077]);
l += 4;
break;
case 0:
break;
}
return l;
}

233
lib/libfetch/fetch.3 Normal file
View File

@ -0,0 +1,233 @@
.\" Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $Id$
.\"
.Dd July 1, 1998
.Dt FETCH 3
.Os
.Sh NAME
.Nm fetchParseURL ,
.Nm fetchFreeURL ,
.Nm fetchGetURL ,
.Nm fetchPutURL ,
.Nm fetchGetFile ,
.Nm fetchPutFile ,
.Nm fetchGetHTTP ,
.Nm fetchPutHTTP ,
.Nm fetchGetFTP ,
.Nm fetchPutFTP
.Nd file transfer library
.Sh SYNOPSIS
.Fd #include <fetch.h>
.Ft url_t *
.Fn fetchParseURL "char *URL" "char *flags"
.Ft void
.Fn fetchFreeURL "url_t *u"
.Ft FILE *
.Fn fetchGetFile "url_t *u" "char *flags"
.Ft FILE *
.Fn fetchPutFile "url_t *u" "char *flags"
.Ft FILE *
.Fn fetchGetHTTP "url_t *u" "char *flags"
.Ft FILE *
.Fn fetchPutHTTP "url_t *u" "char *flags"
.Ft FILE *
.Fn fetchGetFTP "url_t *u" "char *flags"
.Ft FILE *
.Fn fetchPutFTP "url_t *u" "char *flags"
.Sh DESCRIPTION
These functions implement a high-level library for retrieving and
uploading files using Uniform Resource Locators (URLs).
.Pp
.Fn fetchParseURL
takes a URL in the form of a null-terminated string and splits it into
its components function according to the Common Internet Scheme Syntax
detailed in RFC1738. A regular expression which produces this syntax
is:
.Bd -literal
<scheme>:(//(<user>(:<pwd>)?@)?<host>(:<port>)?)?/(<document>)?
.Ed
.Pp
Note that some components of the URL are not necessarily relevant to
all URL schemes. For instance, the file scheme only needs the <scheme>
and <document> components.
.Pp
The pointer returned by
.Fn fetchParseURL
should be freed using
.Fn fetchFreeURL .
.Pp
.Fn fetchGetURL
and
.Fn fetchPutURL
constitute the recommended interface to the
.Nm fetch
library. They examine the URL passed to them to determine the transfer
method, and call the appropriate lower-level functions to perform the
actual transfer. The
.Fa flags
argument is a string of characters which specify transfer options. The
meaning of the individual flags is scheme-dependent, and is detailed
in the appropriate section below.
.Pp
All of the
.Fn fetchGetXXX
and
.Fn fetchPutXXX
functions return a pointer to a stream which can be used to read or
write data from or to the requested document, respectively. Not that
although the implementation details of the individual access methods
vary, it can generally be assumed that a stream returned by one of the
.Fn fetchGetXXX
functions is read-only, and that a stream returned by one of the
.Fn fetchPutXXX
functions is write-only.
.Sh FILE SCHEME
.Fn fetchGetFile
and
.Fn fetchPutFile
provide access to documents which are files in a locally mounted file
system. Only the <document> component of the URL is used.
.Pp
.Fn fetchGetFile
does not accept any flags.
.Pp
.Fn fetchPutFile
accepts the
.Fa a
(append to file) flag. If that flag is specified, the data written to
the stream returned by
.Fn fetchPutFile
will be appended to the previous contents of the file, instead of
replacing them.
.Sh FTP SCHEME
.Fn fetchGetFTP
and
.Fn fetchPutFTP
implement the FTP protocol as described in RFC959.
.Pp
If the
.Fa p
(passive) flag is specified, a passive (rather than active) connection
will be attempted.
.Pp
If no user name or password is given, the
.Nm fetch
library will attempt an anonymous login, with user name "ftp" and
password "ftp".
.Sh HTTP SCHEME
The
.Fn fetchGetHTTP
and
.Fn fetchPutHTTP
functions implement the HTTP/1.1 protocol. With a little luck, there's
even a chance that they comply with RFC2068.
.Pp
Since there seems to be no good way of implementing the HTTP PUT
method in a manner consistent with the rest of the
.Nm fetch
library,
.Fn fetchPutHTTP
is currently unimplemented.
.Sh RETURN VALUES
.Fn fetchParseURL
returns a pointer to a
.Fa url_t
structure containing the individual components of the URL. If it is
unable to allocate memory, or the URL is syntactically incorrect,
.Fn fetchParseURL
returns a NULL pointer.
.Pp
.Fn fetchFreeURL
does not return any value.
.Pp
All other functions return a stream pointer which may be used to
access the requested document. Upon failure of any kind, they return a
NULL pointer.
.Sh ENVIRONMENT
The FTP and HTTP functions use the
.Ev HTTP_PROXY
and
.Ev FTP_PROXY
environment variables, respectively, as the address of a proxy server
to use for transferring files.
.Sh SEE ALSO
.Xr fetch 1 ,
.Xr ftpio 3 ,
.Xr lots_of_other_stuff
.Rs
.%A T. Berners-Lee, L. Masinter & M. McCahill
.%D December 1994
.%T Uniform Resource Locators (URL)
.%O RFC1738
.Re
.Rs
.%A R. Fielding, J. Gettys, J. Mogul, H. Frystyk, T. Berners-Lee
.%D Januray 1997
.%B Hypertext Transfer Protocol -- HTTP/1.1
.%O RFC2068
.Re
.Rs
.%A J. Postel, J. K. Reynolds
.%D October 1985
.%B File Transfer Protocol
.%O RFC959
.Re
.Sh DIAGNOSTICS
Add later.
.Sh NOTES
Some parts of the library are not yet implemented. The most notable
examples of this are
.Fn fetchPutHTTP
and proxy support for the FTP access method.
.Pp
I hate HTTP.
.Pp
Why does the \.Pp macro sometimes insert two blank lines instead of
one?
.Sh HISTORY
The
.Nm fetch
library first appeared in
.Fx 3.0 .
.Sh AUTHORS
The
.Nm fetch
library was mostly written by
.An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org
with numerous suggestions from
.An Jordan K. Hubbard Aq jkh@FreeBSD.org
and other FreeBSD developers.
It incorporates the older
.Nm ftpio
library, which was originally written by
.Nm Poul-Henning Kamp Aq pkh@FreeBSD.org
and later turned inside out by
.An Jordan K. Hubbard Aq jkh@FreeBSD.org .
.Pp
This manual page was written by
.An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org
.Sh BUGS
If I knew, I'd have fixed them.

189
lib/libfetch/fetch.c Normal file
View File

@ -0,0 +1,189 @@
/*-
* Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#include <sys/param.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fetch.h"
#ifndef NDEBUG
#define DEBUG(x) do x; while (0)
#else
#define DEBUG(x) do { } while (0)
#endif
/* get URL */
FILE *
fetchGetURL(char *URL, char *flags)
{
url_t *u;
FILE *f;
/* parse URL */
if ((u = fetchParseURL(URL)) == NULL)
return NULL;
/* select appropriate function */
if (strcasecmp(u->scheme, "file") == 0)
f = fetchGetFile(u, flags);
else if (strcasecmp(u->scheme, "http") == 0)
f = fetchGetHTTP(u, flags);
else if (strcasecmp(u->scheme, "ftp") == 0)
f = fetchGetFTP(u, flags);
else f = NULL;
fetchFreeURL(u);
return f;
}
/* put URL */
FILE *
fetchPutURL(char *URL, char *flags)
{
url_t *u;
FILE *f;
/* parse URL */
if ((u = fetchParseURL(URL)) == NULL)
return NULL;
/* select appropriate function */
if (strcasecmp(u->scheme, "file") == 0)
f = fetchPutFile(u, flags);
else if (strcasecmp(u->scheme, "http") == 0)
f = fetchPutHTTP(u, flags);
else if (strcasecmp(u->scheme, "ftp") == 0)
f = fetchPutFTP(u, flags);
else f = NULL;
fetchFreeURL(u);
return f;
}
/*
* Split an URL into components. URL syntax is:
* method:[//[user[:pwd]@]host[:port]]/[document]
* This almost, but not quite, RFC1738 URL syntax.
*/
url_t *
fetchParseURL(char *URL)
{
char *p, *q;
url_t *u;
int i;
/* allocate url_t */
if ((u = calloc(1, sizeof(url_t))) == NULL)
return NULL;
/* scheme name */
for (i = 0; *URL && (*URL != ':'); URL++)
if (i < URL_SCHEMELEN)
u->scheme[i++] = *URL;
if (!URL[0] || (URL[1] != '/'))
goto ouch;
else URL++;
if (URL[1] != '/') {
p = URL;
goto nohost;
}
else URL += 2;
p = strpbrk(URL, "/@");
if (*p == '@') {
/* username */
for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
if (i < URL_USERLEN)
u->user[i++] = *q;
/* password */
if (*q == ':')
for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
if (i < URL_PWDLEN)
u->pwd[i++] = *q;
p++;
} else p = URL;
/* hostname */
for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
if (i < MAXHOSTNAMELEN)
u->host[i++] = *p;
/* port */
if (*p == ':') {
for (q = ++p; *q && (*q != '/'); q++)
if (isdigit(*q))
u->port = u->port * 10 + (*q - '0');
else return 0; /* invalid port */
while (*p && (*p != '/'))
p++;
}
nohost:
/* document */
if (*p)
u->doc = strdup(p);
u->doc = strdup(*p ? p : "/");
if (!u->doc)
goto ouch;
DEBUG(fprintf(stderr,
"scheme: [\033[1m%s\033[m]\n"
"user: [\033[1m%s\033[m]\n"
"password: [\033[1m%s\033[m]\n"
"host: [\033[1m%s\033[m]\n"
"port: [\033[1m%d\033[m]\n"
"document: [\033[1m%s\033[m]\n",
u->scheme, u->user, u->pwd,
u->host, u->port, u->doc));
return u;
ouch:
free(u);
return NULL;
}
void
fetchFreeURL(url_t *u)
{
if (u) {
if (u->doc)
free(u->doc);
free(u);
}
}

74
lib/libfetch/fetch.h Normal file
View File

@ -0,0 +1,74 @@
/*-
* Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#ifndef _FETCH_H_INCLUDED
#define _FETCH_H_INCLUDED
#include <sys/param.h>
#define _LIBFETCH_VER "libfetch/1.0"
#define URL_SCHEMELEN 16
#define URL_USERLEN 256
#define URL_PWDLEN 256
struct url_s {
char scheme[URL_SCHEMELEN+1];
char user[URL_USERLEN+1];
char pwd[URL_PWDLEN+1];
char host[MAXHOSTNAMELEN+1];
char *doc;
int port;
char *lasterr;
};
typedef struct url_s url_t;
/* FILE-specific functions */
FILE *fetchGetFile(url_t *, char *);
FILE *fetchPutFile(url_t *, char *);
/* HTTP-specific functions */
char *fetchContentType(FILE *f);
FILE *fetchGetHTTP(url_t *, char *);
FILE *fetchPutHTTP(url_t *, char *);
/* FTP-specific functions */
FILE *fetchGetFTP(url_t *, char *);
FILE *fetchPutFTP(url_t *, char *);
/* Generic functions */
url_t *fetchParseURL(char *URL);
void fetchFreeURL(url_t *u);
FILE *fetchGetURL(char *, char *);
FILE *fetchPutURL(char *, char *);
#endif

49
lib/libfetch/file.c Normal file
View File

@ -0,0 +1,49 @@
/*-
* Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#include <stdio.h>
#include <string.h>
#include "fetch.h"
FILE *
fetchGetFile(url_t *u, char *flags)
{
flags = flags; /* unused */
return fopen(u->doc, "r");
}
FILE *
fetchPutFile(url_t *u, char *flags)
{
if (strchr(flags, 'a'))
return fopen(u->doc, "a");
else return fopen(u->doc, "w");
}

250
lib/libfetch/ftp.c Normal file
View File

@ -0,0 +1,250 @@
/*-
* Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
/*
* Portions of this code were taken from ftpio.c:
*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* Major Changelog:
*
* Dag-Erling Coïdan Smørgrav
* 9 Jun 1998
*
* Incorporated into libfetch
*
* Jordan K. Hubbard
* 17 Jan 1996
*
* Turned inside out. Now returns xfers as new file ids, not as a special
* `state' of FTP_t
*
* $ftpioId: ftpio.c,v 1.30 1998/04/11 07:28:53 phk Exp $
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include "fetch.h"
#include "ftperr.c"
#define FTP_ANONYMOUS_USER "ftp"
#define FTP_ANONYMOUS_PASSWORD "ftp"
static url_t cached_host;
static FILE *cached_socket;
static int _ftp_errcode;
static int
_ftp_isconnected(url_t *url)
{
return (cached_socket
&& (strcmp(url->host, cached_host.host) == 0)
&& (strcmp(url->user, cached_host.user) == 0)
&& (strcmp(url->pwd, cached_host.pwd) == 0)
&& (url->port == cached_host.port));
}
/*
* Get server response, check that first digit is a '2'
*/
static int
_ftp_chkerr(FILE *s, char *e)
{
char *line;
size_t len;
do {
if (((line = fgetln(s, &len)) == NULL) || (len < 4))
return -1;
} while (line[3] == '-');
if (!isdigit(line[0]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' '))
return -1;
_ftp_errcode = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0');
if (e)
*e = _ftp_errcode;
return (line[0] == '2') - 1;
}
/*
* Map error code to string
*/
static const char *
_ftp_errstring(int e)
{
struct ftperr *p = _ftp_errlist;
while ((p->num) && (p->num != e))
p++;
return p->string;
}
/*
* Change remote working directory
*/
static int
_ftp_cwd(FILE *s, char *dir)
{
fprintf(s, "CWD %s\n", dir);
if (ferror(s))
return -1;
return _ftp_chkerr(s, NULL); /* expecting 250 */
}
/*
* Retrieve file
*/
static FILE *
_ftp_retr(FILE *s, char *file, int pasv)
{
char *p;
/* change directory */
if (((p = strrchr(file, '/')) != NULL) && (p != file)) {
*p = 0;
if (_ftp_cwd(s, file) < 0) {
*p = '/';
return NULL;
}
*p++ = '/';
} else {
if (_ftp_cwd(s, "/") < 0)
return NULL;
}
/* retrieve file; p now points to file name */
return NULL;
}
/*
* XXX rewrite these
*/
#if 0
FILE *
fetchGetFTP(url_t *url, char *flags)
{
int retcode = 0;
static FILE *fp = NULL;
static char *prev_host = NULL;
FILE *fp2;
#ifdef DEFAULT_TO_ANONYMOUS
if (!url->user[0]) {
strcpy(url->user, FTP_ANONYMOUS_USER);
strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD);
}
#endif
if (fp && prev_host) {
if (!strcmp(prev_host, url->host)) {
/* Try to use cached connection */
fp2 = ftpGet(fp, url->doc, NULL);
if (!fp2) {
/* Connection timed out or was no longer valid */
fclose(fp);
free(prev_host);
prev_host = NULL;
}
else
return fp2;
}
else {
/* It's a different host now, flush old */
fclose(fp);
free(prev_host);
prev_host = NULL;
}
}
fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode);
if (fp) {
if (strchr(flags, 'p')) {
if (ftpPassive(fp, 1) != SUCCESS)
/* XXX what should we do? */ ;
}
fp2 = ftpGet(fp, url->doc, NULL);
if (!fp2) {
/* Connection timed out or was no longer valid */
retcode = ftpErrno(fp);
fclose(fp);
fp = NULL;
}
else
prev_host = strdup(url->host);
return fp2;
}
return NULL;
}
FILE *
fetchPutFTP(url_t *url, char *flags)
{
static FILE *fp = NULL;
FILE *fp2;
int retcode = 0;
if (fp) { /* Close previous managed connection */
fclose(fp);
fp = NULL;
}
fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode);
if (fp) {
if (strchr(flags, 'p')) {
if (ftpPassive(fp, 1) != SUCCESS)
/* XXX what should we do? */ ;
}
fp2 = ftpPut(fp, url->doc);
if (!fp2) {
retcode = ftpErrno(fp);
fclose(fp);
fp = NULL;
}
return fp2;
}
return NULL;
}
#endif

44
lib/libfetch/ftp.errors Normal file
View File

@ -0,0 +1,44 @@
# $Id: ftp.errors,v 1.3 1997/02/22 15:06:47 peter Exp $
#
# This list is taken from RFC 959.
# It probably needs a going over.
#
110 Restart marker reply
120 Service ready in a few minutes
125 Data connection already open; transfer starting
150 File status okay; about to open data connection
200 Command okay
202 Command not implemented, superfluous at this site
211 System status, or system help reply
212 Directory status
213 File status
214 Help message
215 Set system type
220 Service ready for new user
221 Service closing control connection
225 Data connection open; no transfer in progress
226 Requested file action successful
227 Entering Passive Mode
230 User logged in, proceed
250 Requested file action okay, completed
257 File/directory created
331 User name okay, need password
332 Need account for login
350 Requested file action pending further information
421 Service not available, closing control connection
425 Can't open data connection
426 Connection closed; transfer aborted
450 File unavailable (e.g., file busy)
451 Requested action aborted: local error in processing
452 Insufficient storage space in system
500 Syntax error, command unrecognized
501 Syntax error in parameters or arguments
502 Command not implemented
503 Bad sequence of commands
504 Command not implemented for that parameter
530 Not logged in
532 Need account for storing files
550 File unavailable (e.g., file not found, no access)
551 Requested action aborted. Page type unknown
552 Exceeded storage allocation
553 File name not allowed

338
lib/libfetch/http.c Normal file
View File

@ -0,0 +1,338 @@
/*-
* Copyright (c) 1998 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <err.h>
#include <ctype.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fetch.h"
#include "httperr.c"
#ifndef NDEBUG
#define DEBUG(x) do x; while (0)
#else
#define DEBUG(x) do { } while (0)
#endif
extern char *__progname;
extern int fprint64(FILE *f, const unsigned char *buf);
#define ENDL "\r\n"
struct cookie
{
FILE *real_f;
#define ENC_NONE 0
#define ENC_CHUNKED 1
int encoding; /* 1 = chunked, 0 = none */
#define HTTPCTYPELEN 59
char content_type[HTTPCTYPELEN+1];
char *buf;
int b_cur, eof;
unsigned b_len, chunksize;
};
static int
_http_connect(char *host, int port)
{
struct sockaddr_in sin;
struct hostent *he;
int fd;
/* look up host name */
if ((he = gethostbyname(host)) == NULL)
return -1;
/* set up socket address structure */
bzero(&sin, sizeof(sin));
bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
sin.sin_family = he->h_addrtype;
sin.sin_port = htons(port);
/* try to connect */
if ((fd = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
return -1;
if (connect(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
close(fd);
return -1;
}
return fd;
}
static char *
_http_fillbuf(struct cookie *c)
{
char *ln;
unsigned int len;
if (c->eof)
return NULL;
if (c->encoding == ENC_NONE) {
c->buf = fgetln(c->real_f, &(c->b_len));
c->b_cur = 0;
} else if (c->encoding == ENC_CHUNKED) {
if (c->chunksize == 0) {
ln = fgetln(c->real_f, &len);
DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): new chunk: "
"%*.*s\033[m\n", (int)len-2, (int)len-2, ln));
sscanf(ln, "%x", &(c->chunksize));
if (!c->chunksize) {
DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): "
"end of last chunk\033[m\n"));
c->eof = 1;
return NULL;
}
DEBUG(fprintf(stderr, "\033[1m_http_fillbuf(): "
"new chunk: %X\033[m\n", c->chunksize));
}
c->buf = fgetln(c->real_f, &(c->b_len));
if (c->b_len > c->chunksize)
c->b_len = c->chunksize;
c->chunksize -= c->b_len;
c->b_cur = 0;
}
else return NULL; /* unknown encoding */
return c->buf;
}
static int
_http_readfn(struct cookie *c, char *buf, int len)
{
int l, pos = 0;
while (len) {
/* empty buffer */
if (!c->buf || (c->b_cur == c->b_len))
if (!_http_fillbuf(c))
break;
l = c->b_len - c->b_cur;
if (len < l) l = len;
memcpy(buf + pos, c->buf + c->b_cur, l);
c->b_cur += l;
pos += l;
len -= l;
}
if (ferror(c->real_f))
return -1;
else return pos;
}
static int
_http_writefn(struct cookie *c, const char *buf, int len)
{
size_t r = fwrite(buf, 1, (size_t)len, c->real_f);
return r ? r : -1;
}
static int
_http_closefn(struct cookie *c)
{
int r = fclose(c->real_f);
free(c);
return (r == EOF) ? -1 : 0;
}
char *
fetchContentType(FILE *f)
{
/*
* We have no way of making sure this really *is* one of our cookies,
* so just check for a null pointer and hope for the best.
*/
return f->_cookie ? (((struct cookie *)f->_cookie)->content_type) : NULL;
}
FILE *
fetchGetHTTP(url_t *URL, char *flags)
{
int fd = -1, err, i, enc = ENC_NONE;
struct cookie *c;
char *ln, *p, *q;
FILE *f, *cf;
size_t len;
/* allocate cookie */
if ((c = calloc(1, sizeof(struct cookie))) == NULL)
return NULL;
/* check port */
if (!URL->port)
URL->port = 80; /* default HTTP port */
/* attempt to connect to proxy server */
if (getenv("HTTP_PROXY")) {
char *px, host[MAXHOSTNAMELEN];
int port = 3128; /* XXX I think 3128 is default... check? */
size_t len;
/* measure length */
px = getenv("HTTP_PROXY");
len = strcspn(px, ":");
/* get port (atoi is a little too tolerant perhaps?) */
if (px[len] == ':')
port = atoi(px+len+1);
/* get host name */
if (len >= MAXHOSTNAMELEN)
len = MAXHOSTNAMELEN - 1;
strncpy(host, px, len);
host[len] = 0;
/* connect */
fd = _http_connect(host, port);
}
/* if no proxy is configured or could be contacted, try direct */
if (fd < 0) {
if ((fd = _http_connect(URL->host, URL->port)) < 0)
goto ouch;
}
/* reopen as stream */
if ((f = fdopen(fd, "r+")) == NULL)
goto ouch;
c->real_f = f;
/* send request (proxies require absolute form, so use that) */
fprintf(f, "GET http://%s:%d/%s HTTP/1.1" ENDL,
URL->host, URL->port, URL->doc);
/* start sending headers away */
if (URL->user[0] || URL->pwd[0]) {
fprintf(f, "Authorization: Basic ");
fprint64(f, (const unsigned char *)URL->user);
fputc(':', f);
fprint64(f, (const unsigned char *)URL->pwd);
fputs(ENDL, f);
}
fprintf(f, "Host: %s:%d" ENDL, URL->host, URL->port);
fprintf(f, "User-Agent: %s " _LIBFETCH_VER ENDL, __progname);
fprintf(f, "Connection: close" ENDL ENDL);
/* get response */
if ((ln = fgetln(f, &len)) == NULL)
goto fouch;
DEBUG(fprintf(stderr, "response: [\033[1m%*.*s\033[m]\n",
(int)len-2, (int)len-2, ln));
/* we can't use strchr() and friends since ln isn't NUL-terminated */
p = ln;
while ((p < ln + len) && !isspace(*p))
p++;
while ((p < ln + len) && !isdigit(*p))
p++;
if (!isdigit(*p))
goto fouch;
err = atoi(p);
DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", err));
/* add code to handle redirects later */
if (err != 200)
goto fouch;
/* browse through header */
while (1) {
if ((ln = fgetln(f, &len)) == NULL)
goto fouch;
if ((ln[0] == '\r') || (ln[0] == '\n'))
break;
DEBUG(fprintf(stderr, "header: [\033[1m%*.*s\033[m]\n",
(int)len-2, (int)len-2, ln));
#define XFERENC "Transfer-Encoding:"
if (strncasecmp(ln, XFERENC, sizeof(XFERENC)-1) == 0) {
p = ln + sizeof(XFERENC) - 1;
while ((p < ln + len) && isspace(*p))
p++;
for (q = p; (q < ln + len) && !isspace(*q); q++)
/* VOID */ ;
*q = 0;
if (strcasecmp(p, "chunked") == 0)
enc = ENC_CHUNKED;
DEBUG(fprintf(stderr, "xferenc: [\033[1m%s\033[m]\n", p));
#undef XFERENC
#define CONTTYPE "Content-Type:"
} else if (strncasecmp(ln, CONTTYPE, sizeof(CONTTYPE)-1) == 0) {
p = ln + sizeof(CONTTYPE) - 1;
while ((p < ln + len) && isspace(*p))
p++;
for (i = 0; p < ln + len; p++)
if (i < HTTPCTYPELEN)
c->content_type[i++] = *p;
do c->content_type[i--] = 0; while (isspace(c->content_type[i]));
DEBUG(fprintf(stderr, "conttype: [\033[1m%s\033[m]\n",
c->content_type));
#undef CONTTYPE
}
}
/* only body remains */
c->encoding = enc;
cf = funopen(c,
(int (*)(void *, char *, int))_http_readfn,
(int (*)(void *, const char *, int))_http_writefn,
(fpos_t (*)(void *, fpos_t, int))NULL,
(int (*)(void *))_http_closefn);
if (cf == NULL)
goto fouch;
return cf;
ouch:
if (fd >= 0)
close(fd);
free(c);
return NULL;
fouch:
fclose(f);
free(c);
return NULL;
}
FILE *
fetchPutHTTP(url_t *URL, char *flags)
{
warnx("fetchPutHTTP(): not implemented");
return NULL;
}

41
lib/libfetch/http.errors Normal file
View File

@ -0,0 +1,41 @@
# $Id$
#
# This list is taken from RFC 2068.
#
100 Continue
101 Switching Protocols
200 OK
201 Created
202 Accepted
203 Non-Authoritative Information
204 No Content
205 Reset Content
206 Partial Content
300 Multiple Choices
301 Moved Permanently
302 Moved Temporarily
303 See Other
304 Not Modified
305 Use Proxy
400 Bad Request
401 Unauthorized
402 Payment Required
403 Forbidden
404 Not Found
405 Method Not Allowed
406 Not Acceptable
407 Proxy Authentication Required
408 Request Time-out
409 Conflict
410 Gone
411 Length Required
412 Precondition Failed
413 Request Entity Too Large
414 Request-URI Too Large
415 Unsupported Media Type
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable
504 Gateway Time-out
505 HTTP Version not supported