]>
Commit | Line | Data |
---|---|---|
4e0938ef | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
4e0938ef AJ |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
f7f3304a | 9 | #include "squid.h" |
e1f7507e | 10 | |
c21ad0f5 | 11 | #include <cppunit/TestAssert.h> |
12 | ||
ec6f82c1 | 13 | #include "HttpHeader.h" |
c21ad0f5 | 14 | #include "HttpRequest.h" |
5ceaee75 | 15 | #include "MasterXaction.h" |
bf7af17b | 16 | #include "mime_header.h" |
602d9612 | 17 | #include "testHttpRequest.h" |
7f861c77 AJ |
18 | #include "unitTestMain.h" |
19 | ||
c21ad0f5 | 20 | CPPUNIT_TEST_SUITE_REGISTRATION( testHttpRequest ); |
21 | ||
0f9db2d6 AJ |
22 | /** wrapper for testing HttpRequest object private and protected functions */ |
23 | class PrivateHttpRequest : public HttpRequest | |
24 | { | |
25 | public: | |
e16571ed | 26 | PrivateHttpRequest(const MasterXaction::Pointer &mx) : HttpRequest(mx) {} |
84ae6223 | 27 | bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); }; |
0f9db2d6 AJ |
28 | }; |
29 | ||
c21ad0f5 | 30 | /* init memory pools */ |
31 | ||
16555581 | 32 | void |
33 | testHttpRequest::setUp() | |
c21ad0f5 | 34 | { |
16555581 | 35 | Mem::Init(); |
50a43a49 | 36 | AnyP::UriScheme::Init(); |
0f9db2d6 | 37 | httpHeaderInitModule(); |
16555581 | 38 | } |
c21ad0f5 | 39 | |
40 | /* | |
41 | * Test creating an HttpRequest object from a Url and method | |
42 | */ | |
43 | void | |
d6067ac1 | 44 | testHttpRequest::testCreateFromUrl() |
c21ad0f5 | 45 | { |
2f8abb64 | 46 | /* vanilla url, implicit method */ |
f45dd259 | 47 | unsigned short expected_port; |
6c880a16 | 48 | SBuf url("http://foo:90/bar"); |
5ceaee75 CT |
49 | const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient); |
50 | HttpRequest *aRequest = HttpRequest::FromUrl(url, mx); | |
d6067ac1 | 51 | expected_port = 90; |
6c880a16 | 52 | CPPUNIT_ASSERT(aRequest != nullptr); |
d6067ac1 AJ |
53 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
54 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); | |
55 | CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host())); | |
56 | CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path()); | |
57 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); | |
d6067ac1 AJ |
58 | |
59 | /* vanilla url */ | |
6c880a16 | 60 | url = "http://foo:90/bar"; |
5ceaee75 | 61 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET); |
c21ad0f5 | 62 | expected_port = 90; |
6c880a16 | 63 | CPPUNIT_ASSERT(aRequest != nullptr); |
5c51bffb | 64 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 65 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); |
5c51bffb | 66 | CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host())); |
51b5dcf5 | 67 | CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path()); |
4e3f4dc7 | 68 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
cc192b50 | 69 | |
c21ad0f5 | 70 | /* vanilla url, different method */ |
6c880a16 | 71 | url = "http://foo/bar"; |
5ceaee75 | 72 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_PUT); |
c21ad0f5 | 73 | expected_port = 80; |
6c880a16 | 74 | CPPUNIT_ASSERT(aRequest != nullptr); |
5c51bffb | 75 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 76 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT); |
5c51bffb | 77 | CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host())); |
51b5dcf5 | 78 | CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path()); |
4e3f4dc7 | 79 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
cc192b50 | 80 | |
c21ad0f5 | 81 | /* a connect url with non-CONNECT data */ |
d6067ac1 | 82 | HttpRequest *nullRequest = nullptr; |
6c880a16 | 83 | url = ":foo/bar"; |
5ceaee75 | 84 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT); |
c21ad0f5 | 85 | CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest); |
cc192b50 | 86 | |
c21ad0f5 | 87 | /* a CONNECT url with CONNECT data */ |
6c880a16 | 88 | url = "foo:45"; |
5ceaee75 | 89 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT); |
c21ad0f5 | 90 | expected_port = 45; |
6c880a16 | 91 | CPPUNIT_ASSERT(aRequest != nullptr); |
5c51bffb | 92 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 93 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT); |
5c51bffb | 94 | CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host())); |
51b5dcf5 | 95 | CPPUNIT_ASSERT_EQUAL(SBuf(), aRequest->url.path()); |
4e3f4dc7 | 96 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
c21ad0f5 | 97 | |
d6067ac1 | 98 | // XXX: check METHOD_NONE input handling |
c21ad0f5 | 99 | } |
cc192b50 | 100 | |
101 | /* | |
102 | * Test BUG: URL '2000:800:45' opens host 2000 port 800 !! | |
103 | */ | |
104 | void | |
105 | testHttpRequest::testIPv6HostColonBug() | |
106 | { | |
f45dd259 | 107 | unsigned short expected_port; |
cc192b50 | 108 | HttpRequest *aRequest = NULL; |
109 | ||
110 | /* valid IPv6 address without port */ | |
6c880a16 | 111 | SBuf url("http://[2000:800::45]/foo"); |
5ceaee75 CT |
112 | const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient); |
113 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET); | |
cc192b50 | 114 | expected_port = 80; |
5c51bffb | 115 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 116 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); |
5c51bffb | 117 | CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host())); |
51b5dcf5 | 118 | CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path()); |
4e3f4dc7 | 119 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
cc192b50 | 120 | |
121 | /* valid IPv6 address with port */ | |
6c880a16 | 122 | url = "http://[2000:800::45]:90/foo"; |
5ceaee75 | 123 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET); |
cc192b50 | 124 | expected_port = 90; |
5c51bffb | 125 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 126 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); |
5c51bffb | 127 | CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host())); |
51b5dcf5 | 128 | CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path()); |
4e3f4dc7 | 129 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
cc192b50 | 130 | |
131 | /* IPv6 address as invalid (bug trigger) */ | |
6c880a16 | 132 | url = "http://2000:800::45/foo"; |
5ceaee75 | 133 | aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET); |
cc192b50 | 134 | expected_port = 80; |
5c51bffb | 135 | CPPUNIT_ASSERT_EQUAL(expected_port, aRequest->url.port()); |
c2a7cefd | 136 | CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET); |
5c51bffb | 137 | CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host())); |
51b5dcf5 | 138 | CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path()); |
4e3f4dc7 | 139 | CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme())); |
cc192b50 | 140 | } |
0f9db2d6 AJ |
141 | |
142 | void | |
143 | testHttpRequest::testSanityCheckStartLine() | |
144 | { | |
145 | MemBuf input; | |
5ceaee75 CT |
146 | const MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient); |
147 | PrivateHttpRequest engine(mx); | |
955394ce | 148 | Http::StatusCode error = Http::scNone; |
0f9db2d6 AJ |
149 | size_t hdr_len; |
150 | input.init(); | |
151 | ||
152 | // a valid request line | |
153 | input.append("GET / HTTP/1.1\n\n", 16); | |
154 | hdr_len = headersEnd(input.content(), input.contentSize()); | |
84ae6223 | 155 | CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) ); |
955394ce | 156 | CPPUNIT_ASSERT_EQUAL(error, Http::scNone); |
0f9db2d6 | 157 | input.reset(); |
955394ce | 158 | error = Http::scNone; |
0f9db2d6 AJ |
159 | |
160 | input.append("GET / HTTP/1.1\n\n", 18); | |
161 | hdr_len = headersEnd(input.content(), input.contentSize()); | |
84ae6223 | 162 | CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) ); |
955394ce | 163 | CPPUNIT_ASSERT_EQUAL(error, Http::scNone); |
0f9db2d6 | 164 | input.reset(); |
955394ce | 165 | error = Http::scNone; |
0f9db2d6 AJ |
166 | |
167 | // strange but valid methods | |
168 | input.append(". / HTTP/1.1\n\n", 14); | |
169 | hdr_len = headersEnd(input.content(), input.contentSize()); | |
84ae6223 | 170 | CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) ); |
955394ce | 171 | CPPUNIT_ASSERT_EQUAL(error, Http::scNone); |
0f9db2d6 | 172 | input.reset(); |
955394ce | 173 | error = Http::scNone; |
0f9db2d6 AJ |
174 | |
175 | input.append("OPTIONS * HTTP/1.1\n\n", 20); | |
176 | hdr_len = headersEnd(input.content(), input.contentSize()); | |
84ae6223 | 177 | CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) ); |
955394ce | 178 | CPPUNIT_ASSERT_EQUAL(error, Http::scNone); |
0f9db2d6 | 179 | input.reset(); |
955394ce | 180 | error = Http::scNone; |
0f9db2d6 AJ |
181 | |
182 | // TODO no method | |
183 | ||
184 | // TODO binary code in method | |
185 | ||
186 | // TODO no URL | |
187 | ||
188 | // TODO no status (okay) | |
189 | ||
190 | // TODO non-HTTP protocol | |
191 | ||
192 | input.append(" \n\n", 8); | |
193 | hdr_len = headersEnd(input.content(), input.contentSize()); | |
84ae6223 | 194 | CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(input.content(), hdr_len, &error) ); |
955394ce | 195 | CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader); |
0f9db2d6 | 196 | input.reset(); |
955394ce | 197 | error = Http::scNone; |
0f9db2d6 | 198 | } |
f53969cc | 199 |