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
27public:
28 void setUp() override;
29
30protected:
31 void testCreateFromUrl();
34};
35
37
40{
41public:
43 bool doSanityCheckStartLine(const char *b, const size_t h, Http::StatusCode *e) { return sanityCheckStartLine(b,h,e); };
44};
45
46/* init memory pools */
47
48void
50{
51 Mem::Init();
54}
55
56/*
57 * Test creating an HttpRequest object from a Url and method
58 */
59void
61{
62 /* vanilla url, implicit method */
63 SBuf url("http://foo:90/bar");
64 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
65 HttpRequest *aRequest = HttpRequest::FromUrl(url, mx);
66 AnyP::KnownPort expected_port = 90;
67 CPPUNIT_ASSERT(aRequest != nullptr);
68 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
69 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
70 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
71 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
72 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
73
74 /* vanilla url */
75 url = "http://foo:90/bar";
76 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
77 expected_port = 90;
78 CPPUNIT_ASSERT(aRequest != nullptr);
79 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
80 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
81 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
82 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
83 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
84
85 /* vanilla url, different method */
86 url = "http://foo/bar";
87 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_PUT);
88 expected_port = 80;
89 CPPUNIT_ASSERT(aRequest != nullptr);
90 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
91 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_PUT);
92 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
93 CPPUNIT_ASSERT_EQUAL(SBuf("/bar"), aRequest->url.path());
94 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
95
96 /* a connect url with non-CONNECT data */
97 HttpRequest *nullRequest = nullptr;
98 url = ":foo/bar";
99 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
100 CPPUNIT_ASSERT_EQUAL(nullRequest, aRequest);
101
102 /* a CONNECT url with CONNECT data */
103 url = "foo:45";
104 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_CONNECT);
105 expected_port = 45;
106 CPPUNIT_ASSERT(aRequest != nullptr);
107 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
108 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_CONNECT);
109 CPPUNIT_ASSERT_EQUAL(String("foo"), String(aRequest->url.host()));
110 CPPUNIT_ASSERT_EQUAL(SBuf(), aRequest->url.path());
111 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_NONE, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
112
113 // XXX: check METHOD_NONE input handling
114}
115
116/*
117 * Test BUG: URL '2000:800:45' opens host 2000 port 800 !!
118 */
119void
121{
122 HttpRequest *aRequest = nullptr;
123
124 /* valid IPv6 address without port */
125 SBuf url("http://[2000:800::45]/foo");
126 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
127 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
128 AnyP::KnownPort expected_port = 80;
129 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
130 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
131 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
132 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
133 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
134
135 /* valid IPv6 address with port */
136 url = "http://[2000:800::45]:90/foo";
137 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
138 expected_port = 90;
139 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
140 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
141 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
142 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
143 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
144
145 /* IPv6 address as invalid (bug trigger) */
146 url = "http://2000:800::45/foo";
147 aRequest = HttpRequest::FromUrl(url, mx, Http::METHOD_GET);
148 expected_port = 80;
149 CPPUNIT_ASSERT_EQUAL(expected_port, *aRequest->url.port());
150 CPPUNIT_ASSERT(aRequest->method == Http::METHOD_GET);
151 CPPUNIT_ASSERT_EQUAL(String("[2000:800::45]"), String(aRequest->url.host()));
152 CPPUNIT_ASSERT_EQUAL(SBuf("/foo"), aRequest->url.path());
153 CPPUNIT_ASSERT_EQUAL(AnyP::PROTO_HTTP, static_cast<AnyP::ProtocolType>(aRequest->url.getScheme()));
154}
155
156void
158{
159 MemBuf input;
160 const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
161 PrivateHttpRequest engine(mx);
163 size_t hdr_len;
164 input.init();
165
166 // a valid request line
167 input.append("GET / HTTP/1.1\n\n", 16);
168 hdr_len = headersEnd(input.content(), input.contentSize());
169 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
170 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
171 input.reset();
173
174 input.append("GET / HTTP/1.1\n\n", 18);
175 hdr_len = headersEnd(input.content(), input.contentSize());
176 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
177 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
178 input.reset();
180
181 // strange but valid methods
182 input.append(". / HTTP/1.1\n\n", 14);
183 hdr_len = headersEnd(input.content(), input.contentSize());
184 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
185 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
186 input.reset();
188
189 input.append("OPTIONS * HTTP/1.1\n\n", 20);
190 hdr_len = headersEnd(input.content(), input.contentSize());
191 CPPUNIT_ASSERT(engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
192 CPPUNIT_ASSERT_EQUAL(error, Http::scNone);
193 input.reset();
195
196// TODO no method
197
198// TODO binary code in method
199
200// TODO no URL
201
202// TODO no status (okay)
203
204// TODO non-HTTP protocol
205
206 input.append(" \n\n", 8);
207 hdr_len = headersEnd(input.content(), input.contentSize());
208 CPPUNIT_ASSERT(!engine.doSanityCheckStartLine(input.content(), hdr_len, &error) );
209 CPPUNIT_ASSERT_EQUAL(error, Http::scInvalidHeader);
210 input.reset();
212}
213
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:99
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
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 setUp() override
void testSanityCheckStartLine()
CPPUNIT_TEST(testIPv6HostColonBug)
CPPUNIT_TEST(testSanityCheckStartLine)
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
CPPUNIT_TEST_SUITE_REGISTRATION(TestHttpRequest)

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors