summaryrefslogtreecommitdiffstats
path: root/lib/libfetch
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>1998-07-09 16:52:44 +0000
committerdes <des@FreeBSD.org>1998-07-09 16:52:44 +0000
commit9c2d60ed01099cbfa3e878c62cb5ea061a728317 (patch)
tree04d9af7541ed2b2073b59882ba5ff645c502f891 /lib/libfetch
downloadFreeBSD-src-9c2d60ed01099cbfa3e878c62cb5ea061a728317.zip
FreeBSD-src-9c2d60ed01099cbfa3e878c62cb5ea061a728317.tar.gz
Imported libfetch into the tree. It compiles, but there's still some
work to do. I especially need help with the man page.
Diffstat (limited to 'lib/libfetch')
-rw-r--r--lib/libfetch/Makefile44
-rw-r--r--lib/libfetch/README23
-rw-r--r--lib/libfetch/base64.c90
-rw-r--r--lib/libfetch/fetch.3233
-rw-r--r--lib/libfetch/fetch.c189
-rw-r--r--lib/libfetch/fetch.h74
-rw-r--r--lib/libfetch/file.c49
-rw-r--r--lib/libfetch/ftp.c250
-rw-r--r--lib/libfetch/ftp.errors44
-rw-r--r--lib/libfetch/http.c338
-rw-r--r--lib/libfetch/http.errors41
11 files changed, 1375 insertions, 0 deletions
diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile
new file mode 100644
index 0000000..ad502d1
--- /dev/null
+++ b/lib/libfetch/Makefile
@@ -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>
diff --git a/lib/libfetch/README b/lib/libfetch/README
new file mode 100644
index 0000000..30ddeae
--- /dev/null
+++ b/lib/libfetch/README
@@ -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)
diff --git a/lib/libfetch/base64.c b/lib/libfetch/base64.c
new file mode 100644
index 0000000..fcb628c
--- /dev/null
+++ b/lib/libfetch/base64.c
@@ -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;
+}
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
new file mode 100644
index 0000000..347af29
--- /dev/null
+++ b/lib/libfetch/fetch.3
@@ -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.
diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c
new file mode 100644
index 0000000..99a2b9f
--- /dev/null
+++ b/lib/libfetch/fetch.c
@@ -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);
+ }
+}
diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h
new file mode 100644
index 0000000..387d4c4
--- /dev/null
+++ b/lib/libfetch/fetch.h
@@ -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
diff --git a/lib/libfetch/file.c b/lib/libfetch/file.c
new file mode 100644
index 0000000..0c685ef
--- /dev/null
+++ b/lib/libfetch/file.c
@@ -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");
+}
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
new file mode 100644
index 0000000..14d43b9
--- /dev/null
+++ b/lib/libfetch/ftp.c
@@ -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
diff --git a/lib/libfetch/ftp.errors b/lib/libfetch/ftp.errors
new file mode 100644
index 0000000..53a87f0
--- /dev/null
+++ b/lib/libfetch/ftp.errors
@@ -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
diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c
new file mode 100644
index 0000000..1cf9a9f
--- /dev/null
+++ b/lib/libfetch/http.c
@@ -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;
+}
diff --git a/lib/libfetch/http.errors b/lib/libfetch/http.errors
new file mode 100644
index 0000000..c0e3539
--- /dev/null
+++ b/lib/libfetch/http.errors
@@ -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
OpenPOWER on IntegriCloud