libkea_http_la_SOURCES += header_context.h
libkea_http_la_SOURCES += http_acceptor.h
libkea_http_la_SOURCES += http_header.cc http_header.h
+libkea_http_la_SOURCES += http_message.cc http_message.h
libkea_http_la_SOURCES += http_types.h
libkea_http_la_SOURCES += listener.cc listener.h
libkea_http_la_SOURCES += post_request.cc post_request.h
libkea_http_la_SOURCES += request_context.h
libkea_http_la_SOURCES += request_parser.cc request_parser.h
libkea_http_la_SOURCES += response.cc response.h
+libkea_http_la_SOURCES += response_context.h
libkea_http_la_SOURCES += response_creator.cc response_creator.h
libkea_http_la_SOURCES += response_creator_factory.h
libkea_http_la_SOURCES += response_json.cc response_json.h
--- /dev/null
+// Copyright (C) 2017 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <http/http_message.h>
+
+namespace isc {
+namespace http {
+
+HttpMessage::HttpMessage()
+ : required_versions_(), http_version_(HttpVersion::HTTP_10()),
+ required_headers_(), created_(false), finalized_(false), headers_(),
+ body_() {
+}
+
+HttpMessage::~HttpMessage() {
+}
+
+void
+HttpMessage::requireHttpVersion(const HttpVersion& version) {
+ required_versions_.insert(version);
+}
+
+void
+HttpMessage::requireHeader(const std::string& header_name) {
+ // Empty value denotes that the header is required but no specific
+ // value is expected.
+ HttpHeaderPtr hdr(new HttpHeader(header_name));
+ required_headers_[hdr->getLowerCaseName()] = hdr;
+}
+
+void
+HttpMessage::requireHeaderValue(const std::string& header_name,
+ const std::string& header_value) {
+ HttpHeaderPtr hdr(new HttpHeader(header_name, header_value));
+ required_headers_[hdr->getLowerCaseName()] = hdr;
+}
+
+bool
+HttpMessage::requiresBody() const {
+ // If Content-Length is required the body must exist too. There may
+ // be probably some cases when Content-Length is not provided but
+ // the body is provided. But, probably not in our use cases.
+ // Use lower case header name because this is how it is indexed in
+ // the storage.
+ return (required_headers_.find("content-length") != required_headers_.end());
+}
+
+HttpVersion
+HttpMessage::getHttpVersion() const {
+ checkCreated();
+ return (http_version_);
+}
+
+HttpHeaderPtr
+HttpMessage::getHeader(const std::string& header_name) const {
+ HttpHeaderPtr http_header = getHeaderSafe(header_name);
+
+ // No such header.
+ if (!http_header) {
+ isc_throw(HttpMessageNonExistingHeader, header_name << " HTTP header"
+ " not found in the request");
+ }
+
+ // Header found.
+ return (http_header);
+}
+
+HttpHeaderPtr
+HttpMessage::getHeaderSafe(const std::string& header_name) const {
+ checkCreated();
+
+ HttpHeader hdr(header_name);
+ auto header_it = headers_.find(hdr.getLowerCaseName());
+ if (header_it != headers_.end()) {
+ return (header_it->second);
+ }
+
+ // Header not found. Return null pointer.
+ return (HttpHeaderPtr());
+}
+
+std::string
+HttpMessage::getHeaderValue(const std::string& header_name) const {
+ return (getHeader(header_name)->getValue());
+}
+
+uint64_t
+HttpMessage::getHeaderValueAsUint64(const std::string& header_name) const {
+ try {
+ return (getHeader(header_name)->getUint64Value());
+
+ } catch (const std::exception& ex) {
+ // The specified header does exist, but the value is not a number.
+ isc_throw(HttpMessageError, ex.what());
+ }
+}
+
+void
+HttpMessage::checkCreated() const {
+ if (!created_) {
+ isc_throw(HttpMessageError, "unable to retrieve values of HTTP"
+ " message because the HttpMessage::create() must be"
+ " called first. This is a programmatic error");
+ }
+}
+
+void
+HttpMessage::checkFinalized() const {
+ if (!finalized_) {
+ isc_throw(HttpMessageError, "unable to retrieve body of HTTP"
+ " message because the HttpMessage::finalize() must be"
+ " called first. This is a programmatic error");
+ }
+}
+
+} // end of namespace isc::http
+} // end of namespace isc
--- /dev/null
+// Copyright (C) 2017 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef HTTP_MESSAGE_H
+#define HTTP_MESSAGE_H
+
+#include <exceptions/exceptions.h>
+#include <http/http_header.h>
+#include <http/http_types.h>
+#include <map>
+#include <set>
+#include <stdint.h>
+#include <string>
+
+namespace isc {
+namespace http {
+
+/// @brief Generic exception thrown by @ref HttpMessage class.
+class HttpMessageError : public Exception {
+public:
+ HttpMessageError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when attempt is made to retrieve a
+/// non-existing header.
+class HttpMessageNonExistingHeader : public HttpMessageError {
+public:
+ HttpMessageNonExistingHeader(const char* file, size_t line,
+ const char* what) :
+ HttpMessageError(file, line, what) { };
+};
+
+
+/// @brief Base class for @ref HttpRequest and @ref HttpResponse.
+class HttpMessage {
+public:
+
+ /// @brief Constructor.
+ HttpMessage();
+
+ /// @brief Destructor.
+ virtual ~HttpMessage();
+
+ /// @brief Specifies HTTP version allowed.
+ ///
+ /// Allowed HTTP versions must be specified prior to calling @ref create
+ /// method. If no version is specified, all versions are allowed.
+ ///
+ /// @param version Version number allowed for the request.
+ void requireHttpVersion(const HttpVersion& version);
+
+ /// @brief Specifies a required HTTP header for the HTTP message.
+ ///
+ /// Required headers must be specified prior to calling @ref create method.
+ /// The specified header must exist in the received HTTP request. This puts
+ /// no requirement on the header value.
+ ///
+ /// @param header_name Required header name.
+ void requireHeader(const std::string& header_name);
+
+ /// @brief Specifies a required value of a header in the message.
+ ///
+ /// Required header values must be specified prior to calling @ref create
+ /// method. The specified header must exist and its value must be equal to
+ /// the value specified as second parameter.
+ ///
+ /// @param header_name HTTP header name.
+ /// @param header_value HTTP header value.
+ void requireHeaderValue(const std::string& header_name,
+ const std::string& header_value);
+
+ /// @brief Checks if the body is required for the HTTP message.
+ ///
+ /// Current implementation simply checks if the "Content-Length" header
+ /// is required.
+ ///
+ /// @return true if the body is required, false otherwise.
+ bool requiresBody() const;
+
+ /// @brief Reads parsed message from the context, validates the message and
+ /// stores parsed information.
+ ///
+ /// This method must be called before retrieving parsed data using accessors.
+ /// This method doesn't parse the HTTP request body.
+ virtual void create() = 0;
+
+ /// @brief Complete parsing HTTP message or creating an HTTP outbound message.
+ ///
+ /// This method is used in two situations: when a message has been received
+ /// into a context and may be fully parsed (including the body) or when the
+ /// data for the creation of the outbound message have been stored in a context
+ /// and the message can be now created from the context.
+ ///
+ /// This method should call @c create method if it hasn't been called yet and
+ /// then read the message body from the context and interpret it. If the body
+ /// doesn't adhere to the requirements for the message (in particular, when the
+ /// content type of the body is invalid) an exception should be thrown.
+ virtual void finalize() = 0;
+
+ /// @brief Reset the state of the object.
+ virtual void reset() = 0;
+
+ /// @brief Returns HTTP version number (major and minor).
+ HttpVersion getHttpVersion() const;
+
+ /// @brief Returns object encapsulating HTTP header.
+ ///
+ /// @param header_name HTTP header name.
+ ///
+ /// @return Non-null pointer to the header.
+ /// @throw HttpMessageNonExistingHeader if header with the specified name
+ /// doesn't exist.
+ /// @throw HttpMessageError if the request hasn't been created.
+ HttpHeaderPtr getHeader(const std::string& header_name) const;
+
+ /// @brief Returns object encapsulating HTTP header.
+ ///
+ /// This variant doesn't throw an exception if the header doesn't exist.
+ /// It will throw if the request hasn't been created using @c create()
+ /// method.
+ ///
+ /// @param header_name HTTP header name.
+ ///
+ /// @return Pointer to the specified header, or null if such header doesn't
+ /// exist.
+ /// @throw HttpMessageError if the request hasn't been created.
+ HttpHeaderPtr getHeaderSafe(const std::string& header_name) const;
+
+ /// @brief Returns a value of the specified HTTP header.
+ ///
+ /// @param header_name Name of the HTTP header.
+ ///
+ /// @throw HttpMessageError if the header doesn't exist.
+ std::string getHeaderValue(const std::string& header_name) const;
+
+ /// @brief Returns a value of the specified HTTP header as number.
+ ///
+ /// @param header_name Name of the HTTP header.
+ ///
+ /// @throw HttpMessageError if the header doesn't exist or if the
+ /// header value is not number.
+ uint64_t getHeaderValueAsUint64(const std::string& header_name) const;
+
+ /// @brief Returns HTTP message body as string.
+ virtual std::string getBody() const = 0;
+
+ /// @brief Returns HTTP message as text.
+ ///
+ /// This method is called to generate the outbound HTTP message. Make
+ /// sure to call @c finalize prior to calling this method.
+ virtual std::string toString() const = 0;
+
+ /// @brief Checks if the message has been successfully finalized.
+ ///
+ /// The message gets finalized on successful call to @c finalize.
+ ///
+ /// @return true if the message has been finalized, false otherwise.
+ bool isFinalized() const {
+ return (finalized_);
+ }
+
+ /// @brief Checks if the message indicates persistent connection.
+ ///
+ /// @return true if the message indicates persistent connection, false
+ /// otherwise.
+ virtual bool isPersistent() const = 0;
+
+protected:
+
+ /// @brief Checks if the @ref create was called.
+ ///
+ /// @throw HttpMessageError if @ref create wasn't called.
+ void checkCreated() const;
+
+ /// @brief Checks if the @ref finalize was called.
+ ///
+ /// @throw HttpMessageError if @ref finalize wasn't called.
+ void checkFinalized() const;
+
+ /// @brief Checks if the set is empty or the specified element belongs
+ /// to this set.
+ ///
+ /// This is a convenience method used by the class to verify that the
+ /// given HTTP method belongs to "required methods", HTTP version belongs
+ /// to "required versions" etc.
+ ///
+ /// @param element Reference to the element.
+ /// @param element_set Reference to the set of elements.
+ /// @tparam Element type, e.g. @ref Method, @ref HttpVersion etc.
+ ///
+ /// @return true if the element set is empty or if the element belongs
+ /// to the set.
+ template<typename T>
+ bool inRequiredSet(const T& element,
+ const std::set<T>& element_set) const {
+ return (element_set.empty() || element_set.count(element) > 0);
+ }
+
+ /// @brief Set of required HTTP versions.
+ ///
+ /// If the set is empty, all versions are allowed.
+ std::set<HttpVersion> required_versions_;
+
+ /// @brief HTTP version numbers.
+ HttpVersion http_version_;
+
+ /// @brief Map of HTTP headers indexed by lower case header names.
+ typedef std::map<std::string, HttpHeaderPtr> HttpHeaderMap;
+
+ /// @brief Map holding required HTTP headers.
+ ///
+ /// The key of this map specifies the lower case HTTP header name.
+ /// If the value of the HTTP header is empty, the header is required
+ /// but the value of the header is not checked. If the value is
+ /// non-empty, the value in the HTTP request must be equal (case
+ /// insensitive) to the value in the map.
+ HttpHeaderMap required_headers_;
+
+ /// @brief Flag indicating whether @ref create was called.
+ bool created_;
+
+ /// @brief Flag indicating whether @ref finalize was called.
+ bool finalized_;
+
+ /// @brief Parsed HTTP headers.
+ HttpHeaderMap headers_;
+
+ /// @brief HTTP body as string.
+ std::string body_;
+
+};
+
+} // end of namespace isc::http
+} // end of namespace isc
+
+#endif // HTTP_MESSAGE_H
void
PostHttpRequestJson::setBodyAsJson(const data::ConstElementPtr& body) {
if (body) {
- context()->body_ = body->str();
+ context_->body_ = body->str();
json_ = body;
} else {
- context()->body_.clear();
+ context_->body_.clear();
}
}
namespace http {
HttpRequest::HttpRequest()
- : required_methods_(),required_versions_(), required_headers_(),
- created_(false), finalized_(false), method_(Method::HTTP_METHOD_UNKNOWN),
- headers_(), context_(new HttpRequestContext()) {
-}
-
-HttpRequest::~HttpRequest() {
+ : HttpMessage(), required_methods_(),
+ method_(Method::HTTP_METHOD_UNKNOWN),
+ context_(new HttpRequestContext()) {
}
void
required_methods_.insert(method);
}
-void
-HttpRequest::requireHttpVersion(const HttpVersion& version) {
- required_versions_.insert(version);
-}
-
-void
-HttpRequest::requireHeader(const std::string& header_name) {
- // Empty value denotes that the header is required but no specific
- // value is expected.
- HttpHeaderPtr hdr(new HttpHeader(header_name));
- required_headers_[hdr->getLowerCaseName()] = hdr;
-}
-
-void
-HttpRequest::requireHeaderValue(const std::string& header_name,
- const std::string& header_value) {
- HttpHeaderPtr hdr(new HttpHeader(header_name, header_value));
- required_headers_[hdr->getLowerCaseName()] = hdr;
-}
-
-bool
-HttpRequest::requiresBody() const {
- // If Content-Length is required the body must exist too. There may
- // be probably some cases when Content-Length is not provided but
- // the body is provided. But, probably not in our use cases.
- // Use lower case header name because this is how it is indexed in
- // the storage.
- return (required_headers_.find("content-length") != required_headers_.end());
-}
-
void
HttpRequest::create() {
try {
<< " not allowed");
}
+ http_version_.major_ = context_->http_version_major_;
+ http_version_.minor_ = context_->http_version_minor_;
+
// Check if the HTTP version is allowed for this request.
- if (!inRequiredSet(HttpVersion(context_->http_version_major_,
- context_->http_version_minor_),
- required_versions_)) {
+ if (!inRequiredSet(http_version_, required_versions_)) {
isc_throw(BadValue, "use of HTTP version "
- << context_->http_version_major_ << "."
- << context_->http_version_minor_
+ << http_version_.major_ << "."
+ << http_version_.minor_
<< " not allowed");
}
create();
}
- // In this specific case, we don't need to do anything because the
- // body is retrieved from the context object directly. We also don't
- // know what type of body we have received. Derived classes should
- // override this method and handle various types of bodies.
+ // Copy the body from the context. Derive classes may further
+ // interpret the body contents, e.g. against the Content-Type.
+ body_ = context_->body_;
finalized_ = true;
}
finalized_ = false;
method_ = HttpRequest::Method::HTTP_METHOD_UNKNOWN;
headers_.clear();
+ body_.clear();
}
HttpRequest::Method
return (context_->uri_);
}
-HttpVersion
-HttpRequest::getHttpVersion() const {
- checkCreated();
- return (HttpVersion(context_->http_version_major_,
- context_->http_version_minor_));
-}
-
-HttpHeaderPtr
-HttpRequest::getHeader(const std::string& header_name) const {
- HttpHeaderPtr http_header = getHeaderSafe(header_name);
-
- // No such header.
- if (!http_header) {
- isc_throw(HttpRequestNonExistingHeader, header_name << " HTTP header"
- " not found in the request");
- }
-
- // Header found.
- return (http_header);
-}
-
-HttpHeaderPtr
-HttpRequest::getHeaderSafe(const std::string& header_name) const {
- checkCreated();
-
- HttpHeader hdr(header_name);
- auto header_it = headers_.find(hdr.getLowerCaseName());
- if (header_it != headers_.end()) {
- return (header_it->second);
- }
-
- // Header not found. Return null pointer.
- return (HttpHeaderPtr());
-}
-
-std::string
-HttpRequest::getHeaderValue(const std::string& header_name) const {
- return (getHeader(header_name)->getValue());
-}
-
-uint64_t
-HttpRequest::getHeaderValueAsUint64(const std::string& header_name) const {
- try {
- return (getHeader(header_name)->getUint64Value());
-
- } catch (const std::exception& ex) {
- // The specified header does exist, but the value is not a number.
- isc_throw(HttpRequestError, ex.what());
- }
-}
-
std::string
HttpRequest::getBody() const {
checkFinalized();
((HttpVersion::HTTP_10() < ver) && (conn_value.empty() || (conn_value != "close"))));
}
-void
-HttpRequest::checkCreated() const {
- if (!created_) {
- isc_throw(HttpRequestError, "unable to retrieve values of HTTP"
- " request because the HttpRequest::create() must be"
- " called first. This is a programmatic error");
- }
-}
-
-void
-HttpRequest::checkFinalized() const {
- if (!finalized_) {
- isc_throw(HttpRequestError, "unable to retrieve body of HTTP"
- " request because the HttpRequest::finalize() must be"
- " called first. This is a programmatic error");
- }
-}
-
-template<typename T>
-bool
-HttpRequest::inRequiredSet(const T& element,
- const std::set<T>& element_set) const {
- return (element_set.empty() || element_set.count(element) > 0);
-}
-
-
HttpRequest::Method
HttpRequest::methodFromString(std::string method) const {
boost::to_upper(method);
#ifndef HTTP_REQUEST_H
#define HTTP_REQUEST_H
-#include <exceptions/exceptions.h>
-#include <http/http_header.h>
-#include <http/http_types.h>
+#include <http/http_message.h>
#include <http/request_context.h>
#include <boost/shared_ptr.hpp>
-#include <map>
-#include <set>
#include <stdint.h>
-#include <string>
-#include <utility>
namespace isc {
namespace http {
/// @brief Generic exception thrown by @ref HttpRequest class.
-class HttpRequestError : public Exception {
+class HttpRequestError : public HttpMessageError {
public:
HttpRequestError(const char* file, size_t line, const char* what) :
- isc::Exception(file, line, what) { };
+ HttpMessageError(file, line, what) { };
};
/// @brief Exception thrown when attempt is made to retrieve a
/// @ref PostHttpRequestJson, which derives from @ref PostHttpRequest requires
/// that the POST message includes body holding a JSON structure and provides
/// methods to parse the JSON body.
-class HttpRequest {
+class HttpRequest : public HttpMessage {
public:
/// @brief HTTP methods.
/// Creates new context (@ref HttpRequestContext).
HttpRequest();
- /// @brief Destructor.
- virtual ~HttpRequest();
-
/// @brief Returns reference to the @ref HttpRequestContext.
///
- /// This method is called by the @ref HttpRequestParser to retrieve the
- /// context in which parsed data is stored.
+ /// The context holds intermediate data for creating a request. The request
+ /// parser stores parsed raw data in the context. When parsing is finished,
+ /// the data are validated and committed into the @ref HttpRequest.
///
/// @return Pointer to the underlying @ref HttpRequestContext.
const HttpRequestContextPtr& context() const {
/// @param method HTTP method allowed for the request.
void requireHttpMethod(const HttpRequest::Method& method);
- /// @brief Specifies HTTP version allowed.
- ///
- /// Allowed HTTP versions must be specified prior to calling @ref create
- /// method. If no version is specified, all versions are allowed.
- ///
- /// @param version Version number allowed for the request.
- void requireHttpVersion(const HttpVersion& version);
-
- /// @brief Specifies a required HTTP header for the request.
- ///
- /// Required headers must be specified prior to calling @ref create method.
- /// The specified header must exist in the received HTTP request. This puts
- /// no requirement on the header value.
- ///
- /// @param header_name Required header name.
- void requireHeader(const std::string& header_name);
-
- /// @brief Specifies a required value of a header in the request.
- ///
- /// Required header values must be specified prior to calling @ref create
- /// method. The specified header must exist and its value must be equal to
- /// the value specified as second parameter.
- ///
- /// @param header_name HTTP header name.
- /// @param header_value HTTP header valuae.
- void requireHeaderValue(const std::string& header_name,
- const std::string& header_value);
-
- /// @brief Checks if the body is required for the HTTP request.
- ///
- /// Current implementation simply checks if the "Content-Length" header
- /// is required for the request.
- ///
- /// @return true if the body is required for this request.
- bool requiresBody() const;
-
/// @brief Reads parsed request from the @ref HttpRequestContext, validates
/// the request and stores parsed information.
///
/// @brief Reset the state of the object.
virtual void reset();
- /// @name HTTP data accessors.
- ///
- //@{
/// @brief Returns HTTP method of the request.
Method getMethod() const;
/// @brief Returns HTTP request URI.
std::string getUri() const;
- /// @brief Returns HTTP version number (major and minor).
- HttpVersion getHttpVersion() const;
-
- /// @brief Returns object encapsulating HTTP header.
- ///
- /// @param header_name HTTP header name.
- ///
- /// @return Non-null pointer to the header.
- /// @throw HttpRequestNonExistingHeader if header with the specified name
- /// doesn't exist.
- /// @throw HttpRequestError if the request hasn't been created.
- HttpHeaderPtr getHeader(const std::string& header_name) const;
-
- /// @brief Returns object encapsulating HTTP header.
- ///
- /// This variant doesn't throw an exception if the header doesn't exist.
- /// It will throw if the request hasn't been created using @c create()
- /// method.
- ///
- /// @param header_name HTTP header name.
- ///
- /// @return Pointer to the specified header, or null if such header doesn't
- /// exist.
- /// @throw HttpRequestError if the request hasn't been created.
- HttpHeaderPtr getHeaderSafe(const std::string& header_name) const;
-
- /// @brief Returns a value of the specified HTTP header.
- ///
- /// @param header_name Name of the HTTP header.
- ///
- /// @throw HttpRequestError if the header doesn't exist.
- std::string getHeaderValue(const std::string& header_name) const;
-
- /// @brief Returns a value of the specified HTTP header as number.
- ///
- /// @param header_name Name of the HTTP header.
- ///
- /// @throw HttpRequestError if the header doesn't exist or if the
- /// header value is not number.
- uint64_t getHeaderValueAsUint64(const std::string& header_name) const;
/// @brief Returns HTTP message body as string.
std::string getBody() const;
/// @brief Returns HTTP message as text.
///
- /// This method is called to generate the outbound HTTP message to be sent
- /// to a server. Make sure to call @c HttpRequest::finalize prior to
- /// calling this method.
+ /// This method is called to generate the outbound HTTP message. Make
+ /// sure to call @c finalize prior to calling this method.
virtual std::string toString() const;
- /// @brief Checks if the request has been successfully finalized.
- ///
- /// The request is gets finalized on successful call to
- /// @ref HttpRequest::finalize.
- ///
- /// @return true if the request has been finalized, false otherwise.
- bool isFinalized() const {
- return (finalized_);
- }
/// @brief Checks if the client has requested persistent connection.
///
/// otherwise.
bool isPersistent() const;
- //@}
-
protected:
- /// @brief Checks if the @ref create was called.
- ///
- /// @throw HttpRequestError if @ref create wasn't called.
- void checkCreated() const;
-
- /// @brief Checks if the @ref finalize was called.
- ///
- /// @throw HttpRequestError if @ref finalize wasn't called.
- void checkFinalized() const;
-
- /// @brief Checks if the set is empty or the specified element belongs
- /// to this set.
- ///
- /// This is a convenience method used by the class to verify that the
- /// given HTTP method belongs to "required methods", HTTP version belongs
- /// to "required versions" etc.
- ///
- /// @param element Reference to the element.
- /// @param element_set Reference to the set of elements.
- /// @tparam Element type, e.g. @ref Method, @ref HttpVersion etc.
- ///
- /// @return true if the element set is empty or if the element belongs
- /// to the set.
- template<typename T>
- bool inRequiredSet(const T& element,
- const std::set<T>& element_set) const;
-
/// @brief Converts HTTP method specified in textual format to @ref Method.
///
/// @param method HTTP method specified in the textual format. This value
/// If the set is empty, all methods are allowed.
std::set<Method> required_methods_;
- /// @brief Set of required HTTP versions.
- ///
- /// If the set is empty, all versions are allowed.
- std::set<HttpVersion> required_versions_;
-
- /// @brief Map of HTTP headers indexed by lower case header names.
- typedef std::map<std::string, HttpHeaderPtr> HttpHeaderMap;
-
- /// @brief Map holding required HTTP headers.
- ///
- /// The key of this map specifies the lower case HTTP header name.
- /// If the value of the HTTP header is empty, the header is required
- /// but the value of the header is not checked. If the value is
- /// non-empty, the value in the HTTP request must be equal (case
- /// insensitive) to the value in the map.
- HttpHeaderMap required_headers_;
-
- /// @brief Flag indicating whether @ref create was called.
- bool created_;
-
- /// @brief Flag indicating whether @ref finalize was called.
- bool finalized_;
-
/// @brief HTTP method of the request.
Method method_;
- /// @brief Parsed HTTP headers.
- HttpHeaderMap headers_;
-
/// @brief Pointer to the @ref HttpRequestContext holding parsed
/// data.
HttpRequestContextPtr context_;
const HttpStatusCode& status_code,
const CallSetGenericBody& generic_body)
: http_version_(version), status_code_(status_code), headers_(),
- body_() {
+ body_(), context_(new HttpResponseContext()) {
if (generic_body.set_) {
// This currently does nothing, but it is useful to have it here as
// an example how to implement it in the derived classes.
}
}
+void
+HttpResponse::create() {
+}
+
void
HttpResponse::setBody(const std::string& body) {
body_ = body;
#include <exceptions/exceptions.h>
#include <http/http_types.h>
+#include <http/response_context.h>
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <cstdint>
/// A class having virtual methods must have a virtual destructor.
virtual ~HttpResponse() { }
+ /// @brief Returns pointer to the @ref HttpResponseContext.
+ ///
+ /// The context holds intermediate data for creating a response. The response
+ /// parser stores parsed raw data in the context. When parsing is finished,
+ /// the data are validated and committed into the @ref HttpResponse.
+ ///
+ /// @return Pointer to the underlying @ref HttpResponseContext.
+ const HttpResponseContextPtr& context() const {
+ return (context_);
+ }
+
/// @brief Adds HTTP header to the response.
///
/// The "Content-Length" and "Date" headers should not be added using this
addHeaderInternal(name, value, headers_);
}
+ /// @brief Reads parsed response from the @ref HttpResponseContext, validates
+ /// the response and stores parsed information.
+ ///
+ /// This method doesn't prse the HTTP response body.
+ virtual void create();
+
/// @brief Assigns body/content to the message.
///
/// @param body Body to be assigned.
/// @brief Holds the body/content.
std::string body_;
+ /// @brief Pointer to the @ref HttpResponseContext holding parsed
+ /// data.
+ HttpResponseContextPtr context_;
};
} // namespace http
--- /dev/null
+// Copyright (C) 2017 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef HTTP_RESPONSE_CONTEXT_H
+#define HTTP_RESPONSE_CONTEXT_H
+
+#include <http/header_context.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace http {
+
+/// @brief HTTP response context.
+///
+/// This context is used by the @ref HttpResponseParser to store parsed
+/// data. This data is later used to create an instance of the
+/// @ref HttpResponse or its derivation.
+struct HttpResponseContext {
+ /// @brief HTTP major version number.
+ unsigned int http_version_major_;
+ /// @brief HTTP minor version number.
+ unsigned int http_version_minor_;
+ /// @brief HTTP status code.
+ uint16_t status_code_;
+ /// @brief Collection of HTTP headers.
+ std::vector<HttpHeaderContext> headers_;
+ /// @brief HTTP request body.
+ std::string body_;
+};
+
+/// @brief Pointer to the @ref HttpResponseContext.
+typedef boost::shared_ptr<HttpResponseContext> HttpResponseContextPtr;
+
+} // end of namespace http
+} // end of namespace isc
+
+#endif // endif HTTP_RESPONSE_CONTEXT_H
ElementPtr json = Element::fromJSON(json_body_);
request_.setBodyAsJson(json);
+
// Commit and validate the data.
ASSERT_NO_THROW(request_.finalize());
EXPECT_EQ(1, request_.getHttpVersion().minor_);
EXPECT_THROW(request_.getHeaderValue("Content-Length"),
- HttpRequestNonExistingHeader);
+ HttpMessageNonExistingHeader);
}
TEST_F(HttpRequestTest, includeHeaders) {
addHeaderToContext("Content-Type", "text/html");
addHeaderToContext("Content-Length", "1024");
- EXPECT_THROW(static_cast<void>(request_.getMethod()), HttpRequestError);
+ EXPECT_THROW(static_cast<void>(request_.getMethod()), HttpMessageError);
EXPECT_THROW(static_cast<void>(request_.getHttpVersion()),
- HttpRequestError);
- EXPECT_THROW(static_cast<void>(request_.getUri()), HttpRequestError);
+ HttpMessageError);
+ EXPECT_THROW(static_cast<void>(request_.getUri()), HttpMessageError);
EXPECT_THROW(static_cast<void>(request_.getHeaderValue("Content-Type")),
- HttpRequestError);
+ HttpMessageError);
EXPECT_THROW(static_cast<void>(request_.getHeaderValueAsUint64("Content-Length")),
- HttpRequestError);
- EXPECT_THROW(static_cast<void>(request_.getBody()), HttpRequestError);
+ HttpMessageError);
+ EXPECT_THROW(static_cast<void>(request_.getBody()), HttpMessageError);
ASSERT_NO_THROW(request_.finalize());