Crow  0.3
A C++ microframework for the web
parser.h
1 #pragma once
2 
3 #include <string>
4 #include <unordered_map>
5 #include <boost/algorithm/string.hpp>
6 #include <algorithm>
7 
8 #include "crow/http_parser_merged.h"
9 #include "crow/http_request.h"
10 
11 namespace crow
12 {
13  /// A wrapper for `nodejs/http-parser`.
14 
15  /// Used to generate a \ref crow.request from the TCP socket buffer.
16  ///
17  template <typename Handler>
18  struct HTTPParser : public http_parser
19  {
20  static int on_message_begin(http_parser* self_)
21  {
22  HTTPParser* self = static_cast<HTTPParser*>(self_);
23  self->clear();
24  return 0;
25  }
26  static int on_url(http_parser* self_, const char* at, size_t length)
27  {
28  HTTPParser* self = static_cast<HTTPParser*>(self_);
29  self->raw_url.insert(self->raw_url.end(), at, at+length);
30  return 0;
31  }
32  static int on_header_field(http_parser* self_, const char* at, size_t length)
33  {
34  HTTPParser* self = static_cast<HTTPParser*>(self_);
35  switch (self->header_building_state)
36  {
37  case 0:
38  if (!self->header_value.empty())
39  {
40  self->headers.emplace(std::move(self->header_field), std::move(self->header_value));
41  }
42  self->header_field.assign(at, at+length);
43  self->header_building_state = 1;
44  break;
45  case 1:
46  self->header_field.insert(self->header_field.end(), at, at+length);
47  break;
48  }
49  return 0;
50  }
51  static int on_header_value(http_parser* self_, const char* at, size_t length)
52  {
53  HTTPParser* self = static_cast<HTTPParser*>(self_);
54  switch (self->header_building_state)
55  {
56  case 0:
57  self->header_value.insert(self->header_value.end(), at, at+length);
58  break;
59  case 1:
60  self->header_building_state = 0;
61  self->header_value.assign(at, at+length);
62  break;
63  }
64  return 0;
65  }
66  static int on_headers_complete(http_parser* self_)
67  {
68  HTTPParser* self = static_cast<HTTPParser*>(self_);
69  if (!self->header_field.empty())
70  {
71  self->headers.emplace(std::move(self->header_field), std::move(self->header_value));
72  }
73  self->process_header();
74  return 0;
75  }
76  static int on_body(http_parser* self_, const char* at, size_t length)
77  {
78  HTTPParser* self = static_cast<HTTPParser*>(self_);
79  self->body.insert(self->body.end(), at, at+length);
80  return 0;
81  }
82  static int on_message_complete(http_parser* self_)
83  {
84  HTTPParser* self = static_cast<HTTPParser*>(self_);
85 
86  // url params
87  self->url = self->raw_url.substr(0, self->raw_url.find("?"));
88  self->url_params = query_string(self->raw_url);
89 
90  self->process_message();
91  return 0;
92  }
93  HTTPParser(Handler* handler) :
94  handler_(handler)
95  {
96  http_parser_init(this, HTTP_REQUEST);
97  }
98 
99  // return false on error
100  /// Parse a buffer into the different sections of an HTTP request.
101  bool feed(const char* buffer, int length)
102  {
103  const static http_parser_settings settings_{
104  on_message_begin,
105  on_url,
106  nullptr,
107  on_header_field,
108  on_header_value,
109  on_headers_complete,
110  on_body,
111  on_message_complete,
112  };
113 
114  int nparsed = http_parser_execute(this, &settings_, buffer, length);
115  return nparsed == length;
116  }
117 
118  bool done()
119  {
120  return feed(nullptr, 0);
121  }
122 
123  void clear()
124  {
125  url.clear();
126  raw_url.clear();
127  header_building_state = 0;
128  header_field.clear();
129  header_value.clear();
130  headers.clear();
131  url_params.clear();
132  body.clear();
133  }
134 
135  void process_header()
136  {
137  handler_->handle_header();
138  }
139 
140  void process_message()
141  {
142  handler_->handle();
143  }
144 
145  /// Take the parsed HTTP request data and convert it to a \ref crow.request
147  {
148  return request{static_cast<HTTPMethod>(method), std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
149  }
150 
151  bool is_upgrade() const
152  {
153  return upgrade;
154  }
155 
156  bool check_version(int major, int minor) const
157  {
158  return http_major == major && http_minor == minor;
159  }
160 
161  std::string raw_url;
162  std::string url;
163 
164  int header_building_state = 0;
165  std::string header_field;
166  std::string header_value;
167  ci_map headers;
168  query_string url_params; ///< What comes after the `?` in the URL.
169  std::string body;
170 
171  Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
172  };
173 }
crow::HTTPParser::feed
bool feed(const char *buffer, int length)
Parse a buffer into the different sections of an HTTP request.
Definition: parser.h:101
crow::query_string
A class to represent any data coming after the ? in the request URL into key-value pairs.
Definition: query_string.h:291
crow::HTTPParser
A wrapper for nodejs/http-parser.
Definition: parser.h:18
crow::HTTPParser::url_params
query_string url_params
What comes after the ? in the URL.
Definition: parser.h:168
crow::request
An HTTP request.
Definition: http_request.h:26
crow::HTTPParser::handler_
Handler * handler_
This is currently an HTTP connection object (crow::Connection).
Definition: parser.h:171
crow::HTTPParser::to_request
request to_request() const
Take the parsed HTTP request data and convert it to a crow::request.
Definition: parser.h:146