diff --git a/examples/.gitignore b/examples/.gitignore index 5c505521..8f778269 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,3 +1,4 @@ spdycat spdyd spdynative +spdycli diff --git a/examples/spdycat.cc b/examples/spdycat.cc index f8d74702..e9920990 100644 --- a/examples/spdycat.cc +++ b/examples/spdycat.cc @@ -76,56 +76,13 @@ struct Request { Request(const uri::UriStruct& us):us(us), inflater(0) {} ~Request() { - if(inflater) { - inflateEnd(inflater); - delete inflater; - } + spdylay_free_inflate_stream(inflater); } void init_inflater() { - inflater = new z_stream(); - inflater->next_in = Z_NULL; - inflater->zalloc = Z_NULL; - inflater->zfree = Z_NULL; - inflater->opaque = Z_NULL; - int rv = inflateInit2(inflater, 47); - assert(rv == Z_OK); - } - - // 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 -1. - int inflate_data(uint8_t *out, size_t *outlen_ptr, - const uint8_t *in, size_t *inlen_ptr) - { - assert(inflater); - inflater->avail_in = *inlen_ptr; - inflater->next_in = const_cast(in); - inflater->avail_out = *outlen_ptr; - inflater->next_out = out; - - int rv = inflate(inflater, Z_NO_FLUSH); - - *inlen_ptr -= inflater->avail_in; - *outlen_ptr -= inflater->avail_out; - switch(rv) { - case Z_OK: - case Z_STREAM_END: - case Z_BUF_ERROR: - return 0; - case Z_DATA_ERROR: - case Z_STREAM_ERROR: - case Z_NEED_DICT: - case Z_MEM_ERROR: - return -1; - default: - assert(0); - } + inflater = spdylay_new_inflate_stream(); + assert(inflater != NULL); } }; @@ -148,7 +105,7 @@ void on_data_chunk_recv_callback uint8_t out[MAX_OUTLEN]; size_t outlen = MAX_OUTLEN; size_t tlen = len; - int rv = req->inflate_data(out, &outlen, data, &tlen); + int rv = spdylay_inflate_data(req->inflater, out, &outlen, data, &tlen); if(rv == -1) { spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); break; diff --git a/examples/spdycli.c b/examples/spdycli.c index 7dbe7d0e..fe818d26 100644 --- a/examples/spdycli.c +++ b/examples/spdycli.c @@ -132,20 +132,6 @@ static void diec(const char *func, int error_code) exit(EXIT_FAILURE); } -static void request_inflater_init(struct Request *req) -{ - int rv; - req->inflater = malloc(sizeof(z_stream)); - req->inflater->next_in = Z_NULL; - req->inflater->zalloc = Z_NULL; - req->inflater->zfree = Z_NULL; - req->inflater->opaque = Z_NULL; - rv = inflateInit2(req->inflater, 47); - if(rv != Z_OK) { - diec("inflateInit2", rv); - } -} - /* * Check response is content-encoding: gzip. We need this because SPDY * client is required to support gzip. @@ -164,7 +150,10 @@ static void check_gzip(struct Request *req, char **nv) if(req->inflater) { return; } - request_inflater_init(req); + req->inflater = spdylay_new_inflate_stream(); + if (req->inflater == NULL) { + die("Can't allocate inflate stream."); + } } } @@ -329,36 +318,6 @@ static void on_stream_close_callback(spdylay_session *session, } } -static int request_inflate_data(struct Request *req, - uint8_t *out, size_t *outlen_ptr, - const uint8_t *in, size_t *inlen_ptr) -{ - int rv; - assert(req->inflater); - req->inflater->avail_in = *inlen_ptr; - req->inflater->next_in = (unsigned char*)in; - req->inflater->avail_out = *outlen_ptr; - req->inflater->next_out = out; - - rv = inflate(req->inflater, Z_NO_FLUSH); - - *inlen_ptr -= req->inflater->avail_in; - *outlen_ptr -= req->inflater->avail_out; - switch(rv) { - case Z_OK: - case Z_STREAM_END: - case Z_BUF_ERROR: - return 0; - case Z_DATA_ERROR: - case Z_STREAM_ERROR: - case Z_NEED_DICT: - case Z_MEM_ERROR: - return -1; - default: - assert(0); - } -} - #define MAX_OUTLEN 4096 /* @@ -381,7 +340,7 @@ static void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags, size_t outlen = MAX_OUTLEN; size_t tlen = len; int rv; - rv = request_inflate_data(req, out, &outlen, data, &tlen); + rv = spdylay_inflate_data(req->inflater, out, &outlen, data, &tlen); if(rv == -1) { spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); break; @@ -602,10 +561,7 @@ static void request_free(struct Request *req) free(req->host); free(req->path); free(req->hostport); - if(req->inflater) { - inflateEnd(req->inflater); - free(req->inflater); - } + spdylay_free_inflate_stream(req->inflater); } /* diff --git a/lib/Makefile.am b/lib/Makefile.am index 06e18455..f3fdc1c0 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -35,12 +35,12 @@ OBJECTS = spdylay_pq.c spdylay_map.c spdylay_queue.c \ spdylay_buffer.c spdylay_frame.c spdylay_zlib.c \ spdylay_session.c spdylay_helper.c spdylay_stream.c spdylay_npn.c \ spdylay_submit.c spdylay_outbound_item.c \ - spdylay_client_cert_vector.c + spdylay_client_cert_vector.c spdylay_gzip.c HFILES = spdylay_pq.h spdylay_int.h spdylay_map.h spdylay_queue.h \ spdylay_buffer.h spdylay_frame.h spdylay_zlib.h \ spdylay_session.h spdylay_helper.h spdylay_stream.h spdylay_int.h \ - spdylay_npn.h \ + spdylay_npn.h spdylay_gzip.h \ spdylay_submit.h spdylay_outbound_item.h \ spdylay_client_cert_vector.h \ spdylay_net.h diff --git a/lib/includes/spdylay/spdylay.h b/lib/includes/spdylay/spdylay.h index 76237f30..5bff9f2f 100644 --- a/lib/includes/spdylay/spdylay.h +++ b/lib/includes/spdylay/spdylay.h @@ -32,6 +32,7 @@ extern "C" { #include #include #include +#include #include @@ -1827,6 +1828,51 @@ int spdylay_select_next_protocol(unsigned char **out, unsigned char *outlen, */ uint16_t spdylay_npn_get_version(const unsigned char *proto, size_t protolen); +/** + * @function + * + * A helper function to set up a per request zlib stream to inflate data. + */ +z_stream *spdylay_new_inflate_stream(); + +/** + * @function + * Inflates data from in to out. Returns 0 on success and -1 on error. + * E.g + * void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags, + * int32_t stream_id, + * const uint8_t *data, size_t len, + * void *user_data) + * req = spdylay_session_get_stream_user_data(session, stream_id); + * z_stream *inflater = req->inflater; + * while(len > 0) { + * uint8_t out[MAX_OUTLEN]; + * size_t outlen = MAX_OUTLEN; + * size_t tlen = len; + * int rv; + * rv = spdylay_inflate_data(inflater, out, &outlen, data, &tlen); + * if(rv == -1) { + * spdylay_submit_rst_stream(session, stream_id, SPDYLAY_INTERNAL_ERROR); + * break; + * } + * ... Do stuff ... + * data += tlen; + * len -= tlen; + * } + * .... + * } + */ +int spdylay_inflate_data +(z_stream *stream, uint8_t *out, size_t *outlen_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 } #endif diff --git a/lib/spdylay_gzip.c b/lib/spdylay_gzip.c new file mode 100644 index 00000000..5304af8f --- /dev/null +++ b/lib/spdylay_gzip.c @@ -0,0 +1,87 @@ +/* + * 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 +#include +#include +#include "spdylay_gzip.h" + +z_stream *spdylay_new_inflate_stream() +{ + int rv; + z_stream *inflater = malloc(sizeof(z_stream)); + if (inflater == NULL) { + return NULL; + } + + inflater->next_in = Z_NULL; + inflater->zalloc = Z_NULL; + inflater->zfree = Z_NULL; + inflater->opaque = Z_NULL; + rv = inflateInit2(inflater, 47); + if(rv != Z_OK) { + free(inflater); + return NULL; + } + return inflater; +} + + +int spdylay_inflate_data +(z_stream *inflater, uint8_t *out, size_t *outlen_ptr, + const uint8_t *in, size_t *inlen_ptr) { + int rv; + assert(inflater); + inflater->avail_in = *inlen_ptr; + inflater->next_in = (unsigned char*)in; + inflater->avail_out = *outlen_ptr; + inflater->next_out = out; + + rv = inflate(inflater, Z_NO_FLUSH); + + *inlen_ptr -= inflater->avail_in; + *outlen_ptr -= inflater->avail_out; + switch(rv) { + case Z_OK: + case Z_STREAM_END: + case Z_BUF_ERROR: + return 0; + case Z_DATA_ERROR: + case Z_STREAM_ERROR: + case Z_NEED_DICT: + case Z_MEM_ERROR: + return -1; + default: + abort(); + } +} + +void spdylay_free_inflate_stream(z_stream* stream) +{ + if (stream != NULL) { + inflateEnd(stream); + free(stream); + } +} diff --git a/lib/spdylay_gzip.h b/lib/spdylay_gzip.h new file mode 100644 index 00000000..bc10de1d --- /dev/null +++ b/lib/spdylay_gzip.h @@ -0,0 +1,34 @@ +/* + * 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 +#include + +/* See usage comments in spdylay.h */ +z_stream *spdylay_new_inflate_stream(); +int spdylay_inflate_data +(z_stream *stream, uint8_t *out, size_t *outlen_ptr, + const uint8_t *in, size_t *inlen_ptr); +void spdylay_free_inflate_stream(z_stream* stream);