summaryrefslogtreecommitdiffstats
path: root/src/lib/http/response.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/http/response.h')
-rw-r--r--src/lib/http/response.h247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/lib/http/response.h b/src/lib/http/response.h
new file mode 100644
index 0000000..734d92f
--- /dev/null
+++ b/src/lib/http/response.h
@@ -0,0 +1,247 @@
+// Copyright (C) 2016-2022 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_H
+#define HTTP_RESPONSE_H
+
+#include <cc/data.h>
+#include <http/header_context.h>
+#include <http/http_message.h>
+#include <http/response_context.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace http {
+
+/// @brief Generic exception thrown by @ref HttpResponse class.
+class HttpResponseError : public HttpMessageError {
+public:
+ HttpResponseError(const char* file, size_t line, const char* what) :
+ HttpMessageError(file, line, what) { };
+};
+
+/// @brief HTTP status codes (cf RFC 2068)
+enum class HttpStatusCode : std::uint16_t {
+ OK = 200,
+ CREATED = 201,
+ ACCEPTED = 202,
+ NO_CONTENT = 204,
+ MULTIPLE_CHOICES = 300,
+ MOVED_PERMANENTLY = 301,
+ MOVED_TEMPORARILY = 302,
+ NOT_MODIFIED = 304,
+ BAD_REQUEST = 400,
+ UNAUTHORIZED = 401,
+ FORBIDDEN = 403,
+ NOT_FOUND = 404,
+ REQUEST_TIMEOUT = 408,
+ INTERNAL_SERVER_ERROR = 500,
+ NOT_IMPLEMENTED = 501,
+ BAD_GATEWAY = 502,
+ SERVICE_UNAVAILABLE = 503
+};
+
+/// @brief Encapsulates the boolean value indicating if the @ref HttpResponse
+/// constructor should call its @c setGenericBody method during construction.
+struct CallSetGenericBody {
+
+ /// @brief Constructor.
+ ///
+ /// @param set A boolean value indicating if the method should be called
+ /// or not.
+ explicit CallSetGenericBody(const bool set)
+ : set_(set) {
+ }
+
+ /// @brief Returns encapsulated true.
+ static const CallSetGenericBody& yes() {
+ static CallSetGenericBody yes(true);
+ return (yes);
+ }
+
+ /// @brief Returns encapsulated false.
+ static const CallSetGenericBody& no() {
+ static CallSetGenericBody no(false);
+ return (no);
+ }
+
+ /// @brief A storage for the boolean flag.
+ bool set_;
+};
+
+class HttpResponse;
+
+/// @brief Pointer to the @ref HttpResponse object.
+typedef boost::shared_ptr<HttpResponse> HttpResponsePtr;
+
+/// @brief Pointer to the const @ref HttpResponse object.
+typedef boost::shared_ptr<const HttpResponse> ConstHttpResponsePtr;
+
+/// @brief Represents HTTP response message.
+///
+/// This derivation of the @c HttpMessage class is specialized to represent
+/// HTTP responses. This class provides two constructors for creating an inbound
+/// and outbound response instance respectively. This class is associated with
+/// an instance of the @c HttpResponseContext, which is used to provide response
+/// specific values, such as HTTP status and headers.
+///
+/// The derivations of this class provide specializations and specify the HTTP
+/// versions and headers supported/required in the specific use cases. For example,
+/// the @c HttpResponseJson class derives from the @c HttpResponse and it requires
+/// that response includes a body in the JSON format.
+class HttpResponse : public HttpMessage {
+public:
+
+ /// @brief Constructor for the inbound HTTP response.
+ explicit HttpResponse();
+
+
+ /// @brief Constructor for outbound HTTP response.
+ ///
+ /// Creates basic instance of the object. It sets the HTTP version and the
+ /// status code to be included in the response.
+ ///
+ /// @param version HTTP version.
+ /// @param status_code HTTP status code.
+ /// @param generic_body Indicates if the constructor should call
+ /// @c setGenericBody to create a generic content for the given
+ /// status code. This should be set to "no" when the constructor is
+ /// called by the derived class which provides its own implementation
+ /// of the @c setGenericBody method.
+ explicit HttpResponse(const HttpVersion& version,
+ const HttpStatusCode& status_code,
+ const CallSetGenericBody& generic_body =
+ CallSetGenericBody::yes());
+
+ /// @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 @c HttpResponse.
+ ///
+ /// @return Pointer to the underlying @ref HttpResponseContext.
+ const HttpResponseContextPtr& context() const {
+ return (context_);
+ }
+
+ /// @brief Commits information held in the context into the response.
+ ///
+ /// This function reads HTTP version, status code and headers from the
+ /// context and validates their values. For the outbound messages, it
+ /// automatically appends Content-Length and Date headers to the response.
+ /// The Content-Length is set to the body size. The Date is set to the
+ /// current date and time.
+ virtual void create();
+
+ /// @brief Completes creation of the HTTP response.
+ ///
+ /// This method marks the response as finalized. The outbound response may now
+ /// be sent over the TCP socket. The information from the inbound message may
+ /// be read, including the response body.
+ virtual void finalize();
+
+ /// @brief Reset the state of the object.
+ virtual void reset();
+
+ /// @brief Returns HTTP status code.
+ HttpStatusCode getStatusCode() const;
+
+ /// @brief Returns HTTP status phrase.
+ std::string getStatusPhrase() const;
+
+ /// @brief Returns HTTP response body as string.
+ virtual std::string getBody() const;
+
+ /// @brief Retrieves a single JSON element.
+ ///
+ /// The element must be at top level of the JSON structure.
+ ///
+ /// @param element_name Element name.
+ ///
+ /// @return Pointer to the specified element or NULL if such element
+ /// doesn't exist.
+ /// @throw HttpResponseJsonError if an error occurred.
+ data::ConstElementPtr getJsonElement(const std::string& element_name) const;
+
+ /// @brief Checks if the status code indicates client error.
+ ///
+ /// @param status_code HTTP status code.
+ /// @return true if the status code indicates client error.
+ static bool isClientError(const HttpStatusCode& status_code);
+
+ /// @brief Checks if the status code indicates server error.
+ ///
+ /// @param status_code HTTP status code.
+ /// @return true if the status code indicates server error.
+ static bool isServerError(const HttpStatusCode& status_code);
+
+ /// @brief Convenience method converting status code to numeric value.
+ ///
+ /// @param status_code Status code represented as enum.
+ /// @return Numeric representation of the status code.
+ static uint16_t statusCodeToNumber(const HttpStatusCode& status_code);
+
+ /// @brief Converts status code to string.
+ ///
+ /// @param status_code HTTP status code.
+ /// @return Textual representation of the status code.
+ static std::string statusCodeToString(const HttpStatusCode& status_code);
+
+ /// @brief Returns HTTP version and HTTP status as a string.
+ std::string toBriefString() const;
+
+ /// @brief Returns HTTP response as string.
+ ///
+ /// This method is called to generate the outbound HTTP response. Make
+ /// sure to call @c finalize prior to calling this method.
+ virtual std::string toString() const;
+
+ /// @brief Returns current time formatted as required by RFC 1123.
+ ///
+ /// This method is virtual so as it can be overridden in unit tests
+ /// to return a "predictable" value of time, e.g. constant value.
+ ///
+ /// @return Current time formatted as required by RFC 1123.
+ virtual std::string getDateHeaderValue() const;
+
+private:
+
+ /// @brief Sets generic body for the given status code.
+ ///
+ /// Most of the classes derived from @ref HttpResponse will expect
+ /// a certain content type. Depending on the content type used they
+ /// will use different body formats for error messages. For example,
+ /// a response using text/html will use HTML within the response
+ /// body. The application/json will use JSON body etc. There is a
+ /// need to implement class specific way of generating the body
+ /// for error messages. Thus, each derivation of this class is
+ /// required to implement class specific @ref setGenericBody function
+ /// which should be called in the class constructor.
+ ///
+ /// This is also the case for this class, though the implementation
+ /// of @c setGenericBody is currently no-op.
+ ///
+ /// Note that this class can't be declared virtual because it is
+ /// meant to be called from the class constructor.
+ ///
+ /// @param status_code Status code for which the body should be
+ /// generated.
+ void setGenericBody(const HttpStatusCode& /*status_code*/) { };
+
+protected:
+
+ /// @brief Pointer to the @ref HttpResponseContext holding parsed
+ /// data.
+ HttpResponseContextPtr context_;
+};
+
+} // namespace http
+} // namespace isc
+
+#endif