So...at my hotel in Ljubljana, they have a silly Squid proxy that doesn't understand chunked request bodies. I know this has been a huge detriment for some people with serf - so, here's a patch for serf that will try to send C-L bodies for basic HTTP request bodies. With this patch, ra_serf only sends C-L...however, the hotel's version of Squid (squid/2.7.STABLE9) doesn't understand chunked *response* bodies either. So, it ends up "Connection: close"-ing after *every single request*. Needless to say, serf's not amused - it still works just fine; but it's pretty slow as it has to constantly re-open TCP connections. There's nothing serf can do about directly controlling the server-side's logic to avoid chunking responses.
So, I'm on the fence about cleaning up and applying this patch as I think if you're talking to a dumb HTTP proxy, you're likely going to run into other serious issues. Thoughts? -- justin Index: serf_bucket_util.h =================================================================== --- serf_bucket_util.h (revision 1462) +++ serf_bucket_util.h (working copy) @@ -79,6 +79,10 @@ serf_bucket_t *serf_default_read_bucket( serf_bucket_t *bucket, const serf_bucket_type_t *type); +apr_status_t serf_default_advise_length( + serf_bucket_t *bucket, + apr_size_t *len); + /** * Default implementation of the @see destroy functionality. * Index: serf.h =================================================================== --- serf.h (revision 1465) +++ serf.h (working copy) @@ -814,6 +814,10 @@ struct serf_bucket_type_t { const char **data, apr_size_t *len); /** + */ + apr_status_t (*advise_length)(serf_bucket_t *bucket, apr_size_t *len); + + /** * Destroy @a bucket, along with any associated resources. */ void (*destroy)(serf_bucket_t *bucket); @@ -882,6 +886,7 @@ struct serf_bucket_type_t { SERF__RECREAD(b, (b)->type->read_for_sendfile(b,r,h,f,o,l)) #define serf_bucket_read_bucket(b,t) ((b)->type->read_bucket(b,t)) #define serf_bucket_peek(b,d,l) ((b)->type->peek(b,d,l)) +#define serf_bucket_advise_length(b,l) ((b)->type->advise_length(b,l)) #define serf_bucket_destroy(b) ((b)->type->destroy(b)) #define serf_bucket_snapshot(b) ((b)->type->snapshot(b)) #define serf_bucket_restore_snapshot(b) ((b)->type->restore_snapshot(b)) Index: buckets/limit_buckets.c =================================================================== --- buckets/limit_buckets.c (revision 1462) +++ buckets/limit_buckets.c (working copy) @@ -118,6 +118,7 @@ const serf_bucket_type_t serf_bucket_type_limit = serf_default_read_for_sendfile, serf_default_read_bucket, serf_limit_peek, + serf_default_advise_length, serf_limit_destroy, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/file_buckets.c =================================================================== --- buckets/file_buckets.c (revision 1462) +++ buckets/file_buckets.c (working copy) @@ -105,6 +105,22 @@ static apr_status_t serf_file_peek(serf_bucket_t * return serf_databuf_peek(&ctx->databuf, data, len); } +static apr_status_t serf_file_advise_length(serf_bucket_t *bucket, + apr_size_t *len) +{ + file_context_t *ctx = bucket->data; + apr_finfo_t finfo; + apr_status_t status; + + status = apr_file_info_get(&finfo, APR_FINFO_SIZE, ctx->file); + + if (!status) { + *len = finfo.size; + } + + return APR_SUCCESS; +} + const serf_bucket_type_t serf_bucket_type_file = { "FILE", serf_file_read, @@ -113,6 +129,7 @@ const serf_bucket_type_t serf_bucket_type_file = { serf_default_read_for_sendfile, serf_default_read_bucket, serf_file_peek, + serf_file_advise_length, serf_default_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/buckets.c =================================================================== --- buckets/buckets.c (revision 1462) +++ buckets/buckets.c (working copy) @@ -104,6 +104,12 @@ serf_bucket_t *serf_default_read_bucket( return NULL; } +apr_status_t serf_default_advise_length( + serf_bucket_t *bucket, + apr_size_t *len) +{ + return APR_ENOTIMPL; +} void serf_default_destroy(serf_bucket_t *bucket) { Index: buckets/dechunk_buckets.c =================================================================== --- buckets/dechunk_buckets.c (revision 1462) +++ buckets/dechunk_buckets.c (working copy) @@ -181,6 +181,7 @@ const serf_bucket_type_t serf_bucket_type_dechunk serf_default_read_for_sendfile, serf_default_read_bucket, serf_dechunk_peek, + serf_default_advise_length, serf_dechunk_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/aggregate_buckets.c =================================================================== --- buckets/aggregate_buckets.c (revision 1465) +++ buckets/aggregate_buckets.c (working copy) @@ -370,6 +370,28 @@ static apr_status_t serf_aggregate_peek(serf_bucke return APR_ENOTIMPL; } +static apr_status_t serf_aggregate_advise_length(serf_bucket_t *bucket, + apr_size_t *len) +{ + aggregate_context_t *ctx = bucket->data; + bucket_list_t *l = ctx->list; + + *len = 0; + while (l) { + apr_status_t status; + apr_size_t bucket_len; + + status = serf_bucket_advise_length(l->bucket, &bucket_len); + if (status) { + return status; + } + *len += bucket_len; + l = l->next; + } + + return APR_SUCCESS; +} + static serf_bucket_t * serf_aggregate_read_bucket( serf_bucket_t *bucket, const serf_bucket_type_t *type) @@ -462,6 +484,7 @@ const serf_bucket_type_t serf_bucket_type_aggregat serf_default_read_for_sendfile, serf_aggregate_read_bucket, serf_aggregate_peek, + serf_aggregate_advise_length, serf_aggregate_destroy_and_data, serf_aggregate_snapshot, serf_aggregate_restore_snapshot, Index: buckets/barrier_buckets.c =================================================================== --- buckets/barrier_buckets.c (revision 1462) +++ buckets/barrier_buckets.c (working copy) @@ -93,6 +93,7 @@ const serf_bucket_type_t serf_bucket_type_barrier serf_default_read_for_sendfile, serf_default_read_bucket, serf_barrier_peek, + serf_default_advise_length, serf_barrier_destroy, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/request_buckets.c =================================================================== --- buckets/request_buckets.c (revision 1462) +++ buckets/request_buckets.c (working copy) @@ -112,9 +112,23 @@ static void serialize_data(serf_bucket_t *bucket) serf_bucket_aggregate_append(bucket, new_bucket); serf_bucket_aggregate_append(bucket, ctx->headers); if (ctx->body != NULL) { - /* Morph the body bucket to a chunked encoding bucket for now. */ - serf_bucket_headers_set(ctx->headers, "Transfer-Encoding", "chunked"); - ctx->body = serf_bucket_chunk_create(ctx->body, bucket->allocator); + apr_status_t body_len_status; + apr_size_t body_len; + + body_len_status = serf_bucket_advise_length(ctx->body, &body_len); + if (!body_len_status) { + char len_hdr[20]; + apr_size_t len_hdr_len; + + len_hdr_len = apr_snprintf(len_hdr, sizeof(len_hdr), + "%" APR_SIZE_T_FMT, body_len); + + serf_bucket_headers_set(ctx->headers, "Content-Length", len_hdr); + } else { + /* Morph the body bucket to a chunked encoding bucket for now. */ + serf_bucket_headers_set(ctx->headers, "Transfer-Encoding", "chunked"); + ctx->body = serf_bucket_chunk_create(ctx->body, bucket->allocator); + } serf_bucket_aggregate_append(bucket, ctx->body); } @@ -199,6 +213,7 @@ const serf_bucket_type_t serf_bucket_type_request serf_default_read_for_sendfile, serf_default_read_bucket, serf_request_peek, + serf_default_advise_length, serf_default_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/socket_buckets.c =================================================================== --- buckets/socket_buckets.c (revision 1462) +++ buckets/socket_buckets.c (working copy) @@ -110,6 +110,7 @@ const serf_bucket_type_t serf_bucket_type_socket = serf_default_read_for_sendfile, serf_default_read_bucket, serf_socket_peek, + serf_default_advise_length, serf_default_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/simple_buckets.c =================================================================== --- buckets/simple_buckets.c (revision 1462) +++ buckets/simple_buckets.c (working copy) @@ -122,6 +122,16 @@ static apr_status_t serf_simple_peek(serf_bucket_t return APR_EOF; } +static apr_status_t serf_simple_advise_length(serf_bucket_t *bucket, + apr_size_t *len) +{ + simple_context_t *ctx = bucket->data; + + *len = ctx->remaining; + + return APR_SUCCESS; +} + static void serf_simple_destroy(serf_bucket_t *bucket) { simple_context_t *ctx = bucket->data; @@ -169,6 +179,7 @@ const serf_bucket_type_t serf_bucket_type_simple = serf_default_read_for_sendfile, serf_default_read_bucket, serf_simple_peek, + serf_simple_advise_length, serf_simple_destroy, serf_simple_snapshot, serf_simple_restore_snapshot, Index: buckets/mmap_buckets.c =================================================================== --- buckets/mmap_buckets.c (revision 1462) +++ buckets/mmap_buckets.c (working copy) @@ -106,6 +106,16 @@ static apr_status_t serf_mmap_peek(serf_bucket_t * return APR_ENOTIMPL; } +static apr_status_t serf_mmap_advise_length(serf_bucket_t *bucket, + apr_size_t *len) +{ + mmap_context_t *ctx = bucket->data; + + *len = ctx->remaining; + + return APR_SUCCESS; +} + const serf_bucket_type_t serf_bucket_type_mmap = { "MMAP", serf_mmap_read, @@ -114,6 +124,7 @@ const serf_bucket_type_t serf_bucket_type_mmap = { serf_default_read_for_sendfile, serf_default_read_bucket, serf_mmap_peek, + serf_mmap_advise_length, serf_default_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/response_buckets.c =================================================================== --- buckets/response_buckets.c (revision 1462) +++ buckets/response_buckets.c (working copy) @@ -425,6 +425,7 @@ const serf_bucket_type_t serf_bucket_type_response serf_default_read_for_sendfile, serf_default_read_bucket, serf_response_peek, + serf_default_advise_length, serf_response_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/ssl_buckets.c =================================================================== --- buckets/ssl_buckets.c (revision 1467) +++ buckets/ssl_buckets.c (working copy) @@ -1488,6 +1488,7 @@ const serf_bucket_type_t serf_bucket_type_ssl_encr serf_default_read_for_sendfile, serf_default_read_bucket, serf_ssl_peek, + serf_default_advise_length, serf_ssl_encrypt_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, @@ -1502,6 +1503,7 @@ const serf_bucket_type_t serf_bucket_type_ssl_decr serf_default_read_for_sendfile, serf_default_read_bucket, serf_ssl_peek, + serf_default_advise_length, serf_ssl_decrypt_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/deflate_buckets.c =================================================================== --- buckets/deflate_buckets.c (revision 1462) +++ buckets/deflate_buckets.c (working copy) @@ -372,6 +372,7 @@ const serf_bucket_type_t serf_bucket_type_deflate serf_default_read_for_sendfile, serf_default_read_bucket, serf_deflate_peek, + serf_default_advise_length, serf_deflate_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/iovec_buckets.c =================================================================== --- buckets/iovec_buckets.c (revision 1462) +++ buckets/iovec_buckets.c (working copy) @@ -186,6 +186,7 @@ const serf_bucket_type_t serf_bucket_type_iovec = serf_default_read_for_sendfile, serf_default_read_bucket, serf_iovec_peek, + serf_default_advise_length, serf_iovec_destroy, serf_iovec_snapshot, serf_iovec_restore_snapshot, Index: buckets/chunk_buckets.c =================================================================== --- buckets/chunk_buckets.c (revision 1462) +++ buckets/chunk_buckets.c (working copy) @@ -231,6 +231,7 @@ const serf_bucket_type_t serf_bucket_type_chunk = serf_default_read_for_sendfile, serf_default_read_bucket, serf_chunk_peek, + serf_default_advise_length, serf_chunk_destroy, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/headers_buckets.c =================================================================== --- buckets/headers_buckets.c (revision 1462) +++ buckets/headers_buckets.c (working copy) @@ -425,6 +425,7 @@ const serf_bucket_type_t serf_bucket_type_headers serf_default_read_for_sendfile, serf_default_read_bucket, serf_headers_peek, + serf_default_advise_length, serf_headers_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, Index: buckets/bwtp_buckets.c =================================================================== --- buckets/bwtp_buckets.c (revision 1462) +++ buckets/bwtp_buckets.c (working copy) @@ -306,6 +306,7 @@ const serf_bucket_type_t serf_bucket_type_bwtp_fra serf_default_read_for_sendfile, serf_default_read_bucket, serf_bwtp_frame_peek, + serf_default_advise_length, serf_default_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot, @@ -595,6 +596,7 @@ const serf_bucket_type_t serf_bucket_type_bwtp_inc serf_default_read_for_sendfile, serf_default_read_bucket, bwtp_incoming_peek, + serf_default_advise_length, bwtp_incoming_destroy_and_data, serf_default_snapshot, serf_default_restore_snapshot,