From 4f027c156283232b0227cdd5f6aae09f67399b3b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 6 May 2014 23:10:50 +0900 Subject: [PATCH] libnghttp2: Remove dependency to zlib We inherited gzip compression API from spdylay codebase. In spdylay, the cost of having such API is almost free because spdylay requires zlib for header compression. nghttp2 no longer uses gzip to header compression. zlib dependency exists just for gzip compression API, which is not an essential. So we decided to move gzip code to under src and remove zlib dependency from libnghttp2 itself. As nghttp2 package, we depend on zlib to compile tools under src. --- configure.ac | 15 ++-- examples/client.c | 55 +----------- lib/Makefile.am | 4 +- lib/includes/nghttp2/nghttp2.h | 90 -------------------- lib/libnghttp2.pc.in | 1 - lib/nghttp2_gzip.h | 39 --------- src/Makefile.am | 10 ++- src/nghttp.cc | 1 + {lib => src}/nghttp2_gzip.c | 0 src/nghttp2_gzip.h | 132 +++++++++++++++++++++++++++++ {tests => src}/nghttp2_gzip_test.c | 0 {tests => src}/nghttp2_gzip_test.h | 0 src/shrpx-unittest.cc | 3 +- tests/main.c | 2 - 14 files changed, 154 insertions(+), 198 deletions(-) delete mode 100644 lib/nghttp2_gzip.h rename {lib => src}/nghttp2_gzip.c (100%) create mode 100644 src/nghttp2_gzip.h rename {tests => src}/nghttp2_gzip_test.c (100%) rename {tests => src}/nghttp2_gzip_test.h (100%) 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",