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