Annotation of libwww/Library/src/HTTChunk.c, revision 2.4.2.1
2.1 frystyk 1: /*
2: ** CHUNKED TRANSFER CODING
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.4.2.1 ! eric 6: ** @(#) $Id: HTTChunk.c,v 2.4 1996/08/08 02:17:01 frystyk Exp $
2.1 frystyk 7: **
8: ** This stream parses a chunked transfer encoding using multiple chunks.
9: **
10: ** Authors
11: ** HF Henrik Frystyk <frystyk@w3.org>
12: **
13: ** History:
14: ** Apr 96 Written from scratch
15: **
16: */
17:
18: /* Library include files */
19: #include "sysdep.h"
20: #include "WWWUtil.h"
21: #include "WWWCore.h"
22: #include "HTTChunk.h" /* Implemented here */
23:
24: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
2.2 frystyk 25: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
2.1 frystyk 26:
27: struct _HTStream {
28: const HTStreamClass * isa;
29: HTEncoding coding;
30: HTStream * target;
31: HTRequest * request;
2.2 frystyk 32: char * param; /* Extra parameters for encoding */
2.1 frystyk 33: long left; /* Remaining bytes in this chunk */
34: long total; /* Full length */
2.4 frystyk 35: BOOL done;
2.1 frystyk 36: HTEOLState state;
37: HTChunk * buf;
2.4.2.1 ! eric 38: int status; /* return code from down stream */
2.1 frystyk 39: };
40:
41: /* ------------------------------------------------------------------------- */
42:
43: /*
2.2 frystyk 44: ** Chunked Decoder stream
2.1 frystyk 45: */
2.2 frystyk 46: PRIVATE BOOL HTChunkDecode_header (HTStream * me)
2.1 frystyk 47: {
2.2 frystyk 48: char * line = HTChunk_data(me->buf);
49: if (line) {
50: me->left = strtol(line, (char **) NULL, 16); /* hex! */
51: if (STREAM_TRACE) HTTrace("Chunked..... chunk size: %X\n", me->left);
52: if (me->left) {
53: me->total += me->left;
2.1 frystyk 54:
2.2 frystyk 55: /* Look for arguments */
2.1 frystyk 56:
2.2 frystyk 57: HTChunk_clear(me->buf);
2.4.2.1 ! eric 58: } else /* Last chunk */
! 59: me->done = YES;
2.2 frystyk 60: return YES;
2.1 frystyk 61: }
2.2 frystyk 62: return NO;
2.1 frystyk 63: }
64:
2.2 frystyk 65: PRIVATE int HTChunkDecode_block (HTStream * me, const char * b, int l)
2.1 frystyk 66: {
2.4.2.1 ! eric 67: int length = l;
2.1 frystyk 68: while (l > 0) {
2.4.2.1 ! eric 69: if (me->left <= 0 && !me->done) {
2.1 frystyk 70: while (l > 0) {
71: if (me->state == EOL_FLF) {
2.2 frystyk 72: HTChunkDecode_header(me);
2.1 frystyk 73: me->state = EOL_DOT;
2.4.2.1 ! eric 74: if (me->done) /* look for new line or MIME header */
! 75: continue;
2.1 frystyk 76: break;
77: } else if (*b == CR) {
78: me->state = me->state == EOL_DOT ? EOL_SCR : EOL_FCR;
79: } else if (*b == LF) {
80: me->state = me->state == EOL_SCR ? EOL_BEGIN : EOL_FLF;
2.4.2.1 ! eric 81: } else {
! 82: if (me->done) {
! 83: HTRequest * request = me->request;
! 84: me->target = HTStreamStack(WWW_MIME_FOOT, WWW_SOURCE,
! 85: me->target, request, NO);
! 86: break;
! 87: }
! 88: HTChunk_putc(me->buf, *b); }
2.1 frystyk 89: b++, l--;
90: }
91: }
92: if (l > 0) {
93: int bytes = me->left ? HTMIN(l, me->left) : l;
2.4.2.1 ! eric 94: int status;
! 95: HTHost_setConsumed(HTNet_host(HTRequest_net(me->request)), length - l);
! 96: length = l;
! 97: if ((status = (*me->target->isa->put_block)(me->target, b, bytes)) < 0)
2.1 frystyk 98: return status;
2.4.2.1 ! eric 99: me->status = HT_LOADED;
! 100: me->left -= bytes;
! 101: l -= bytes, b+= bytes;
! 102: /*
! 103: ** If we are processing footers, the consumed is taken care of downstream
! 104: */
! 105: if (me->done)
! 106: length = l;
2.1 frystyk 107: }
2.4.2.1 ! eric 108: /*
! 109: ** account for the bytes used
! 110: */
! 111: HTHost_setConsumed(HTNet_host(HTRequest_net(me->request)), length - l);
! 112: length = l;
2.1 frystyk 113: }
2.4.2.1 ! eric 114: return me->done ? me->status : HT_OK;
2.1 frystyk 115: }
116:
2.2 frystyk 117: PRIVATE int HTChunkDecode_string (HTStream * me, const char * s)
2.1 frystyk 118: {
2.2 frystyk 119: return HTChunkDecode_block(me, s, (int) strlen(s));
2.1 frystyk 120: }
121:
2.2 frystyk 122: PRIVATE int HTChunkDecode_character (HTStream * me, char c)
2.1 frystyk 123: {
2.2 frystyk 124: return HTChunkDecode_block(me, &c, 1);
2.1 frystyk 125: }
126:
2.2 frystyk 127: PRIVATE int HTChunkDecode_flush (HTStream * me)
2.1 frystyk 128: {
129: return (*me->target->isa->flush)(me->target);
130: }
131:
2.2 frystyk 132: PRIVATE int HTChunkDecode_free (HTStream * me)
2.1 frystyk 133: {
134: int status = HT_OK;
135: HTParentAnchor * anchor = HTRequest_anchor(me->request);
136: HTAnchor_setLength(anchor, me->total);
137: if (me->target) {
138: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
139: return HT_WOULD_BLOCK;
140: }
141: if (PROT_TRACE) HTTrace("Chunked..... FREEING....\n");
142: HTChunk_delete(me->buf);
143: HT_FREE(me);
144: return status;
145: }
146:
2.2 frystyk 147: PRIVATE int HTChunkDecode_abort (HTStream * me, HTList * e)
2.1 frystyk 148: {
149: int status = HT_ERROR;
150: if (me->target) status = (*me->target->isa->abort)(me->target, e);
151: if (PROT_TRACE) HTTrace("Chunked..... ABORTING...\n");
2.2 frystyk 152: HTChunk_delete(me->buf);
2.1 frystyk 153: HT_FREE(me);
154: return status;
155: }
156:
2.2 frystyk 157: PRIVATE const HTStreamClass HTChunkDecodeClass =
2.1 frystyk 158: {
2.2 frystyk 159: "ChunkDecoder",
160: HTChunkDecode_flush,
161: HTChunkDecode_free,
162: HTChunkDecode_abort,
163: HTChunkDecode_character,
164: HTChunkDecode_string,
165: HTChunkDecode_block
2.1 frystyk 166: };
167:
168: PUBLIC HTStream * HTChunkedDecoder (HTRequest * request,
169: void * param,
170: HTEncoding coding,
171: HTStream * target)
172: {
173: HTStream * me;
174: HTParentAnchor * anchor = HTRequest_anchor(request);
175: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
2.2 frystyk 176: HT_OUTOFMEM("HTChunkDecoder");
177: me->isa = &HTChunkDecodeClass;
2.1 frystyk 178: me->coding = coding;
179: me->target = target;
180: me->request = request;
181: me->state = EOL_BEGIN;
182: me->buf = HTChunk_new(64);
2.4.2.1 ! eric 183: me->status = HT_OK;
2.1 frystyk 184:
185: /* Adjust information in anchor */
2.2 frystyk 186: HTAnchor_setLength(anchor, -1);
2.1 frystyk 187: HTAnchor_setTransfer(anchor, NULL);
188:
189: if (STREAM_TRACE) HTTrace("Chunked..... Decoder stream created\n");
190: return me;
191: }
2.2 frystyk 192:
193: /*
194: ** Chunked Encoder Stream
195: */
196: PRIVATE int HTChunkEncode_block (HTStream * me, const char * b, int l)
197: {
198: char * chunky = HTChunk_data(me->buf);
2.4 frystyk 199: if (me->done) return HT_LOADED;
2.2 frystyk 200: if (me->param) {
201: if (me->total)
202: sprintf(chunky, "%c%c%x %s %c%c", CR, LF, l, me->param, CR, LF);
203: else
204: sprintf(chunky, "%x %s %c%c", l, me->param, CR, LF);
205: } else {
206: if (me->total)
207: sprintf(chunky, "%c%c%x%c%c", CR, LF, l, CR, LF);
208: else
209: sprintf(chunky, "%x%c%c", l, CR, LF);
210: }
211: me->total += l;
212: PUTBLOCK(chunky, (int) strlen(chunky));
2.4 frystyk 213: if (STREAM_TRACE) HTTrace("Chunked..... chunk size 0x%X\n", l);
2.2 frystyk 214: if (l > 0) return PUTBLOCK(b, l);
215:
216: /* Here we should provide a footer */
217:
218: PUTC(CR);
219: PUTC(LF);
2.4 frystyk 220: me->done = YES;
221: (*me->target->isa->flush)(me->target);
2.3 frystyk 222: return HT_LOADED;
2.2 frystyk 223: }
224:
225: PRIVATE int HTChunkEncode_string (HTStream * me, const char * s)
226: {
227: return HTChunkEncode_block(me, s, (int) strlen(s));
228: }
229:
230: PRIVATE int HTChunkEncode_character (HTStream * me, char c)
231: {
232: return HTChunkEncode_block(me, &c, 1);
233: }
234:
235: PRIVATE int HTChunkEncode_flush (HTStream * me)
236: {
237: return (*me->target->isa->flush)(me->target);
238: }
239:
240: PRIVATE int HTChunkEncode_free (HTStream * me)
241: {
2.4 frystyk 242: #if 0
2.2 frystyk 243: int status = HTChunkEncode_block(me, NULL, 0);
244: if (status != HT_WOULD_BLOCK) {
245: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
246: return HT_WOULD_BLOCK;
247: HT_FREE(me);
248: }
249: return status;
2.4 frystyk 250: #else
251: int status = me->target ? (*me->target->isa->_free)(me->target) : HT_OK;
252: HT_FREE(me);
253: return status;
254: #endif
2.2 frystyk 255: }
256:
257: PRIVATE int HTChunkEncode_abort (HTStream * me, HTList * e)
258: {
259: int status = HT_ERROR;
260: if (me->target) status = (*me->target->isa->_free)(me->target);
261: if (PROT_TRACE) HTTrace("Chunked..... ABORTING...\n");
262: HT_FREE(me);
263: return status;
264: }
265:
266: PRIVATE const HTStreamClass HTChunkEncoderClass =
267: {
268: "ChunkEncoder",
269: HTChunkEncode_flush,
270: HTChunkEncode_free,
271: HTChunkEncode_abort,
272: HTChunkEncode_character,
273: HTChunkEncode_string,
274: HTChunkEncode_block
275: };
276:
277: PUBLIC HTStream * HTChunkedEncoder (HTRequest * request,
278: void * param,
279: HTEncoding coding,
280: HTStream * target)
281: {
282: HTStream * me;
283: HTParentAnchor * anchor = HTRequest_anchor(request);
284: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
285: HT_OUTOFMEM("HTChunkEncoder");
286: me->isa = &HTChunkEncoderClass;
287: me->coding = coding;
288: me->target = target;
289: me->request = request;
290: me->param = (char *) param;
291: me->state = EOL_BEGIN;
292: {
293: int length = me->param ? strlen(me->param)+20 : 20;
294: me->buf = HTChunk_new(length);
295: HTChunk_ensure(me->buf, length);
296: }
297:
298: /* Adjust information in anchor */
299: HTAnchor_setTransfer(anchor, NULL);
300:
301: if (STREAM_TRACE) HTTrace("Chunked..... Encoder stream created\n");
302: return me;
303: }
304:
305:
306:
Webmaster