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; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805111329.JAA15707>