response.h 8.1 KB

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