summaryrefslogtreecommitdiff
path: root/test/decoders/http/http_gtest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/decoders/http/http_gtest.cpp')
-rw-r--r--test/decoders/http/http_gtest.cpp313
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 = &gtest_flow_data;
+ flow->parser.flow_ref = flow;
+ llhttp_settings_init(&flow->parser.settings);
+ memset(&gtest_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);