diff --git a/plugin/protocol/http/include/internal/http_half.h b/plugin/protocol/http/include/internal/http_half.h index ebee3ee..1a09995 100644 --- a/plugin/protocol/http/include/internal/http_half.h +++ b/plugin/protocol/http/include/internal/http_half.h @@ -65,8 +65,10 @@ struct http_half_private char * url_storage; /* Content-Encoding */ + uint16_t accept_content_encoding; uint16_t content_encoding; struct hf_content_uncompress * cv_uncompress_object; + struct hf_content_compress * cv_compress_object; /* Header Parser */ struct evbuffer * evbuf_header_field; diff --git a/plugin/protocol/http/src/http_half.cpp b/plugin/protocol/http/src/http_half.cpp index 0fd3148..1634933 100644 --- a/plugin/protocol/http/src/http_half.cpp +++ b/plugin/protocol/http/src/http_half.cpp @@ -157,7 +157,6 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st /* uri is stored in underlay evbuffer, we need to append a terminal zero */ static const char __zero = 0; evbuffer_add(hf_private->evbuf_uri, &__zero, sizeof(__zero)); - hf_req_spec->uri = (char *) evbuffer_pullup(hf_private->evbuf_uri, evbuffer_get_length(hf_private->evbuf_uri)); /* TODO: url is more complex. need to review RFC */ @@ -172,6 +171,18 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st hf_req_spec->url = hf_private->url_storage; assert(hf_req_spec->url != NULL); + + /* Accept-Encoding */ + const static struct http_field_name __accept_encoding_name = {TFE_HTTP_ACCEPT_ENCODING, NULL}; + const char * __str_accept_encoding = tfe_http_field_read(hf_public, &__accept_encoding_name); + if (__str_accept_encoding != NULL) + { + hf_private->accept_content_encoding = __hf_content_encoding_parse(__str_accept_encoding); + } + else + { + hf_private->accept_content_encoding = HTTP_ACCEPT_ENCODING_NONE; + } } void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser) @@ -489,7 +500,18 @@ int hf_ops_append_body(struct tfe_http_half * half, char * buff, size_t size, in hf_private->evbuf_body = evbuffer_new(); } - return evbuffer_add(hf_private->evbuf_body, buff, size); + int ret = 0; + if (hf_private->cv_compress_object) + { + ret = hf_content_compress_write(hf_private->cv_compress_object, + (const unsigned char *)buff, size, hf_private->evbuf_body, 0); + } + else + { + ret = evbuffer_add(hf_private->evbuf_body, buff, size); + } + + return ret; } void hf_private_destory(struct http_half_private * hf_private) @@ -686,6 +708,27 @@ struct tfe_http_half * hs_ops_response_create(struct tfe_http_session * session, hf_resp_private->method_or_status = resp_code; hf_resp_private->is_setup_by_user = true; + + /* Inherit from request in currect session */ + struct http_session_private * ss_private = to_hs_private(session); + struct http_half_private * hf_req_private = to_hf_request_private(ss_private); + + /* we must send content in encode that client asked, + * but dont need to be accordance with upstream server's response */ + unsigned int content_encoding = HTTP_ACCEPT_ENCODING_NONE; + if (hf_req_private != NULL) + { + hf_resp_private->content_encoding = hf_req_private->accept_content_encoding; + content_encoding = hf_resp_private->content_encoding; + } + + /* Create content compress content */ + if (content_encoding != HTTP_ACCEPT_ENCODING_NONE) + { + hf_resp_private->cv_compress_object = hf_content_compress_create(content_encoding); + assert(hf_resp_private->cv_compress_object != NULL); + } + return to_hf_public(hf_resp_private); } @@ -760,6 +803,13 @@ void hf_private_construct(struct http_half_private * hf_private) /* delimitor between header and body */ evbuffer_add_printf(hf_private->evbuf_raw, "\r\n"); + + /* Terminal the end of gzip stream */ + if (hf_private->evbuf_body && hf_private->cv_compress_object) + { + hf_content_compress_write(hf_private->cv_compress_object, NULL, 0, hf_private->evbuf_body, 1); + } + /* add body */ if (hf_private->evbuf_body) { diff --git a/plugin/protocol/http/test/test_http_convert.cpp b/plugin/protocol/http/test/test_http_convert.cpp index d67ac26..cd613ec 100644 --- a/plugin/protocol/http/test/test_http_convert.cpp +++ b/plugin/protocol/http/test/test_http_convert.cpp @@ -262,7 +262,7 @@ TEST_F(HttpConvertCompress, MonkeyToGzip) EXPECT_EQ(memcmp(uncompress_buf.data(), monkey, sizeof(monkey)), 0); } -TEST_F(HttpConvertCompress, MonkeyToGzipStrem) +TEST_F(HttpConvertCompress, MonkeyToGzipStream) { unsigned frag_length = sizeof(monkey) / 2; @@ -286,6 +286,34 @@ TEST_F(HttpConvertCompress, MonkeyToGzipStrem) EXPECT_EQ(memcmp(uncompress_buf.data(), monkey, sizeof(monkey)), 0); } +TEST_F(HttpConvertCompress, MonkeyToGzipStreamWithNullEnd) +{ + unsigned frag_length = sizeof(monkey) / 2; + + /* First frag */ + int ret = hf_content_compress_write(cv_compress_object, monkey, frag_length, buf, 0); + ASSERT_EQ(ret, 0); + + /* Last frag */ + ret = hf_content_compress_write(cv_compress_object, monkey + frag_length, sizeof(monkey) - frag_length, buf, 0); + ASSERT_EQ(ret, 0); + + /* End frag */ + ret = hf_content_compress_write(cv_compress_object, NULL, 0, buf, 1); + ASSERT_EQ(ret, 0); + + unsigned char * __raw_buf_ptr = evbuffer_pullup(buf, -1); + size_t __raw_buf_length = evbuffer_get_length(buf); + + ret = hf_content_uncompress_write(cv_uncompress_object, NULL, EV_HTTP_REQ_BODY_CONT, + __raw_buf_ptr, __raw_buf_length); + + ASSERT_TRUE(__raw_buf_ptr != NULL); + ASSERT_EQ(ret, 1); + EXPECT_EQ(uncompress_buf.size(), sizeof(monkey)); + EXPECT_EQ(memcmp(uncompress_buf.data(), monkey, sizeof(monkey)), 0); +} + void tfe_stream_write_access_log(const struct tfe_stream * stream, int level, const char * fmt, ...) { return;