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