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