Crow  1.1
A C++ microframework for the web
 
Loading...
Searching...
No Matches
parser.h
1#pragma once
2
3#include <string>
4#include <unordered_map>
5#include <algorithm>
6
7#include "crow/http_request.h"
8#include "crow/http_parser_merged.h"
9
10namespace crow
11{
12 /// A wrapper for `nodejs/http-parser`.
13
14 ///
15 /// Used to generate a \ref crow.request from the TCP socket buffer.
16 template<typename Handler>
17 struct HTTPParser : public http_parser
18 {
19 static int on_message_begin(http_parser*)
20 {
21 return 0;
22 }
23 static int on_method(http_parser* self_)
24 {
25 HTTPParser* self = static_cast<HTTPParser*>(self_);
26 self->req.method = static_cast<HTTPMethod>(self->method);
27
28 return 0;
29 }
30 static int on_url(http_parser* self_, const char* at, size_t length)
31 {
32 HTTPParser* self = static_cast<HTTPParser*>(self_);
33 self->req.raw_url.insert(self->req.raw_url.end(), at, at + length);
34 self->req.url_params = query_string(self->req.raw_url);
35 self->req.url = self->req.raw_url.substr(0, self->qs_point != 0 ? self->qs_point : std::string::npos);
36
37 self->process_url();
38
39 return 0;
40 }
41 static int on_header_field(http_parser* self_, const char* at, size_t length)
42 {
43 HTTPParser* self = static_cast<HTTPParser*>(self_);
44 switch (self->header_building_state)
45 {
46 case 0:
47 if (!self->header_value.empty())
48 {
49 self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value));
50 }
51 self->header_field.assign(at, at + length);
52 self->header_building_state = 1;
53 break;
54 case 1:
55 self->header_field.insert(self->header_field.end(), at, at + length);
56 break;
57 }
58 return 0;
59 }
60 static int on_header_value(http_parser* self_, const char* at, size_t length)
61 {
62 HTTPParser* self = static_cast<HTTPParser*>(self_);
63 switch (self->header_building_state)
64 {
65 case 0:
66 self->header_value.insert(self->header_value.end(), at, at + length);
67 break;
68 case 1:
69 self->header_building_state = 0;
70 self->header_value.assign(at, at + length);
71 break;
72 }
73 return 0;
74 }
75 static int on_headers_complete(http_parser* self_)
76 {
77 HTTPParser* self = static_cast<HTTPParser*>(self_);
78 if (!self->header_field.empty())
79 {
80 self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value));
81 }
82
83 self->set_connection_parameters();
84
85 self->process_header();
86 return 0;
87 }
88 static int on_body(http_parser* self_, const char* at, size_t length)
89 {
90 HTTPParser* self = static_cast<HTTPParser*>(self_);
91 self->req.body.insert(self->req.body.end(), at, at + length);
92 return 0;
93 }
94 static int on_message_complete(http_parser* self_)
95 {
96 HTTPParser* self = static_cast<HTTPParser*>(self_);
97
98 self->message_complete = true;
99 self->process_message();
100 return 0;
101 }
102 HTTPParser(Handler* handler):
103 http_parser(),
104 handler_(handler)
105 {
106 http_parser_init(this);
107 }
108
109 // return false on error
110 /// Parse a buffer into the different sections of an HTTP request.
111 bool feed(const char* buffer, int length)
112 {
113 if (message_complete)
114 return true;
115
116 const static http_parser_settings settings_{
117 on_message_begin,
118 on_method,
119 on_url,
120 on_header_field,
121 on_header_value,
122 on_headers_complete,
123 on_body,
124 on_message_complete,
125 };
126
127 int nparsed = http_parser_execute(this, &settings_, buffer, length);
128 if (http_errno != CHPE_OK)
129 {
130 return false;
131 }
132 return nparsed == length;
133 }
134
135 bool done()
136 {
137 return feed(nullptr, 0);
138 }
139
140 void clear()
141 {
142 req = crow::request();
143 header_field.clear();
144 header_value.clear();
145 header_building_state = 0;
146 qs_point = 0;
147 message_complete = false;
148 state = CROW_NEW_MESSAGE();
149 }
150
151 inline void process_url()
152 {
153 handler_->handle_url();
154 }
155
156 inline void process_header()
157 {
158 handler_->handle_header();
159 }
160
161 inline void process_message()
162 {
163 handler_->handle();
164 }
165
166 inline void set_connection_parameters()
167 {
168 req.http_ver_major = http_major;
169 req.http_ver_minor = http_minor;
170
171 //NOTE(EDev): it seems that the problem is with crow's policy on closing the connection for HTTP_VERSION < 1.0, the behaviour for that in crow is "don't close the connection, but don't send a keep-alive either"
172
173 // HTTP1.1 = always send keep_alive, HTTP1.0 = only send if header exists, HTTP?.? = never send
174 req.keep_alive = (http_major == 1 && http_minor == 0) ?
175 ((flags & F_CONNECTION_KEEP_ALIVE) ? true : false) :
176 ((http_major == 1 && http_minor == 1) ? true : false);
177
178 // HTTP1.1 = only close if close header exists, HTTP1.0 = always close unless keep_alive header exists, HTTP?.?= never close
179 req.close_connection = (http_major == 1 && http_minor == 0) ?
180 ((flags & F_CONNECTION_KEEP_ALIVE) ? false : true) :
181 ((http_major == 1 && http_minor == 1) ? ((flags & F_CONNECTION_CLOSE) ? true : false) : false);
182 req.upgrade = static_cast<bool>(upgrade);
183 }
184
185 /// The final request that this parser outputs.
186 ///
187 /// Data parsed is put directly into this object as soon as the related callback returns. (e.g. the request will have the cooorect method as soon as on_method() returns)
189
190 private:
191 int header_building_state = 0;
192 bool message_complete = false;
193 std::string header_field;
194 std::string header_value;
195
196 Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
197 };
198} // namespace crow
199
200#undef CROW_NEW_MESSAGE
201#undef CROW_start_state
A class to represent any data coming after the ? in the request URL into key-value pairs.
Definition query_string.h:294
The main namespace of the library. In this namespace is defined the most important classes and functi...
A wrapper for nodejs/http-parser.
Definition parser.h:18
request req
Definition parser.h:188
bool feed(const char *buffer, int length)
Parse a buffer into the different sections of an HTTP request.
Definition parser.h:111
Definition http_parser_merged.h:181
Definition http_parser_merged.h:148
unsigned char http_major
Definition http_parser_merged.h:163
unsigned int flags
Definition http_parser_merged.h:150
An HTTP request.
Definition http_request.h:36
bool close_connection
Whether or not the server should shut down the TCP connection once a response is sent.
Definition http_request.h:46
bool keep_alive
Whether or not the server should send a connection: Keep-Alive header to the client.
Definition http_request.h:45
std::string raw_url
The full URL containing the ? and URL parameters.
Definition http_request.h:38
query_string url_params
The parameters associated with the request. (everything after the ? in the URL)
Definition http_request.h:40
std::string url
The endpoint without any parameters.
Definition http_request.h:39
bool upgrade
Whether or noth the server should change the HTTP connection to a different connection.
Definition http_request.h:47