Project

General

Profile

lighttpd_1.4.29_chunked_decoding.patch

lvs, 2012-08-17 12:43

View differences:

lighttpd-1.4.29/src/base.h 2011-08-09 14:43:51.229299190 +0200
334 334
	CON_STATE_WRITE,
335 335
	CON_STATE_RESPONSE_END,
336 336
	CON_STATE_ERROR,
337
	CON_STATE_CLOSE
337
	CON_STATE_CLOSE,
338
	CON_STATE_READ_CHUNKED /* Added by Andreas Stoeckel for "transfer-encoding: chunked" support*/
338 339
} connection_state_t;
339 340

  
340 341
typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
......
442 443
	etag_flags_t etag_flags;
443 444

  
444 445
	int conditional_is_valid[COMP_LAST_ELEMENT]; 
446

  
447
	/* Added by Andreas Stoeckel for "transfer-encoding: chunked" support */
448
	void *chunk_decoder;
445 449
} connection;
446 450

  
447 451
typedef struct {
lighttpd-1.4.29/src/chunk_decoder.c 2011-08-09 14:43:51.229299190 +0200
1
/*
2
  chunk_decoder.c
3

  
4
  small library for decoding http requests with "transfer-encoding: chunked".
5

  
6
  (c) by Andreas Stöckel 2010
7

  
8
  This file is licensed under the revised BSD license, see ../COPYING for more info
9
*/
10

  
11
#include "chunk_decoder.h"
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <string.h>
15

  
16
#define INT_STATE_READ_NUMBER 100
17
#define INT_STATE_READ_NUMBER_WAIT_FOR_CR 101
18
#define INT_STATE_READ_NUMBER_WAIT_FOR_LF 102
19
#define INT_STATE_READ_CHUNK 103
20
#define INT_STATE_READ_CHUNK_WAIT_FOR_CR 104
21
#define INT_STATE_READ_CHUNK_WAIT_FOR_LF 105
22
#define IS_NUMBER(nb) ((nb >= 48) && (nb <= 57))
23
#define IS_HEX_NUMBER(nb) (((nb >= '0') && (nb <= '9')) || ((nb >= 'A') && (nb <= 'F')) || ((nb >= 'a') && (nb <= 'f')))
24
#define IS_CRLF(c) ((c == '\r') || (c == '\n'))
25
#define IS_CR(c) (c == '\r')
26
#define IS_LF(c) (c == '\n')
27
#define IS_SPACE(c) (c == ' ')
28
#define CHAR_TO_NB(nb) (nb - 48)
29
#define HEX_CHAR_TO_NB(nb) (\
30
	(nb <= '9') ?\
31
		(nb - 48) :\
32
		((nb <= 'F') ?\
33
			(nb - 65 + 10) :\
34
			(nb - 97 + 10))\
35
)
36

  
37
typedef struct{
38
	chunk_decoder dec;
39
	int int_state;
40
	chk_int64 numberbuf;
41
	chk_int64 cur_chunk_size;
42
} chunk_decoder_int;
43
typedef chunk_decoder_int* lp_chunk_decoder_int;
44

  
45
lp_chunk_decoder chunk_decoder_create()
46
{
47
	/* Reserve some memory for the chunk_decoder structure and return it */
48
	lp_chunk_decoder_int dec = malloc(sizeof(*dec));
49
	memset(dec, 0, sizeof(*dec));
50
	dec->dec.state = CHUNK_DECODER_STATE_START;
51
	dec->dec.size = 0;
52

  
53
	return (lp_chunk_decoder)dec;
54
}
55

  
56
void chunk_decoder_free(lp_chunk_decoder decoder)
57
{
58
	/* Free the memory reserved for the chunk_decoder */
59
	if (decoder != NULL)
60
		free(decoder);
61
}
62

  
63
#define READCHAR() {mem_in++; data_remaining--;}
64
#define WRITECHAR(c) {mem_out[0] = c; mem_out++; dec->dec.size++; dec->cur_chunk_size--; (*write_size)++;}
65

  
66
/* Decode mem_in and write it to mem_out */
67
int chunk_decoder_work(lp_chunk_decoder decoder, char *mem_in, char *mem_out,
68
	size_t read_size, size_t *write_size)
69
{
70
	*write_size = 0;
71
	size_t data_remaining = read_size;
72
	lp_chunk_decoder_int dec = (lp_chunk_decoder_int)decoder;
73

  
74
	while (data_remaining > 0)
75
	{
76
		switch (dec->dec.state)
77
		{
78

  
79
			/* Handle the chunk decoder start state */
80
			case CHUNK_DECODER_STATE_START:
81
				if (IS_CRLF(mem_in[0]))
82
				{
83
					READCHAR();
84
				}
85
				else
86
				{
87
					dec->dec.state = CHUNK_DECODER_STATE_READING;
88
					dec->int_state = INT_STATE_READ_NUMBER;
89
					dec->numberbuf = -1;
90
				}
91
					
92
				break;
93
			
94
			/* Handle the chunk decoder read state. This is the state where the
95
			   acutal information is read */
96
			case CHUNK_DECODER_STATE_READING:
97
				switch (dec->int_state)
98
				{
99
					/* Reading the preceding number from every chunk */
100
					case INT_STATE_READ_NUMBER:
101
						/* Check whether the current char is a hex number char */
102
						if (IS_HEX_NUMBER(mem_in[0]))
103
						{
104
							/* Append the hex number char to the current hex number being read */
105
							if (dec->numberbuf == -1)
106
								dec->numberbuf = HEX_CHAR_TO_NB(mem_in[0]);
107
							else
108
								dec->numberbuf = (dec->numberbuf << 4) + HEX_CHAR_TO_NB(mem_in[0]);
109
							READCHAR();
110
						}
111
						else
112
						{
113
							/* As there had been no other hex number following, go on
114
							   reading the actual chunk data */
115
							if (dec->numberbuf == -1)
116
							{
117
								/* There was no chunk size read at all, exit */
118
								dec->dec.state = CHUNK_DECODER_STATE_ERROR;
119
								return -1;
120
							}
121
							else
122
							{
123
								/* If the number read was zero, we're at the end of
124
								   the chunked encoded data */
125
								dec->cur_chunk_size = dec->numberbuf;
126
								if (dec->cur_chunk_size == 0)
127
								{
128
									dec->dec.state = CHUNK_DECODER_STATE_END;
129
									return 1;
130
								}
131
								dec->numberbuf = -1;
132
								dec->int_state = INT_STATE_READ_NUMBER_WAIT_FOR_CR;
133
							}
134
						}
135

  
136
						break;
137

  
138
					/* Wait for an CR after reading the number */
139
					case INT_STATE_READ_NUMBER_WAIT_FOR_CR:
140
						if (IS_CR(mem_in[0]))
141
						{
142
							dec->int_state = INT_STATE_READ_NUMBER_WAIT_FOR_LF;
143
						}
144
						READCHAR();
145

  
146
						break;
147

  
148
					/* Wait for an LF after reading the CR. LF has to follow the
149
					   CR immediately */
150
					case INT_STATE_READ_NUMBER_WAIT_FOR_LF:
151
						if (IS_LF(mem_in[0]))
152
						{
153
							dec->int_state = INT_STATE_READ_CHUNK;
154
							READCHAR();
155
						}
156
						else
157
						{
158
							dec->dec.state = CHUNK_DECODER_STATE_ERROR;
159
							return -1;
160
						}
161
							
162
						break;
163

  
164
					/* Read the actual chunk data */
165
					case INT_STATE_READ_CHUNK:
166
						if (dec->cur_chunk_size > 0)
167
						{
168
							WRITECHAR(mem_in[0]);
169
							READCHAR();
170
						}
171
						else
172
						{
173
							dec->int_state = INT_STATE_READ_CHUNK_WAIT_FOR_CR;
174
						}
175

  
176
						break;
177

  
178
					/* Wait for the CR which should follow each chunk */
179
					case INT_STATE_READ_CHUNK_WAIT_FOR_CR:
180
						if (IS_CR(mem_in[0]))
181
						{
182
							dec->int_state = INT_STATE_READ_CHUNK_WAIT_FOR_LF;
183
						}
184
						READCHAR();
185

  
186
						break;
187

  
188
					/* Wait for the LF which should follow the CR (see above) */
189
					case INT_STATE_READ_CHUNK_WAIT_FOR_LF:
190
						if (IS_LF(mem_in[0]))
191
						{
192
							dec->int_state = INT_STATE_READ_NUMBER;
193
							READCHAR();
194
						}
195
						else
196
						{
197
							dec->dec.state = CHUNK_DECODER_STATE_ERROR;
198
							return -1;
199
						}
200

  
201
						break;
202

  
203
					/* Default must not happen! */
204
					default:
205
						dec->dec.state = CHUNK_DECODER_STATE_ERROR;
206
						return -1;
207
				}
208

  
209
				break;
210

  
211
			case CHUNK_DECODER_STATE_ERROR:
212
				return -1;
213

  
214
			case CHUNK_DECODER_STATE_END:
215
				/* This function must not be called if the chunk decoder is already finished! */
216
				dec->dec.state = CHUNK_DECODER_STATE_ERROR;
217
				return -1;
218

  
219
			/* Default must not happen! */
220
			default:
221
				dec->dec.state = CHUNK_DECODER_STATE_ERROR;
222
				return -1;
223
		}
224
	}
225
	return 0;
226
}
227

  
228

  
lighttpd-1.4.29/src/chunk_decoder.h 2011-08-09 14:43:51.229299190 +0200
1
/*
2
  chunk_decoder.h
3

  
4
  small library for decoding http requests with "transfer-encoding: chunked".
5

  
6
  (c) by Andreas Stöckel 2010
7

  
8
  This file is licensed under the revised BSD license, see ../COPYING for more info
9
*/
10

  
11
#ifndef _CHUNK_DECODER_H_
12
#define _CHUNK_DECODER_H_
13

  
14
#include <stddef.h>
15

  
16
#define CHUNK_DECODER_STATE_START 0
17
#define CHUNK_DECODER_STATE_READING 1
18
#define CHUNK_DECODER_STATE_END 2
19
#define CHUNK_DECODER_STATE_ERROR 3
20

  
21
//Int64 data type used for storing the size information for (hypotetically) very large files
22
typedef long long chk_int64;
23

  
24
/*Public data of the chunk decoder. You must not set any of these values, they
25
are for read access only.*/
26
typedef struct{
27
	/*The current state of the chunk decoder. May be CHUNK_DECODER_STATE_START if
28
	the chunk decoder has just been created, CHUNK_DECODER_STATE_READING if the
29
	chunk decoder is just working on the data, CHUNK_DECODER_STATE_END if the
30
	chunk decoder has come to a normal end and CHUNK_DEOCDER_STATE_ERROR if the
31
	chunk decoder came to an abnormal ending and has not been able to go on decoding
32
	the data. */
33
	int state;
34
	/*Contains the full size of the decoded data.*/
35
	chk_int64 size;
36
} chunk_decoder;
37

  
38
/*Pointer on chunk_decoder*/
39
typedef chunk_decoder* lp_chunk_decoder;
40

  
41
/*Create an instance of chunk_decoder*/
42
lp_chunk_decoder chunk_decoder_create();
43

  
44
/*Feed the deocder with data from mem_in of read_size size. The deocder should
45
write the decoded data to mem_out. The size of the data written is stored in
46
write_size. The memory reserved on mem_out should at least have the size of
47
read_size. chunk_decoder_work will return 0 if the operation had been executed
48
successfully, -1 if an error occurred and 1 if decoding has finished. Additionally
49
it set decoder->state accordingly.*/
50
int chunk_decoder_work(lp_chunk_decoder decoder, char *mem_in, char *mem_out,
51
	size_t read_size, size_t *write_size);
52

  
53
/*Free the instance of chunk_decoder*/
54
void chunk_decoder_free(lp_chunk_decoder decoder);
55

  
56
#endif /*_CHUNK_DECODER_H_*/
57

  
lighttpd-1.4.29/src/connections.c 2011-08-09 14:43:51.269300391 +0200
15 15

  
16 16
#include "inet_ntop_cache.h"
17 17

  
18
#include "chunk_decoder.h"
19

  
18 20
#include <sys/stat.h>
19 21

  
20 22
#include <stdlib.h>
......
125 127
	}
126 128
#endif
127 129

  
130
	/* If a transfer-encoding "chunked" connection gets closed, destroy the chunk decoder */
131
	if (con->chunk_decoder != NULL) {
132
		chunk_decoder_free((lp_chunk_decoder)con->chunk_decoder);
133
		con->chunk_decoder = NULL;
134
	}
135

  
128 136
	fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
129 137
	fdevent_unregister(srv->ev, con->fd);
130 138
#ifdef __WIN32
......
801 809

  
802 810
	con->mode = DIRECT;
803 811

  
812
	/* Destroy the chunk decoder if it is still persistent */
813
	if (con->chunk_decoder != NULL) {
814
		chunk_decoder_free(con->chunk_decoder);
815
		con->chunk_decoder = NULL;
816
	}
817

  
804 818
#define CLEAN(x) \
805 819
	if (con->x) buffer_reset(con->x);
806 820

  
......
890 904
	off_t last_offset;
891 905
	chunkqueue *cq = con->read_queue;
892 906
	chunkqueue *dst_cq = con->request_content_queue;
907
	lp_chunk_decoder dec = NULL;
893 908
	int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
894 909

  
895 910
	if (con->is_readable) {
......
1163 1178
		}
1164 1179

  
1165 1180
		break;
1166
	default: break;
1181

  
1182
#define FREE_AND_QUIT {\
1183
chunk_decoder_free(dec);\
1184
con->chunk_decoder = NULL;\
1185
dec = NULL;\
1186
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);\
1187
}
1188

  
1189
	/* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
1190
	case CON_STATE_READ_CHUNKED:
1191
		/* Check whether the chunk decoder has been created, if not, create it */
1192
		if (con->chunk_decoder == NULL)	{
1193
			dec = chunk_decoder_create();
1194
			con->chunk_decoder = dec;
1195
		} else {
1196
			dec = (lp_chunk_decoder)con->chunk_decoder;
1197
		}
1198

  
1199
		for (c = cq->first; c != NULL; c = c->next) {
1200
			/* Reserve some memory which should contain the decoded data */
1201
			int toRead = c->mem->used - c->offset - 1;
1202
			char *target = malloc(toRead);
1203
			memset(target, 0, toRead);
1204

  
1205
			size_t decoded_size = 0;
1206

  
1207
			int res = chunk_decoder_work(dec, c->mem->ptr + c->offset, target, toRead,
1208
				&decoded_size);
1209
			if (res >= 0)
1210
			{
1211
				/* the new way, copy everything into a chunkqueue whcih might use tempfiles */
1212
				chunk *dst_c = NULL;
1213

  
1214
				/* copy everything to max 1Mb sized tempfiles */
1215

  
1216
				/*
1217
				 * if the last chunk is
1218
				 * - smaller than 1Mb (size < 1Mb)
1219
				 * - not read yet (offset == 0)
1220
				 * -> append to it
1221
				 * otherwise
1222
				 * -> create a new chunk
1223
				 *
1224
				 * */
1225

  
1226
				if (dst_cq->last &&
1227
					dst_cq->last->type == FILE_CHUNK &&
1228
					dst_cq->last->file.is_temp &&
1229
					dst_cq->last->offset == 0) {
1230
					/* ok, take the last chunk for our job */
1231

  
1232
			 		if (dst_cq->last->file.length < 1 * 1024 * 1024) {
1233
						dst_c = dst_cq->last;
1234

  
1235
						if (dst_c->file.fd == -1) {
1236
							/* this should not happen as we cache the fd, but you never know */
1237
							dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
1238
#ifdef FD_CLOEXEC
1239
							fcntl(dst_c->file.fd, F_SETFD, FD_CLOEXEC);
1240
#endif
1241
						}
1242
					} else {
1243
						/* the chunk is too large now, close it */
1244
						dst_c = dst_cq->last;
1245

  
1246
						if (dst_c->file.fd != -1) {
1247
							close(dst_c->file.fd);
1248
							dst_c->file.fd = -1;
1249
						}
1250
						dst_c = chunkqueue_get_append_tempfile(dst_cq);
1251
					}
1252
				} else {
1253
					dst_c = chunkqueue_get_append_tempfile(dst_cq);
1254
				}
1255

  
1256
				/* we have a chunk, let's write to it */
1257

  
1258
				if (dst_c->file.fd == -1) {
1259
					/* we don't have file to write to,
1260
					 * EACCES might be one reason.
1261
					 *
1262
					 * Instead of sending 500 we send 413 and say the request is too large
1263
					 *  */
1264

  
1265
					log_error_write(srv, __FILE__, __LINE__, "sbs",
1266
							"denying upload as opening to temp-file for upload failed:",
1267
							dst_c->file.name, strerror(errno));
1268

  
1269
					con->http_status = 413; /* Request-Entity too large */
1270
					con->keep_alive = 0;
1271

  
1272
					FREE_AND_QUIT;
1273
					free(target);
1274

  
1275
					break;
1276
				}
1277

  
1278
				if ((int)decoded_size != write(dst_c->file.fd, target, decoded_size)) {
1279
					/* write failed for some reason ... disk full ? */
1280
					log_error_write(srv, __FILE__, __LINE__, "sbs",
1281
							"denying upload as writing to file failed:",
1282
							dst_c->file.name, strerror(errno));
1283

  
1284
					con->http_status = 413; /* Request-Entity too large */
1285
					con->keep_alive = 0;
1286

  
1287
					close(dst_c->file.fd);
1288
					dst_c->file.fd = -1;
1289

  
1290
					FREE_AND_QUIT;
1291
					free(target);
1292

  
1293
					break;
1294
				}
1295

  
1296
				if (res == 1) {
1297
					/* we read everything, close the chunk */
1298
					close(dst_c->file.fd);
1299
					dst_c->file.fd = -1;
1300
				}
1301

  
1302
				dst_c->file.length += decoded_size;
1303
				dst_cq->bytes_in += decoded_size;
1304
				c->offset += toRead;
1305
			}
1306
			free(target);
1307
		}
1308

  
1309
		/* Check whether the file upload limit has been exhausted */
1310

  
1311
		/* divide by 1024 as srvconf.max_request_size is in kBytes */
1312
		if (dec != NULL) {
1313
			if (srv->srvconf.max_request_size != 0 &&
1314
				(dec->size >> 10) > srv->srvconf.max_request_size) {
1315
				con->http_status = 413;
1316
				con->keep_alive = 0;
1317

  
1318
				log_error_write(srv, __FILE__, __LINE__, "sos",
1319
						"request-size too long:", (off_t) dec->size, "-> 413");
1320

  
1321
				FREE_AND_QUIT;
1322
			}
1323
		}
1324

  
1325
		if (dec != NULL) {
1326
			if (dec->state >= CHUNK_DECODER_STATE_END) {
1327
				switch (dec->state) {
1328
					case CHUNK_DECODER_STATE_END:
1329
						/* Set the content length to allow the plugins to treat this request as
1330
						   if it had been send with content_lenght */
1331
						con->request.content_length = dec->size;
1332

  
1333
						break;
1334
					case CHUNK_DECODER_STATE_ERROR:
1335
						/* Chunk decoding failed. Return an error 400, bad request */
1336
						log_error_write(srv, __FILE__, __LINE__, "s",
1337
							"chunked transfer-encoding decoding failed.");
1338

  
1339
						con->http_status = 400;
1340
						con->keep_alive = 0;
1341
						break;
1342
				}
1343
				FREE_AND_QUIT;
1344
			}
1345
		}
1346

  
1347
		break;
1348

  
1349

  
1350
	default:
1351
		break;
1167 1352
	}
1168 1353

  
1169 1354
	/* the connection got closed and we didn't got enough data to leave one of the READ states
......
1419 1604
			buffer_reset(con->uri.query);
1420 1605
			buffer_reset(con->request.orig_uri);
1421 1606

  
1422
			if (http_request_parse(srv, con)) {
1423
				/* we have to read some data from the POST request */
1424

  
1425
				connection_set_state(srv, con, CON_STATE_READ_POST);
1426

  
1427
				break;
1607
			/* As we've now got three possible results, a "switch" is needed (Andreas Stöckel) */
1608
			int res = http_request_parse(srv, con);
1609
			switch (res)
1610
			{
1611
				case 1:
1612
					/* we have to read some data from the POST request */
1613
					connection_set_state(srv, con, CON_STATE_READ_POST);
1614
					break;
1615
				case 2:
1616
					/* we have to read chunk encoded data */
1617
					connection_set_state(srv, con, CON_STATE_READ_CHUNKED);
1618
					break;
1619
				default:
1620
					connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1428 1621
			}
1429 1622

  
1430
			connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1431

  
1432 1623
			break;
1433 1624
		case CON_STATE_HANDLE_REQUEST:
1434 1625
			/*
......
1637 1828
			}
1638 1829

  
1639 1830
			break;
1831
		case CON_STATE_READ_CHUNKED: /* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
1640 1832
		case CON_STATE_READ_POST:
1641 1833
		case CON_STATE_READ:
1642 1834
			if (srv->srvconf.log_state_handling) {
......
1790 1982
	}
1791 1983

  
1792 1984
	switch(con->state) {
1985
	case CON_STATE_READ_CHUNKED: /* Added by Andreas Stoeckel for "transfer-encoding: chunked" support */
1793 1986
	case CON_STATE_READ_POST:
1794 1987
	case CON_STATE_READ:
1795 1988
	case CON_STATE_CLOSE:
lighttpd-1.4.29/src/Makefile.am 2011-08-09 14:43:51.269300391 +0200
74 74
      network_write.c network_linux_sendfile.c \
75 75
      network_freebsd_sendfile.c network_writev.c \
76 76
      network_solaris_sendfilev.c network_openssl.c \
77
      splaytree.c status_counter.c
77
      splaytree.c status_counter.c chunk_decoder.c
78 78

  
79 79
src = server.c response.c connections.c network.c \
80 80
      configfile.c configparser.c request.c proc_open.c
......
279 279
      sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
280 280
      splaytree.h proc_open.h status_counter.h \
281 281
      mod_magnet_cache.h \
282
      version.h
282
      version.h chunk_decoder.h
283 283

  
284 284
DEFS= @DEFS@ -DHAVE_VERSION_H -DLIBRARY_DIR="\"$(libdir)\"" -DSBIN_DIR="\"$(sbindir)\""
285 285

  
lighttpd-1.4.29/src/request.c 2011-08-09 14:43:51.269300391 +0200
1120 1120
		return 0;
1121 1121
	}
1122 1122

  
1123
	data_string *teval = (data_string*)array_get_element(con->request.headers, "Transfer-Encoding");
1124
	int chunked_transfer_encoding =
1125
		((teval != NULL) && (strcasecmp(teval->value->ptr, "chunked") == 0)) ? 1 : 0;
1126

  
1123 1127
	switch(con->request.http_method) {
1124 1128
	case HTTP_METHOD_GET:
1125 1129
	case HTTP_METHOD_HEAD:
......
1133 1137
			con->http_status = 400;
1134 1138
			return 0;
1135 1139
		}
1140
		/* transfer-encoding is forbidden for those */ /* Changed to support "transfer-encoding: chunked" (Andreas Stöckel) */
1141
		if (con_length_set && (chunked_transfer_encoding != 0)) {
1142
			/* content-length is missing */
1143
			log_error_write(srv, __FILE__, __LINE__, "s",
1144
				"GET/HEAD with transfer-encoding -> 400");
1145
			con->keep_alive = 0;
1146
			con->http_status = 400;
1147
			return 0;
1148
		}
1136 1149
		break;
1137 1150
	case HTTP_METHOD_POST:
1138 1151
		/* content-length is required for them */
1139
		if (!con_length_set) {
1152
		if (!con_length_set && (chunked_transfer_encoding != 1)) { /* Changed to support "transfer-encoding: chunked" (Andreas Stoeckel) */
1140 1153
			/* content-length is missing */
1141 1154
			log_error_write(srv, __FILE__, __LINE__, "s",
1142 1155
					"POST-request, but content-length missing -> 411");
......
1187 1200
		}
1188 1201
	}
1189 1202

  
1203
	/* Added to support "transfer-encoding: chunked" (Andreas Stoeckel) */
1204
	if (chunked_transfer_encoding == 1)
1205
		return 2;
1206

  
1190 1207
	return 0;
1191 1208
}
1192 1209