Project

General

Profile

lighttpd_1.4.26_chunked_decoding3b.patch

andreas_stoe, 2010-05-10 09:29

View differences:

lighttpd-1.4.26/src/base.h 2010-04-29 15:27:24.671174348 +0200
331 331
	CON_STATE_WRITE,
332 332
	CON_STATE_RESPONSE_END,
333 333
	CON_STATE_ERROR,
334
	CON_STATE_CLOSE
334
	CON_STATE_CLOSE,
335
	CON_STATE_READ_CHUNKED, /* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
335 336
} connection_state_t;
336 337

  
337 338
typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
......
439 440
	etag_flags_t etag_flags;
440 441

  
441 442
	int conditional_is_valid[COMP_LAST_ELEMENT]; 
443

  
444
	/* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
445
	void *chunk_decoder;
442 446
} connection;
443 447

  
444 448
typedef struct {
lighttpd-1.4.26/src/chunk_decoder.c 2010-05-07 15:00:17.766849645 +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

  
lighttpd-1.4.26/src/chunk_decoder.h 2010-04-29 15:10:32.711175470 +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.26/src/connections.c 2010-05-07 14:50:54.470347296 +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>
......
120 122
	}
121 123
#endif
122 124

  
125
	/* If a transfer-encoding "chunked" connection gets closed, destroy the chunk decoder */
126
	if (con->chunk_decoder != NULL) {
127
		chunk_decoder_free((lp_chunk_decoder)con->chunk_decoder);
128
		con->chunk_decoder = NULL;
129
	}
130

  
123 131
	fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
124 132
	fdevent_unregister(srv->ev, con->fd);
125 133
#ifdef __WIN32
......
793 801

  
794 802
	con->mode = DIRECT;
795 803

  
804
	/* Destroy the chunk decoder if it is still persistent */
805
	if (con->chunk_decoder != NULL) {
806
		chunk_decoder_free(con->chunk_decoder);
807
		con->chunk_decoder = NULL;
808
	}
809

  
796 810
#define CLEAN(x) \
797 811
	if (con->x) buffer_reset(con->x);
798 812

  
......
882 896
	off_t last_offset;
883 897
	chunkqueue *cq = con->read_queue;
884 898
	chunkqueue *dst_cq = con->request_content_queue;
899
	lp_chunk_decoder dec = NULL;
885 900
	int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
886 901

  
887 902
	if (con->is_readable) {
......
1031 1046
			connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1032 1047
		}
1033 1048
		break;
1049

  
1034 1050
	case CON_STATE_READ_POST:
1035 1051
		for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
1036 1052
			off_t weWant, weHave, toRead;
......
1155 1171
		}
1156 1172

  
1157 1173
		break;
1158
	default: break;
1174

  
1175
#define FREE_AND_QUIT {\
1176
chunk_decoder_free(dec);\
1177
con->chunk_decoder = NULL;\
1178
dec = NULL;\
1179
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);\
1180
}
1181

  
1182
	/* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
1183
	case CON_STATE_READ_CHUNKED:
1184
		/* Check whether the chunk decoder has been created, if not, create it */
1185
		if (con->chunk_decoder == NULL)	{
1186
			dec = chunk_decoder_create();
1187
			con->chunk_decoder = dec;
1188
		} else {
1189
			dec = (lp_chunk_decoder)con->chunk_decoder;
1190
		}		
1191

  
1192
		for (c = cq->first; c != NULL; c = c->next) {
1193
			/* Reserve some memory which should contain the decoded data */
1194
			int toRead = c->mem->used - c->offset - 1;
1195
			char *target = malloc(toRead);
1196
			memset(target, 0, toRead);
1197

  
1198
			size_t decoded_size = 0;
1199

  
1200
			int res = chunk_decoder_work(dec, c->mem->ptr + c->offset, target, toRead,
1201
				&decoded_size);
1202
			if (res >= 0)
1203
			{
1204
				/* the new way, copy everything into a chunkqueue whcih might use tempfiles */
1205
				chunk *dst_c = NULL;
1206

  
1207
				/* copy everything to max 1Mb sized tempfiles */
1208

  
1209
				/*
1210
				 * if the last chunk is
1211
				 * - smaller than 1Mb (size < 1Mb)
1212
				 * - not read yet (offset == 0)
1213
				 * -> append to it
1214
				 * otherwise
1215
				 * -> create a new chunk
1216
				 *
1217
				 * */
1218

  
1219
				if (dst_cq->last &&
1220
					dst_cq->last->type == FILE_CHUNK &&
1221
					dst_cq->last->file.is_temp &&
1222
					dst_cq->last->offset == 0) {
1223
					/* ok, take the last chunk for our job */
1224

  
1225
			 		if (dst_cq->last->file.length < 1 * 1024 * 1024) {
1226
						dst_c = dst_cq->last;
1227

  
1228
						if (dst_c->file.fd == -1) {
1229
							/* this should not happen as we cache the fd, but you never know */
1230
							dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND);
1231
#ifdef FD_CLOEXEC
1232
							fcntl(dst_c->file.fd, F_SETFD, FD_CLOEXEC);
1233
#endif
1234
						}
1235
					} else {
1236
						/* the chunk is too large now, close it */
1237
						dst_c = dst_cq->last;
1238

  
1239
						if (dst_c->file.fd != -1) {
1240
							close(dst_c->file.fd);
1241
							dst_c->file.fd = -1;
1242
						}
1243
						dst_c = chunkqueue_get_append_tempfile(dst_cq);
1244
					}
1245
				} else {
1246
					dst_c = chunkqueue_get_append_tempfile(dst_cq);
1247
				}
1248

  
1249
				/* we have a chunk, let's write to it */
1250

  
1251
				if (dst_c->file.fd == -1) {
1252
					/* we don't have file to write to,
1253
					 * EACCES might be one reason.
1254
					 *
1255
					 * Instead of sending 500 we send 413 and say the request is too large
1256
					 *  */
1257

  
1258
					log_error_write(srv, __FILE__, __LINE__, "sbs",
1259
							"denying upload as opening to temp-file for upload failed:",
1260
							dst_c->file.name, strerror(errno));
1261

  
1262
					con->http_status = 413; /* Request-Entity too large */
1263
					con->keep_alive = 0;
1264
					
1265
					FREE_AND_QUIT;
1266
					free(target);			
1267

  
1268
					break;
1269
				}
1270

  
1271
				if ((int)decoded_size != write(dst_c->file.fd, target, decoded_size)) {
1272
					/* write failed for some reason ... disk full ? */
1273
					log_error_write(srv, __FILE__, __LINE__, "sbs",
1274
							"denying upload as writing to file failed:",
1275
							dst_c->file.name, strerror(errno));
1276

  
1277
					con->http_status = 413; /* Request-Entity too large */
1278
					con->keep_alive = 0;
1279

  
1280
					close(dst_c->file.fd);
1281
					dst_c->file.fd = -1;
1282

  
1283
					FREE_AND_QUIT;
1284
					free(target);
1285

  
1286
					break;
1287
				}
1288

  
1289
				if (res == 1) {
1290
					/* we read everything, close the chunk */
1291
					close(dst_c->file.fd);
1292
					dst_c->file.fd = -1;
1293
				}
1294

  
1295
				dst_c->file.length += decoded_size;
1296
				dst_cq->bytes_in += decoded_size;
1297
				c->offset += toRead;
1298
			}
1299
			free(target);
1300
		}
1301

  
1302
		/* Check whether the file upload limit has been exhausted */
1303

  
1304
		/* divide by 1024 as srvconf.max_request_size is in kBytes */
1305
		if (dec != NULL) {
1306
			if (srv->srvconf.max_request_size != 0 &&
1307
				(dec->size >> 10) > srv->srvconf.max_request_size) {
1308
				con->http_status = 413;
1309
				con->keep_alive = 0;
1310

  
1311
				log_error_write(srv, __FILE__, __LINE__, "sos",
1312
						"request-size too long:", (off_t) dec->size, "-> 413");
1313

  
1314
				FREE_AND_QUIT;
1315
			}
1316
		}
1317

  
1318
		if (dec != NULL) {
1319
			if (dec->state >= CHUNK_DECODER_STATE_END) {
1320
				switch (dec->state) {
1321
					case CHUNK_DECODER_STATE_END:
1322
						/* Set the content length to allow the plugins to treat this request as
1323
						   if it had been send with content_lenght */
1324
						con->request.content_length = dec->size;
1325
					
1326
						break;
1327
					case CHUNK_DECODER_STATE_ERROR:
1328
						/* Chunk decoding failed. Return an error 400, bad request */
1329
						log_error_write(srv, __FILE__, __LINE__, "s",
1330
							"chunked transfer-encoding decoding failed.");
1331

  
1332
						con->http_status = 400;
1333
						con->keep_alive = 0;
1334
						break;
1335
				}
1336
				FREE_AND_QUIT;
1337
			}
1338
		}
1339
	
1340
		break;
1341

  
1342
	default:
1343
		break;
1159 1344
	}
1160 1345

  
1161 1346
	/* the connection got closed and we didn't got enough data to leave one of the READ states
......
1406 1591
			buffer_reset(con->uri.query);
1407 1592
			buffer_reset(con->request.orig_uri);
1408 1593

  
1409
			if (http_request_parse(srv, con)) {
1410
				/* we have to read some data from the POST request */
1411

  
1412
				connection_set_state(srv, con, CON_STATE_READ_POST);
1413

  
1414
				break;
1594
			/* As we've now got three possible results, a "switch" is needed (Andreas Stöckel) */
1595
			int res = http_request_parse(srv, con);
1596
			switch (res)
1597
			{
1598
				case 1:
1599
					/* we have to read some data from the POST request */
1600
					connection_set_state(srv, con, CON_STATE_READ_POST);
1601
					break;
1602
				case 2:
1603
					/* we have to read chunk encoded data */
1604
					connection_set_state(srv, con, CON_STATE_READ_CHUNKED);
1605
					break;
1606
				default:
1607
					connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1415 1608
			}
1416 1609

  
1417
			connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
1418

  
1419 1610
			break;
1420 1611
		case CON_STATE_HANDLE_REQUEST:
1421 1612
			/*
......
1624 1815
			}
1625 1816

  
1626 1817
			break;
1818
		case CON_STATE_READ_CHUNKED: /* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
1627 1819
		case CON_STATE_READ_POST:
1628 1820
		case CON_STATE_READ:
1629 1821
			if (srv->srvconf.log_state_handling) {
......
1777 1969
	}
1778 1970

  
1779 1971
	switch(con->state) {
1780
	case CON_STATE_READ_POST:
1972
	case CON_STATE_READ_CHUNKED:
1973
	case CON_STATE_READ_POST: /* Added by Andreas Stöckel for "transfer-encoding: chunked" support */
1781 1974
	case CON_STATE_READ:
1782 1975
	case CON_STATE_CLOSE:
1783 1976
		fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
lighttpd-1.4.26/src/request.c 2010-04-29 15:29:38.103175268 +0200
1010 1010
									return 0;
1011 1011
								}
1012 1012
							}
1013

  
1014 1013
							if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
1015 1014
						} else {
1016 1015
							/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
......
1120 1119
		return 0;
1121 1120
	}
1122 1121

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

  
1146
			con->keep_alive = 0;
1147
			con->http_status = 400;
1148
			return 0;
1149
		}
1136 1150
		break;
1137 1151
	case HTTP_METHOD_POST:
1138 1152
		/* content-length is required for them */
1139
		if (!con_length_set) {
1153
		if (!con_length_set && (chunked_transfer_encoding != 1)) { /* Changed to support "transfer-encoding: chunked" (Andreas Stöckel) */
1140 1154
			/* content-length is missing */
1141 1155
			log_error_write(srv, __FILE__, __LINE__, "s",
1142 1156
					"POST-request, but content-length missing -> 411");
......
1187 1201
		}
1188 1202
	}
1189 1203

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

  
1190 1208
	return 0;
1191 1209
}
1192 1210