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