1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/vespalib/portal/http_request.h>
using namespace vespalib;
using namespace vespalib::portal;
vespalib::string simple_req("GET /my/path HTTP/1.1\r\n"
"Host: my.host.com:80\r\n"
"CustomHeader: CustomValue\r\n"
"\r\n123456789");
size_t simple_req_padding = 9;
size_t simple_req_size = (simple_req.size() - simple_req_padding);
void verify_simple_req(const HttpRequest &req) {
EXPECT_TRUE(!req.need_more_data());
EXPECT_TRUE(req.valid());
EXPECT_TRUE(req.is_get());
EXPECT_EQUAL(req.get_uri(), "/my/path");
EXPECT_EQUAL(req.get_header("host"), "my.host.com:80");
EXPECT_EQUAL(req.get_header("customheader"), "CustomValue");
EXPECT_EQUAL(req.get_header("non-existing-header"), "");
}
HttpRequest make_request(const vespalib::string &req) {
HttpRequest result;
ASSERT_EQUAL(result.handle_data(req.data(), req.size()), req.size());
ASSERT_TRUE(result.valid());
return result;
}
void verify_invalid_request(const vespalib::string &req) {
HttpRequest result;
EXPECT_EQUAL(result.handle_data(req.data(), req.size()), req.size());
EXPECT_TRUE(!result.need_more_data());
EXPECT_TRUE(!result.valid());
}
TEST("require that request can be parsed in one go") {
HttpRequest req;
EXPECT_EQUAL(req.handle_data(simple_req.data(), simple_req_size), simple_req_size);
TEST_DO(verify_simple_req(req));
}
TEST("require that trailing data is not consumed") {
HttpRequest req;
EXPECT_EQUAL(req.handle_data(simple_req.data(), simple_req.size()), simple_req_size);
TEST_DO(verify_simple_req(req));
}
TEST("require that request can be parsed incrementally") {
HttpRequest req;
size_t chunk = 7;
size_t done = 0;
while (done < simple_req_size) {
size_t expect = std::min(simple_req_size - done, chunk);
EXPECT_EQUAL(req.handle_data(simple_req.data() + done, chunk), expect);
done += expect;
}
EXPECT_EQUAL(done, simple_req_size);
TEST_DO(verify_simple_req(req));
}
TEST("require that header continuation is replaced by single space") {
auto req = make_request("GET /my/path HTTP/1.1\r\n"
"test: one\r\n"
" two\r\n"
"\tthree\r\n"
"\r\n");
EXPECT_EQUAL(req.get_header("test"), "one two three");
}
TEST("require that duplicate headers are combined as list") {
auto req = make_request("GET /my/path HTTP/1.1\r\n"
"test: one\r\n"
"test: two\r\n"
"test: three\r\n"
"\r\n");
EXPECT_EQUAL(req.get_header("test"), "one,two,three");
}
TEST("require that leading and trailing whitespaces are stripped") {
auto req = make_request("GET /my/path HTTP/1.1\r\n"
"test: one \r\n"
" , two \r\n"
"test: three \r\n"
"\r\n");
EXPECT_EQUAL(req.get_header("test"), "one , two,three");
}
TEST("require that non-GET requests are detected") {
auto req = make_request("POST /my/path HTTP/1.1\r\n"
"\r\n");
EXPECT_TRUE(!req.is_get());
}
TEST("require that request line must contain all relevant parts") {
TEST_DO(verify_invalid_request("/my/path HTTP/1.1\r\n"));
TEST_DO(verify_invalid_request("GET HTTP/1.1\r\n"));
TEST_DO(verify_invalid_request("GET /my/path\r\n"));
}
TEST("require that first header line cannot be a continuation") {
TEST_DO(verify_invalid_request("GET /my/path HTTP/1.1\r\n"
" two\r\n"));
}
TEST("require that header name is not allowed to be empty") {
TEST_DO(verify_invalid_request("GET /my/path HTTP/1.1\r\n"
": value\r\n"));
}
TEST("require that header line must contain separator") {
TEST_DO(verify_invalid_request("GET /my/path HTTP/1.1\r\n"
"ok-header: ok-value\r\n"
"missing separator\r\n"));
}
TEST_MAIN() { TEST_RUN_ALL(); }
|