Kea 2.5.8
response.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2024 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
15using namespace boost::local_time;
16using namespace isc::http;
17
18namespace {
19
21const 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
42const std::string crlf = "\r\n";
43
44}
45
46namespace isc {
47namespace http {
48
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
68void
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 const& header : context_->headers_) {
84 HttpHeaderPtr hdr(new HttpHeader(header.name_, header.value_));
85 headers_[hdr->getLowerCaseName()] = hdr;
86 }
87
89 HttpHeaderPtr length_header(new HttpHeader("Content-Length", boost::lexical_cast<std::string>
90 (context_->body_.length())));
91 headers_["content-length"] = length_header;
92
93 HttpHeaderPtr date_header(new HttpHeader("Date", getDateHeaderValue()));;
94 headers_["date"] = date_header;
95 }
96
97 // Iterate over required headers and check that they exist
98 // in the HTTP response.
99 for (auto const& req_header : required_headers_) {
100 auto header = headers_.find(req_header.first);
101 if (header == headers_.end()) {
102 isc_throw(BadValue, "required header " << req_header.first
103 << " not found in the HTTP response");
104 } else if (!req_header.second->getValue().empty() &&
105 !header->second->isValueEqual(req_header.second->getValue())) {
106 // If specific value is required for the header, check
107 // that the value in the HTTP response matches it.
108 isc_throw(BadValue, "required header's " << header->first
109 << " value is " << req_header.second->getValue()
110 << ", but " << header->second->getValue() << " was found");
111 }
112 }
113
114 } catch (const std::exception& ex) {
115 // Reset the state of the object if we failed at any point.
116 reset();
118 }
119
120 // All ok.
121 created_ = true;
122}
123
124void
126 if (!created_) {
127 create();
128 }
129
130 finalized_ = true;
131}
132
133void
135 created_ = false;
136 finalized_ = false;
137 headers_.clear();
138}
139
142 checkCreated();
143 return (static_cast<HttpStatusCode>(context_->status_code_));
144}
145
146std::string
148 checkCreated();
149 return (context_->phrase_);
150}
151
152std::string
155 return (context_->body_);
156}
157
158bool
160 // Client errors have status codes of 4XX.
161 uint16_t c = statusCodeToNumber(status_code);
162 return ((c >= 400) && (c < 500));
163}
164
165bool
167 // Server errors have status codes of 5XX.
168 uint16_t c = statusCodeToNumber(status_code);
169 return ((c >= 500) && (c < 600));
170}
171
172std::string
174 auto status_code_it = status_code_to_description.find(status_code);
175 if (status_code_it == status_code_to_description.end()) {
176 isc_throw(HttpResponseError, "internal server error: no HTTP status"
177 " description for the given status code "
178 << static_cast<uint16_t>(status_code));
179 }
180 return (status_code_it->second);
181}
182
183uint16_t
185 return (static_cast<uint16_t>(status_code));
186}
187
188std::string
190 // This returns current time in the recommended format.
191 HttpDateTime date_time;
192 return (date_time.rfc1123Format());
193}
194
195std::string
198
199 std::ostringstream s;
200 // HTTP version number and status code.
201 s << "HTTP/" << http_version_.major_ << "." << http_version_.minor_;
202 s << " " << context_->status_code_;
203 s << " " << statusCodeToString(static_cast<HttpStatusCode>(context_->status_code_));
204 return (s.str());
205}
206
207std::string
209
210 std::ostringstream s;
211 // HTTP version number and status code.
212 s << toBriefString() << crlf;
213
214 for (auto const& header_it : headers_) {
215 s << header_it.second->getName() << ": " << header_it.second->getValue()
216 << crlf;
217 }
218
219 s << crlf;
220
221 // Include message body.
222 s << getBody();
223
224 return (s.str());
225}
226
227} // namespace http
228} // namespace isc
int version()
returns Kea hooks version.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
This class parses and generates time values used in HTTP.
Definition: date_time.h:41
std::string rfc1123Format() const
Returns time value formatted as specified in RFC 1123.
Definition: date_time.cc:30
Represents HTTP header including a header name and value.
Definition: http_header.h:20
Base class for HttpRequest and HttpResponse.
Definition: http_message.h:62
HttpHeaderMap headers_
Parsed HTTP headers.
Definition: http_message.h:259
HttpVersion http_version_
HTTP version numbers.
Definition: http_message.h:238
void checkFinalized() const
Checks if the finalize was called.
Definition: http_message.cc:99
void checkCreated() const
Checks if the create was called.
Definition: http_message.cc:90
bool created_
Flag indicating whether create was called.
Definition: http_message.h:253
std::set< HttpVersion > required_versions_
Set of required HTTP versions.
Definition: http_message.h:235
Direction getDirection() const
Returns HTTP message direction.
Definition: http_message.h:80
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
bool finalized_
Flag indicating whether finalize was called.
Definition: http_message.h:256
HttpHeaderMap required_headers_
Map holding required HTTP headers.
Definition: http_message.h:250
Generic exception thrown by HttpResponse class.
Definition: response.h:23
HttpResponseContextPtr context_
Pointer to the HttpResponseContext holding parsed data.
Definition: response.h:241
virtual std::string getBody() const
Returns HTTP response body as string.
Definition: response.cc:153
HttpResponse()
Constructor for the inbound HTTP response.
Definition: response.cc:49
static uint16_t statusCodeToNumber(const HttpStatusCode &status_code)
Convenience method converting status code to numeric value.
Definition: response.cc:184
static bool isClientError(const HttpStatusCode &status_code)
Checks if the status code indicates client error.
Definition: response.cc:159
HttpStatusCode getStatusCode() const
Returns HTTP status code.
Definition: response.cc:141
virtual std::string getDateHeaderValue() const
Returns current time formatted as required by RFC 1123.
Definition: response.cc:189
static bool isServerError(const HttpStatusCode &status_code)
Checks if the status code indicates server error.
Definition: response.cc:166
std::string toBriefString() const
Returns HTTP version and HTTP status as a string.
Definition: response.cc:196
virtual void finalize()
Completes creation of the HTTP response.
Definition: response.cc:125
virtual std::string toString() const
Returns HTTP response as string.
Definition: response.cc:208
std::string getStatusPhrase() const
Returns HTTP status phrase.
Definition: response.cc:147
virtual void reset()
Reset the state of the object.
Definition: response.cc:134
virtual void create()
Commits information held in the context into the response.
Definition: response.cc:69
static std::string statusCodeToString(const HttpStatusCode &status_code)
Converts status code to string.
Definition: response.cc:173
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
HttpStatusCode
HTTP status codes (cf RFC 2068)
Definition: response.h:30
boost::shared_ptr< HttpHeader > HttpHeaderPtr
Pointer to the HttpHeader class.
Definition: http_header.h:65
Defines the logger used by the top-level component of kea-lfc.
Encapsulates the boolean value indicating if the HttpResponse constructor should call its setGenericB...
Definition: response.h:52
bool set_
A storage for the boolean flag.
Definition: response.h:75
HTTP response context.
HTTP protocol version.
Definition: http_types.h:14
unsigned minor_
Minor HTTP version.
Definition: http_types.h:16
unsigned major_
Major HTTP version.
Definition: http_types.h:15