Author: rhuijben
Date: Wed Nov 11 21:07:58 2015
New Revision: 1713932

URL: http://svn.apache.org/viewvc?rev=1713932&view=rev
Log:
Make the deflate buckets properly read to completion in all scenarios.
Fixing this made visible that the compress code calculated the crc and
size in the wrong way.

* buckets/deflate_buckets.c
  (serf_deflate_destroy_and_data): Assume streams attached the other way
    around.
  (serf_deflate_refill): Always calculate the crc on the uncompressed data.
    Store bytes in magic value as big endian.
  (serf_deflate_wait_for_data): Attach input stream to the stream we read from
    when done, to handle read to end promises.
  (serf_deflate_read): Simplify by checking against DONE.
  (serf_deflate_set_config): Avoid segfault when we are done reading from
    stream.

Modified:
    serf/trunk/buckets/deflate_buckets.c

Modified: serf/trunk/buckets/deflate_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/deflate_buckets.c?rev=1713932&r1=1713931&r2=1713932&view=diff
==============================================================================
--- serf/trunk/buckets/deflate_buckets.c (original)
+++ serf/trunk/buckets/deflate_buckets.c Wed Nov 11 21:07:58 2015
@@ -178,17 +178,22 @@ static void serf_deflate_destroy_and_dat
 {
     deflate_context_t *ctx = bucket->data;
 
-    if (ctx->state > STATE_INIT &&
-        ctx->state <= STATE_FINISH)
-        inflateEnd(&ctx->zstream);
+    if ((ctx->state > STATE_INIT && ctx->state <= STATE_FINISH)
+        || (ctx->state > STATE_COMPRESS_INIT
+            && ctx->state < STATE_COMPRESS_FINISH))
+    {
+        if (ctx->memLevel >= 0)
+            deflateEnd(&ctx->zstream);
+        else
+            inflateEnd(&ctx->zstream);
+    }
 
-    /* We may have appended inflate_stream into the stream bucket.
+    /* We may have appended stream into the inflate bucket.
      * If so, avoid free'ing it twice.
      */
-    if (ctx->inflate_stream) {
-        serf_bucket_destroy(ctx->inflate_stream);
-    }
-    serf_bucket_destroy(ctx->stream);
+    serf_bucket_destroy(ctx->inflate_stream);
+    if (ctx->stream)
+        serf_bucket_destroy(ctx->stream);
 
     serf_default_destroy_and_data(bucket);
 }
@@ -237,6 +242,9 @@ static apr_status_t serf_deflate_refill(
         if (private_len) {
             ctx->zstream.next_in = (unsigned char*)private_data;
             ctx->zstream.avail_in = private_len;
+            if (ctx->memLevel >= 0)
+                ctx->crc = crc32(ctx->crc, (const Bytef *)private_data,
+                                 private_len);
         } else {
             ctx->zstream.next_in = Z_NULL;
             ctx->zstream.avail_in = 0;
@@ -259,8 +267,9 @@ static apr_status_t serf_deflate_refill(
             ctx->zstream.next_out = ctx->buffer;
             private_len = ctx->bufferSize - ctx->zstream.avail_out;
 
-            ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
-                              private_len);
+            if (ctx->memLevel < 0)
+              ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
+                               private_len);
 
             /* FIXME: There probably needs to be a free func. */
             tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
@@ -278,8 +287,9 @@ static apr_status_t serf_deflate_refill(
             serf_bucket_t *tmp;
 
             private_len = ctx->bufferSize - ctx->zstream.avail_out;
-            ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
-                              private_len);
+            if (ctx->memLevel < 0)
+              ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
+                               private_len);
             /* FIXME: There probably needs to be a free func. */
             tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
                                                 private_len,
@@ -313,15 +323,15 @@ static apr_status_t serf_deflate_refill(
                                                 bucket->allocator,
                                                 DEFLATE_VERIFY_SIZE);
 
-                     verify_header[0] = (ctx->crc >> 24) & 0xFF;
-                     verify_header[1] = (ctx->crc >> 16) & 0xFF;
-                     verify_header[2] = (ctx->crc >>  8) & 0xFF;
-                     verify_header[3] =  ctx->crc        & 0xFF;
-
-                     verify_header[4] = (ctx->zstream.total_out >> 24) & 0xFF;
-                     verify_header[5] = (ctx->zstream.total_out >> 16) & 0xFF;
-                     verify_header[6] = (ctx->zstream.total_out >>  8) & 0xFF;
-                     verify_header[7] =  ctx->zstream.total_out        & 0xFF;
+                     verify_header[0] =  ctx->crc        & 0xFF;               
        
+                     verify_header[1] = (ctx->crc >>  8) & 0xFF;
+                     verify_header[2] = (ctx->crc >> 16) & 0xFF;
+                     verify_header[3] = (ctx->crc >> 24) & 0xFF;
+
+                     verify_header[4] =  ctx->zstream.total_in & 0xFF;
+                     verify_header[5] = (ctx->zstream.total_in >>  8) & 0xFF;
+                     verify_header[6] = (ctx->zstream.total_in >> 16) & 0xFF;
+                     verify_header[7] = (ctx->zstream.total_in >> 24) & 0xFF;
 
                      serf_bucket_aggregate_append(
                               ctx->inflate_stream,
@@ -465,9 +475,10 @@ static apr_status_t serf_deflate_wait_fo
             break;
         case STATE_FINISH:
             inflateEnd(&ctx->zstream);
-            serf_bucket_aggregate_prepend(ctx->stream, ctx->inflate_stream);
-            ctx->inflate_stream = 0;
-            ctx->state++;
+            serf_bucket_aggregate_append(ctx->inflate_stream,
+                                         ctx->stream);
+            ctx->stream = NULL;
+            ctx->state = STATE_DONE;
             break;
         case STATE_INFLATE:
             return APR_SUCCESS;
@@ -506,9 +517,10 @@ static apr_status_t serf_deflate_wait_fo
             break;
         case STATE_COMPRESS_FINISH:
             deflateEnd(&ctx->zstream);
-            serf_bucket_aggregate_prepend(ctx->stream, ctx->inflate_stream);
-            ctx->inflate_stream = NULL;
-            ctx->state++;
+            serf_bucket_aggregate_append(ctx->inflate_stream,
+                                         ctx->stream);
+            ctx->stream = NULL;
+            ctx->state = STATE_DONE;
             break;
         default:
             /* Not reachable */
@@ -534,7 +546,7 @@ static apr_status_t serf_deflate_read(se
     }
 
     status = serf_bucket_read(ctx->inflate_stream, requested, data, len);
-    if (APR_STATUS_IS_EOF(status))
+    if (APR_STATUS_IS_EOF(status) && ctx->state != STATE_DONE)
         status = APR_SUCCESS;
 
     if (status || *len || ctx->state != STATE_INFLATE) {
@@ -555,7 +567,7 @@ static apr_status_t serf_deflate_read(se
     if (APR_STATUS_IS_EOF(status)) {
 
         /* If the inflation wasn't finished, return APR_SUCCESS. */
-        if (ctx->state == STATE_INFLATE)
+        if (ctx->state != STATE_DONE)
             return APR_SUCCESS; /* Not at EOF yet */
 
         /* If our stream is finished too and all data was inflated,
@@ -567,7 +579,7 @@ static apr_status_t serf_deflate_read(se
                 should have been advanced to STATE_READING_VERIFY or
                 STATE_FINISH. If not, then the data was incomplete
                 and we have an error. */
-            if (ctx->state != STATE_INFLATE)
+            if (ctx->state != STATE_DONE)
                 return APR_SUCCESS;
             else {
                 serf__log(LOGLVL_ERROR, LOGCOMP_COMPR, __FILE__,
@@ -650,7 +662,10 @@ static apr_status_t serf_deflate_set_con
 
     ctx->config = config;
 
-    return serf_bucket_set_config(ctx->stream, config);
+    if (ctx->stream)
+        return serf_bucket_set_config(ctx->stream, config);
+
+    return APR_SUCCESS;
 }
 
 const serf_bucket_type_t serf_bucket_type_deflate = {


Reply via email to