Date: Mon, 11 May 1998 09:29:24 -0400 (EDT) From: Garrett Wollman <wollman@khavrinen.lcs.mit.edu> To: dag-erli@ifi.uio.no (Dag-Erling Coidan =?iso-8859-1?Q?Sm=F8rgrav?= ) Cc: Mike Smith <mike@smith.net.au>, "Jordan K. Hubbard" <jkh@time.cdrom.com>, Julian Elischer <julian@FreeBSD.ORG>, cvs-committers@FreeBSD.ORG, cvs-all@FreeBSD.ORG, cvs-lib@FreeBSD.ORG Subject: Re: cvs commit: src/lib/libftpio ftpio.c Message-ID: <199805111329.JAA15707@khavrinen.lcs.mit.edu> In-Reply-To: <xzp7m3u5k4a.fsf@hrotti.ifi.uio.no> References: <199805090554.WAA00630@antipodes.cdrom.com> <xzp7m3u5k4a.fsf@hrotti.ifi.uio.no>
next in thread | previous in thread | raw e-mail | index | archive | help
<<On 10 May 1998 15:30:13 +0200, dag-erli@ifi.uio.no (Dag-Erling Coidan =?iso-8859-1?Q?Sm=F8rgrav?= ) said:
> BTW, I have the HTTP code pretty much knocked into place now, though
> there are some problems with transfer-coding I need to work out (using
> funopen() so I can decode chunk-encoded data transparently. I'll soon
> start banging the FTP code from libftpio into place...
I would have hoped that you started from the HTTP code that's already
in fetch(1)... Here's a solution for your problem:
-GAWollman
------------------------------------
/*
* 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.
*/
static const char rcsid[] =
"$Id$";
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "streams.h" /* really independent of lpr/lpd */
/*
* substreams -- implement a stdio stream which returns EOF after a
* specified number of characters are read from it, with the data
* being read via another stdio stream.
*/
struct substream {
FILE *masterfp;
size_t len;
};
static int read_substream(void *cookie, char *buf, int len);
static int close_substream(void *cookie);
FILE *
create_substream(FILE *orig, size_t len)
{
struct substream *ssp;
FILE *rv;
ssp = malloc(sizeof *ssp);
if (ssp == 0)
return 0;
ssp->masterfp = orig;
ssp->len = len;
rv = funopen(ssp, read_substream, 0, 0, close_substream);
if (rv == 0)
free(ssp);
return rv;
}
static int
read_substream(void *cookie, char *buf, int len)
{
struct substream *ssp = cookie;
int rv;
if (len < 0)
return -1;
if (len != 0 && ssp->len == 0)
return 0;
if (len > ssp->len)
len = ssp->len;
rv = fread(buf, 1, len, ssp->masterfp);
if (rv < 0)
return rv;
if (rv == 0) {
ssp->len = 0; /* oops... eof before end of substream */
return 0;
}
ssp->len -= rv;
return rv;
}
static int
close_substream(void *cookie)
{
free(cookie);
return 0;
}
/*
* chunked substreams -- implement the HTTP/1.1 ``chunked'' transfer
* coding, which allows for multiple ``files'' to be transmitted on a
* stream without knowing in advance how long the files are. The HTTP/1.1
* protocol specifies an additional ``footer'' section, which we don't
* implement---that would be the responsibility of our caller if this
* code were to be used in an actual HTTP/1.1 implementation.
* The caller must be able to tolerate our use of fgetln() on the
* master stream.
*/
struct chunked_substream {
FILE *masterfp;
size_t chunklen;
int eof;
};
static int chunked_read(void *cookie, char *buf, int len);
static int chunked_write(void *cookie, const char *buf, int len);
static int chunked_close_ro(void *cookie);
static int chunked_close_wr(void *cookie);
FILE *
create_chunked_substream(FILE *orig, const char *mode)
{
int reading, writing;
struct chunked_substream *cssp;
FILE *rv;
reading = writing = 0;
switch(mode[0]) {
case 'r':
reading = 1;
break;
case 'a':
case 'w':
writing = 1;
break;
default:
errno = EINVAL;
return 0;
}
while (*++mode) {
if (*mode == '+')
reading = 1;
}
if (!(reading || writing)) {
errno = EINVAL;
return 0;
}
cssp = malloc(sizeof *cssp);
if (cssp == 0)
return 0;
cssp->masterfp = 0;
cssp->eof = 0;
cssp->chunklen = 0;
rv = funopen(cssp, reading ? chunked_read : 0,
writing ? chunked_write : 0, 0,
writing ? chunked_close_wr : chunked_close_ro);
if (rv == 0) {
free(cssp);
return 0;
}
return rv;
}
static int
chunked_read(void *cookie, char *buf, int len)
{
struct chunked_substream *cssp = cookie;
int rv;
if (cssp->eof) /* if we have read EOF, keep returning it */
return 0;
if (cssp->chunklen == 0) { /* we have yet to read the length */
char *len, *ep;
size_t lenlen;
unsigned long ilen;
if ((len = fgetln(cssp->masterfp, &lenlen)) == 0
|| len[lenlen - 1] != '\n') {
cssp->eof = 1;
return 0;
}
len[lenlen - 1] = '\0';
ilen = strtoul(len, &ep, 16);
if (ep - len < 2) { /* must be at least 1 valid digit */
cssp->eof = 1;
return 0;
}
cssp->chunklen = ilen;
if (ilen == 0) {
cssp->eof = 1;
return 0;
}
}
if (len > cssp->chunklen)
len = cssp->chunklen;
rv = fread(buf, 1, len, cssp->masterfp);
if (rv < 0)
return rv;
if (rv == 0)
cssp->eof = 1;
cssp->chunklen -= rv;
return rv;
}
static int
chunked_write(void *cookie, const char *buf, int len)
{
struct chunked_substream *cssp = cookie;
if (len < 0) {
errno = EINVAL;
return -1;
}
if (len == 0)
return 0;
fprintf(cssp->masterfp, "%d\r\n", len);
return fwrite(buf, 1, len, cssp->masterfp);
}
static int
chunked_close_ro(void *cookie)
{
free(cookie);
return 0;
}
static int
chunked_close_wr(void *cookie)
{
struct chunked_substream *cssp = cookie;
fputs("0\r\n", cssp->masterfp);
free(cssp);
return 0;
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe cvs-all" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805111329.JAA15707>
