From c8476df58018aecebc7720b784cf454b6eb6dbae Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Thu, 10 Jul 2014 21:36:41 +0200 Subject: [PATCH] better reporting whether the response was sent out completely --- php_http_buffer.c | 11 ++++++++--- php_http_buffer.h | 2 +- php_http_env_response.c | 21 +++++++++++++-------- tests/envresponse016.phpt | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 tests/envresponse016.phpt diff --git a/php_http_buffer.c b/php_http_buffer.c index 1a4fdc4..35155e7 100644 --- a/php_http_buffer.c +++ b/php_http_buffer.c @@ -222,13 +222,17 @@ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, c return 0; } -PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC) +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_len, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC) { char *chunk = NULL; - size_t got = 0; + size_t passed = 0, got = 0; while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) { - passout(opaque, chunk, got TSRMLS_CC); + if (PHP_HTTP_BUFFER_PASS0 == passout(opaque, chunk, got TSRMLS_CC)) { + STR_SET(chunk, NULL); + return PHP_HTTP_BUFFER_PASS0; + } + ++passed; if (!chunk_len) { /* we already got the last chunk, and freed all resources */ @@ -239,6 +243,7 @@ PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, c STR_SET(chunk, NULL); } STR_FREE(chunk); + return passed; } PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC) diff --git a/php_http_buffer.h b/php_http_buffer.h index bc2a7f2..cf9b458 100644 --- a/php_http_buffer.h +++ b/php_http_buffer.h @@ -191,7 +191,7 @@ typedef size_t (*php_http_buffer_pass_func_t)(void *opaque, char *, size_t TSRML PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg TSRMLS_DC); /* wrapper around php_http_buffer_chunk_buffer, which passes available chunks to passthru() */ -PHP_HTTP_BUFFER_API void php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC); +PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque TSRMLS_DC); /* write chunks directly into php_http_buffer_t buffer */ PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque TSRMLS_DC); diff --git a/php_http_env_response.c b/php_http_env_response.c index 275b91b..4d6ef03 100644 --- a/php_http_env_response.c +++ b/php_http_env_response.c @@ -217,7 +217,9 @@ static size_t output(void *context, char *buf, size_t len TSRMLS_DC) { php_http_env_response_t *r = context; - r->ops->write(r, buf, len); + if (SUCCESS != r->ops->write(r, buf, len)) { + return (size_t) -1; + } /* we really only need to flush when throttling is enabled, because we push the data as fast as possible anyway if not */ @@ -231,7 +233,7 @@ static size_t output(void *context, char *buf, size_t len TSRMLS_DC) #define php_http_env_response_send_done(r) php_http_env_response_send_data((r), NULL, 0) static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len) { - size_t chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE; + size_t chunks_sent, chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE; TSRMLS_FETCH_FROM_CTX(r->ts); if (r->content.encoder) { @@ -248,15 +250,16 @@ static STATUS php_http_env_response_send_data(php_http_env_response_t *r, const } } - if (enc_str) { - php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC); - STR_FREE(enc_str); + if (!enc_str) { + return SUCCESS; } + chunks_sent = php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r TSRMLS_CC); + STR_FREE(enc_str); } else { - php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC); + chunks_sent = php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r TSRMLS_CC); } - return SUCCESS; + return chunks_sent != (size_t) -1 ? SUCCESS : FAILURE; } php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg TSRMLS_DC) @@ -996,7 +999,9 @@ static STATUS php_http_env_response_stream_write(php_http_env_response_t *r, con } } - php_stream_write(stream_ctx->stream, data_str, data_len); + if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) { + return FAILURE; + } return SUCCESS; } diff --git a/tests/envresponse016.phpt b/tests/envresponse016.phpt new file mode 100644 index 0000000..67595b4 --- /dev/null +++ b/tests/envresponse016.phpt @@ -0,0 +1,34 @@ +--TEST-- +env response send failure +--SKIPIF-- + +--FILE-- +getBody()->append(str_repeat("a", 16*1024*4)); +$s = fopen("php://temp", "w"); +stream_filter_append($s, "closer"); +var_dump($r->send($s)); +?> +DONE +--EXPECTF-- +Test +Warning: http\Env\Response::send(): Failed to send response body in %s on line %d +bool(false) +DONE -- 2.30.2