Renamed spdylay_gzip API. Added test for them.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-05-07 22:56:28 +09:00
parent 1a384a6000
commit 5412ccf129
9 changed files with 283 additions and 94 deletions

View File

@ -51,7 +51,6 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <spdylay/spdylay.h> #include <spdylay/spdylay.h>
#include <zlib.h>
#include "spdylay_ssl.h" #include "spdylay_ssl.h"
#include "uri.h" #include "uri.h"
@ -72,17 +71,18 @@ struct Config {
struct Request { struct Request {
uri::UriStruct us; uri::UriStruct us;
z_stream *inflater; spdylay_gzip *inflater;
Request(const uri::UriStruct& us):us(us), inflater(0) {} Request(const uri::UriStruct& us):us(us), inflater(0) {}
~Request() ~Request()
{ {
spdylay_free_inflate_stream(inflater); spdylay_gzip_inflate_del(inflater);
} }
void init_inflater() void init_inflater()
{ {
inflater = spdylay_new_inflate_stream(); int rv;
assert(inflater != NULL); rv = spdylay_gzip_inflate_new(&inflater);
assert(rv == 0);
} }
}; };
@ -105,7 +105,7 @@ void on_data_chunk_recv_callback
uint8_t out[MAX_OUTLEN]; uint8_t out[MAX_OUTLEN];
size_t outlen = MAX_OUTLEN; size_t outlen = MAX_OUTLEN;
size_t tlen = len; size_t tlen = len;
int rv = spdylay_inflate_data(req->inflater, out, &outlen, data, &tlen); int rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
if(rv == -1) { if(rv == -1) {
spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
break; break;

View File

@ -45,8 +45,6 @@
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <zlib.h>
enum { enum {
IO_NONE, IO_NONE,
WANT_READ, WANT_READ,
@ -75,8 +73,8 @@ struct Request {
char *hostport; char *hostport;
/* Stream ID for this request. */ /* Stream ID for this request. */
int32_t stream_id; int32_t stream_id;
/* zlib context for gzip response */ /* The gzip stream inflater for the compressed response. */
z_stream *inflater; spdylay_gzip *inflater;
}; };
struct URI { struct URI {
@ -147,11 +145,12 @@ static void check_gzip(struct Request *req, char **nv)
} }
} }
if(gzip) { if(gzip) {
int rv;
if(req->inflater) { if(req->inflater) {
return; return;
} }
req->inflater = spdylay_new_inflate_stream(); rv = spdylay_gzip_inflate_new(&req->inflater);
if (req->inflater == NULL) { if(rv != 0) {
die("Can't allocate inflate stream."); die("Can't allocate inflate stream.");
} }
} }
@ -340,7 +339,7 @@ static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
size_t outlen = MAX_OUTLEN; size_t outlen = MAX_OUTLEN;
size_t tlen = len; size_t tlen = len;
int rv; int rv;
rv = spdylay_inflate_data(req->inflater, out, &outlen, data, &tlen); rv = spdylay_gzip_inflate(req->inflater, out, &outlen, data, &tlen);
if(rv == -1) { if(rv == -1) {
spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR);
break; break;
@ -561,7 +560,7 @@ static void request_free(struct Request *req)
free(req->host); free(req->host);
free(req->path); free(req->path);
free(req->hostport); free(req->hostport);
spdylay_free_inflate_stream(req->inflater); spdylay_gzip_inflate_del(req->inflater);
} }
/* /*

View File

@ -160,6 +160,10 @@ typedef enum {
* requested operation. * requested operation.
*/ */
SPDYLAY_ERR_INVALID_STATE = -519, SPDYLAY_ERR_INVALID_STATE = -519,
/**
* The gzip error.
*/
SPDYLAY_ERR_GZIP = -520,
/** /**
* The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is * The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is
* under unexpected condition and cannot process any further data * under unexpected condition and cannot process any further data
@ -1828,31 +1832,73 @@ int spdylay_select_next_protocol(unsigned char **out, unsigned char *outlen,
*/ */
uint16_t spdylay_npn_get_version(const unsigned char *proto, size_t protolen); uint16_t spdylay_npn_get_version(const unsigned char *proto, size_t protolen);
struct spdylay_gzip;
/** /**
* @function * @struct
* *
* A helper function to set up a per request zlib stream to inflate data. * The gzip stream to inflate data. The details of this structure are
* intentionally hidden from the public API.
*/ */
z_stream *spdylay_new_inflate_stream(); typedef struct spdylay_gzip spdylay_gzip;
/** /**
* @function * @function
* Inflates data from in to out. Returns 0 on success and -1 on error. *
* E.g * A helper function to set up a per request gzip stream to inflate data.
* void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags, *
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`SPDYLAY_ERR_GZIP`
* The initialization of gzip stream failed.
* :enum:`SPDYLAY_ERR_NOMEM`
* Out of memory.
*/
int spdylay_gzip_inflate_new(spdylay_gzip **inflater_ptr);
/**
* @function
*
* Frees the inflate stream. The |inflater| may be ``NULL``.
*/
void spdylay_gzip_inflate_del(spdylay_gzip *inflater);
/**
* @function
*
* Inflates data in |in| with the length |*inlen_ptr| and stores the
* inflated data to |out| which has allocated size at least
* |*outlen_ptr|. On return, |*outlen_ptr| is updated to represent
* the number of data written in |out|. Similarly, |*inlen_ptr| is
* updated to represent the number of input bytes processed.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :enum:`SPDYLAY_ERR_GZIP`
* The inflation of gzip stream failed.
*
* The example follows::
*
* void on_data_chunk_recv_callback(spdylay_session *session,
* uint8_t flags,
* int32_t stream_id, * int32_t stream_id,
* const uint8_t *data, size_t len, * const uint8_t *data, size_t len,
* void *user_data) * void *user_data)
* {
* ...
* req = spdylay_session_get_stream_user_data(session, stream_id); * req = spdylay_session_get_stream_user_data(session, stream_id);
* z_stream *inflater = req->inflater; * spdylay_gzip *inflater = req->inflater;
* while(len > 0) { * while(len > 0) {
* uint8_t out[MAX_OUTLEN]; * uint8_t out[MAX_OUTLEN];
* size_t outlen = MAX_OUTLEN; * size_t outlen = MAX_OUTLEN;
* size_t tlen = len; * size_t tlen = len;
* int rv; * int rv;
* rv = spdylay_inflate_data(inflater, out, &outlen, data, &tlen); * rv = spdylay_gzip_inflate(inflater, out, &outlen, data, &tlen);
* if(rv == -1) { * if(rv != 0) {
* spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); * spdylay_submit_rst_stream(session, stream_id,
* SPDYLAY_INTERNAL_ERROR);
* break; * break;
* } * }
* ... Do stuff ... * ... Do stuff ...
@ -1862,17 +1908,10 @@ z_stream *spdylay_new_inflate_stream();
* .... * ....
* } * }
*/ */
int spdylay_inflate_data int spdylay_gzip_inflate(spdylay_gzip *inflater,
(z_stream *stream, uint8_t *out, size_t *outlen_ptr, uint8_t *out, size_t *outlen_ptr,
const uint8_t *in, size_t *inlen_ptr); const uint8_t *in, size_t *inlen_ptr);
/**
* @function
* Frees the inflate stream. inflater may be null.
*/
void spdylay_free_inflate_stream(z_stream* inflater);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -22,47 +22,52 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <assert.h>
#include <stdlib.h>
#include <zlib.h>
#include "spdylay_gzip.h" #include "spdylay_gzip.h"
z_stream *spdylay_new_inflate_stream() #include <assert.h>
int spdylay_gzip_inflate_new(spdylay_gzip **inflater_ptr)
{ {
int rv; int rv;
z_stream *inflater = malloc(sizeof(z_stream)); *inflater_ptr = malloc(sizeof(spdylay_gzip));
if (inflater == NULL) { if(*inflater_ptr == NULL) {
return NULL; return SPDYLAY_ERR_NOMEM;
} }
(*inflater_ptr)->zst.next_in = Z_NULL;
inflater->next_in = Z_NULL; (*inflater_ptr)->zst.avail_in = 0;
inflater->zalloc = Z_NULL; (*inflater_ptr)->zst.zalloc = Z_NULL;
inflater->zfree = Z_NULL; (*inflater_ptr)->zst.zfree = Z_NULL;
inflater->opaque = Z_NULL; (*inflater_ptr)->zst.opaque = Z_NULL;
rv = inflateInit2(inflater, 47); rv = inflateInit2(&(*inflater_ptr)->zst, 47);
if(rv != Z_OK) { if(rv != Z_OK) {
free(*inflater_ptr);
return SPDYLAY_ERR_GZIP;
}
return 0;
}
void spdylay_gzip_inflate_del(spdylay_gzip *inflater)
{
if(inflater != NULL) {
inflateEnd(&inflater->zst);
free(inflater); free(inflater);
return NULL;
} }
return inflater;
} }
int spdylay_gzip_inflate(spdylay_gzip *inflater,
int spdylay_inflate_data uint8_t *out, size_t *outlen_ptr,
(z_stream *inflater, uint8_t *out, size_t *outlen_ptr, const uint8_t *in, size_t *inlen_ptr)
const uint8_t *in, size_t *inlen_ptr) { {
int rv; int rv;
assert(inflater); inflater->zst.avail_in = *inlen_ptr;
inflater->avail_in = *inlen_ptr; inflater->zst.next_in = (unsigned char*)in;
inflater->next_in = (unsigned char*)in; inflater->zst.avail_out = *outlen_ptr;
inflater->avail_out = *outlen_ptr; inflater->zst.next_out = out;
inflater->next_out = out;
rv = inflate(inflater, Z_NO_FLUSH); rv = inflate(&inflater->zst, Z_NO_FLUSH);
*inlen_ptr -= inflater->avail_in; *inlen_ptr -= inflater->zst.avail_in;
*outlen_ptr -= inflater->avail_out; *outlen_ptr -= inflater->zst.avail_out;
switch(rv) { switch(rv) {
case Z_OK: case Z_OK:
case Z_STREAM_END: case Z_STREAM_END:
@ -72,16 +77,8 @@ int spdylay_inflate_data
case Z_STREAM_ERROR: case Z_STREAM_ERROR:
case Z_NEED_DICT: case Z_NEED_DICT:
case Z_MEM_ERROR: case Z_MEM_ERROR:
return -1; return SPDYLAY_ERR_GZIP;
default: default:
abort(); assert(0);
}
}
void spdylay_free_inflate_stream(z_stream* stream)
{
if (stream != NULL) {
inflateEnd(stream);
free(stream);
} }
} }

View File

@ -22,13 +22,17 @@
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifndef SPDYLAY_GZIP_H
#include <stdint.h> #ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <zlib.h> #include <zlib.h>
/* See usage comments in spdylay.h */ #include <spdylay/spdylay.h>
z_stream *spdylay_new_inflate_stream();
int spdylay_inflate_data struct spdylay_gzip {
(z_stream *stream, uint8_t *out, size_t *outlen_ptr, z_stream zst;
const uint8_t *in, size_t *inlen_ptr); };
void spdylay_free_inflate_stream(z_stream* stream);
#endif /* SPDYLAY_GZIP_H */

View File

@ -29,12 +29,12 @@ check_PROGRAMS = main failmalloc
OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \ OBJECTS = main.c spdylay_pq_test.c spdylay_map_test.c spdylay_queue_test.c \
spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \ spdylay_buffer_test.c spdylay_zlib_test.c spdylay_session_test.c \
spdylay_frame_test.c spdylay_stream_test.c spdylay_npn_test.c \ spdylay_frame_test.c spdylay_stream_test.c spdylay_npn_test.c \
spdylay_client_cert_vector_test.c spdylay_client_cert_vector_test.c spdylay_gzip_test.c
HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \ HFILES = spdylay_pq_test.h spdylay_map_test.h spdylay_queue_test.h \
spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \ spdylay_buffer_test.h spdylay_zlib_test.h spdylay_session_test.h \
spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h \ spdylay_frame_test.h spdylay_stream_test.h spdylay_npn_test.h \
spdylay_client_cert_vector_test.h spdylay_client_cert_vector_test.h spdylay_gzip_test.h
main_SOURCES = $(HFILES) $(OBJECTS) main_SOURCES = $(HFILES) $(OBJECTS)

View File

@ -36,6 +36,7 @@
#include "spdylay_stream_test.h" #include "spdylay_stream_test.h"
#include "spdylay_npn_test.h" #include "spdylay_npn_test.h"
#include "spdylay_client_cert_vector_test.h" #include "spdylay_client_cert_vector_test.h"
#include "spdylay_gzip_test.h"
static int init_suite1(void) static int init_suite1(void)
{ {
@ -204,7 +205,8 @@ int main(int argc, char* argv[])
!CU_add_test(pSuite, "client_cert_vector_resize", !CU_add_test(pSuite, "client_cert_vector_resize",
test_spdylay_client_cert_vector_resize) || test_spdylay_client_cert_vector_resize) ||
!CU_add_test(pSuite, "client_cert_vector_get_origin", !CU_add_test(pSuite, "client_cert_vector_get_origin",
test_spdylay_client_cert_vector_get_origin)) { test_spdylay_client_cert_vector_get_origin) ||
!CU_add_test(pSuite, "gzip_inflate", test_spdylay_gzip_inflate)) {
CU_cleanup_registry(); CU_cleanup_registry();
return CU_get_error(); return CU_get_error();
} }

118
tests/spdylay_gzip_test.c Normal file
View File

@ -0,0 +1,118 @@
/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "spdylay_gzip_test.h"
#include <stdio.h>
#include <assert.h>
#include <CUnit/CUnit.h>
#include <zlib.h>
#include "spdylay_gzip.h"
static ssize_t deflate_data(uint8_t *out, size_t outlen,
const
uint8_t *in, size_t inlen)
{
int rv;
z_stream zst;
zst.next_in = Z_NULL;
zst.zalloc = Z_NULL;
zst.zfree = Z_NULL;
zst.opaque = Z_NULL;
rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION);
assert(rv == Z_OK);
zst.avail_in = inlen;
zst.next_in = (uint8_t*)in;
zst.avail_out = outlen;
zst.next_out = out;
rv = deflate(&zst, Z_SYNC_FLUSH);
assert(rv == Z_OK);
deflateEnd(&zst);
return outlen-zst.avail_out;
}
static const char input[] =
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND "
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND "
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE "
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION "
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION "
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.";
void test_spdylay_gzip_inflate(void)
{
spdylay_gzip *inflater;
uint8_t in[4096], out[4096], *inptr;
size_t inlen = sizeof(in);
size_t inproclen, outproclen;
const char *inputptr = input;
inlen = deflate_data(in, inlen, (const uint8_t*)input, sizeof(input)-1);
CU_ASSERT(0 == spdylay_gzip_inflate_new(&inflater));
/* First 16 bytes */
inptr = in;
inproclen = inlen;
outproclen = 16;
CU_ASSERT(0 == spdylay_gzip_inflate(inflater, out, &outproclen,
inptr, &inproclen));
CU_ASSERT(16 == outproclen);
CU_ASSERT(inproclen > 0);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
/* Next 32 bytes */
inptr += inproclen;
inlen -= inproclen;
inproclen = inlen;
inputptr += outproclen;
outproclen = 32;
CU_ASSERT(0 == spdylay_gzip_inflate(inflater, out, &outproclen,
inptr, &inproclen));
CU_ASSERT(32 == outproclen);
CU_ASSERT(inproclen > 0);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
/* Rest */
inptr += inproclen;
inlen -= inproclen;
inproclen = inlen;
inputptr += outproclen;
outproclen = sizeof(out);
CU_ASSERT(0 == spdylay_gzip_inflate(inflater, out, &outproclen,
inptr, &inproclen));
CU_ASSERT(sizeof(input)-49 == outproclen);
CU_ASSERT(inproclen > 0);
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
inlen -= inproclen;
CU_ASSERT(0 == inlen);
spdylay_gzip_inflate_del(inflater);
}

30
tests/spdylay_gzip_test.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SPDYLAY_GZIP_TEST_H
#define SPDYLAY_GZIP_TEST_H
void test_spdylay_gzip_inflate(void);
#endif /* SPDYLAY_GZIP_TEST_H */