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