diff options
Diffstat (limited to 'test/decoders/http/http_gtest.cpp')
| -rw-r--r-- | test/decoders/http/http_gtest.cpp | 313 |
1 files changed, 298 insertions, 15 deletions
diff --git a/test/decoders/http/http_gtest.cpp b/test/decoders/http/http_gtest.cpp index 4f99fb6..300e221 100644 --- a/test/decoders/http/http_gtest.cpp +++ b/test/decoders/http/http_gtest.cpp @@ -3,14 +3,45 @@ #include <stdio.h> #include "zlib.h" #include "md5/md5.h" +#include "stellar/http.h" +#include "http_decoder.h" +#include "http_decoder_utils.h" +#include "http_decoder_half.h" +#include "http_decoder_decompress.h" +#ifdef __cplusplus +extern "C" +{ +#endif #include "http.h" -#include "http_decoder_private.h" +#include "llhttp.h" #include "brotli/decode.h" #include "brotli/encode.h" -#include "event2/buffer.h" +#ifdef __cplusplus +} +#endif #define ZIP_UNZIP_TEST_DATA_LEN (1024 * 1024) void httpd_url_decode(const char *string, size_t length, char *ostring, size_t *olen); +TEST(http_url_decoder, onebyte_ascii) +{ + char decoded_url_buf[2048] = {}; + size_t decode_url_buf_len = sizeof(decoded_url_buf); + const char *encode_url = "h"; + size_t decoded_url_len = http_url_decode(encode_url, strlen(encode_url), decoded_url_buf, decode_url_buf_len); + EXPECT_EQ(decoded_url_len, strlen("h")); + EXPECT_STREQ("h", decoded_url_buf); +} + +TEST(http_url_decoder, onebyte_hex) +{ + char decoded_url_buf[2048] = {}; + size_t decode_url_buf_len = sizeof(decoded_url_buf); + const char *encode_url = "%FF"; + size_t decoded_url_len = http_url_decode(encode_url, strlen(encode_url), decoded_url_buf, decode_url_buf_len); + EXPECT_EQ(decoded_url_len, 1); + EXPECT_EQ((unsigned char)decoded_url_buf[0], 0xFF); +} + TEST(http_url_decoder, none_encode) { char decoded_url_buf[2048] = {}; @@ -60,27 +91,55 @@ TEST(http_url_decoder, chinese2) EXPECT_EQ(decoded_url_len, strlen("http://www.baidu.com/\xE7\xBC\x96\xE8\xA7\xA3\xE7\xA0\x81\xE6\xB5\x8B\xE8\xAF\x95\xE5\x93\x88\xE5\x93\x88")); } -TEST(http, event_buffer) +TEST(http, buffer) { - struct evbuffer *evbuf = evbuffer_new(); + struct http_buffer *hbuf = http_buffer_new(); - evbuffer_add(evbuf, "hello", 5); + http_buffer_add(hbuf, "hello", 5); + + char *data; + size_t len; + http_buffer_read(hbuf, &data, &len); - size_t len = evbuffer_get_length(evbuf); - EXPECT_EQ(len, 5); - char outbuf[16]; - len = evbuffer_copyout(evbuf, outbuf, sizeof(outbuf)); EXPECT_EQ(len, 5); - EXPECT_EQ(0, memcmp(outbuf, "hello", 5)); + EXPECT_EQ(0, memcmp(data, "hello", 5)); - evbuffer_add(evbuf, ",", 1); - evbuffer_add(evbuf, "world", 5); + http_buffer_add(hbuf, ",", 1); + http_buffer_add(hbuf, "world", 5); - len = evbuffer_copyout(evbuf, outbuf, sizeof(outbuf)); + http_buffer_read(hbuf, &data, &len); EXPECT_EQ(len, 11); - EXPECT_EQ(0, memcmp(outbuf, "hello,world", 11)); + EXPECT_EQ(0, memcmp(data, "hello,world", 11)); + + http_buffer_free(hbuf); +} + +TEST(http, strtoll) +{ + ASSERT_EQ(0, http_strtoll(NULL, 0)); + ASSERT_EQ(0, http_strtoll("", 1)); + ASSERT_EQ(0, http_strtoll("abcd", 4)); + ASSERT_EQ(123, http_strtoll("123", 3)); + ASSERT_EQ(123, http_strtoll(" 123", 4)); + ASSERT_EQ(123, http_strtoll(" 123\r\n", 6)); + ASSERT_EQ(123456789, http_strtoll("123456789", 9)); +} - evbuffer_free(evbuf); +TEST(http, line_header_is_completed) +{ + ASSERT_EQ(0, http_line_header_completed(NULL, 0)); + ASSERT_EQ(0, http_line_header_completed("GET ", 4)); + ASSERT_EQ(0, http_line_header_completed("GET / HTTP/1.1\r\n", strlen("GET / HTTP/1.1\r\n"))); + ASSERT_EQ(strlen("GET / HTTP/1.1\r\n\r\n"), http_line_header_completed("GET / HTTP/1.1\r\n\r\n", strlen("GET / HTTP/1.1\r\n\r\n"))); +} + +TEST(http, identify) +{ + ASSERT_EQ(-1, http_protocol_identify(NULL, 0)); + ASSERT_EQ(-1, http_protocol_identify("123", 3)); + ASSERT_EQ(1, http_protocol_identify("GET / HTTP/1.1\r\n", strlen("GET / HTTP/1.1\r\n"))); + ASSERT_EQ(1, http_protocol_identify("POST / HTTP/1.1\r\n", strlen("POST / HTTP/1.1\r\n"))); + ASSERT_EQ(1, http_protocol_identify("HTTP/1.1 200 OK\r\n", strlen("HTTP/1.1 200 OK\r\n"))); } static int http_compress_use_deflate(unsigned char *indata, size_t indata_len, unsigned char *zip_data, size_t *zip_data_len) @@ -351,6 +410,230 @@ TEST(http, DISABLED_brotli_ascii) free(raw_data); } +#include "http_decoder_half.c" +#include "http_decoder_llhttp_wrap.c" +struct gtest_llhttp_callback_flag +{ + uint8_t on_message_begin; + uint8_t on_message_complete; + uint8_t on_uri; + uint8_t on_uri_complete; + uint8_t on_status; + uint8_t on_status_complete; + uint8_t on_method; + uint8_t on_method_complete; + uint8_t on_version; + uint8_t on_version_complete; + uint8_t on_header_field; + uint8_t on_header_field_complete; + uint8_t on_header_value; + uint8_t on_header_value_complete; + uint8_t on_chunk_header; + uint8_t on_chunk_header_complete; + uint8_t on_headers_complete; + uint8_t on_body; +}; +static struct gtest_llhttp_callback_flag gtest_llhttp_cb_flags; +static struct http_half_data gtest_flow_data; + +static int gtest_llhttp_on_message_begin(UNUSED llhttp_t *http) +{ + struct http_half_parser *parser = container_of(http, struct http_half_parser, llhttp_parser); + struct http_half *flow = parser->flow_ref; + flow->event = HTTP_EVENT_REQ_INIT; + gtest_llhttp_cb_flags.on_message_begin++; + return 0; +} +static int gtest_llhttp_on_message_complete(llhttp_t *http) +{ + struct http_half_parser *parser = container_of(http, struct http_half_parser, llhttp_parser); + struct http_half *flow = parser->flow_ref; + flow->event = __HTTP_EVENT_RESERVED; + flow->shaper.headers_cache = NULL; + gtest_llhttp_cb_flags.on_message_complete++; + return 0; +} +static int gtest_llhttp_on_headers_complete(llhttp_t *http) +{ + struct http_half_parser *parser = container_of(http, struct http_half_parser, llhttp_parser); + struct http_half *flow = parser->flow_ref; + flow->event = HTTP_EVENT_REQ_HDR_END; + gtest_llhttp_cb_flags.on_headers_complete++; + return 0; +} +static int gtest_llhttp_on_uri(UNUSED llhttp_t *http, UNUSED const char *at, UNUSED size_t length) +{ + gtest_llhttp_cb_flags.on_uri++; + return 0; +} +static int gtest_llhttp_on_method(UNUSED llhttp_t *http, UNUSED const char *at, UNUSED size_t length) +{ + gtest_llhttp_cb_flags.on_method++; + return 0; +} +static int gtest_llhttp_on_version(UNUSED llhttp_t *http, UNUSED const char *at, UNUSED size_t length) +{ + gtest_llhttp_cb_flags.on_version++; + return 0; +} +static int gtest_llhttp_on_body(UNUSED llhttp_t *http, UNUSED const char *at, UNUSED size_t length) +{ + gtest_llhttp_cb_flags.on_body++; + return 0; +} + +static void gtest_llhttp_init(struct http_half *flow) +{ + memset(flow, 0, sizeof(struct http_half)); + flow->flow_data = >est_flow_data; + flow->parser.flow_ref = flow; + llhttp_settings_init(&flow->parser.settings); + memset(>est_llhttp_cb_flags, 0, sizeof(gtest_llhttp_cb_flags)); + flow->parser.settings.on_message_begin = gtest_llhttp_on_message_begin; + flow->parser.settings.on_message_complete = gtest_llhttp_on_message_complete; + flow->parser.settings.on_url = gtest_llhttp_on_uri; + flow->parser.settings.on_method = gtest_llhttp_on_method; + flow->parser.settings.on_version = gtest_llhttp_on_version; + flow->parser.settings.on_body = gtest_llhttp_on_body; + flow->parser.settings.on_headers_complete = gtest_llhttp_on_headers_complete; + + llhttp_init(&flow->parser.llhttp_parser, HTTP_BOTH, &flow->parser.settings); +} + +TEST(http, stage_request_completed) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: keep-alive\r\n\r\n"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + http_flow_stage_shaping(&flow, newdata, new_datalen); + + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_complete); +} + +TEST(http, headers_extract) +{ + const char *raw_data = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: keep-alive\r\n\r\n"; + const char *headers_start, *headers_end; + http_truncate_extract_headers(raw_data, strlen(raw_data), &headers_start, &headers_end); + ASSERT_TRUE(headers_start != NULL); + ASSERT_TRUE(headers_end != NULL); + ASSERT_EQ(0, memcmp(headers_start, "Host: www.example.com\r\nConnection: keep-alive\r\n\r\n", headers_end - headers_start)); +} + +TEST(http, stage_request_with_body) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,world"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + gtest_flow_data.header.content_length = 11; + http_flow_stage_shaping(&flow, newdata, new_datalen); + + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_body); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_complete); +} + +TEST(http, stage_request_with_body_pipeline_many) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example1.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,worldGET / HTTP/1.1\r\nHost: www.example2.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,secndGET / HTTP/1.1\r\nHost: www.example3.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,third"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + gtest_flow_data.header.content_length = 11; + http_flow_stage_shaping(&flow, newdata, new_datalen); + + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_body); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_complete); +} + +TEST(http, stage_request_with_body_pipeline_many_one_by_one) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example1.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,worldGET / HTTP/1.1\r\nHost: www.example2.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,secndGET / HTTP/1.1\r\nHost: www.example3.com\r\nConnection: keep-alive\r\nContent-Length: 11\r\n\r\nhello,third"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + gtest_flow_data.header.content_length = 11; + + for (size_t i = 0; i < new_datalen; i++) + { + http_flow_stage_shaping(&flow, newdata + i, 1); + } + + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_complete); +} + +TEST(http, stage_request_completed_pipeline) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example1.com\r\nConnection: keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost: www.example2.com\r\nConnection: keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost: www.example3.com\r\nConnection: keep-alive\r\n\r\n"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + http_flow_stage_shaping(&flow, newdata, new_datalen); + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(3, gtest_llhttp_cb_flags.on_message_complete); +} + +TEST(http, stage_request_one_by_one) +{ + const char *newdata = "GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: keep-alive\r\n\r\n"; + size_t new_datalen = strlen(newdata); + struct http_half flow = {}; + gtest_llhttp_init(&flow); + + for (size_t i = 0; i < new_datalen; i++) + { + http_flow_stage_shaping(&flow, newdata + i, 1); + } + llhttp_finish(&flow.parser.llhttp_parser); + http_buffer_free(flow.shaper.headers_cache); + + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_begin); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_method); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_uri); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_version); + ASSERT_EQ(1, gtest_llhttp_cb_flags.on_message_complete); +} + int main(int argc, char const *argv[]) { ::testing::InitGoogleTest(&argc, (char **)argv); |
