Kea  1.9.9-git
request.cc
Go to the documentation of this file.
1 // Copyright (C) 2016-2020 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/request.h>
10 #include <boost/algorithm/string.hpp>
11 #include <boost/lexical_cast.hpp>
12 #include <sstream>
13 
14 namespace {
15 
17 const std::string crlf = "\r\n";
18 
19 }
20 
21 namespace isc {
22 namespace http {
23 
25  : HttpMessage(INBOUND), required_methods_(),
26  method_(Method::HTTP_METHOD_UNKNOWN),
27  context_(new HttpRequestContext()) {
28 }
29 
31  const std::string& uri,
32  const HttpVersion& version,
33  const HostHttpHeader& host_header,
34  const BasicHttpAuthPtr& basic_auth)
35  : HttpMessage(OUTBOUND), required_methods_(),
36  method_(Method::HTTP_METHOD_UNKNOWN),
37  context_(new HttpRequestContext()) {
38  context()->method_ = methodToString(method);
39  context()->uri_ = uri;
40  context()->http_version_major_ = version.major_;
41  context()->http_version_minor_ = version.minor_;
42  // The Host header is mandatory in HTTP/1.1 and should be placed before
43  // any other headers. We also include it for HTTP/1.0 as it doesn't
44  // harm to include it.
45  context()->headers_.push_back(HttpHeaderContext(host_header.getName(),
46  host_header.getValue()));
47  if (basic_auth) {
48  context()->headers_.push_back(BasicAuthHttpHeaderContext(*basic_auth));
49  }
50 }
51 
52 void
54  required_methods_.insert(method);
55 }
56 
57 void
59  try {
60  // The RequestParser doesn't validate the method name. Thus, this
61  // may throw an exception. But, we're fine with lower case names,
62  // e.g. get, post etc.
63  method_ = methodFromString(context_->method_);
64 
65  // Check if the method is allowed for this request.
67  isc_throw(BadValue, "use of HTTP " << methodToString(method_)
68  << " not allowed");
69  }
70 
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 hdr(new HttpHeader("Content-Length",
92  boost::lexical_cast<std::string>(context_->body_.length())));
93  headers_["content-length"] = hdr;
94  }
95 
96  // Iterate over required headers and check that they exist
97  // in the HTTP request.
98  for (auto req_header = required_headers_.begin();
99  req_header != required_headers_.end();
100  ++req_header) {
101  auto header = headers_.find(req_header->first);
102  if (header == headers_.end()) {
103  isc_throw(BadValue, "required header " << req_header->first
104  << " not found in the HTTP request");
105  } else if (!req_header->second->getValue().empty() &&
106  !header->second->isValueEqual(req_header->second->getValue())) {
107  // If specific value is required for the header, check
108  // that the value in the HTTP request matches it.
109  isc_throw(BadValue, "required header's " << header->first
110  << " value is " << req_header->second->getValue()
111  << ", but " << header->second->getValue() << " was found");
112  }
113  }
114 
115  } catch (const std::exception& ex) {
116  // Reset the state of the object if we failed at any point.
117  reset();
119  }
120 
121  // All ok.
122  created_ = true;
123 }
124 
125 void
127  if (!created_) {
128  create();
129  }
130 
131  // Copy the body from the context. Derive classes may further
132  // interpret the body contents, e.g. against the Content-Type.
133  finalized_ = true;
134 }
135 
136 void
138  created_ = false;
139  finalized_ = false;
141  headers_.clear();
142 }
143 
146  checkCreated();
147  return (method_);
148 }
149 
150 std::string
152  checkCreated();
153  return (context_->uri_);
154 }
155 
156 std::string
158  checkFinalized();
159  return (context_->body_);
160 }
161 
162 std::string
164  checkFinalized();
165 
166  std::ostringstream s;
167  s << methodToString(getMethod()) << " " << getUri() << " HTTP/" <<
169  return (s.str());
170 }
171 
172 std::string
174  checkFinalized();
175 
176  std::ostringstream s;
177  // HTTP method, URI and version number.
178  s << toBriefString() << crlf;
179 
180  // Host header must go first.
181  HttpHeaderPtr host_header;
182  try {
183  host_header = getHeader("Host");
184  if (host_header) {
185  s << host_header->getName() << ": " << host_header->getValue() << crlf;
186  }
187 
188  } catch (...) {
189  // impossible condition
190  }
191 
192  // Add all other headers.
193  for (auto header_it = headers_.cbegin(); header_it != headers_.cend();
194  ++header_it) {
195  if (header_it->second->getName() != "Host") {
196  s << header_it->second->getName() << ": " << header_it->second->getValue()
197  << crlf;
198  }
199  }
200 
201  s << crlf;
202 
203  s << getBody();
204 
205  return (s.str());
206 }
207 
208 bool
210  HttpHeaderPtr conn;
211 
212  try {
213  conn = getHeader("connection");
214 
215  } catch (...) {
216  // If there is an exception, it means that the header was not found.
217  }
218 
219  std::string conn_value;
220  if (conn) {
221  conn_value = conn->getLowerCaseValue();
222  }
223 
224  HttpVersion ver = getHttpVersion();
225 
226  return (((ver == HttpVersion::HTTP_10()) && (conn_value == "keep-alive")) ||
227  ((HttpVersion::HTTP_10() < ver) && (conn_value.empty() || (conn_value != "close"))));
228 }
229 
231 HttpRequest::methodFromString(std::string method) const {
232  boost::to_upper(method);
233  if (method == "GET") {
234  return (Method::HTTP_GET);
235  } else if (method == "POST") {
236  return (Method::HTTP_POST);
237  } else if (method == "HEAD") {
238  return (Method::HTTP_HEAD);
239  } else if (method == "PUT") {
240  return (Method::HTTP_PUT);
241  } else if (method == "DELETE") {
242  return (Method::HTTP_DELETE);
243  } else if (method == "OPTIONS") {
244  return (Method::HTTP_OPTIONS);
245  } else if (method == "CONNECT") {
246  return (Method::HTTP_CONNECT);
247  } else {
248  isc_throw(HttpRequestError, "unknown HTTP method " << method);
249  }
250 }
251 
252 std::string
254  switch (method) {
255  case Method::HTTP_GET:
256  return ("GET");
257  case Method::HTTP_POST:
258  return ("POST");
259  case Method::HTTP_HEAD:
260  return ("HEAD");
261  case Method::HTTP_PUT:
262  return ("PUT");
263  case Method::HTTP_DELETE:
264  return ("DELETE");
266  return ("OPTIONS");
268  return ("CONNECT");
269  default:
270  return ("unknown HTTP method");
271  }
272 }
273 
274 }
275 }
void requireHttpMethod(const HttpRequest::Method &method)
Specifies an HTTP method allowed for the request.
Definition: request.cc:53
bool isPersistent() const
Checks if the client has requested persistent connection.
Definition: request.cc:209
boost::shared_ptr< HttpHeader > HttpHeaderPtr
Pointer to the HttpHeader class.
Definition: http_header.h:65
Represents HTTP Host header.
Definition: http_header.h:68
Generic exception thrown by HttpRequest class.
Definition: request.h:21
Method method_
HTTP method of the request.
Definition: request.h:177
Direction getDirection() const
Returns HTTP message direction.
Definition: http_message.h:80
bool finalized_
Flag indicating whether finalize was called.
Definition: http_message.h:256
HTTP protocol version.
Definition: http_types.h:14
virtual std::string toString() const
Returns HTTP message as string.
Definition: request.cc:173
HttpRequestContextPtr context_
Pointer to the HttpRequestContext holding parsed data.
Definition: request.h:181
Represents basic HTTP authentication header.
Definition: basic_auth.h:73
std::string getName() const
Returns header name.
Definition: http_header.h:31
unsigned major_
Major HTTP version.
Definition: http_types.h:15
HttpHeaderPtr getHeader(const std::string &header_name) const
Returns object encapsulating HTTP header.
Definition: http_message.cc:60
Method methodFromString(std::string method) const
Converts HTTP method specified in textual format to Method.
Definition: request.cc:231
std::string methodToString(const HttpRequest::Method &method) const
Converts HTTP method to string.
Definition: request.cc:253
#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...
std::string getBody() const
Returns HTTP message body as string.
Definition: request.cc:157
bool created_
Flag indicating whether create was called.
Definition: http_message.h:253
HttpHeaderMap required_headers_
Map holding required HTTP headers.
Definition: http_message.h:250
Base class for HttpRequest and HttpResponse.
Definition: http_message.h:62
std::string getUri() const
Returns HTTP request URI.
Definition: request.cc:151
HttpRequest()
Constructor for inbound HTTP request.
Definition: request.cc:24
std::string toBriefString() const
Returns HTTP method, URI and HTTP version as a string.
Definition: request.cc:163
HttpVersion getHttpVersion() const
Returns HTTP version number (major and minor).
Definition: http_message.cc:54
int version()
returns Kea hooks version.
Method
HTTP methods.
Definition: request.h:53
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
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
const HttpRequestContextPtr & context() const
Returns pointer to the HttpRequestContext.
Definition: request.h:90
HttpVersion http_version_
HTTP version numbers.
Definition: http_message.h:238
virtual void create()
Commits information held in the context into the request.
Definition: request.cc:58
std::set< HttpVersion > required_versions_
Set of required HTTP versions.
Definition: http_message.h:235
static const HttpVersion & HTTP_10()
HTTP version 1.0.
Definition: http_types.h:53
boost::shared_ptr< BasicHttpAuth > BasicHttpAuthPtr
Type of pointers to basic HTTP authentication objects.
Definition: basic_auth.h:70
virtual void finalize()
Completes creation of the HTTP request.
Definition: request.cc:126
std::string getValue() const
Returns header value.
Definition: http_header.h:36
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
std::set< Method > required_methods_
Set of required HTTP methods.
Definition: request.h:174
HTTP request context.
Method getMethod() const
Returns HTTP method of the request.
Definition: request.cc:145
HTTP header context.
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
virtual void reset()
Reset the state of the object.
Definition: request.cc:137