Project

General

Profile

lighttpd_1.4.43_chunked_prep.patch

gstrauss, 2016-12-12 00:29

View differences:

src/base.h
170 170
	array  *headers;
171 171

  
172 172
	/* CONTENT */
173
	size_t content_length; /* returned by strtoul() */
173
	off_t content_length; /* returned by strtoll() */
174 174

  
175 175
	/* internal representation */
176 176
	int     accept_encoding;
src/connections-glue.c
315 315
	return 0;
316 316
}
317 317

  
318
static handler_t connection_handle_read_post_error(server *srv, connection *con, int http_status) {
319
	UNUSED(srv);
320

  
321
	con->keep_alive = 0;
322

  
323
	/* (do not change status if response headers already set and possibly sent) */
324
	if (0 != con->bytes_header) return HANDLER_ERROR;
325

  
326
	con->http_status = http_status;
327
	con->mode = DIRECT;
328
	chunkqueue_reset(con->write_queue);
329
	return HANDLER_FINISHED;
330
}
331

  
318 332
handler_t connection_handle_read_post_state(server *srv, connection *con) {
319 333
	chunkqueue *cq = con->read_queue;
320 334
	chunkqueue *dst_cq = con->request_content_queue;
......
337 351

  
338 352
	chunkqueue_remove_finished_chunks(cq);
339 353

  
340
	if (con->request.content_length <= 64*1024) {
354

  
355
	/* future: add support to keep state, decode Transfer-Encoding: chunked
356
	 *   (set con->request.content_length to actual len once body received)
357
	 *
358
	 * For now, require Content-Length if request contains request body
359
	 */
360
	if (-1 == con->request.content_length) {
361
		/* presence of Transfer-Encoding in request headers requires "chunked"
362
		 * be final encoding in HTTP/1.1.  Return 411 Length Required as
363
		 * lighttpd does not support request input transfer-encodings */
364
		return connection_handle_read_post_error(srv, con, 411); /* Length Required */
365
	}
366

  
367

  
368
	if (-1 == con->request.content_length) { /*(Transfer-Encoding: chunked)*/
369
		if (cq->bytes_in <= 64*1024) {
370
			/* don't buffer request bodies <= 64k on disk */
371
			chunkqueue_steal(dst_cq, cq, cq->bytes_in - cq->bytes_out);
372
		}
373
		else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, cq->bytes_in - cq->bytes_out)) {
374
			return connection_handle_read_post_error(srv, con, 500); /* Internal Server Error */
375
		}
376
		/* con->conf.max_request_size is in kBytes */
377
		if (0 != con->conf.max_request_size &&
378
		    dst_cq->bytes_in > ((off_t)con->conf.max_request_size << 10)) {
379
			log_error_write(srv, __FILE__, __LINE__, "sos",
380
					"request-size too long:", dst_cq->bytes_in, "-> 413");
381
			return connection_handle_read_post_error(srv, con, 413); /* Payload Too Large */
382
		}
383
	}
384
	else if (con->request.content_length <= 64*1024) {
341 385
		/* don't buffer request bodies <= 64k on disk */
342 386
		chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
343 387
	}
344 388
	else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
345 389
		/* writing to temp file failed */
346
		con->http_status = 500; /* Internal Server Error */
347
		con->keep_alive = 0;
348
		con->mode = DIRECT;
349
		chunkqueue_reset(con->write_queue);
350

  
351
		return HANDLER_FINISHED;
390
		return connection_handle_read_post_error(srv, con, 500); /* Internal Server Error */
352 391
	}
353 392

  
354 393
	chunkqueue_remove_finished_chunks(cq);
......
362 401
		return HANDLER_GO_ON;
363 402
	} else if (is_closed) {
364 403
	      #if 0
365
		con->http_status = 400; /* Bad Request */
366
		con->keep_alive = 0;
367
		con->mode = DIRECT;
368
		chunkqueue_reset(con->write_queue);
369

  
370
		return HANDLER_FINISHED;
404
		return connection_handle_read_post_error(srv, con, 400); /* Bad Request */
371 405
	      #endif
372 406
		return HANDLER_ERROR;
373 407
	} else {
src/connections.c
1199 1199
								plugins_call_connection_reset(srv, con);
1200 1200

  
1201 1201
								if (con->request.content_length) {
1202
									if ((off_t)con->request.content_length != chunkqueue_length(con->request_content_queue)) {
1202
									if (con->request.content_length != con->request_content_queue->bytes_in) {
1203 1203
										con->keep_alive = 0;
1204 1204
									}
1205 1205
									con->request.content_length = 0;
src/mod_cgi.c
542 542
							buffer_copy_buffer(con->request.uri, ds->value);
543 543

  
544 544
							if (con->request.content_length) {
545
								if ((off_t)con->request.content_length != chunkqueue_length(con->request_content_queue)) {
545
								if (con->request.content_length != con->request_content_queue->bytes_in) {
546 546
									con->keep_alive = 0;
547 547
								}
548 548
								con->request.content_length = 0;
......
1055 1055
		}
1056 1056
	} else {
1057 1057
		off_t cqlen = cq->bytes_in - cq->bytes_out;
1058
		if (cq->bytes_in < (off_t)con->request.content_length && cqlen < 65536 - 16384) {
1058
		if (cq->bytes_in != con->request.content_length && cqlen < 65536 - 16384) {
1059 1059
			/*(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST)*/
1060 1060
			if (!(con->conf.stream_request_body & FDEVENT_STREAM_REQUEST_POLLIN)) {
1061 1061
				con->conf.stream_request_body |= FDEVENT_STREAM_REQUEST_POLLIN;
......
1349 1349
	if (!S_ISREG(st->st_mode)) return HANDLER_GO_ON;
1350 1350
	if (p->conf.execute_x_only == 1 && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return HANDLER_GO_ON;
1351 1351

  
1352
	if (NULL != cgi_get_handler(p->conf.cgi, fn)) {
1352
	if (NULL == cgi_get_handler(p->conf.cgi, fn)) {
1353
		return HANDLER_GO_ON;
1354
	}
1355

  
1356
	/* CGI environment requires that Content-Length be set.
1357
	 * Send 411 Length Required if Content-Length missing.
1358
	 * (Alternatively, collect full request body before proceeding
1359
	 *  in mod_cgi_handle_subrequest(), which can be done if not
1360
	 *  attempting to stream request body) */
1361
	if (-1 == con->request.content_length) {/*(Transfer-Encoding: chunked)*/
1362
		con->keep_alive = 0;
1363
		con->http_status = 411; /* Length Required */
1364
		con->mode = DIRECT;
1365
		return HANDLER_FINISHED;
1366
	}
1367

  
1368
	{
1353 1369
		handler_ctx *hctx = cgi_handler_ctx_init();
1354 1370
		hctx->remote_conn = con;
1355 1371
		hctx->plugin_data = p;
src/mod_fastcgi.c
3400 3400
		return HANDLER_GO_ON;
3401 3401
	}
3402 3402

  
3403
	/* CGI environment requires that Content-Length be set.
3404
	 * Send 411 Length Required if Content-Length missing.
3405
	 * (Alternatively, collect full request body before proceeding
3406
	 *  in mod_fastcgi_handle_subrequest(), which can be done if not
3407
	 *  attempting to stream request body) */
3408
	if (-1 == con->request.content_length) {/*(Transfer-Encoding: chunked)*/
3409
		con->keep_alive = 0;
3410
		con->http_status = 411; /* Length Required */
3411
		con->mode = DIRECT;
3412
		return HANDLER_FINISHED;
3413
	}
3414

  
3403 3415
	/* check if we have at least one server for this extension up and running */
3404 3416
	host = fcgi_extension_host_get(srv, con, p, extension);
3405 3417
	if (NULL == host) {
src/mod_proxy.c
1291 1291
		return HANDLER_GO_ON;
1292 1292
	}
1293 1293

  
1294
	/* mod_proxy sends HTTP/1.0 request and ideally should send
1295
	 * Content-Length with request if request body is present, so
1296
	 * send 411 Length Required if Content-Length missing.
1297
	 * (Alternatively, collect full request body before proceeding
1298
	 *  in mod_proxy_handle_subrequest(), which can be done if not
1299
	 *  attempting to stream request body) */
1300
	if (-1 == con->request.content_length) {/*(Transfer-Encoding: chunked)*/
1301
		con->keep_alive = 0;
1302
		con->http_status = 411; /* Length Required */
1303
		con->mode = DIRECT;
1304
		return HANDLER_FINISHED;
1305
	}
1306

  
1294 1307
	host = mod_proxy_extension_host_get(srv, con, extension, p->conf.balance, (int)p->conf.debug);
1295 1308
	if (NULL == host) {
1296 1309
		return HANDLER_FINISHED;
src/mod_scgi.c
2739 2739
	/* SCGI requires that Content-Length be set.
2740 2740
	 * Send 411 Length Required if Content-Length missing.
2741 2741
	 * (Alternatively, collect full request body before proceeding
2742
	 *  in mod_scgi_handle_subrequest()) */
2743
	if (0 == con->request.content_length
2744
	    && array_get_element(con->request.headers, "Transfer-Encoding")) {
2742
	 *  in mod_scgi_handle_subrequest(), which can be done if not
2743
	 *  attempting to stream request body) */
2744
	if (-1 == con->request.content_length) {/*(Transfer-Encoding: chunked)*/
2745 2745
		con->keep_alive = 0;
2746 2746
		con->http_status = 411; /* Length Required */
2747 2747
		con->mode = DIRECT;
src/request.c
954 954

  
955 955
							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
956 956
								char *err;
957
								unsigned long int r;
957
								off_t r;
958 958
								size_t j, jlen;
959 959

  
960 960
								if (con_length_set) {
......
987 987
									}
988 988
								}
989 989

  
990
								r = strtoul(ds->value->ptr, &err, 10);
990
								r = strtoll(ds->value->ptr, &err, 10);
991 991

  
992
								if (*err == '\0') {
992
								if (*err == '\0' && r >= 0) {
993 993
									con_length_set = 1;
994 994
									con->request.content_length = r;
995 995
								} else {
......
1236 1236
		return 0;
1237 1237
	}
1238 1238

  
1239
	{
1240
		data_string *ds = (data_string *)array_get_element(con->request.headers, "Transfer-Encoding");
1241
		if (NULL != ds) {
1242
			if (con->request.http_version == HTTP_VERSION_1_0) {
1243
				log_error_write(srv, __FILE__, __LINE__, "s",
1244
						"HTTP/1.0 with Transfer-Encoding (bad HTTP/1.0 proxy?) -> 400");
1245
				con->keep_alive = 0;
1246
				con->http_status = 400; /* Bad Request */
1247
				return 0;
1248
			}
1249

  
1250
			if (0 != strcasecmp(ds->value->ptr, "chunked")) {
1251
				/* Transfer-Encoding might contain additional encodings,
1252
				 * which are not currently supported by lighttpd */
1253
				con->keep_alive = 0;
1254
				con->http_status = 501; /* Not Implemented */
1255
				return 0;
1256
			}
1257

  
1258
			/* reset value for Transfer-Encoding, a hop-by-hop header,
1259
			 * which must not be blindly forwarded to backends */
1260
			buffer_reset(ds->value); /* headers with empty values are ignored */
1261

  
1262
			con_length_set = 1;
1263
			con->request.content_length = -1;
1264

  
1265
			/*(note: ignore whether or not Content-Length was provided)*/
1266
			ds = (data_string *)array_get_element(con->request.headers, "Content-Length");
1267
			if (NULL != ds) buffer_reset(ds->value); /* headers with empty values are ignored */
1268
		}
1269
	}
1270

  
1239 1271
	switch(con->request.http_method) {
1240 1272
	case HTTP_METHOD_GET:
1241 1273
	case HTTP_METHOD_HEAD:
......
1264 1296
		}
1265 1297
		break;
1266 1298
	default:
1267
		/* require Content-Length if request contains request body */
1268
		if (array_get_element(con->request.headers, "Transfer-Encoding")) {
1269
			/* presence of Transfer-Encoding in request headers requires "chunked"
1270
			 * be final encoding in HTTP/1.1.  Return 411 Length Required as
1271
			 * lighttpd does not support request input transfer-encodings */
1272
			con->keep_alive = 0;
1273
			con->http_status = 411; /* 411 Length Required */
1274
			return 0;
1275
		}
1276 1299
		break;
1277 1300
	}
1278 1301

  
1279 1302

  
1280 1303
	/* check if we have read post data */
1281 1304
	if (con_length_set) {
1282
		/* don't handle more the SSIZE_MAX bytes in content-length */
1283
		if (con->request.content_length > SSIZE_MAX) {
1284
			con->http_status = 413;
1285
			con->keep_alive = 0;
1286

  
1287
			log_error_write(srv, __FILE__, __LINE__, "sos",
1288
					"request-size too long:", (off_t) con->request.content_length, "-> 413");
1289
			return 0;
1290
		}
1291

  
1292 1305
		/* we have content */
1293 1306
		if (con->request.content_length != 0) {
1294 1307
			return 1;