diff --git a/configure.ac b/configure.ac index 65a4930f..17eda546 100644 --- a/configure.ac +++ b/configure.ac @@ -193,11 +193,13 @@ esac # zlib if test "x$android_build" = "xyes"; then # Use zlib provided by NDK - LIBS="-lz $LIBS" + SRC_LIBS="-lz $SRC_LIBS" else - PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3]) - LIBS="$ZLIB_LIBS $LIBS" - CFLAGS="$CFLAGS $ZLIB_CFLAGS" + PKG_CHECK_MODULES([ZLIB], [zlib >= 1.2.3], [have_zlib=yes], [have_zlib=no]) + + if test "x${have_zlib}" = "xno"; then + AC_MSG_NOTICE($ZLIB_PKG_ERRORS) + fi fi # cunit @@ -304,10 +306,11 @@ fi AM_CONDITIONAL([HAVE_SPDYLAY], [ test "x${have_spdylay}" = "xyes" ]) -# The nghttp, nghttpd and nghttpx under src depend on OpenSSL and -# libevent_openssl +# The nghttp, nghttpd and nghttpx under src depend on zlib, OpenSSL +# and libevent_openssl enable_app=no if test "x${request_app}" != "xno" && + test "x${have_zlib}" = "xyes" && test "x${have_openssl}" = "xyes" && test "x${have_libevent_openssl}" = "xyes"; then enable_app=yes diff --git a/examples/client.c b/examples/client.c index c58e6ade..959bea39 100644 --- a/examples/client.c +++ b/examples/client.c @@ -72,8 +72,6 @@ struct Connection { }; struct Request { - /* The gzip stream inflater for the compressed response. */ - nghttp2_gzip *inflater; char *host; /* In this program, path contains query component as well. */ char *path; @@ -139,36 +137,6 @@ static void diec(const char *func, int error_code) exit(EXIT_FAILURE); } -static char CONTENT_LENGTH[] = "content-encoding"; -static size_t CONTENT_LENGTH_LEN = sizeof(CONTENT_LENGTH) - 1; -static char GZIP[] = "gzip"; -static size_t GZIP_LEN = sizeof(GZIP) - 1; - -/* - * Check response is content-encoding: gzip. We need this because - * HTTP/2 client is required to support gzip. - */ -static void check_gzip(struct Request *req, nghttp2_nv *nva, size_t nvlen) -{ - size_t i; - if(req->inflater) { - return; - } - for(i = 0; i < nvlen; ++i) { - if(CONTENT_LENGTH_LEN == nva[i].namelen && - memcmp(CONTENT_LENGTH, nva[i].name, nva[i].namelen) == 0 && - GZIP_LEN == nva[i].valuelen && - memcmp(GZIP, nva[i].value, nva[i].valuelen) == 0) { - int rv; - rv = nghttp2_gzip_inflate_new(&req->inflater); - if(rv != 0) { - die("Can't allocate inflate stream."); - } - break; - } - } -} - /* * The implementation of nghttp2_send_callback type. Here we write * |data| with size |length| to the network and return the number of @@ -290,7 +258,6 @@ static int on_frame_recv_callback(nghttp2_session *session, struct Request *req; req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); if(req) { - check_gzip(req, frame->headers.nva, frame->headers.nvlen); printf("[INFO] C <---------------------------- S (HEADERS)\n"); for(i = 0; i < frame->headers.nvlen; ++i) { fwrite(nva[i].name, nva[i].namelen, 1, stdout); @@ -351,25 +318,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags, if(req) { printf("[INFO] C <---------------------------- S (DATA chunk)\n" "%lu bytes\n", (unsigned long int)len); - if(req->inflater) { - while(len > 0) { - uint8_t out[MAX_OUTLEN]; - size_t outlen = MAX_OUTLEN; - size_t tlen = len; - int rv; - rv = nghttp2_gzip_inflate(req->inflater, out, &outlen, data, &tlen); - if(rv == -1) { - nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id, - NGHTTP2_INTERNAL_ERROR); - break; - } - fwrite(out, 1, outlen, stdout); - data += tlen; - len -= tlen; - } - } else { - fwrite(data, 1, len, stdout); - } + fwrite(data, 1, len, stdout); printf("\n"); } return 0; @@ -561,7 +510,6 @@ static void request_init(struct Request *req, const struct URI *uri) req->path = strcopy(uri->path, uri->pathlen); req->hostport = strcopy(uri->hostport, uri->hostportlen); req->stream_id = -1; - req->inflater = NULL; } static void request_free(struct Request *req) @@ -569,7 +517,6 @@ static void request_free(struct Request *req) free(req->host); free(req->path); free(req->hostport); - nghttp2_gzip_inflate_del(req->inflater); } /* diff --git a/lib/Makefile.am b/lib/Makefile.am index c4d75629..74182585 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -37,7 +37,7 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ nghttp2_stream.c nghttp2_outbound_item.c \ nghttp2_session.c nghttp2_submit.c \ nghttp2_helper.c \ - nghttp2_npn.c nghttp2_gzip.c \ + nghttp2_npn.c \ nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \ nghttp2_version.c \ nghttp2_priority_spec.c \ @@ -47,7 +47,7 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_frame.h \ nghttp2_buf.h \ nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \ - nghttp2_npn.h nghttp2_gzip.h \ + nghttp2_npn.h \ nghttp2_submit.h nghttp2_outbound_item.h \ nghttp2_net.h \ nghttp2_hd.h nghttp2_hd_huffman.h \ diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index d1bf4634..79801520 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -2726,96 +2726,6 @@ int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs); int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen); -struct nghttp2_gzip; - -/** - * @struct - * - * The gzip stream to inflate data. The details of this structure are - * intentionally hidden from the public API. - */ -typedef struct nghttp2_gzip nghttp2_gzip; - -/** - * @function - * - * A helper function to set up a per request gzip stream to inflate - * data. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :enum:`NGHTTP2_ERR_GZIP` - * The initialization of gzip stream failed. - * :enum:`NGHTTP2_ERR_NOMEM` - * Out of memory. - */ -int nghttp2_gzip_inflate_new(nghttp2_gzip **inflater_ptr); - -/** - * @function - * - * Frees the inflate stream. The |inflater| may be ``NULL``. - */ -void nghttp2_gzip_inflate_del(nghttp2_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:`NGHTTP2_ERR_GZIP` - * The inflation of gzip stream failed. - * - * The example follows:: - * - * void on_data_chunk_recv_callback(nghttp2_session *session, - * uint8_t flags, - * int32_t stream_id, - * const uint8_t *data, size_t len, - * void *user_data) - * { - * ... - * req = nghttp2_session_get_stream_user_data(session, stream_id); - * nghttp2_gzip *inflater = req->inflater; - * while(len > 0) { - * uint8_t out[MAX_OUTLEN]; - * size_t outlen = MAX_OUTLEN; - * size_t tlen = len; - * int rv; - * rv = nghttp2_gzip_inflate(inflater, out, &outlen, data, &tlen); - * if(rv != 0) { - * nghttp2_submit_rst_stream(session, stream_id, - * NGHTTP2_INTERNAL_ERROR); - * break; - * } - * ... Do stuff ... - * data += tlen; - * len -= tlen; - * } - * .... - * } - */ -int nghttp2_gzip_inflate(nghttp2_gzip *inflater, - uint8_t *out, size_t *outlen_ptr, - const uint8_t *in, size_t *inlen_ptr); - -/** - * @function - * - * Returns nonzero if |inflater| sees the end of deflate stream. - * After this function returns nonzero, `nghttp2_gzip_inflate()` with - * |inflater| gets to return error. - */ -int nghttp2_gzip_inflate_finished(nghttp2_gzip *inflater); - /** * @function * diff --git a/lib/libnghttp2.pc.in b/lib/libnghttp2.pc.in index e41f4f47..da6938f2 100644 --- a/lib/libnghttp2.pc.in +++ b/lib/libnghttp2.pc.in @@ -30,5 +30,4 @@ Description: HTTP/2 C library URL: https://github.com/tatsuhiro-t/nghttp2 Version: @VERSION@ Libs: -L${libdir} -lnghttp2 -Libs.private: -lz Cflags: -I${includedir} diff --git a/lib/nghttp2_gzip.h b/lib/nghttp2_gzip.h deleted file mode 100644 index f0fe48b9..00000000 --- a/lib/nghttp2_gzip.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * nghttp2 - HTTP/2 C 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 NGHTTP2_GZIP_H - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ -#include - -#include - -struct nghttp2_gzip { - z_stream zst; - int8_t finished; -}; - -#endif /* NGHTTP2_GZIP_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 1cc9ae2a..759a5721 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,6 +36,7 @@ AM_CPPFLAGS = \ @LIBEVENT_OPENSSL_CFLAGS@ \ @OPENSSL_CFLAGS@ \ @JANSSON_CFLAGS@ \ + @ZLIB_CFLAGS@ \ @DEFS@ AM_LDFLAGS = \ @LIBSPDYLAY_LIBS@ \ @@ -43,6 +44,7 @@ AM_LDFLAGS = \ @LIBEVENT_OPENSSL_LIBS@ \ @OPENSSL_LIBS@ \ @JANSSON_LIBS@ \ + @ZLIB_LIBS@ \ @JEMALLOC_LIBS@ \ @SRC_LIBS@ @@ -54,8 +56,9 @@ if ENABLE_APP bin_PROGRAMS += nghttp nghttpd nghttpx h2load -HELPER_OBJECTS = util.cc http2.cc timegm.c app_helper.cc -HELPER_HFILES = util.h http2.h timegm.h app_helper.h nghttp2_config.h +HELPER_OBJECTS = util.cc http2.cc timegm.c app_helper.cc nghttp2_gzip.c +HELPER_HFILES = util.h http2.h timegm.h app_helper.h nghttp2_config.h \ + nghttp2_gzip.h HTML_PARSER_OBJECTS = HTML_PARSER_HFILES = HtmlParser.h @@ -124,7 +127,8 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \ shrpx_downstream_test.cc shrpx_downstream_test.h \ shrpx_config_test.cc shrpx_config_test.h \ http2_test.cc http2_test.h \ - util_test.cc util_test.h + util_test.cc util_test.h \ + nghttp2_gzip_test.c nghttp2_gzip_test.h nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS}\ -DNGHTTP2_TESTS_DIR=\"$(top_srcdir)/tests\" nghttpx_unittest_LDFLAGS = -static diff --git a/src/nghttp.cc b/src/nghttp.cc index 1f634f41..96ca2522 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -68,6 +68,7 @@ #include "util.h" #include "base64.h" #include "http2.h" +#include "nghttp2_gzip.h" #ifndef O_BINARY # define O_BINARY (0) diff --git a/lib/nghttp2_gzip.c b/src/nghttp2_gzip.c similarity index 100% rename from lib/nghttp2_gzip.c rename to src/nghttp2_gzip.c diff --git a/src/nghttp2_gzip.h b/src/nghttp2_gzip.h new file mode 100644 index 00000000..26b92d94 --- /dev/null +++ b/src/nghttp2_gzip.h @@ -0,0 +1,132 @@ +/* + * nghttp2 - HTTP/2 C 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 NGHTTP2_GZIP_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct + * + * The gzip stream to inflate data. + */ +typedef struct { + z_stream zst; + int8_t finished; +} nghttp2_gzip; + +/** + * @function + * + * A helper function to set up a per request gzip stream to inflate + * data. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_GZIP` + * The initialization of gzip stream failed. + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory. + */ +int nghttp2_gzip_inflate_new(nghttp2_gzip **inflater_ptr); + +/** + * @function + * + * Frees the inflate stream. The |inflater| may be ``NULL``. + */ +void nghttp2_gzip_inflate_del(nghttp2_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:`NGHTTP2_ERR_GZIP` + * The inflation of gzip stream failed. + * + * The example follows:: + * + * void on_data_chunk_recv_callback(nghttp2_session *session, + * uint8_t flags, + * int32_t stream_id, + * const uint8_t *data, size_t len, + * void *user_data) + * { + * ... + * req = nghttp2_session_get_stream_user_data(session, stream_id); + * nghttp2_gzip *inflater = req->inflater; + * while(len > 0) { + * uint8_t out[MAX_OUTLEN]; + * size_t outlen = MAX_OUTLEN; + * size_t tlen = len; + * int rv; + * rv = nghttp2_gzip_inflate(inflater, out, &outlen, data, &tlen); + * if(rv != 0) { + * nghttp2_submit_rst_stream(session, stream_id, + * NGHTTP2_INTERNAL_ERROR); + * break; + * } + * ... Do stuff ... + * data += tlen; + * len -= tlen; + * } + * .... + * } + */ +int nghttp2_gzip_inflate(nghttp2_gzip *inflater, + uint8_t *out, size_t *outlen_ptr, + const uint8_t *in, size_t *inlen_ptr); + +/** + * @function + * + * Returns nonzero if |inflater| sees the end of deflate stream. + * After this function returns nonzero, `nghttp2_gzip_inflate()` with + * |inflater| gets to return error. + */ +int nghttp2_gzip_inflate_finished(nghttp2_gzip *inflater); + +#ifdef __cplusplus +} +#endif + +#endif /* NGHTTP2_GZIP_H */ diff --git a/tests/nghttp2_gzip_test.c b/src/nghttp2_gzip_test.c similarity index 100% rename from tests/nghttp2_gzip_test.c rename to src/nghttp2_gzip_test.c diff --git a/tests/nghttp2_gzip_test.h b/src/nghttp2_gzip_test.h similarity index 100% rename from tests/nghttp2_gzip_test.h rename to src/nghttp2_gzip_test.h diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index 1ecff329..fc9eb50e 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -116,7 +116,8 @@ int main(int argc, char* argv[]) !CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) || !CU_add_test(pSuite, "util_percent_encode_token", - shrpx::test_util_percent_encode_token)) { + shrpx::test_util_percent_encode_token) || + !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate)) { CU_cleanup_registry(); return CU_get_error(); } diff --git a/tests/main.c b/tests/main.c index 8dea5a8d..b4afb9cc 100644 --- a/tests/main.c +++ b/tests/main.c @@ -34,7 +34,6 @@ #include "nghttp2_stream_test.h" #include "nghttp2_hd_test.h" #include "nghttp2_npn_test.h" -#include "nghttp2_gzip_test.h" #include "nghttp2_helper_test.h" #include "nghttp2_buf_test.h" @@ -279,7 +278,6 @@ int main(int argc, char* argv[]) !CU_add_test(pSuite, "hd_deflate_inflate", test_nghttp2_hd_deflate_inflate) || !CU_add_test(pSuite, "hd_no_index", test_nghttp2_hd_no_index) || - !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || !CU_add_test(pSuite, "adjust_local_window_size", test_nghttp2_adjust_local_window_size) || !CU_add_test(pSuite, "check_header_name",