From eb1e7a1e2244b47e14748a1a2dd35d31caec8da5 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Tue, 16 Apr 2019 18:33:50 +0200 Subject: [PATCH] [#360,!305] Always include Host header in the HTTP requests. --- src/lib/http/http_header.h | 18 ++++++++++- src/lib/http/request.cc | 13 ++++++-- src/lib/http/request.h | 10 ++++-- src/lib/http/tests/request_unittests.cc | 43 ++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/lib/http/http_header.h b/src/lib/http/http_header.h index 975ad35efe..35d4c17db5 100644 --- a/src/lib/http/http_header.h +++ b/src/lib/http/http_header.h @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -64,6 +64,22 @@ private: /// @brief Pointer to the @c HttpHeader class. typedef boost::shared_ptr HttpHeaderPtr; +/// @brief Represents HTTP Host header. +class HostHttpHeader : public HttpHeader { +public: + + /// @brief Constructor. + /// + /// @param header_value Host header value. The default is empty + /// string. + explicit HostHttpHeader(const std::string& header_value = "") + : HttpHeader("Host", header_value) { + } +}; + +/// @brief Pointer to the HTTP host header. +typedef boost::shared_ptr HostHttpHeaderPtr; + } // end of namespace isc::http } // end of namespace isc diff --git a/src/lib/http/request.cc b/src/lib/http/request.cc index d782795f1b..a6e846e250 100644 --- a/src/lib/http/request.cc +++ b/src/lib/http/request.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -27,8 +27,10 @@ HttpRequest::HttpRequest() context_(new HttpRequestContext()) { } -HttpRequest::HttpRequest(const Method& method, const std::string& uri, - const HttpVersion& version) +HttpRequest::HttpRequest(const Method& method, + const std::string& uri, + const HttpVersion& version, + const HostHttpHeader& host_header) : HttpMessage(OUTBOUND), required_methods_(), method_(Method::HTTP_METHOD_UNKNOWN), context_(new HttpRequestContext()) { @@ -36,6 +38,11 @@ HttpRequest::HttpRequest(const Method& method, const std::string& uri, context()->uri_ = uri; context()->http_version_major_ = version.major_; context()->http_version_minor_ = version.minor_; + // The Host header is mandatory in HTTP/1.1 and should be placed before + // any other headers. We also include it for HTTP/1.0 as it doesn't + // harm to include it. + context()->headers_.push_back(HttpHeaderContext(host_header.getName(), + host_header.getValue())); } void diff --git a/src/lib/http/request.h b/src/lib/http/request.h index 945483d443..dc06600a53 100644 --- a/src/lib/http/request.h +++ b/src/lib/http/request.h @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -65,10 +65,16 @@ public: /// @brief Constructor for outbound HTTP request. /// + /// The constructor always includes Host header in the request, regardless + /// of the HTTP version used. + /// /// @param method HTTP method, e.g. POST. /// @param uri URI. /// @param version HTTP version. - HttpRequest(const Method& method, const std::string& uri, const HttpVersion& version); + /// @param host_header Host header to be included in the request. The default + /// is the empty Host header. + HttpRequest(const Method& method, const std::string& uri, const HttpVersion& version, + const HostHttpHeader& host_header = HostHttpHeader()); /// @brief Returns pointer to the @ref HttpRequestContext. /// diff --git a/src/lib/http/tests/request_unittests.cc b/src/lib/http/tests/request_unittests.cc index 6e0dc598b7..60f1f6398e 100644 --- a/src/lib/http/tests/request_unittests.cc +++ b/src/lib/http/tests/request_unittests.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2018 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2016-2019 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -80,6 +80,47 @@ TEST_F(HttpRequestTest, minimal) { HttpMessageNonExistingHeader); } +// This test verifies that empty Host header is included in the +// request if it is not explicitly specified. +TEST_F(HttpRequestTest, hostHeaderDefault) { + HttpRequestPtr request; + ASSERT_NO_THROW(request.reset(new HttpRequest(HttpRequest::Method::HTTP_GET, + "/isc/org", + HttpVersion(1, 0)))); + + ASSERT_NO_THROW(request->finalize()); + + EXPECT_EQ(HttpRequest::Method::HTTP_GET, request->getMethod()); + EXPECT_EQ("/isc/org", request->getUri()); + EXPECT_EQ(1, request->getHttpVersion().major_); + EXPECT_EQ(0, request->getHttpVersion().minor_); + + std::string host_hdr; + ASSERT_NO_THROW(host_hdr = request->getHeaderValue("Host")); + EXPECT_TRUE(host_hdr.empty()); +} + +// This test verifies that it is possible to explicitly specify a +// Host header value while creating a request. +TEST_F(HttpRequestTest, hostHeaderCustom) { + HttpRequestPtr request; + ASSERT_NO_THROW(request.reset(new HttpRequest(HttpRequest::Method::HTTP_GET, + "/isc/org", + HttpVersion(1, 1), + HostHttpHeader("www.example.org")))); + + ASSERT_NO_THROW(request->finalize()); + + EXPECT_EQ(HttpRequest::Method::HTTP_GET, request->getMethod()); + EXPECT_EQ("/isc/org", request->getUri()); + EXPECT_EQ(1, request->getHttpVersion().major_); + EXPECT_EQ(1, request->getHttpVersion().minor_); + + std::string host_hdr; + ASSERT_NO_THROW(host_hdr = request->getHeaderValue("Host")); + EXPECT_EQ("www.example.org", host_hdr); +} + TEST_F(HttpRequestTest, includeHeaders) { setContextBasics("POST", "/isc/org", HttpVersion(1, 0)); addHeaderToContext("Content-Length", "1024"); -- 2.47.2