On the get-remaining branch: Revert r1700019

git-svn-id: https://svn.apache.org/repos/asf/serf/branches/get-remaining@1701860 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/buckets/aggregate_buckets.c b/buckets/aggregate_buckets.c
index 215cff5..bd9f042 100644
--- a/buckets/aggregate_buckets.c
+++ b/buckets/aggregate_buckets.c
@@ -492,6 +492,29 @@
     return serf_bucket_read_bucket(ctx->list->bucket, type);
 }
 
+static apr_uint64_t serf_aggregate_get_remaining(serf_bucket_t *bucket)
+{
+    aggregate_context_t *ctx = bucket->data;
+    apr_uint64_t remaining = 0;
+    bucket_list_t *cur;
+
+    if (ctx->hold_open) {
+        return SERF_LENGTH_UNKNOWN;
+    }
+
+    for(cur = ctx->list; cur != NULL; cur = cur->next) {
+        apr_uint64_t bucket_remaining = serf_bucket_get_remaining(cur->bucket);
+
+        if (bucket_remaining == SERF_LENGTH_UNKNOWN) {
+            return SERF_LENGTH_UNKNOWN;
+        }
+
+        remaining += bucket_remaining;
+    }
+
+    return remaining;
+}
+
 static apr_status_t serf_aggregate_set_config(serf_bucket_t *bucket,
                                               serf_config_t *config)
 {
@@ -524,5 +547,6 @@
     serf_aggregate_peek,
     serf_aggregate_destroy_and_data,
     serf_aggregate_read_bucket,
+    serf_aggregate_get_remaining,
     serf_aggregate_set_config,
 };
diff --git a/buckets/barrier_buckets.c b/buckets/barrier_buckets.c
index d65d4bc..9d54f22 100644
--- a/buckets/barrier_buckets.c
+++ b/buckets/barrier_buckets.c
@@ -79,6 +79,13 @@
     serf_default_destroy(bucket);
 }
 
+static apr_uint64_t serf_barrier_get_remaining(serf_bucket_t *bucket)
+{
+    serf_bucket_t *stream = bucket->data;
+
+    return serf_bucket_get_remaining(stream);
+}
+
 static apr_status_t serf_barrier_set_config(serf_bucket_t *bucket,
                                             serf_config_t *config)
 {
@@ -99,5 +106,6 @@
     serf_barrier_peek,
     serf_barrier_destroy,
     serf_default_read_bucket,
+    serf_barrier_get_remaining,
     serf_barrier_set_config,
 };
diff --git a/buckets/chunk_buckets.c b/buckets/chunk_buckets.c
index 5be2c0f..13b2a75 100644
--- a/buckets/chunk_buckets.c
+++ b/buckets/chunk_buckets.c
@@ -255,5 +255,6 @@
     serf_chunk_peek,
     serf_chunk_destroy,
     serf_default_read_bucket,
+    NULL,
     serf_chunk_set_config,
 };
diff --git a/buckets/copy_buckets.c b/buckets/copy_buckets.c
index 1e1f331..042d1ba 100644
--- a/buckets/copy_buckets.c
+++ b/buckets/copy_buckets.c
@@ -198,5 +198,6 @@
     serf_copy_peek,
     serf_copy_destroy,
     serf_copy_read_bucket,
+    NULL,
     serf_copy_set_config,
 };
diff --git a/buckets/dechunk_buckets.c b/buckets/dechunk_buckets.c
index 4711acd..c99051f 100644
--- a/buckets/dechunk_buckets.c
+++ b/buckets/dechunk_buckets.c
@@ -212,5 +212,6 @@
     serf_dechunk_peek,
     serf_dechunk_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_dechunk_set_config,
 };
diff --git a/buckets/deflate_buckets.c b/buckets/deflate_buckets.c
index 3891032..f43b2dc 100644
--- a/buckets/deflate_buckets.c
+++ b/buckets/deflate_buckets.c
@@ -458,5 +458,6 @@
     serf_deflate_peek,
     serf_deflate_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_deflate_set_config,
 };
diff --git a/buckets/file_buckets.c b/buckets/file_buckets.c
index 6a9051b..fe9e0be 100644
--- a/buckets/file_buckets.c
+++ b/buckets/file_buckets.c
@@ -27,6 +27,7 @@
     apr_file_t *file;
 
     serf_databuf_t databuf;
+    apr_uint64_t remaining;
 } file_context_t;
 
 
@@ -45,11 +46,11 @@
 {
     apr_status_t status;
     file_context_t *ctx;
-#if APR_HAS_MMAP
     apr_finfo_t finfo;
 
     status = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
 
+#if APR_HAS_MMAP
     /* See if we'd be better off mmap'ing this file instead.
      *
      * Note that there is a failure case here that we purposely fall through:
@@ -77,6 +78,13 @@
     ctx->databuf.read = file_reader;
     ctx->databuf.read_baton = ctx;
 
+    if (status == APR_SUCCESS) {
+        ctx->remaining = finfo.size;
+    }
+    else {
+        ctx->remaining = SERF_LENGTH_UNKNOWN;
+    }
+
     return serf_bucket_create(&serf_bucket_type_file, allocator, ctx);
 }
 
@@ -85,8 +93,21 @@
                                    const char **data, apr_size_t *len)
 {
     file_context_t *ctx = bucket->data;
+    apr_status_t status;
 
-    return serf_databuf_read(&ctx->databuf, requested, data, len);
+    status = serf_databuf_read(&ctx->databuf, requested, data, len);
+
+    if (SERF_BUCKET_READ_ERROR(status))
+    {
+        return status;
+    }
+
+    /* Update remaining length if known. */
+    if (ctx->remaining != SERF_LENGTH_UNKNOWN) {
+        ctx->remaining -= *len;
+    }
+
+    return status;
 }
 
 static apr_status_t serf_file_readline(serf_bucket_t *bucket,
@@ -94,8 +115,22 @@
                                        const char **data, apr_size_t *len)
 {
     file_context_t *ctx = bucket->data;
+    apr_status_t status;
 
-    return serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
+    status = serf_databuf_readline(&ctx->databuf, acceptable, found, data, len);
+
+    if (SERF_BUCKET_READ_ERROR(status))
+    {
+        return status;
+    }
+
+    /* Update remaining length if known. */
+    if (ctx->remaining != SERF_LENGTH_UNKNOWN) {
+        ctx->remaining -= *len;
+    }
+
+    return status;
+
 }
 
 static apr_status_t serf_file_peek(serf_bucket_t *bucket,
@@ -107,6 +142,12 @@
     return serf_databuf_peek(&ctx->databuf, data, len);
 }
 
+static apr_uint64_t serf_file_get_remaining(serf_bucket_t *bucket)
+{
+    file_context_t *ctx = bucket->data;
+    return ctx->remaining;
+}
+
 const serf_bucket_type_t serf_bucket_type_file = {
     "FILE",
     serf_file_read,
@@ -117,5 +158,6 @@
     serf_file_peek,
     serf_default_destroy_and_data,
     serf_default_read_bucket,
+    serf_file_get_remaining,
     serf_default_ignore_config,
 };
diff --git a/buckets/limit_buckets.c b/buckets/limit_buckets.c
index 6db7247..df7f4a5 100644
--- a/buckets/limit_buckets.c
+++ b/buckets/limit_buckets.c
@@ -121,6 +121,13 @@
     serf_default_destroy_and_data(bucket);
 }
 
+static apr_uint64_t serf_limit_get_remaining(serf_bucket_t *bucket)
+{
+    limit_context_t *ctx = bucket->data;
+
+    return ctx->remaining;
+}
+
 static apr_status_t serf_limit_set_config(serf_bucket_t *bucket,
                                           serf_config_t *config)
 {
@@ -141,5 +148,6 @@
     serf_limit_peek,
     serf_limit_destroy,
     serf_default_read_bucket,
+    serf_limit_get_remaining,
     serf_limit_set_config,
 };
diff --git a/buckets/log_wrapper_buckets.c b/buckets/log_wrapper_buckets.c
index 391554d..5152b33 100644
--- a/buckets/log_wrapper_buckets.c
+++ b/buckets/log_wrapper_buckets.c
@@ -161,6 +161,7 @@
     bkt_type->read_for_sendfile = wrapped->type->read_for_sendfile;
     if (wrapped->type->read_bucket == serf_buckets_are_v2) {
         bkt_type->read_bucket_v2 = wrapped->type->read_bucket_v2;
+        bkt_type->get_remaining = wrapped->type->get_remaining;
     }
 
     /* Wrap these functions */
diff --git a/buckets/mmap_buckets.c b/buckets/mmap_buckets.c
index 4cbb864..8d0b448 100644
--- a/buckets/mmap_buckets.c
+++ b/buckets/mmap_buckets.c
@@ -118,6 +118,12 @@
     return APR_EOF;
 }
 
+static apr_uint64_t serf_mmap_get_remaining(serf_bucket_t *bucket)
+{
+    mmap_context_t *ctx = bucket->data;
+    return ctx->remaining;
+}
+
 const serf_bucket_type_t serf_bucket_type_mmap = {
     "MMAP",
     serf_mmap_read,
@@ -128,6 +134,7 @@
     serf_mmap_peek,
     serf_default_destroy_and_data,
     serf_default_read_bucket,
+    serf_mmap_get_remaining,
     serf_default_ignore_config,
 };
 
@@ -150,6 +157,7 @@
     NULL,
     NULL,
     NULL,
+    NULL,
 };
 
 #endif
diff --git a/buckets/request_buckets.c b/buckets/request_buckets.c
index dd70f05..02a5a2d 100644
--- a/buckets/request_buckets.c
+++ b/buckets/request_buckets.c
@@ -245,6 +245,7 @@
     serf_request_peek,
     serf_request_destroy,
     serf_default_read_bucket,
+    NULL,
     serf_request_set_config,
 };
 
diff --git a/buckets/response_body_buckets.c b/buckets/response_body_buckets.c
index 03a8acf..33726cc 100644
--- a/buckets/response_body_buckets.c
+++ b/buckets/response_body_buckets.c
@@ -149,5 +149,6 @@
     serf_response_body_peek,
     serf_response_body_destroy,
     serf_default_read_bucket,
+    NULL,
     serf_response_body_set_config,
 };
diff --git a/buckets/response_buckets.c b/buckets/response_buckets.c
index 52cde96..bc1d3a6 100644
--- a/buckets/response_buckets.c
+++ b/buckets/response_buckets.c
@@ -545,5 +545,6 @@
     serf_response_peek,
     serf_response_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_response_set_config,
 };
diff --git a/buckets/simple_buckets.c b/buckets/simple_buckets.c
index f5b0a3a..264f736 100644
--- a/buckets/simple_buckets.c
+++ b/buckets/simple_buckets.c
@@ -153,6 +153,12 @@
     serf_default_destroy_and_data(bucket);
 }
 
+static apr_uint64_t serf_simple_get_remaining(serf_bucket_t *bucket)
+{
+    simple_context_t *ctx = bucket->data;
+    return ctx->remaining;
+}
+
 const serf_bucket_type_t serf_bucket_type_simple = {
     "SIMPLE",
     serf_simple_read,
@@ -163,5 +169,6 @@
     serf_simple_peek,
     serf_simple_destroy,
     serf_default_read_bucket,
+    serf_simple_get_remaining,
     serf_default_ignore_config,
 };
diff --git a/buckets/socket_buckets.c b/buckets/socket_buckets.c
index d080503..ec67246 100644
--- a/buckets/socket_buckets.c
+++ b/buckets/socket_buckets.c
@@ -119,5 +119,6 @@
     serf_socket_peek,
     serf_default_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_default_ignore_config,
 };
diff --git a/buckets/ssl_buckets.c b/buckets/ssl_buckets.c
index df7c4a9..4a6c1d3 100644
--- a/buckets/ssl_buckets.c
+++ b/buckets/ssl_buckets.c
@@ -2161,6 +2161,7 @@
     serf_ssl_peek,
     serf_ssl_encrypt_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_ssl_set_config,
 };
 
@@ -2174,5 +2175,6 @@
     serf_ssl_peek,
     serf_ssl_decrypt_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_ssl_set_config,
 };
diff --git a/serf.h b/serf.h
index ae56530..94bcf28 100644
--- a/serf.h
+++ b/serf.h
@@ -779,6 +779,11 @@
  */
 #define SERF_NEWLINE_CRLF_SPLIT 0x0010
 
+/** Used to indicate that length of remaining data in bucket is unknown. See 
+ * serf_bucket_type_t->get_remaining().
+ */
+#define SERF_LENGTH_UNKNOWN ((apr_uint64_t) -1)
+
 struct serf_bucket_type_t {
 
     /** name of this bucket type */
@@ -923,6 +928,13 @@
     serf_bucket_t * (*read_bucket_v2)(serf_bucket_t *bucket,
                                       const serf_bucket_type_t *type);
 
+    /* Returns length of remaining data to be read in @a bucket. Returns
+     * SERF_LENGTH_UNKNOWN if length is unknown.
+     *
+     * @since New in 1.4.
+     */
+    apr_uint64_t (*get_remaining)(serf_bucket_t *bucket);
+
     /* Provides a reference to a config object containing all configuration
      * values relevant for this bucket.
      *
@@ -981,6 +993,10 @@
 #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_destroy(b) ((b)->type->destroy(b))
+#define serf_bucket_get_remaining(b) \
+            ((b)->type->read_bucket == serf_buckets_are_v2 ? \
+             (b)->type->get_remaining(b) : \
+             SERF_LENGTH_UNKNOWN)
 #define serf_bucket_set_config(b,c) \
             ((b)->type->read_bucket == serf_buckets_are_v2 ? \
             (b)->type->set_config(b,c) : \
diff --git a/test/mock_sock_buckets.c b/test/mock_sock_buckets.c
index 1b9f616..efca8e1 100644
--- a/test/mock_sock_buckets.c
+++ b/test/mock_sock_buckets.c
@@ -95,5 +95,6 @@
     serf_mock_sock_peek,
     serf_default_destroy_and_data,
     serf_default_read_bucket,
+    NULL,
     serf_mock_sock_set_config,
 };
diff --git a/test/test_buckets.c b/test/test_buckets.c
index 8756e74..408c845 100644
--- a/test/test_buckets.c
+++ b/test/test_buckets.c
@@ -606,6 +606,12 @@
     bkt = SERF_BUCKET_SIMPLE_STRING(BODY, alloc);
     serf_bucket_aggregate_append(aggbkt, bkt);
 
+    /* If you see result -1 in the next line, this is most likely caused by
+       not properly detecting v2 buckets via the magic function pointer.
+       Most likely you are seeing a linkage problem which causes seeing
+       different pointers for serf_buckets_are_v2() */
+    CuAssertIntEquals(tc, 62, (int)serf_bucket_get_remaining(aggbkt));
+
     status = serf_bucket_read_iovec(aggbkt, 0, 32,
                                     tgt_vecs, &vecs_used);
     CuAssertIntEquals(tc, APR_SUCCESS, status);
@@ -635,6 +641,8 @@
     bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY+15, strlen(BODY)-15, alloc);
     serf_bucket_aggregate_append(aggbkt, bkt);
 
+    CuAssertTrue(tc, serf_bucket_get_remaining(aggbkt) == 62);
+
     read_and_check_bucket(tc, aggbkt, BODY);
 
     /* Test 5: multiple child buckets prepended. */
@@ -645,6 +653,8 @@
     bkt = SERF_BUCKET_SIMPLE_STRING_LEN(BODY, 15, alloc);
     serf_bucket_aggregate_prepend(aggbkt, bkt);
 
+    CuAssertTrue(tc, serf_bucket_get_remaining(aggbkt) == 62);
+
     read_and_check_bucket(tc, aggbkt, BODY);
 
     /* Test 6: ensure peek doesn't return APR_EAGAIN, or APR_EOF incorrectly. */