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 
19 class TestHttpRequest : public CPPUNIT_NS::TestFixture
20 {
26 
27 protected:
28  void testCreateFromUrl();
29  void testIPv6HostColonBug();
31 };
32 
34 
37 {
38 public:
40  bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
41 };
42 
44 class MyTestProgram: public TestProgram
45 {
46 public:
47  /* TestProgram API */
48  void startup() override;
49 };
50 
51 void
53 {
54  Mem::Init();
57 }
58 
59 /*
60  * Test creating an HttpRequest object from a Url and method
61  */
62 void
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  */
122 void
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 
159 void
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 
217 int
218 main(int argc, char *argv[])
219 {
220  return MyTestProgram().run(argc, argv);
221 }
222 
int main(int argc, char *argv[])
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
@ scNone
Definition: StatusCode.h:21
@ PROTO_NONE
Definition: ProtocolType.h:24
void error(char *format,...)
implements test program's main() function while enabling customization
Definition: unitTestMain.h:25
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
Definition: SBuf.h:93
StatusCode
Definition: StatusCode.h:20
int run(int argc, char *argv[])
Definition: unitTestMain.h:44
void testSanityCheckStartLine()
ProtocolType
Definition: ProtocolType.h:23
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
CPPUNIT_TEST_SUITE_REGISTRATION(TestHttpRequest)
uint16_t KnownPort
validated/supported port number; these values are never zero
Definition: UriScheme.h:23
static void Init()
initializes down-cased protocol scheme names array
Definition: UriScheme.cc:38
Definition: MemBuf.h:23
@ METHOD_CONNECT
Definition: MethodType.h:29
void httpHeaderInitModule(void)
Definition: HttpHeader.cc:121
@ METHOD_PUT
Definition: MethodType.h:27
const AnyP::UriScheme & getScheme() const
Definition: Uri.h:58
void port(const Port p)
reset authority port subcomponent
Definition: Uri.h:90
CPPUNIT_TEST(testCreateFromUrl)
HttpRequestMethod method
Definition: HttpRequest.h:114
void path(const char *p)
Definition: Uri.h:96
@ PROTO_HTTP
Definition: ProtocolType.h:25
char * content()
start of the added data
Definition: MemBuf.h:41
bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e)
void Init()
Definition: old_api.cc:281
PrivateHttpRequest(const MasterXaction::Pointer &mx)
void reset()
Definition: MemBuf.cc:129
@ scInvalidHeader
Squid header parsing error.
Definition: StatusCode.h:88
customizes our test setup
@ METHOD_GET
Definition: MethodType.h:25
size_t headersEnd(const char *mime, size_t l, bool &containsObsFold)
Definition: mime_header.cc:17
void host(const char *src)
Definition: Uri.cc:123
bool sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error) override
Definition: HttpRequest.cc:268
void startup() override
CPPUNIT_TEST_SUITE(TestHttpRequest)

 

Introduction

Documentation

Support

Miscellaneous