Author: rhuijben
Date: Fri Oct 30 00:23:19 2015
New Revision: 1711392
URL: http://svn.apache.org/viewvc?rev=1711392&view=rev
Log:
Make the response bucket follow RFC 7231 a bit more closely by handling
Transfer-Encoding chunked even when content length is passed and when
another transfer-encoding flag is passed. Make the undo of
Content-Encoding optional.
At the same time add Transfer-Encoding gzip support, which unlike
Content-Encoding should be handled by the transport layer.
* buckets/response_buckets.c
(response_context_t): Add flag.
(serf_bucket_response_create): Initialize flag.
(serf_bucket_response_set_decode_content): New function.
* serf_bucket_types.h
(serf_bucket_response_decode_content): New function.
Modified:
serf/trunk/buckets/response_buckets.c
serf/trunk/serf_bucket_types.h
Modified: serf/trunk/buckets/response_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/response_buckets.c?rev=1711392&r1=1711391&r2=1711392&view=diff
==============================================================================
--- serf/trunk/buckets/response_buckets.c (original)
+++ serf/trunk/buckets/response_buckets.c Fri Oct 30 00:23:19 2015
@@ -43,6 +43,7 @@ typedef struct response_context_t {
int chunked; /* Do we need to read trailers? */
int head_req; /* Was this a HEAD request? */
+ int decode_content; /* Do we want to decode 'Content-Encoding' */
serf_config_t *config;
@@ -92,6 +93,7 @@ serf_bucket_t *serf_bucket_response_crea
ctx->state = STATE_STATUS_LINE;
ctx->chunked = 0;
ctx->head_req = 0;
+ ctx->decode_content = TRUE;
ctx->error_on_eof = 0;
ctx->config = NULL;
@@ -108,6 +110,14 @@ void serf_bucket_response_set_head(
ctx->head_req = 1;
}
+void serf_bucket_response_set_decode_content(serf_bucket_t *bucket,
+ int decode)
+{
+ response_context_t *ctx = bucket->data;
+
+ ctx->decode_content = decode;
+}
+
serf_bucket_t *serf_bucket_response_get_headers(
serf_bucket_t *bucket)
{
@@ -282,7 +292,9 @@ static apr_status_t run_machine(serf_buc
* Move on to the body.
*/
if (ctx->linebuf.state == SERF_LINEBUF_READY && !ctx->linebuf.used) {
- const void *v;
+ const char *v;
+ int chunked = 0;
+ int gzip = 0;
/* Advance the state. */
ctx->state = STATE_BODY;
@@ -299,29 +311,62 @@ static apr_status_t run_machine(serf_buc
ctx->body =
serf_bucket_barrier_create(ctx->stream, bkt->allocator);
- /* Are we C-L, chunked, or conn close? */
- v = serf_bucket_headers_get(ctx->headers, "Content-Length");
+ /* Are we chunked, C-L, or conn close? */
+ v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");
+
+ /* Need a copy cuz we're going to write NUL characters into the
+ string. */
if (v) {
- apr_uint64_t length;
- length = apr_strtoi64(v, NULL, 10);
- if (errno == ERANGE) {
- return APR_FROM_OS_ERROR(ERANGE);
+ char *attrs = serf_bstrdup(bkt->allocator, v);
+ char *at = attrs;
+ char *next = NULL;
+
+ while ((v = apr_strtok(at, ", ", &next))) {
+ at = NULL;
+
+ if (!strcasecmp(v, "chunked"))
+ chunked = 1;
+ else if (!strcasecmp(v, "gzip"))
+ gzip = 1;
+ /* ### Others? */
}
- ctx->body = serf_bucket_response_body_create(
- ctx->body, length, bkt->allocator);
+ serf_bucket_mem_free(bkt->allocator, attrs);
}
- else {
- v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding");
- /* Need to handle multiple transfer-encoding. */
- if (v && strcasecmp("chunked", v) == 0) {
- ctx->chunked = 1;
- ctx->body = serf_bucket_dechunk_create(ctx->body,
- bkt->allocator);
+ if (chunked) {
+ ctx->chunked = 1;
+ ctx->body = serf_bucket_dechunk_create(ctx->body,
+ bkt->allocator);
+ serf_bucket_set_config(ctx->body, ctx->config);
+ }
+ else {
+ /* RFC 7231 specifies that we should determine the message
+ length via Transfer-Encoding chunked, when both chunked
+ and Content-Length are passed */
+
+ v = serf_bucket_headers_get(ctx->headers, "Content-Length");
+ if (v) {
+ apr_uint64_t length;
+ length = apr_strtoi64(v, NULL, 10);
+ if (errno == ERANGE) {
+ return APR_FROM_OS_ERROR(ERANGE);
+ }
+ ctx->body = serf_bucket_response_body_create(
+ ctx->body, length, bkt->allocator);
}
}
+
+ /* Transfer encodings are handled by the transport, while content
+ encoding is part of the data itself. */
+ if (gzip) {
+ ctx->body =
+ serf_bucket_deflate_create(ctx->body, bkt->allocator,
+ SERF_DEFLATE_GZIP);
+ serf_bucket_set_config(ctx->body, ctx->config);
+ }
+
v = serf_bucket_headers_get(ctx->headers, "Content-Encoding");
- if (v) {
+ if (v && ctx->decode_content) {
/* Need to handle multiple content-encoding. */
if (v && strcasecmp("gzip", v) == 0) {
ctx->body =
Modified: serf/trunk/serf_bucket_types.h
URL:
http://svn.apache.org/viewvc/serf/trunk/serf_bucket_types.h?rev=1711392&r1=1711391&r2=1711392&view=diff
==============================================================================
--- serf/trunk/serf_bucket_types.h (original)
+++ serf/trunk/serf_bucket_types.h Fri Oct 30 00:23:19 2015
@@ -138,6 +138,16 @@ serf_bucket_t *serf_bucket_response_get_
void serf_bucket_response_set_head(
serf_bucket_t *bucket);
+/**
+ * Ask the response @a bucket, to decode content based on the value of the
+ * 'Content- Encoding' header, or not. The default setting of a response
+ * bucket is to decode when the header is found.
+ */
+void serf_bucket_response_decode_content(
+ serf_bucket_t *bucket,
+ int decode);
+
+
/* ==================================================================== */
extern const serf_bucket_type_t serf_bucket_type_response_body;