Annotation of libwww/Library/src/HTConLen.c, revision 2.7

2.1       frystyk     1: /*                                                                  HTConlen.c
                      2: **     CONTENT LENGTH COUNTER STREAM
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
                      6: **
                      7: **     This stream counts the number of bytes in a stream until it reaches
                      8: **     max number of bytes it can occupy. If this happens then it gives up.
                      9: */
                     10: 
                     11: /* Library include files */
                     12: #include "tcp.h"
                     13: #include "HTUtils.h"
                     14: #include "HTString.h"
                     15: #include "HTReq.h"
                     16: #include "HTConLen.h"                                   /* Implemented here */
                     17: 
2.7     ! frystyk    18: #define HT_MIN_BLOCK   0x100
2.1       frystyk    19: #define HT_MAX_BLOCK   0x2000
                     20: #define HT_MAX_SIZE    0x10000
                     21: #define PUTBLOCK(b, l) (*me->target->isa->put_block)        (me->target, b, l)
                     22: 
                     23: typedef struct _HTBufItem {
                     24:     int                        len;
                     25:     char *             buf;
                     26:     struct _HTBufItem *        next;
                     27: } HTBufItem;
                     28: 
                     29: struct _HTStream {
                     30:     HTStreamClass *    isa;
                     31:     HTRequest *                request;
                     32:     HTStream *         target;
                     33: 
                     34:     char *             tmp_buf;
                     35:     int                        tmp_ind;
                     36:     int                        tmp_max;
                     37:     HTBufItem *                head;
                     38:     HTBufItem *                tail;
                     39: 
                     40:     int                        max_size;
                     41:     int                        cur_size;
                     42:     int                        conlen;
                     43: 
                     44:     BOOL               ignore;
                     45:     BOOL               give_up;
                     46: };
                     47: 
                     48: /* ------------------------------------------------------------------------- */
                     49: 
                     50: /*
                     51: **     MIME output with content-length calculation
                     52: **     -------------------------------------------
                     53: **     This stream also buffers the result to find out the content length.
                     54: **     If a maximum buffer limit is reached Content-Length is calculated
                     55: **     for logs but it is not sent to the client -- rather the buffer is
                     56: **     flushed right away.
                     57: **     Code taken from HTRequest.c written by Ari Luotonen and modified to
                     58: **     fit new stream model
                     59: */
                     60: 
                     61: PRIVATE BOOL free_buf (HTBufItem * me)
                     62: {
                     63:     if (me) {
                     64:        FREE(me->buf);
                     65:        free(me);
                     66:        return YES;
                     67:     }
                     68:     return NO;
                     69: }
                     70: 
                     71: PRIVATE void free_buf_all (HTStream * me)
                     72: {
                     73:     HTBufItem * cur = me->head;
                     74:     HTBufItem * killme;
2.6       frystyk    75:     me->tmp_ind = 0;
                     76:     me->tmp_max = 0;
                     77:     FREE(me->tmp_buf);
2.1       frystyk    78:     while (cur) {
                     79:        killme = cur;
                     80:        cur = cur->next;
                     81:        free_buf(cur);
                     82:     }
                     83:     me->head = me->tail = NULL;
                     84: }
                     85: 
                     86: PRIVATE void append_buf (HTStream * me)
                     87: {
                     88:     HTBufItem * b = (HTBufItem *) calloc(1, sizeof(HTBufItem));
                     89:     if (!b) outofmem(__FILE__, "append_buf");
                     90:     b->len = me->tmp_ind;
                     91:     b->buf = me->tmp_buf;
                     92:     me->tmp_ind = 0;
                     93:     me->tmp_max = 0;
                     94:     me->tmp_buf = 0;
                     95:     if (me->tail)
                     96:        me->tail->next = b;
                     97:     else
                     98:        me->head = b;
                     99:     me->tail = b;
                    100: }
                    101: 
                    102: PRIVATE BOOL alloc_new (HTStream * me, int size)
                    103: {
                    104:     if (me->conlen >= me->max_size) {
                    105:        if (STREAM_TRACE)
2.4       frystyk   106:            TTYPrint(TDEST,"StreamBuffer size %d reached, going transparent\n",
2.1       frystyk   107:                    me->max_size);
                    108:        return NO;
                    109:     } else if (size) {
                    110:        me->tmp_ind = 0;
                    111:        me->tmp_max = size;
                    112:        me->tmp_buf = (char *) malloc(size);
                    113:        if (!me->tmp_buf) outofmem(__FILE__, "buf_put_char");
                    114:        if (STREAM_TRACE)
2.2       frystyk   115:            TTYPrint(TDEST, "StreamBuffer created with len %d\n", size);
2.1       frystyk   116:        return YES;
                    117:     }
                    118:     return NO;
                    119: }
                    120: 
                    121: PRIVATE int buf_flush (HTStream * me)
                    122: {
                    123:     HTBufItem * cur;
                    124:     if (me->tmp_buf) append_buf(me);
                    125:     while ((cur = me->head)) {
2.4       frystyk   126:        int status;
                    127:        if ((status = PUTBLOCK(cur->buf, cur->len)) != HT_OK) return status;
2.1       frystyk   128:        me->head = cur->next;
                    129:        free_buf(cur);
                    130:     }
2.5       frystyk   131:     me->give_up = YES;
2.1       frystyk   132:     return HT_OK;
                    133: }
                    134: 
                    135: PRIVATE int buf_put_block (HTStream * me, CONST char * b, int l)
                    136: {
                    137:     me->conlen += l;
                    138:     if (!me->give_up) {
                    139:        if (me->tmp_buf && me->tmp_max-me->tmp_ind >= l) {     /* Still room */
                    140:            memcpy(me->tmp_buf + me->tmp_ind, b, l);
                    141:            me->tmp_ind += l;
                    142:            return HT_OK;
                    143:        } else {
                    144:            if (me->tmp_buf) append_buf(me);
                    145:            if (me->cur_size < HT_MAX_BLOCK) {
                    146:                int newsize = me->cur_size ? me->cur_size : HT_MIN_BLOCK;
                    147:                while (l > newsize && newsize < HT_MAX_BLOCK) newsize *= 2;
                    148:                me->cur_size = newsize;
                    149:            }
                    150:            if (!alloc_new(me, me->cur_size)) {
                    151:                int status = buf_flush(me);
                    152:                if (status != HT_OK) return status;
                    153:                me->give_up = YES;
                    154:            } else {
                    155:                memcpy(me->tmp_buf, b, l);
                    156:                me->tmp_ind = l;
                    157:            }
                    158:        }
                    159:     }
                    160:     if (me->give_up) return PUTBLOCK(b, l);
                    161:     return HT_OK;
                    162: }
                    163: 
                    164: PRIVATE int buf_put_char (HTStream * me, char c)
                    165: {
                    166:     return buf_put_block(me, &c, 1);
                    167: }
                    168: 
                    169: PRIVATE int buf_put_string (HTStream * me, CONST char * s)
                    170: {
                    171:     return buf_put_block(me, s, (int) strlen(s));
                    172: }
                    173: 
                    174: PRIVATE int buf_free (HTStream * me)
                    175: {
                    176:     int status = HT_OK;
                    177:     if (!me->ignore) {
                    178:        HTParentAnchor *anchor = HTRequest_anchor(me->request);
                    179:        if (STREAM_TRACE)
2.2       frystyk   180:            TTYPrint(TDEST,"\nCalculated.. content-length: %d\n", me->conlen);
2.1       frystyk   181:        HTAnchor_setLength(anchor, me->conlen);
                    182:     }
                    183:     if (!me->give_up && (status = buf_flush(me)) != HT_OK)
                    184:        return status;
                    185:     if ((status = (*me->target->isa->_free)(me->target)) != HT_OK)
                    186:        return status;
                    187:     free(me);
                    188:     return status;
                    189: }
                    190: 
2.3       frystyk   191: PRIVATE int buf_abort (HTStream * me, HTList * e)
2.1       frystyk   192: {
2.6       frystyk   193:     if (me->target) (*me->target->isa->abort)(me->target,e);
                    194:     free_buf_all(me);
2.1       frystyk   195:     free(me);
2.2       frystyk   196:     if (PROT_TRACE) TTYPrint(TDEST, "Length...... ABORTING...\n");
2.1       frystyk   197:     return HT_ERROR;
                    198: }
                    199: 
                    200: HTStreamClass HTContentCounterClass = {
                    201:     "ContentCounter",
                    202:     buf_flush,
                    203:     buf_free,
                    204:     buf_abort,
                    205:     buf_put_char,
                    206:     buf_put_string,
                    207:     buf_put_block
                    208: };
                    209: 
                    210: PUBLIC HTStream * HTContentCounter (HTStream * target,
                    211:                                    HTRequest * request,
                    212:                                    int         max_size)
                    213: {
                    214:     HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
                    215:     if (!me) outofmem(__FILE__, "HTContentCounter");
                    216:     me->isa = &HTContentCounterClass;
                    217:     me->target = target;
                    218:     me->request = request;
                    219:     me->max_size = (max_size > 0) ? max_size : HT_MAX_SIZE;
                    220:     if (STREAM_TRACE)
2.2       frystyk   221:        TTYPrint(TDEST, "Buffer...... Created with size %d\n", me->max_size);
2.1       frystyk   222:     return me;
                    223: }
                    224: 
                    225: PUBLIC HTStream * HTBuffer_new (HTStream *     target,
                    226:                                HTRequest *     request,
                    227:                                int             max_size)
                    228: {
                    229:     HTStream * me = HTContentCounter(target, request, max_size);
                    230:     if (me) me->ignore = YES;
                    231:     return me;
                    232: }

Webmaster