From 449d4c0b1c6ea0f5dfe7b56c99d9fc4f2033d27c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 10 Sep 2013 13:13:33 +0200 Subject: [PATCH] make reading php://input JIT if enable_post_data_reading=0 --- ext/standard/php_fopen_wrapper.c | 55 ++++++++++++++++++++--- main/SAPI.c | 76 +++++++++++++++++--------------- main/SAPI.h | 3 +- 3 files changed, 92 insertions(+), 42 deletions(-) diff --git a/ext/standard/php_fopen_wrapper.c b/ext/standard/php_fopen_wrapper.c index ca0b92ebde..aa7924d211 100644 --- a/ext/standard/php_fopen_wrapper.c +++ b/ext/standard/php_fopen_wrapper.c @@ -63,6 +63,12 @@ php_stream_ops php_stream_output_ops = { NULL /* set_option */ }; +typedef struct php_stream_input { /* {{{ */ + php_stream **body_ptr; + off_t position; +} php_stream_input_t; +/* }}} */ + static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) /* {{{ */ { return -1; @@ -71,20 +77,52 @@ static size_t php_stream_input_write(php_stream *stream, const char *buf, size_t static size_t php_stream_input_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ { - php_stream *inner = stream->abstract; + php_stream_input_t *input = stream->abstract; + size_t read; + //fprintf(stderr, "Attempt to read %lu bytes (%lu)\n", count, SG(read_post_bytes)); + + if (!SG(post_read) && SG(read_post_bytes) < input->position + count) { + /* read requested data from SAPI */ + int read_bytes = sapi_read_post_block(buf, count TSRMLS_CC); + + //fprintf(stderr, "Did read %d bytes\n", read_bytes); + if (read_bytes > 0) { + php_stream_seek(*input->body_ptr, 0, SEEK_END); + php_stream_write(*input->body_ptr, buf, read_bytes); + } + } + + php_stream_seek(*input->body_ptr, input->position, SEEK_SET); + read = (*input->body_ptr)->ops->read(*input->body_ptr, buf, count TSRMLS_CC); + + if (!read || read == (size_t) -1) { + stream->eof = 1; + } else { + input->position += read; + } + + return read; +} +/* }}} */ + +static size_t php_stream_input_read_x(php_stream *stream, char *buf, size_t count TSRMLS_DC) /* {{{ */ +{ + php_stream_input_t *input = stream->abstract; + php_stream *inner = *input->body_ptr; if (inner && inner->ops->read) { size_t read = inner->ops->read(inner, buf, count TSRMLS_CC); stream->eof = inner->eof; return read; } - return -1; } /* }}} */ static int php_stream_input_close(php_stream *stream, int close_handle TSRMLS_DC) /* {{{ */ { + efree(stream->abstract); + return 0; } /* }}} */ @@ -193,18 +231,23 @@ php_stream * php_stream_url_wrap_php(php_stream_wrapper *wrapper, const char *pa } if (!strcasecmp(path, "input")) { + php_stream_input_t *input; + if ((options & STREAM_OPEN_FOR_INCLUDE) && !PG(allow_url_include) ) { if (options & REPORT_ERRORS) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "URL file-access is disabled in the server configuration"); } return NULL; } - if (SG(request_info).request_body) { - php_stream_rewind(SG(request_info).request_body); + + input = ecalloc(1, sizeof(*input)); + if (*(input->body_ptr = &SG(request_info).request_body)) { + php_stream_rewind(*input->body_ptr); } else { - sapi_read_standard_form_data(TSRMLS_C); + *input->body_ptr = php_stream_temp_create(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE); } - return php_stream_alloc(&php_stream_input_ops, SG(request_info).request_body, 0, "rb"); + + return php_stream_alloc(&php_stream_input_ops, input, 0, "rb"); } if (!strcasecmp(path, "stdin")) { diff --git a/main/SAPI.c b/main/SAPI.c index ccfb1e507d..9c8bcb1420 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -180,10 +180,6 @@ SAPI_API void sapi_handle_post(void *arg TSRMLS_DC) { if (SG(request_info).post_entry && SG(request_info).content_type_dup) { SG(request_info).post_entry->post_handler(SG(request_info).content_type_dup, arg TSRMLS_CC); - /*if (SG(request_info).request_body) { - php_stream_close(SG(request_info).request_body); - SG(request_info).request_body = NULL; - }*/ efree(SG(request_info).content_type_dup); SG(request_info).content_type_dup = NULL; } @@ -249,43 +245,61 @@ static void sapi_read_post_data(TSRMLS_D) } } - -SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data) +SAPI_API int sapi_read_post_block(char *buffer, size_t buflen TSRMLS_DC) { int read_bytes; + if (!sapi_module.read_post) { + return -1; + } + + read_bytes = sapi_module.read_post(buffer, buflen TSRMLS_CC); + + if (read_bytes > 0) { + /* gogo */ + SG(read_post_bytes) += read_bytes; + } + if (read_bytes < buflen) { + /* done */ + SG(post_read) = 1; + } + + return read_bytes; +} + +SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data) +{ if ((SG(post_max_size) > 0) && (SG(request_info).content_length > SG(post_max_size))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size)); return; } + SG(request_info).request_body = php_stream_temp_create(TEMP_STREAM_DEFAULT, SAPI_POST_BLOCK_SIZE); if (sapi_module.read_post) { + int read_bytes; + for (;;) { char buffer[SAPI_POST_BLOCK_SIZE]; - read_bytes = sapi_module.read_post(buffer, SAPI_POST_BLOCK_SIZE TSRMLS_CC); - if (read_bytes<=0) { - /* failure */ - break; + read_bytes = sapi_read_post_block(buffer, SAPI_POST_BLOCK_SIZE TSRMLS_CC); + + if (read_bytes > 0) { + php_stream_write(SG(request_info).request_body, buffer, read_bytes); } - SG(read_post_bytes) += read_bytes; if ((SG(post_max_size) > 0) && (SG(read_post_bytes) > SG(post_max_size))) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Actual POST length does not match Content-Length, and exceeds %ld bytes", SG(post_max_size)); break; } - php_stream_write(SG(request_info).request_body, buffer, read_bytes); - if (read_bytes < SAPI_POST_BLOCK_SIZE) { /* done */ break; } } - - php_stream_rewind(SG(request_info).request_body); + php_stream_rewind(SG(request_info).request_body); } } @@ -455,21 +469,13 @@ SAPI_API void sapi_activate(TSRMLS_D) /* Handle request method */ if (SG(server_context)) { - if (SG(request_info).request_method) { - if (PG(enable_post_data_reading) - && SG(request_info).content_type - && !strcmp(SG(request_info).request_method, "POST")) { - /* HTTP POST may contain form data to be processed into variables - * depending on given content type */ - sapi_read_post_data(TSRMLS_C); - } else { - /* Any other method with content payload will fill php://input stream. - * It's up to the webserver to decide whether to allow a method or not. */ - SG(request_info).content_type_dup = NULL; - if (sapi_module.default_post_reader) { - sapi_module.default_post_reader(TSRMLS_C); - } - } + if (PG(enable_post_data_reading) + && SG(request_info).content_type + && SG(request_info).request_method + && !strcmp(SG(request_info).request_method, "POST")) { + /* HTTP POST may contain form data to be processed into variables + * depending on given content type */ + sapi_read_post_data(TSRMLS_C); } else { SG(request_info).content_type_dup = NULL; } @@ -500,15 +506,15 @@ SAPI_API void sapi_deactivate(TSRMLS_D) zend_llist_destroy(&SG(sapi_headers).headers); if (SG(request_info).request_body) { SG(request_info).request_body = NULL; - } else if (SG(server_context)) { - if(sapi_module.read_post) { + } else if (SG(server_context)) { + if (!SG(post_read)) { /* make sure we've consumed all request input data */ char dummy[SAPI_POST_BLOCK_SIZE]; int read_bytes; - while((read_bytes = sapi_module.read_post(dummy, sizeof(dummy)-1 TSRMLS_CC)) > 0) { - SG(read_post_bytes) += read_bytes; - } + do { + read_bytes = sapi_read_post_block(dummy, SAPI_POST_BLOCK_SIZE TSRMLS_CC); + } while (SAPI_POST_BLOCK_SIZE == read_bytes); } } if (SG(request_info).auth_user) { diff --git a/main/SAPI.h b/main/SAPI.h index ed6b0494f4..5525a2aabd 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -120,6 +120,7 @@ typedef struct _sapi_globals_struct { sapi_request_info request_info; sapi_headers_struct sapi_headers; int64_t read_post_bytes; + unsigned char post_read; unsigned char headers_sent; struct stat global_stat; char *default_mimetype; @@ -188,7 +189,7 @@ SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bo SAPI_API int sapi_send_headers(TSRMLS_D); SAPI_API void sapi_free_header(sapi_header_struct *sapi_header); SAPI_API void sapi_handle_post(void *arg TSRMLS_DC); - +SAPI_API int sapi_read_post_block(char *buffer, size_t buflen TSRMLS_DC); SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entry TSRMLS_DC); SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC); SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry TSRMLS_DC); -- 2.40.0