mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 21:05:08 +00:00
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:
parent
932634cdff
commit
4ca1ab9434
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/DES/; revision=37535
44
lib/libfetch/Makefile
Normal file
44
lib/libfetch/Makefile
Normal 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
23
lib/libfetch/README
Normal 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
90
lib/libfetch/base64.c
Normal 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
233
lib/libfetch/fetch.3
Normal 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
189
lib/libfetch/fetch.c
Normal 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
74
lib/libfetch/fetch.h
Normal 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
49
lib/libfetch/file.c
Normal 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
250
lib/libfetch/ftp.c
Normal 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
44
lib/libfetch/ftp.errors
Normal 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
338
lib/libfetch/http.c
Normal 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
41
lib/libfetch/http.errors
Normal 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
|
Loading…
Reference in a new issue