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 handler_(handler)
104 {
105 http_parser_init(this);
106 }
107
108 // return false on error
109 /// Parse a buffer into the different sections of an HTTP request.
110 bool feed(const char* buffer, int length)
111 {
112 if (message_complete)
113 return true;
114
115 const static http_parser_settings settings_{
116 on_message_begin,
117 on_method,
118 on_url,
119 on_header_field,
120 on_header_value,
121 on_headers_complete,
122 on_body,
123 on_message_complete,
124 };
125
126 int nparsed = http_parser_execute(this, &settings_, buffer, length);
127 if (http_errno != CHPE_OK)
128 {
129 return false;
130 }
131 return nparsed == length;
132 }
133
134 bool done()
135 {
136 return feed(nullptr, 0);
137 }
138
139 void clear()
140 {
141 req = crow::request();
142 header_field.clear();
143 header_value.clear();
144 header_building_state = 0;
145 qs_point = 0;
146 message_complete = false;
147 state = CROW_NEW_MESSAGE();
148 }
149
150 inline void process_url()
151 {
152 handler_->handle_url();
153 }
154
155 inline void process_header()
156 {
157 handler_->handle_header();
158 }
159
160 inline void process_message()
161 {
162 handler_->handle();
163 }
164
165 inline void set_connection_parameters()
166 {
167 req.http_ver_major = http_major;
168 req.http_ver_minor = http_minor;
169
170 //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"
171
172 // HTTP1.1 = always send keep_alive, HTTP1.0 = only send if header exists, HTTP?.? = never send
173 req.keep_alive = (http_major == 1 && http_minor == 0) ?
174 ((flags & F_CONNECTION_KEEP_ALIVE) ? true : false) :
175 ((http_major == 1 && http_minor == 1) ? true : false);
176
177 // HTTP1.1 = only close if close header exists, HTTP1.0 = always close unless keep_alive header exists, HTTP?.?= never close
178 req.close_connection = (http_major == 1 && http_minor == 0) ?
179 ((flags & F_CONNECTION_KEEP_ALIVE) ? false : true) :
180 ((http_major == 1 && http_minor == 1) ? ((flags & F_CONNECTION_CLOSE) ? true : false) : false);
181 req.upgrade = static_cast<bool>(upgrade);
182 }
183
184 /// The final request that this parser outputs.
185 ///
186 /// 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)
188
189 private:
190 int header_building_state = 0;
191 bool message_complete = false;
192 std::string header_field;
193 std::string header_value;
194
195 Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
196 };
197} // namespace crow
198
199#undef CROW_NEW_MESSAGE
200#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:187
bool feed(const char *buffer, int length)
Parse a buffer into the different sections of an HTTP request.
Definition parser.h:110
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