Kea 3.3.1
response.cc
Go to the documentation of this file.
1// Copyright (C) 2016-2026 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
52
54 const HttpStatusCode& status_code,
55 const CallSetGenericBody& generic_body)
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_ << "."
78 << http_version_.minor_
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();
117 isc_throw(HttpResponseError, ex.what());
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
140void
142 // Make sense only for outbound responses.
144 return;
145 }
146 // A previous header must be present.
147 if (!headers_.count("content-length")) {
148 return;
149 }
150 // Copied from create().
151 std::string length =
152 boost::lexical_cast<std::string>(context_->body_.length());
153 HttpHeaderPtr length_header(new HttpHeader("Content-Length", length));
154 headers_["content-length"] = length_header;
155}
156
159 checkCreated();
160 return (static_cast<HttpStatusCode>(context_->status_code_));
161}
162
163std::string
165 checkCreated();
166 return (context_->phrase_);
167}
168
169std::string
172 return (context_->body_);
173}
174
175bool
177 // Client errors have status codes of 4XX.
178 uint16_t c = statusCodeToNumber(status_code);
179 return ((c >= 400) && (c < 500));
180}
181
182bool
184 // Server errors have status codes of 5XX.
185 uint16_t c = statusCodeToNumber(status_code);
186 return ((c >= 500) && (c < 600));
187}
188
189std::string
191 auto status_code_it = status_code_to_description.find(status_code);
192 if (status_code_it == status_code_to_description.end()) {
193 isc_throw(HttpResponseError, "internal server error: no HTTP status"
194 " description for the given status code "
195 << static_cast<uint16_t>(status_code));
196 }
197 return (status_code_it->second);
198}
199
200uint16_t
202 return (static_cast<uint16_t>(status_code));
203}
204
205std::string
207 // This returns current time in the recommended format.
208 HttpDateTime date_time;
209 return (date_time.rfc1123Format());
210}
211
212std::string
215
216 std::ostringstream s;
217 // HTTP version number and status code.
218 s << "HTTP/" << http_version_.major_ << "." << http_version_.minor_;
219 s << " " << context_->status_code_;
220 s << " " << statusCodeToString(static_cast<HttpStatusCode>(context_->status_code_));
221 return (s.str());
222}
223
224std::string
226
227 std::ostringstream s;
228 // HTTP version number and status code.
229 s << toBriefString() << crlf;
230
231 for (auto const& header_it : headers_) {
232 s << header_it.second->getName() << ": " << header_it.second->getValue()
233 << crlf;
234 }
235
236 s << crlf;
237
238 // Include message body.
239 s << getBody();
240
241 return (s.str());
242}
243
244} // namespace http
245} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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:39
Represents HTTP header including a header name and value.
Definition http_header.h:20
HttpHeaderMap headers_
Parsed HTTP headers.
HttpVersion http_version_
HTTP version numbers.
void checkFinalized() const
Checks if the finalize was called.
void checkCreated() const
Checks if the create was called.
bool created_
Flag indicating whether create was called.
HttpMessage(const Direction &direction)
Constructor.
std::set< HttpVersion > required_versions_
Set of required HTTP versions.
Direction getDirection() const
Returns HTTP message direction.
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.
bool finalized_
Flag indicating whether finalize was called.
HttpHeaderMap required_headers_
Map holding required HTTP headers.
Generic exception thrown by HttpResponse class.
Definition response.h:23
HttpResponseContextPtr context_
Pointer to the HttpResponseContext holding parsed data.
Definition response.h:247
virtual std::string getBody() const
Returns HTTP response body as string.
Definition response.cc:170
HttpResponse()
Constructor for the inbound HTTP response.
Definition response.cc:49
void resetContentLength()
Reset the Content-Length header.
Definition response.cc:141
static uint16_t statusCodeToNumber(const HttpStatusCode &status_code)
Convenience method converting status code to numeric value.
Definition response.cc:201
static bool isClientError(const HttpStatusCode &status_code)
Checks if the status code indicates client error.
Definition response.cc:176
HttpStatusCode getStatusCode() const
Returns HTTP status code.
Definition response.cc:158
virtual std::string getDateHeaderValue() const
Returns current time formatted as required by RFC 1123.
Definition response.cc:206
static bool isServerError(const HttpStatusCode &status_code)
Checks if the status code indicates server error.
Definition response.cc:183
std::string toBriefString() const
Returns HTTP version and HTTP status as a string.
Definition response.cc:213
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:225
std::string getStatusPhrase() const
Returns HTTP status phrase.
Definition response.cc:164
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:190
int version()
returns Kea hooks version.
#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 protocol version.
Definition http_types.h:14