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

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) {
2.8       frystyk    64:        HT_FREE(me->buf);
                     65:        HT_FREE(me);
2.1       frystyk    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;
2.8       frystyk    77:     HT_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: {
2.8       frystyk    88:     HTBufItem * b;
                     89:     if ((b = (HTBufItem  *) HT_CALLOC(1, sizeof(HTBufItem))) == NULL)
                     90:         HT_OUTOFMEM("append_buf");
2.1       frystyk    91:     b->len = me->tmp_ind;
                     92:     b->buf = me->tmp_buf;
                     93:     me->tmp_ind = 0;
                     94:     me->tmp_max = 0;
                     95:     me->tmp_buf = 0;
                     96:     if (me->tail)
                     97:        me->tail->next = b;
                     98:     else
                     99:        me->head = b;
                    100:     me->tail = b;
                    101: }
                    102: 
                    103: PRIVATE BOOL alloc_new (HTStream * me, int size)
                    104: {
                    105:     if (me->conlen >= me->max_size) {
                    106:        if (STREAM_TRACE)
2.9     ! eric      107:            HTTrace("StreamBuffer size %d reached, going transparent\n",
2.1       frystyk   108:                    me->max_size);
                    109:        return NO;
                    110:     } else if (size) {
                    111:        me->tmp_ind = 0;
                    112:        me->tmp_max = size;
2.8       frystyk   113:        if ((me->tmp_buf = (char  *) HT_MALLOC(size)) == NULL)
                    114:            HT_OUTOFMEM("buf_put_char");
2.1       frystyk   115:        if (STREAM_TRACE)
2.9     ! eric      116:            HTTrace("StreamBuffer created with len %d\n", size);
2.1       frystyk   117:        return YES;
                    118:     }
                    119:     return NO;
                    120: }
                    121: 
                    122: PRIVATE int buf_flush (HTStream * me)
                    123: {
                    124:     HTBufItem * cur;
                    125:     if (me->tmp_buf) append_buf(me);
                    126:     while ((cur = me->head)) {
2.4       frystyk   127:        int status;
                    128:        if ((status = PUTBLOCK(cur->buf, cur->len)) != HT_OK) return status;
2.1       frystyk   129:        me->head = cur->next;
                    130:        free_buf(cur);
                    131:     }
2.5       frystyk   132:     me->give_up = YES;
2.1       frystyk   133:     return HT_OK;
                    134: }
                    135: 
                    136: PRIVATE int buf_put_block (HTStream * me, CONST char * b, int l)
                    137: {
                    138:     me->conlen += l;
                    139:     if (!me->give_up) {
                    140:        if (me->tmp_buf && me->tmp_max-me->tmp_ind >= l) {     /* Still room */
                    141:            memcpy(me->tmp_buf + me->tmp_ind, b, l);
                    142:            me->tmp_ind += l;
                    143:            return HT_OK;
                    144:        } else {
                    145:            if (me->tmp_buf) append_buf(me);
                    146:            if (me->cur_size < HT_MAX_BLOCK) {
                    147:                int newsize = me->cur_size ? me->cur_size : HT_MIN_BLOCK;
                    148:                while (l > newsize && newsize < HT_MAX_BLOCK) newsize *= 2;
                    149:                me->cur_size = newsize;
                    150:            }
                    151:            if (!alloc_new(me, me->cur_size)) {
                    152:                int status = buf_flush(me);
                    153:                if (status != HT_OK) return status;
                    154:                me->give_up = YES;
                    155:            } else {
                    156:                memcpy(me->tmp_buf, b, l);
                    157:                me->tmp_ind = l;
                    158:            }
                    159:        }
                    160:     }
                    161:     if (me->give_up) return PUTBLOCK(b, l);
                    162:     return HT_OK;
                    163: }
                    164: 
                    165: PRIVATE int buf_put_char (HTStream * me, char c)
                    166: {
                    167:     return buf_put_block(me, &c, 1);
                    168: }
                    169: 
                    170: PRIVATE int buf_put_string (HTStream * me, CONST char * s)
                    171: {
                    172:     return buf_put_block(me, s, (int) strlen(s));
                    173: }
                    174: 
                    175: PRIVATE int buf_free (HTStream * me)
                    176: {
                    177:     int status = HT_OK;
                    178:     if (!me->ignore) {
                    179:        HTParentAnchor *anchor = HTRequest_anchor(me->request);
                    180:        if (STREAM_TRACE)
2.9     ! eric      181:            HTTrace("\nCalculated.. content-length: %d\n", me->conlen);
2.1       frystyk   182:        HTAnchor_setLength(anchor, me->conlen);
                    183:     }
                    184:     if (!me->give_up && (status = buf_flush(me)) != HT_OK)
                    185:        return status;
                    186:     if ((status = (*me->target->isa->_free)(me->target)) != HT_OK)
                    187:        return status;
2.8       frystyk   188:     HT_FREE(me);
2.1       frystyk   189:     return status;
                    190: }
                    191: 
2.3       frystyk   192: PRIVATE int buf_abort (HTStream * me, HTList * e)
2.1       frystyk   193: {
2.6       frystyk   194:     if (me->target) (*me->target->isa->abort)(me->target,e);
                    195:     free_buf_all(me);
2.8       frystyk   196:     HT_FREE(me);
2.9     ! eric      197:     if (PROT_TRACE) HTTrace("Length...... ABORTING...\n");
2.1       frystyk   198:     return HT_ERROR;
                    199: }
                    200: 
                    201: HTStreamClass HTContentCounterClass = {
                    202:     "ContentCounter",
                    203:     buf_flush,
                    204:     buf_free,
                    205:     buf_abort,
                    206:     buf_put_char,
                    207:     buf_put_string,
                    208:     buf_put_block
                    209: };
                    210: 
                    211: PUBLIC HTStream * HTContentCounter (HTStream * target,
                    212:                                    HTRequest * request,
                    213:                                    int         max_size)
                    214: {
2.8       frystyk   215:     HTStream * me;
                    216:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    217:         HT_OUTOFMEM("HTContentCounter");
2.1       frystyk   218:     me->isa = &HTContentCounterClass;
                    219:     me->target = target;
                    220:     me->request = request;
                    221:     me->max_size = (max_size > 0) ? max_size : HT_MAX_SIZE;
                    222:     if (STREAM_TRACE)
2.9     ! eric      223:        HTTrace("Buffer...... Created with size %d\n", me->max_size);
2.1       frystyk   224:     return me;
                    225: }
                    226: 
                    227: PUBLIC HTStream * HTBuffer_new (HTStream *     target,
                    228:                                HTRequest *     request,
                    229:                                int             max_size)
                    230: {
                    231:     HTStream * me = HTContentCounter(target, request, max_size);
                    232:     if (me) me->ignore = YES;
                    233:     return me;
                    234: }

Webmaster