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