1 /* ====================================================================
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
18 * ====================================================================
21 #include <apr_strings.h>
25 /* This conditional isn't defined anywhere yet. */
31 #include "serf_bucket_util.h"
34 static char deflate_magic[2] = { '\037', '\213' };
35 #define DEFLATE_MAGIC_SIZE 10
36 #define DEFLATE_VERIFY_SIZE 8
37 #define DEFLATE_BUFFER_SIZE 8096
39 static const int DEFLATE_WINDOW_SIZE = -15;
40 static const int DEFLATE_MEMLEVEL = 9;
43 serf_bucket_t *stream;
44 serf_bucket_t *inflate_stream;
46 int format; /* Are we 'deflate' or 'gzip'? */
49 STATE_READING_HEADER, /* reading the gzip header */
50 STATE_HEADER, /* read the gzip header */
51 STATE_INIT, /* init'ing zlib functions */
52 STATE_INFLATE, /* inflating the content now */
53 STATE_READING_VERIFY, /* reading the final gzip CRC */
54 STATE_VERIFY, /* verifying the final gzip CRC */
55 STATE_FINISH, /* clean up after reading body */
56 STATE_DONE, /* body is done; we'll return EOF here */
60 char hdr_buffer[DEFLATE_MAGIC_SIZE];
61 unsigned char buffer[DEFLATE_BUFFER_SIZE];
67 /* How much of the chunk, or the terminator, do we have left to read? */
68 apr_size_t stream_left;
70 /* How much are we supposed to read? */
71 apr_size_t stream_size;
73 int stream_status; /* What was the last status we read? */
77 /* Inputs a string and returns a long. */
78 static unsigned long getLong(unsigned char *string)
80 return ((unsigned long)string[0])
81 | (((unsigned long)string[1]) << 8)
82 | (((unsigned long)string[2]) << 16)
83 | (((unsigned long)string[3]) << 24);
86 serf_bucket_t *serf_bucket_deflate_create(
87 serf_bucket_t *stream,
88 serf_bucket_alloc_t *allocator,
91 deflate_context_t *ctx;
93 ctx = serf_bucket_mem_alloc(allocator, sizeof(*ctx));
95 ctx->stream_status = APR_SUCCESS;
96 ctx->inflate_stream = serf_bucket_aggregate_create(allocator);
99 /* zstream must be NULL'd out. */
100 memset(&ctx->zstream, 0, sizeof(ctx->zstream));
102 switch (ctx->format) {
103 case SERF_DEFLATE_GZIP:
104 ctx->state = STATE_READING_HEADER;
106 case SERF_DEFLATE_DEFLATE:
107 /* deflate doesn't have a header. */
108 ctx->state = STATE_INIT;
115 /* Initial size of gzip header. */
116 ctx->stream_left = ctx->stream_size = DEFLATE_MAGIC_SIZE;
118 ctx->windowSize = DEFLATE_WINDOW_SIZE;
119 ctx->memLevel = DEFLATE_MEMLEVEL;
120 ctx->bufferSize = DEFLATE_BUFFER_SIZE;
122 return serf_bucket_create(&serf_bucket_type_deflate, allocator, ctx);
125 static void serf_deflate_destroy_and_data(serf_bucket_t *bucket)
127 deflate_context_t *ctx = bucket->data;
129 if (ctx->state > STATE_INIT &&
130 ctx->state <= STATE_FINISH)
131 inflateEnd(&ctx->zstream);
133 /* We may have appended inflate_stream into the stream bucket.
134 * If so, avoid free'ing it twice.
136 if (ctx->inflate_stream) {
137 serf_bucket_destroy(ctx->inflate_stream);
139 serf_bucket_destroy(ctx->stream);
141 serf_default_destroy_and_data(bucket);
144 static apr_status_t serf_deflate_read(serf_bucket_t *bucket,
145 apr_size_t requested,
146 const char **data, apr_size_t *len)
148 deflate_context_t *ctx = bucket->data;
150 const char *private_data;
151 apr_size_t private_len;
155 switch (ctx->state) {
156 case STATE_READING_HEADER:
157 case STATE_READING_VERIFY:
158 status = serf_bucket_read(ctx->stream, ctx->stream_left,
159 &private_data, &private_len);
161 if (SERF_BUCKET_READ_ERROR(status)) {
165 memcpy(ctx->hdr_buffer + (ctx->stream_size - ctx->stream_left),
166 private_data, private_len);
168 ctx->stream_left -= private_len;
170 if (ctx->stream_left == 0) {
172 if (APR_STATUS_IS_EAGAIN(status)) {
183 if (ctx->hdr_buffer[0] != deflate_magic[0] ||
184 ctx->hdr_buffer[1] != deflate_magic[1]) {
185 return SERF_ERROR_DECOMPRESSION_FAILED;
187 if (ctx->hdr_buffer[3] != 0) {
188 return SERF_ERROR_DECOMPRESSION_FAILED;
194 unsigned long compCRC, compLen, actualLen;
196 /* Do the checksum computation. */
197 compCRC = getLong((unsigned char*)ctx->hdr_buffer);
198 if (ctx->crc != compCRC) {
199 return SERF_ERROR_DECOMPRESSION_FAILED;
201 compLen = getLong((unsigned char*)ctx->hdr_buffer + 4);
202 /* The length in the trailer is module 2^32, so do the same for
203 the actual length. */
204 actualLen = ctx->zstream.total_out;
205 actualLen &= 0xFFFFFFFF;
206 if (actualLen != compLen) {
207 return SERF_ERROR_DECOMPRESSION_FAILED;
213 zRC = inflateInit2(&ctx->zstream, ctx->windowSize);
215 return SERF_ERROR_DECOMPRESSION_FAILED;
217 ctx->zstream.next_out = ctx->buffer;
218 ctx->zstream.avail_out = ctx->bufferSize;
222 inflateEnd(&ctx->zstream);
223 serf_bucket_aggregate_prepend(ctx->stream, ctx->inflate_stream);
224 ctx->inflate_stream = 0;
228 /* Do we have anything already uncompressed to read? */
229 status = serf_bucket_read(ctx->inflate_stream, requested, data,
231 if (SERF_BUCKET_READ_ERROR(status)) {
235 if (APR_STATUS_IS_EOF(status)) {
236 status = ctx->stream_status;
237 if (APR_STATUS_IS_EOF(status)) {
238 /* We've read all of the data from our stream, but we
239 * need to continue to iterate until we flush
240 * out the zlib buffer.
242 status = APR_SUCCESS;
249 /* We tried; but we have nothing buffered. Fetch more. */
251 /* It is possible that we maxed out avail_out before
252 * exhausting avail_in; therefore, continue using the
253 * previous buffer. Otherwise, fetch more data from
256 if (ctx->zstream.avail_in == 0) {
257 /* When we empty our inflated stream, we'll return this
258 * status - this allow us to eventually pass up EAGAINs.
260 ctx->stream_status = serf_bucket_read(ctx->stream,
265 if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) {
266 return ctx->stream_status;
269 if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) {
271 status = ctx->stream_status;
272 ctx->stream_status = APR_SUCCESS;
276 ctx->zstream.next_in = (unsigned char*)private_data;
277 ctx->zstream.avail_in = private_len;
282 zRC = inflate(&ctx->zstream, Z_NO_FLUSH);
284 /* We're full or zlib requires more space. Either case, clear
285 out our buffer, reset, and return. */
286 if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) {
288 ctx->zstream.next_out = ctx->buffer;
289 private_len = ctx->bufferSize - ctx->zstream.avail_out;
291 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
294 /* FIXME: There probably needs to be a free func. */
295 tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
298 serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
299 ctx->zstream.avail_out = ctx->bufferSize;
303 if (zRC == Z_STREAM_END) {
306 private_len = ctx->bufferSize - ctx->zstream.avail_out;
307 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
309 /* FIXME: There probably needs to be a free func. */
310 tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
313 serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
315 ctx->zstream.avail_out = ctx->bufferSize;
317 /* Push back the remaining data to be read. */
318 tmp = serf_bucket_aggregate_create(bucket->allocator);
319 serf_bucket_aggregate_prepend(tmp, ctx->stream);
322 /* We now need to take the remaining avail_in and
323 * throw it in ctx->stream so our next read picks it up.
325 tmp = SERF_BUCKET_SIMPLE_STRING_LEN(
326 (const char*)ctx->zstream.next_in,
327 ctx->zstream.avail_in,
329 serf_bucket_aggregate_prepend(ctx->stream, tmp);
331 switch (ctx->format) {
332 case SERF_DEFLATE_GZIP:
333 ctx->stream_left = ctx->stream_size =
337 case SERF_DEFLATE_DEFLATE:
338 /* Deflate does not have a verify footer. */
339 ctx->state = STATE_FINISH;
349 /* Any other error? */
351 return SERF_ERROR_DECOMPRESSION_FAILED;
354 /* As long as zRC == Z_OK, just keep looping. */
356 /* Okay, we've inflated. Try to read. */
357 status = serf_bucket_read(ctx->inflate_stream, requested, data,
360 if (APR_STATUS_IS_EOF(status)) {
361 status = ctx->stream_status;
363 /* If the inflation wasn't finished, return APR_SUCCESS. */
364 if (zRC != Z_STREAM_END)
367 /* If our stream is finished too and all data was inflated,
368 * return SUCCESS so we'll iterate one more time.
370 if (APR_STATUS_IS_EOF(status)) {
371 /* No more data to read from the stream, and everything
372 inflated. If all data was received correctly, state
373 should have been advanced to STATE_READING_VERIFY or
374 STATE_FINISH. If not, then the data was incomplete
375 and we have an error. */
376 if (ctx->state != STATE_INFLATE)
379 return SERF_ERROR_DECOMPRESSION_FAILED;
384 /* We're done inflating. Use our finished buffer. */
385 return serf_bucket_read(ctx->stream, requested, data, len);
395 /* ### need to implement */
396 #define serf_deflate_readline NULL
397 #define serf_deflate_peek NULL
399 const serf_bucket_type_t serf_bucket_type_deflate = {
402 serf_deflate_readline,
403 serf_default_read_iovec,
404 serf_default_read_for_sendfile,
405 serf_default_read_bucket,
407 serf_deflate_destroy_and_data,