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