testHttpRequest.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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
9#include "squid.h"
10#include "compat/cppunit.h"
11#include "HttpHeader.h"
12#include "HttpRequest.h"
13#include "MasterXaction.h"
14#include "mime_header.h"
15#include "unitTestMain.h"
16
17#include <cppunit/TestAssert.h>
18
19class TestHttpRequest : public CPPUNIT_NS::TestFixture
20{
26
27protected:
28 void testCreateFromUrl();
31};
32
34
37{
38public:
40 bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
41};
42
44class MyTestProgram: public TestProgram
45{
46public:
47 /* TestProgram API */
48 void startup() override;
49};
50
51void
53{
54 Mem::Init();
57}
58
59/*
60 * Test creating an HttpRequest object from a Url and method
61 */
62void
64{
65 /* vanilla url, implicit method */
66 SBuf url("http://foo:90/bar");
67 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
68 HttpRequest *aRequest = HttpRequest::FromUrl(url, mx);
69 AnyP::KnownPort expected_port = 90;
70 CPPUNIT_ASSERT(aRequest != nullptr);
71 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
72 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
73 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
74 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
75 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
76
77 /* vanilla url */
78 url = "http://foo:90/bar";
79 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
80 expected_port = 90;
81 CPPUNIT_ASSERT(aRequest != nullptr);
82 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
83 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
84 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
85 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
86 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
87
88 /* vanilla url, different method */
89 url = "http://foo/bar";
90 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_PUT);
91 expected_port = 80;
92 CPPUNIT_ASSERT(aRequest != nullptr);
93 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
94 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT);
95 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
96 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
97 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
98
99 /* a connect url with non-CONNECT data */
100 HttpRequest *nullRequest = nullptr;
101 url = ":foo/bar";
102 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
103 CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest);
104
105 /* a CONNECT url with CONNECT data */
106 url = "foo:45";
107 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
108 expected_port = 45;
109 CPPUNIT_ASSERT(aRequest != nullptr);
110 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
111 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT);
112 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
113 CPPUNIT_ASSERT_EQUAL(SBuf(), aRequest->url.path());
114 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
115
116 // XXX: check METHOD_NONE input handling
117}
118
119/*
120 * Test BUG: URL '2000:800:45' opens host 2000 port 800 !!
121 */
122void
124{
125 HttpRequest *aRequest = nullptr;
126
127 /* valid IPv6 address without port */
128 SBuf url("http://[2000:800::45]/foo");
129 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
130 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
131 AnyP::KnownPort expected_port = 80;
132 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
133 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
134 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
135 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
136 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
137
138 /* valid IPv6 address with port */
139 url = "http://[2000:800::45]:90/foo";
140 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
141 expected_port = 90;
142 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
143 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
144 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
145 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
146 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
147
148 /* IPv6 address as invalid (bug trigger) */
149 url = "http://2000:800::45/foo";
150 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
151 expected_port = 80;
152 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
153 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
154 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
155 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
156 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
157}
158
159void
161{
162 MemBuf input;
163 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
164 PrivateHttpRequest engine(mx);
166 size_t hdr_len;
167 input.init();
168
169 // a valid request line
170 input.append("GET / HTTP/1.1\n\n", 16);
171 hdr_len = headersEnd(input.content(), input.contentSize());
172 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
173 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
174 input.reset();
176
177 input.append("GET / HTTP/1.1\n\n", 18);
178 hdr_len = headersEnd(input.content(), input.contentSize());
179 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
180 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
181 input.reset();
183
184 // strange but valid methods
185 input.append(". / HTTP/1.1\n\n", 14);
186 hdr_len = headersEnd(input.content(), input.contentSize());
187 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
188 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
189 input.reset();
191
192 input.append("OPTIONS * HTTP/1.1\n\n", 20);
193 hdr_len = headersEnd(input.content(), input.contentSize());
194 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
195 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
196 input.reset();
198
199// TODO no method
200
201// TODO binary code in method
202
203// TODO no URL
204
205// TODO no status (okay)
206
207// TODO non-HTTP protocol
208
209 input.append(" \n\n", 8);
210 hdr_len = headersEnd(input.content(), input.contentSize());
211 CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
212 CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
213 input.reset();
215}
216
217int
218main(int argc, char *argv[])
219{
220 return MyTestProgram().run(argc, argv);
221}
222
void httpHeaderInitModule(void)
Definition: HttpHeader.cc:121
void error(char *format,...)
static void Init()
initializes down-cased protocol scheme names array
Definition: UriScheme.cc:38
AnyP::UriScheme const & getScheme() const
Definition: Uri.h:67
void path(const char *p)
Definition: Uri.h:101
void port(const Port p)
reset authority port subcomponent
Definition: Uri.h:95
void host(const char *src)
Definition: Uri.cc:100
HttpRequestMethod method
Definition: HttpRequest.h:114
bool sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error) override
Definition: HttpRequest.cc:268
static HttpRequest * FromUrl(const SBuf &url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:517
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
Definition: MemBuf.h:24
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
char * content()
start of the added data
Definition: MemBuf.h:41
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void reset()
Definition: MemBuf.cc:129
customizes our test setup
void startup() override
bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e)
PrivateHttpRequest(const MasterXaction::Pointer &mx)
Definition: SBuf.h:94
CPPUNIT_TEST_SUITE(TestHttpRequest)
CPPUNIT_TEST(testCreateFromUrl)
void testSanityCheckStartLine()
CPPUNIT_TEST(testIPv6HostColonBug)
CPPUNIT_TEST(testSanityCheckStartLine)
implements test program's main() function while enabling customization
Definition: unitTestMain.h:26
int run(int argc, char *argv[])
Definition: unitTestMain.h:44
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:17
uint16_t KnownPort
validated/supported port number; these values are never zero
Definition: UriScheme.h:23
ProtocolType
Definition: ProtocolType.h:23
@ PROTO_NONE
Definition: ProtocolType.h:24
@ PROTO_HTTP
Definition: ProtocolType.h:25
StatusCode
Definition: StatusCode.h:20
@ scInvalidHeader
Definition: StatusCode.h:86
@ scNone
Definition: StatusCode.h:21
@ METHOD_PUT
Definition: MethodType.h:27
@ METHOD_CONNECT
Definition: MethodType.h:29
@ METHOD_GET
Definition: MethodType.h:25
void Init()
Definition: old_api.cc:425
int main(int argc, char *argv[])
CPPUNIT_TEST_SUITE_REGISTRATION(TestHttpRequest)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors