response.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef HTTP_RESPONSE_H
  7. #define HTTP_RESPONSE_H
  8. #include <exceptions/exceptions.h>
  9. #include <http/http_types.h>
  10. #include <boost/lexical_cast.hpp>
  11. #include <boost/shared_ptr.hpp>
  12. #include <cstdint>
  13. #include <map>
  14. #include <string>
  15. namespace isc {
  16. namespace http {
  17. /// @brief Generic exception thrown by @ref HttpResponse class.
  18. class HttpResponseError : public Exception {
  19. public:
  20. HttpResponseError(const char* file, size_t line, const char* what) :
  21. isc::Exception(file, line, what) { };
  22. };
  23. /// @brief HTTP status codes (cf RFC 2068)
  24. enum class HttpStatusCode : std::uint16_t {
  25. OK = 200,
  26. CREATED = 201,
  27. ACCEPTED = 202,
  28. NO_CONTENT = 204,
  29. MULTIPLE_CHOICES = 300,
  30. MOVED_PERMANENTLY = 301,
  31. MOVED_TEMPORARILY = 302,
  32. NOT_MODIFIED = 304,
  33. BAD_REQUEST = 400,
  34. UNAUTHORIZED = 401,
  35. FORBIDDEN = 403,
  36. NOT_FOUND = 404,
  37. REQUEST_TIMEOUT = 408,
  38. INTERNAL_SERVER_ERROR = 500,
  39. NOT_IMPLEMENTED = 501,
  40. BAD_GATEWAY = 502,
  41. SERVICE_UNAVAILABLE = 503
  42. };
  43. /// @brief Encapsulates the boolean value indicating if the @ref HttpResponse
  44. /// constructor should call its @c setGenericBody method during construction.
  45. struct CallSetGenericBody {
  46. /// @brief Constructor.
  47. ///
  48. /// @param set A boolean value indicating if the method should be called
  49. /// or not.
  50. explicit CallSetGenericBody(const bool set)
  51. : set_(set) {
  52. }
  53. /// @brief Returns encapsulated true.
  54. static const CallSetGenericBody& yes() {
  55. static CallSetGenericBody yes(true);
  56. return (yes);
  57. }
  58. /// @brief Returns encapsulated false.
  59. static const CallSetGenericBody& no() {
  60. static CallSetGenericBody no(false);
  61. return (no);
  62. }
  63. /// @brief A storage for the boolean flag.
  64. bool set_;
  65. };
  66. class HttpResponse;
  67. /// @brief Pointer to the @ref HttpResponse object.
  68. typedef boost::shared_ptr<HttpResponse> HttpResponsePtr;
  69. /// @brief Pointer to the const @ref HttpResponse object.
  70. typedef boost::shared_ptr<const HttpResponse> ConstHttpResponsePtr;
  71. /// @brief Represents HTTP response message.
  72. ///
  73. /// This class represents HTTP response message. An instance of this object
  74. /// or its derivation is typically created by the implementation of the
  75. /// @ref HttpResponseCreator interface.
  76. ///
  77. /// It contains @c toString method generating a textual representation of
  78. /// the HTTP response, which is send to the client over TCP socket.
  79. class HttpResponse {
  80. public:
  81. /// @brief Constructor.
  82. ///
  83. /// Creates basic instance of the object. It sets the HTTP version and the
  84. /// status code to be included in the response.
  85. ///
  86. /// @param version HTTP version.
  87. /// @param status_code HTTP status code.
  88. /// @param generic_body Indicates if the constructor should call
  89. /// @c setGenericBody to create a generic content for the given
  90. /// status code. This should be set to "no" when the constructor is
  91. /// called by the derived class which provides its own implementation
  92. /// of the @c setGenericBody method.
  93. explicit HttpResponse(const HttpVersion& version,
  94. const HttpStatusCode& status_code,
  95. const CallSetGenericBody& generic_body =
  96. CallSetGenericBody::yes());
  97. /// @brief Destructor.
  98. ///
  99. /// A class having virtual methods must have a virtual destructor.
  100. virtual ~HttpResponse() { }
  101. /// @brief Adds HTTP header to the response.
  102. ///
  103. /// The "Content-Length" and "Date" headers should not be added using this
  104. /// method because they are generated and added automatically when the
  105. /// @c toString is called.
  106. ///
  107. /// @param name Header name.
  108. /// @param value Header value.
  109. /// @tparam ValueType Type of the header value.
  110. template<typename ValueType>
  111. void addHeader(const std::string& name, const ValueType& value) {
  112. addHeaderInternal(name, value, headers_);
  113. }
  114. /// @brief Assigns body/content to the message.
  115. ///
  116. /// @param body Body to be assigned.
  117. void setBody(const std::string& body);
  118. /// @brief Checks if the status code indicates client error.
  119. ///
  120. /// @param status_code HTTP status code.
  121. /// @return true if the status code indicates client error.
  122. static bool isClientError(const HttpStatusCode& status_code);
  123. /// @brief Checks if the status code indicates server error.
  124. ///
  125. /// @param status_code HTTP status code.
  126. /// @return true if the status code indicates server error.
  127. static bool isServerError(const HttpStatusCode& status_code);
  128. /// @brief Converts status code to string.
  129. ///
  130. /// @param status_code HTTP status code.
  131. /// @return Textual representation of the status code.
  132. static std::string statusCodeToString(const HttpStatusCode& status_code);
  133. /// @brief Returns textual representation of the HTTP response.
  134. ///
  135. /// It includes the "Date" header with the current time in RFC 1123 format.
  136. /// It also includes "Content-Length" when the response has a non-empty
  137. /// body.
  138. ///
  139. /// @return Textual representation of the HTTP response.
  140. std::string toString() const ;
  141. protected:
  142. /// @brief Adds HTTP header to the map.
  143. ///
  144. /// @param name Header name.
  145. /// @param value Header value.
  146. /// @param [out] headers A map to which header value should be inserted.
  147. /// @tparam ValueType Type of the header value.
  148. template<typename ValueType>
  149. void addHeaderInternal(const std::string& name, const ValueType& value,
  150. std::map<std::string, std::string>& headers) const {
  151. try {
  152. headers[name] = boost::lexical_cast<std::string>(value);
  153. } catch (const boost::bad_lexical_cast& ex) {
  154. isc_throw(HttpResponseError, "unable to convert the "
  155. << name << " header value to a string");
  156. }
  157. }
  158. /// @brief Returns current time formatted as required by RFC 1123.
  159. ///
  160. /// This method is virtual so as it can be overridden in unit tests
  161. /// to return a "predictable" value of time, e.g. constant value.
  162. ///
  163. /// @return Current time formatted as required by RFC 1123.
  164. virtual std::string getDateHeaderValue() const;
  165. /// @brief Convenience method converting status code to numeric value.
  166. ///
  167. /// @param status_code Status code represented as enum.
  168. /// @return Numeric representation of the status code.
  169. static uint16_t statusCodeToNumber(const HttpStatusCode& status_code);
  170. private:
  171. /// @brief Sets generic body for the given status code.
  172. ///
  173. /// Most of the classes derived from @ref HttpResponse will expect
  174. /// a certain content type. Depending on the content type used they
  175. /// will use different body formats for error messages. For example,
  176. /// a response using text/html will use HTML within the response
  177. /// body. The application/json will use JSON body etc. There is a
  178. /// need to implement class specific way of generating the body
  179. /// for error messages. Thus, each derivation of this class is
  180. /// required to implement class specific @ref setGenericBody function
  181. /// which should be called in the class constructor.
  182. ///
  183. /// This is also the case for this class, though the implementation
  184. /// of @c setGenericBody is currently no-op.
  185. ///
  186. /// Note that this class can't be declared virtual because it is
  187. /// meant to be called from the class constructor.
  188. ///
  189. /// @param status_code Status code for which the body should be
  190. /// generated.
  191. void setGenericBody(const HttpStatusCode& /*status_code*/) { };
  192. /// @brief Holds HTTP version for the response.
  193. HttpVersion http_version_;
  194. /// @brief Holds status code for the response.
  195. HttpStatusCode status_code_;
  196. /// @brief Holds HTTP headers for the response.
  197. std::map<std::string, std::string> headers_;
  198. /// @brief Holds the body/content.
  199. std::string body_;
  200. };
  201. } // namespace http
  202. } // namespace isc
  203. #endif