Annotation of libwww/Library/src/HTTChunk.c, revision 2.14
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.14 ! frystyk 6: ** @(#) $Id: HTTChunk.c,v 2.13 1998/03/22 21:39:43 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 */
2.14 ! frystyk 19: #include "wwwsys.h"
2.1 frystyk 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.6 frystyk 35: BOOL lastchunk; /* Is this the last chunk? */
36: BOOL trailer; /* Do we have a trailer? */
2.1 frystyk 37: HTEOLState state;
38: HTChunk * buf;
2.5 frystyk 39: int status; /* return code from down stream */
2.1 frystyk 40: };
41:
42: /* ------------------------------------------------------------------------- */
43:
44: /*
2.2 frystyk 45: ** Chunked Decoder stream
2.1 frystyk 46: */
2.2 frystyk 47: PRIVATE BOOL HTChunkDecode_header (HTStream * me)
2.1 frystyk 48: {
2.2 frystyk 49: char * line = HTChunk_data(me->buf);
50: if (line) {
2.9 frystyk 51: char *errstr = NULL;
52: me->left = strtol(line, &errstr, 16); /* hex! */
53: if (STREAM_TRACE) HTTrace("Chunked..... `%s\' chunk size: %X\n", line, me->left);
2.13 frystyk 54: if (errstr == line)
55: HTDebugBreak(__FILE__, __LINE__, "Chunk decoder received illigal chunk size: `%s\'\n", line);
2.6 frystyk 56: if (me->left > 0) {
2.2 frystyk 57: me->total += me->left;
2.1 frystyk 58:
2.2 frystyk 59: /* Look for arguments */
2.1 frystyk 60:
2.2 frystyk 61: HTChunk_clear(me->buf);
2.6 frystyk 62: } else if (me->left == 0) /* Last chunk */
63: me->lastchunk = YES;
64: else if (me->left < 0)
65: return NO;
2.2 frystyk 66: return YES;
2.1 frystyk 67: }
2.2 frystyk 68: return NO;
2.1 frystyk 69: }
70:
2.2 frystyk 71: PRIVATE int HTChunkDecode_block (HTStream * me, const char * b, int l)
2.1 frystyk 72: {
73: while (l > 0) {
2.7 frystyk 74: int length = l;
2.8 frystyk 75: if (me->left <= 0 && !me->trailer) {
2.1 frystyk 76: while (l > 0) {
77: if (me->state == EOL_FLF) {
2.6 frystyk 78: if (HTChunkDecode_header(me) == NO) return HT_ERROR;
2.8 frystyk 79: if (me->lastchunk) if (*b != CR && *b != LF) me->trailer = YES;
80: me->state = EOL_DOT;
2.1 frystyk 81: break;
2.8 frystyk 82: } else if (me->state == EOL_SLF) {
83: if (me->lastchunk) break;
84: me->state = EOL_BEGIN;
85: HTChunk_putc(me->buf, *b);
2.1 frystyk 86: } else if (*b == CR) {
87: me->state = me->state == EOL_DOT ? EOL_SCR : EOL_FCR;
88: } else if (*b == LF) {
2.8 frystyk 89: me->state = me->state == EOL_SCR ? EOL_SLF : EOL_FLF;
2.6 frystyk 90: } else
91: HTChunk_putc(me->buf, *b);
2.1 frystyk 92: b++, l--;
93: }
94: }
2.6 frystyk 95:
96: /*
2.7 frystyk 97: ** Account for the parts we read in the chunk header +
98: ** the chunk that we are reading.
2.6 frystyk 99: */
2.8 frystyk 100: if (length != l)
2.7 frystyk 101: HTHost_setConsumed(HTNet_host(HTRequest_net(me->request)), length - l);
102:
103: /*
104: ** If we have to read trailers. Otherwise we are done.
105: */
2.9 frystyk 106: if (me->trailer) {
2.8 frystyk 107: me->target = HTStreamStack(WWW_MIME_FOOT, WWW_SOURCE,
108: me->target, me->request, NO);
2.9 frystyk 109: } else if (me->state == EOL_SLF) {
2.8 frystyk 110: if (me->lastchunk) return HT_LOADED;
111: me->state = EOL_BEGIN;
2.7 frystyk 112: }
2.6 frystyk 113:
114: /*
115: ** Handle the rest of the data including trailers
116: */
2.8 frystyk 117: if (l > 0 && me->left) {
118: int bytes = HTMIN(l, me->left);
119: int status = (*me->target->isa->put_block)(me->target, b, bytes);
120: if (status != HT_OK) return status;
2.7 frystyk 121: HTHost_setConsumed(HTNet_host(HTRequest_net(me->request)), bytes);
2.5 frystyk 122: me->left -= bytes;
123: l -= bytes, b+= bytes;
2.1 frystyk 124: }
125: }
2.8 frystyk 126: return HT_OK;
2.1 frystyk 127: }
128:
2.2 frystyk 129: PRIVATE int HTChunkDecode_string (HTStream * me, const char * s)
2.1 frystyk 130: {
2.2 frystyk 131: return HTChunkDecode_block(me, s, (int) strlen(s));
2.1 frystyk 132: }
133:
2.2 frystyk 134: PRIVATE int HTChunkDecode_character (HTStream * me, char c)
2.1 frystyk 135: {
2.2 frystyk 136: return HTChunkDecode_block(me, &c, 1);
2.1 frystyk 137: }
138:
2.2 frystyk 139: PRIVATE int HTChunkDecode_flush (HTStream * me)
2.1 frystyk 140: {
141: return (*me->target->isa->flush)(me->target);
142: }
143:
2.2 frystyk 144: PRIVATE int HTChunkDecode_free (HTStream * me)
2.1 frystyk 145: {
146: int status = HT_OK;
147: HTParentAnchor * anchor = HTRequest_anchor(me->request);
2.7 frystyk 148:
149: /*
150: ** Update the amount of data that we read in all.
151: */
2.1 frystyk 152: HTAnchor_setLength(anchor, me->total);
2.7 frystyk 153:
2.1 frystyk 154: if (me->target) {
155: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
156: return HT_WOULD_BLOCK;
157: }
158: if (PROT_TRACE) HTTrace("Chunked..... FREEING....\n");
159: HTChunk_delete(me->buf);
160: HT_FREE(me);
161: return status;
162: }
163:
2.2 frystyk 164: PRIVATE int HTChunkDecode_abort (HTStream * me, HTList * e)
2.1 frystyk 165: {
166: int status = HT_ERROR;
167: if (me->target) status = (*me->target->isa->abort)(me->target, e);
168: if (PROT_TRACE) HTTrace("Chunked..... ABORTING...\n");
2.2 frystyk 169: HTChunk_delete(me->buf);
2.1 frystyk 170: HT_FREE(me);
171: return status;
172: }
173:
2.2 frystyk 174: PRIVATE const HTStreamClass HTChunkDecodeClass =
2.1 frystyk 175: {
2.2 frystyk 176: "ChunkDecoder",
177: HTChunkDecode_flush,
178: HTChunkDecode_free,
179: HTChunkDecode_abort,
180: HTChunkDecode_character,
181: HTChunkDecode_string,
182: HTChunkDecode_block
2.1 frystyk 183: };
184:
185: PUBLIC HTStream * HTChunkedDecoder (HTRequest * request,
186: void * param,
187: HTEncoding coding,
188: HTStream * target)
189: {
190: HTStream * me;
191: HTParentAnchor * anchor = HTRequest_anchor(request);
192: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
2.2 frystyk 193: HT_OUTOFMEM("HTChunkDecoder");
194: me->isa = &HTChunkDecodeClass;
2.1 frystyk 195: me->coding = coding;
196: me->target = target;
197: me->request = request;
198: me->state = EOL_BEGIN;
199: me->buf = HTChunk_new(64);
2.7 frystyk 200: me->status = HT_ERROR;
2.1 frystyk 201:
202: /* Adjust information in anchor */
2.2 frystyk 203: HTAnchor_setLength(anchor, -1);
2.1 frystyk 204:
205: if (STREAM_TRACE) HTTrace("Chunked..... Decoder stream created\n");
206: return me;
207: }
2.2 frystyk 208:
209: /*
210: ** Chunked Encoder Stream
211: */
212: PRIVATE int HTChunkEncode_block (HTStream * me, const char * b, int l)
213: {
214: char * chunky = HTChunk_data(me->buf);
2.6 frystyk 215: if (me->lastchunk) return HT_LOADED;
2.2 frystyk 216: if (me->param) {
217: if (me->total)
218: sprintf(chunky, "%c%c%x %s %c%c", CR, LF, l, me->param, CR, LF);
219: else
220: sprintf(chunky, "%x %s %c%c", l, me->param, CR, LF);
221: } else {
222: if (me->total)
223: sprintf(chunky, "%c%c%x%c%c", CR, LF, l, CR, LF);
224: else
225: sprintf(chunky, "%x%c%c", l, CR, LF);
226: }
227: me->total += l;
228: PUTBLOCK(chunky, (int) strlen(chunky));
2.4 frystyk 229: if (STREAM_TRACE) HTTrace("Chunked..... chunk size 0x%X\n", l);
2.2 frystyk 230: if (l > 0) return PUTBLOCK(b, l);
231:
232: /* Here we should provide a footer */
233:
234: PUTC(CR);
235: PUTC(LF);
2.6 frystyk 236: me->lastchunk = YES;
2.4 frystyk 237: (*me->target->isa->flush)(me->target);
2.3 frystyk 238: return HT_LOADED;
2.2 frystyk 239: }
240:
241: PRIVATE int HTChunkEncode_string (HTStream * me, const char * s)
242: {
243: return HTChunkEncode_block(me, s, (int) strlen(s));
244: }
245:
246: PRIVATE int HTChunkEncode_character (HTStream * me, char c)
247: {
248: return HTChunkEncode_block(me, &c, 1);
249: }
250:
251: PRIVATE int HTChunkEncode_flush (HTStream * me)
252: {
253: return (*me->target->isa->flush)(me->target);
254: }
255:
256: PRIVATE int HTChunkEncode_free (HTStream * me)
257: {
2.4 frystyk 258: #if 0
2.2 frystyk 259: int status = HTChunkEncode_block(me, NULL, 0);
260: if (status != HT_WOULD_BLOCK) {
261: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
262: return HT_WOULD_BLOCK;
263: HT_FREE(me);
264: }
265: return status;
2.4 frystyk 266: #else
267: int status = me->target ? (*me->target->isa->_free)(me->target) : HT_OK;
268: HT_FREE(me);
269: return status;
270: #endif
2.2 frystyk 271: }
272:
273: PRIVATE int HTChunkEncode_abort (HTStream * me, HTList * e)
274: {
275: int status = HT_ERROR;
276: if (me->target) status = (*me->target->isa->_free)(me->target);
277: if (PROT_TRACE) HTTrace("Chunked..... ABORTING...\n");
278: HT_FREE(me);
279: return status;
280: }
281:
282: PRIVATE const HTStreamClass HTChunkEncoderClass =
283: {
284: "ChunkEncoder",
285: HTChunkEncode_flush,
286: HTChunkEncode_free,
287: HTChunkEncode_abort,
288: HTChunkEncode_character,
289: HTChunkEncode_string,
290: HTChunkEncode_block
291: };
292:
293: PUBLIC HTStream * HTChunkedEncoder (HTRequest * request,
294: void * param,
295: HTEncoding coding,
296: HTStream * target)
297: {
298: HTStream * me;
299: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
300: HT_OUTOFMEM("HTChunkEncoder");
301: me->isa = &HTChunkEncoderClass;
302: me->coding = coding;
303: me->target = target;
304: me->request = request;
305: me->param = (char *) param;
306: me->state = EOL_BEGIN;
2.7 frystyk 307: me->status = HT_ERROR;
2.2 frystyk 308: {
309: int length = me->param ? strlen(me->param)+20 : 20;
310: me->buf = HTChunk_new(length);
311: HTChunk_ensure(me->buf, length);
312: }
313:
314: if (STREAM_TRACE) HTTrace("Chunked..... Encoder stream created\n");
315: return me;
316: }
317:
318:
319:
Webmaster