Kea  1.9.9-git
response.cc
Go to the documentation of this file.
1 // Copyright (C) 2016-2018 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 
7 #include <config.h>
8 
9 #include <http/date_time.h>
10 #include <http/response.h>
11 #include <boost/date_time/local_time/local_time.hpp>
12 #include <boost/date_time/time_facet.hpp>
13 #include <sstream>
14 
15 using namespace boost::local_time;
16 using namespace isc::http;
17 
18 namespace {
19 
21 const std::map<HttpStatusCode, std::string> status_code_to_description = {
22  { HttpStatusCode::OK, "OK" },
23  { HttpStatusCode::CREATED, "Created" },
24  { HttpStatusCode::ACCEPTED, "Accepted" },
25  { HttpStatusCode::NO_CONTENT, "No Content" },
26  { HttpStatusCode::MULTIPLE_CHOICES, "Multiple Choices" },
27  { HttpStatusCode::MOVED_PERMANENTLY, "Moved Permanently" },
28  { HttpStatusCode::MOVED_TEMPORARILY, "Moved Temporarily" },
29  { HttpStatusCode::NOT_MODIFIED, "Not Modified" },
30  { HttpStatusCode::BAD_REQUEST, "Bad Request" },
31  { HttpStatusCode::UNAUTHORIZED, "Unauthorized" },
32  { HttpStatusCode::FORBIDDEN, "Forbidden" },
33  { HttpStatusCode::NOT_FOUND, "Not Found" },
34  { HttpStatusCode::REQUEST_TIMEOUT, "Request Timeout" },
35  { HttpStatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error" },
36  { HttpStatusCode::NOT_IMPLEMENTED, "Not Implemented" },
37  { HttpStatusCode::BAD_GATEWAY, "Bad Gateway" },
38  { HttpStatusCode::SERVICE_UNAVAILABLE, "Service Unavailable" }
39 };
40 
42 const std::string crlf = "\r\n";
43 
44 }
45 
46 namespace isc {
47 namespace http {
48 
49 HttpResponse::HttpResponse()
50  : HttpMessage(INBOUND), context_(new HttpResponseContext()) {
51 }
52 
54  const HttpStatusCode& status_code,
55  const CallSetGenericBody& generic_body)
56  : HttpMessage(OUTBOUND), context_(new HttpResponseContext()) {
57  context_->http_version_major_ = version.major_;
58  context_->http_version_minor_ = version.minor_;
59  context_->status_code_ = static_cast<unsigned int>(status_code);
60 
61  if (generic_body.set_) {
62  // This currently does nothing, but it is useful to have it here as
63  // an example how to implement it in the derived classes.
64  setGenericBody(status_code);
65  }
66 }
67 
68 void
70  try {
71  http_version_.major_ = context_->http_version_major_;
72  http_version_.minor_ = context_->http_version_minor_;
73 
74  // Check if the HTTP version is allowed for this request.
76  isc_throw(BadValue, "use of HTTP version "
77  << http_version_.major_ << "."
79  << " not allowed");
80  }
81 
82  // Copy headers from the context.
83  for (auto header = context_->headers_.begin();
84  header != context_->headers_.end();
85  ++header) {
86  HttpHeaderPtr hdr(new HttpHeader(header->name_, header->value_));
87  headers_[hdr->getLowerCaseName()] = hdr;
88  }
89 
91  HttpHeaderPtr length_header(new HttpHeader("Content-Length", boost::lexical_cast<std::string>
92  (context_->body_.length())));
93  headers_["content-length"] = length_header;
94 
95  HttpHeaderPtr date_header(new HttpHeader("Date", getDateHeaderValue()));;
96  headers_["date"] = date_header;
97  }
98 
99  // Iterate over required headers and check that they exist
100  // in the HTTP response.
101  for (auto req_header = required_headers_.begin();
102  req_header != required_headers_.end();
103  ++req_header) {
104  auto header = headers_.find(req_header->first);
105  if (header == headers_.end()) {
106  isc_throw(BadValue, "required header " << req_header->first
107  << " not found in the HTTP response");
108  } else if (!req_header->second->getValue().empty() &&
109  !header->second->isValueEqual(req_header->second->getValue())) {
110  // If specific value is required for the header, check
111  // that the value in the HTTP response matches it.
112  isc_throw(BadValue, "required header's " << header->first
113  << " value is " << req_header->second->getValue()
114  << ", but " << header->second->getValue() << " was found");
115  }
116  }
117 
118  } catch (const std::exception& ex) {
119  // Reset the state of the object if we failed at any point.
120  reset();
122  }
123 
124  // All ok.
125  created_ = true;
126 }
127 
128 void
130  if (!created_) {
131  create();
132  }
133 
134  finalized_ = true;
135 }
136 
137 void
139  created_ = false;
140  finalized_ = false;
141  headers_.clear();
142 }
143 
146  checkCreated();
147  return (static_cast<HttpStatusCode>(context_->status_code_));
148 }
149 
150 std::string
152  checkCreated();
153  return (context_->phrase_);
154 }
155 
156 std::string
158  checkFinalized();
159  return (context_->body_);
160 }
161 
162 bool
164  // Client errors have status codes of 4XX.
165  uint16_t c = statusCodeToNumber(status_code);
166  return ((c >= 400) && (c < 500));
167 }
168 
169 bool
171  // Server errors have status codes of 5XX.
172  uint16_t c = statusCodeToNumber(status_code);
173  return ((c >= 500) && (c < 600));
174 }
175 
176 std::string
178  auto status_code_it = status_code_to_description.find(status_code);
179  if (status_code_it == status_code_to_description.end()) {
180  isc_throw(HttpResponseError, "internal server error: no HTTP status"
181  " description for the given status code "
182  << static_cast<uint16_t>(status_code));
183  }
184  return (status_code_it->second);
185 }
186 
187 uint16_t
189  return (static_cast<uint16_t>(status_code));
190 }
191 
192 std::string
194  // This returns current time in the recommended format.
195  HttpDateTime date_time;
196  return (date_time.rfc1123Format());
197 }
198 
199 std::string
201  checkFinalized();
202 
203  std::ostringstream s;
204  // HTTP version number and status code.
205  s << "HTTP/" << http_version_.major_ << "." << http_version_.minor_;
206  s << " " << context_->status_code_;
207  s << " " << statusCodeToString(static_cast<HttpStatusCode>(context_->status_code_));
208  return (s.str());
209 }
210 
211 std::string
213 
214  std::ostringstream s;
215  // HTTP version number and status code.
216  s << toBriefString() << crlf;
217 
218  for (auto header_it = headers_.cbegin(); header_it != headers_.cend();
219  ++header_it) {
220  s << header_it->second->getName() << ": " << header_it->second->getValue()
221  << crlf;
222  }
223 
224  s << crlf;
225 
226  // Include message body.
227  s << getBody();
228 
229  return (s.str());
230 }
231 
232 } // namespace http
233 } // namespace isc
boost::shared_ptr< HttpHeader > HttpHeaderPtr
Pointer to the HttpHeader class.
Definition: http_header.h:65
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
Definition: date_time.cc:30
virtual void finalize()
Completes creation of the HTTP response.
Definition: response.cc:129
Direction getDirection() const
Returns HTTP message direction.
Definition: http_message.h:80
static bool isClientError(const HttpStatusCode &status_code)
Checks if the status code indicates client error.
Definition: response.cc:163
bool finalized_
Flag indicating whether finalize was called.
Definition: http_message.h:256
std::string getStatusPhrase() const
Returns HTTP status phrase.
Definition: response.cc:151
HTTP protocol version.
Definition: http_types.h:14
virtual std::string toString() const
Returns HTTP response as string.
Definition: response.cc:212
virtual std::string getBody() const
Returns HTTP response body as string.
Definition: response.cc:157
unsigned major_
Major HTTP version.
Definition: http_types.h:15
virtual void create()
Commits information held in the context into the response.
Definition: response.cc:69
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
bool created_
Flag indicating whether create was called.
Definition: http_message.h:253
HttpResponseContextPtr context_
Pointer to the HttpResponseContext holding parsed data.
Definition: response.h:237
HttpHeaderMap required_headers_
Map holding required HTTP headers.
Definition: http_message.h:250
Base class for HttpRequest and HttpResponse.
Definition: http_message.h:62
int version()
returns Kea hooks version.
virtual std::string getDateHeaderValue() const
Returns current time formatted as required by RFC 1123.
Definition: response.cc:193
Generic exception thrown by HttpResponse class.
Definition: response.h:23
static bool isServerError(const HttpStatusCode &status_code)
Checks if the status code indicates server error.
Definition: response.cc:170
This class parses and generates time values used in HTTP.
Definition: date_time.h:41
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
HttpStatusCode getStatusCode() const
Returns HTTP status code.
Definition: response.cc:145
static std::string statusCodeToString(const HttpStatusCode &status_code)
Converts status code to string.
Definition: response.cc:177
Defines the logger used by the top-level component of kea-dhcp-ddns.
void checkFinalized() const
Checks if the finalize was called.
Definition: http_message.cc:99
virtual void reset()
Reset the state of the object.
Definition: response.cc:138
HttpVersion http_version_
HTTP version numbers.
Definition: http_message.h:238
std::set< HttpVersion > required_versions_
Set of required HTTP versions.
Definition: http_message.h:235
std::string toBriefString() const
Returns HTTP version and HTTP status as a string.
Definition: response.cc:200
static uint16_t statusCodeToNumber(const HttpStatusCode &status_code)
Convenience method converting status code to numeric value.
Definition: response.cc:188
void checkCreated() const
Checks if the create was called.
Definition: http_message.cc:90
HttpHeaderMap headers_
Parsed HTTP headers.
Definition: http_message.h:259
Represents HTTP header including a header name and value.
Definition: http_header.h:20
HTTP response context.
HttpResponse()
Constructor for the inbound HTTP response.
Definition: response.cc:49
bool inRequiredSet(const T &element, const std::set< T > &element_set) const
Checks if the set is empty or the specified element belongs to this set.
Definition: http_message.h:224
unsigned minor_
Minor HTTP version.
Definition: http_types.h:16
bool set_
A storage for the boolean flag.
Definition: response.h:75
Encapsulates the boolean value indicating if the HttpResponse constructor should call its setGenericB...
Definition: response.h:52
HttpStatusCode
HTTP status codes (cf RFC 2068)
Definition: response.h:30