/src/crow/include/crow/parser.h
Line | Count | Source |
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 | | |
10 | | namespace 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 | 0 | { |
21 | 0 | return 0; |
22 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_message_begin(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_message_begin(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_message_begin(crow::http_parser*) |
23 | | static int on_method(http_parser* self_) |
24 | 0 | { |
25 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
26 | 0 | self->req.method = static_cast<HTTPMethod>(self->method); |
27 | |
|
28 | 0 | return 0; |
29 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_method(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_method(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_method(crow::http_parser*) |
30 | | static int on_url(http_parser* self_, const char* at, size_t length) |
31 | 0 | { |
32 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
33 | 0 | self->req.raw_url.insert(self->req.raw_url.end(), at, at + length); |
34 | 0 | self->req.url_params = query_string(self->req.raw_url); |
35 | 0 | self->req.url = self->req.raw_url.substr(0, self->qs_point != 0 ? self->qs_point : std::string::npos); |
36 | |
|
37 | 0 | self->process_url(); |
38 | |
|
39 | 0 | return 0; |
40 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_url(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_url(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_url(crow::http_parser*, char const*, unsigned long) |
41 | | static int on_header_field(http_parser* self_, const char* at, size_t length) |
42 | 0 | { |
43 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
44 | 0 | switch (self->header_building_state) |
45 | 0 | { |
46 | 0 | case 0: |
47 | 0 | if (!self->header_value.empty()) |
48 | 0 | { |
49 | 0 | self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value)); |
50 | 0 | } |
51 | 0 | self->header_field.assign(at, at + length); |
52 | 0 | self->header_building_state = 1; |
53 | 0 | break; |
54 | 0 | case 1: |
55 | 0 | self->header_field.insert(self->header_field.end(), at, at + length); |
56 | 0 | break; |
57 | 0 | } |
58 | 0 | return 0; |
59 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_header_field(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_header_field(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_header_field(crow::http_parser*, char const*, unsigned long) |
60 | | static int on_header_value(http_parser* self_, const char* at, size_t length) |
61 | 0 | { |
62 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
63 | 0 | switch (self->header_building_state) |
64 | 0 | { |
65 | 0 | case 0: |
66 | 0 | self->header_value.insert(self->header_value.end(), at, at + length); |
67 | 0 | break; |
68 | 0 | case 1: |
69 | 0 | self->header_building_state = 0; |
70 | 0 | self->header_value.assign(at, at + length); |
71 | 0 | break; |
72 | 0 | } |
73 | 0 | return 0; |
74 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_header_value(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_header_value(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_header_value(crow::http_parser*, char const*, unsigned long) |
75 | | static int on_headers_complete(http_parser* self_) |
76 | 0 | { |
77 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
78 | 0 | if (!self->header_field.empty()) |
79 | 0 | { |
80 | 0 | self->req.headers.emplace(std::move(self->header_field), std::move(self->header_value)); |
81 | 0 | } |
82 | |
|
83 | 0 | self->set_connection_parameters(); |
84 | |
|
85 | 0 | self->process_header(); |
86 | 0 | return 0; |
87 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_headers_complete(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_headers_complete(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_headers_complete(crow::http_parser*) |
88 | | static int on_body(http_parser* self_, const char* at, size_t length) |
89 | 0 | { |
90 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
91 | 0 | self->req.body.insert(self->req.body.end(), at, at + length); |
92 | 0 | return 0; |
93 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_body(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_body(crow::http_parser*, char const*, unsigned long) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_body(crow::http_parser*, char const*, unsigned long) |
94 | | static int on_message_complete(http_parser* self_) |
95 | 0 | { |
96 | 0 | HTTPParser* self = static_cast<HTTPParser*>(self_); |
97 | |
|
98 | 0 | self->message_complete = true; |
99 | 0 | self->process_message(); |
100 | 0 | return 0; |
101 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::on_message_complete(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::on_message_complete(crow::http_parser*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::on_message_complete(crow::http_parser*) |
102 | | HTTPParser(Handler* handler): |
103 | 0 | http_parser(), |
104 | 0 | handler_(handler) |
105 | 0 | { |
106 | 0 | http_parser_init(this); |
107 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::HTTPParser(DummyHandler*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::HTTPParser(crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>*) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::HTTPParser(crow::Connection<crow::SocketAdaptor, crow::Crow<>>*) |
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 | 0 | { |
113 | 0 | if (message_complete) |
114 | 0 | return true; |
115 | | |
116 | 0 | const static http_parser_settings settings_{ |
117 | 0 | on_message_begin, |
118 | 0 | on_method, |
119 | 0 | on_url, |
120 | 0 | on_header_field, |
121 | 0 | on_header_value, |
122 | 0 | on_headers_complete, |
123 | 0 | on_body, |
124 | 0 | on_message_complete, |
125 | 0 | }; |
126 | |
|
127 | 0 | int nparsed = http_parser_execute(this, &settings_, buffer, length); |
128 | 0 | if (http_errno != CHPE_OK) |
129 | 0 | { |
130 | 0 | return false; |
131 | 0 | } |
132 | 0 | return nparsed == length; |
133 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::feed(char const*, int) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::feed(char const*, int) Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::feed(char const*, int) |
134 | | |
135 | | bool done() |
136 | 0 | { |
137 | 0 | return feed(nullptr, 0); |
138 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::done() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::done() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::done() |
139 | | |
140 | | void clear() |
141 | 0 | { |
142 | 0 | req = crow::request(); |
143 | 0 | header_field.clear(); |
144 | 0 | header_value.clear(); |
145 | 0 | header_building_state = 0; |
146 | 0 | qs_point = 0; |
147 | 0 | message_complete = false; |
148 | 0 | state = CROW_NEW_MESSAGE(); |
149 | 0 | } Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::clear() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::clear() |
150 | | |
151 | | inline void process_url() |
152 | 0 | { |
153 | 0 | handler_->handle_url(); |
154 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::process_url() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::process_url() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::process_url() |
155 | | |
156 | | inline void process_header() |
157 | 0 | { |
158 | 0 | handler_->handle_header(); |
159 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::process_header() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::process_header() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::process_header() |
160 | | |
161 | | inline void process_message() |
162 | 0 | { |
163 | 0 | handler_->handle(); |
164 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::process_message() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::process_message() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::process_message() |
165 | | |
166 | | inline void set_connection_parameters() |
167 | 0 | { |
168 | 0 | req.http_ver_major = http_major; |
169 | 0 | 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 | 0 | req.keep_alive = (http_major == 1 && http_minor == 0) ? |
175 | 0 | ((flags & F_CONNECTION_KEEP_ALIVE) ? true : false) : |
176 | 0 | ((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 | 0 | req.close_connection = (http_major == 1 && http_minor == 0) ? |
180 | 0 | ((flags & F_CONNECTION_KEEP_ALIVE) ? false : true) : |
181 | 0 | ((http_major == 1 && http_minor == 1) ? ((flags & F_CONNECTION_CLOSE) ? true : false) : false); |
182 | 0 | req.upgrade = static_cast<bool>(upgrade); |
183 | 0 | } Unexecuted instantiation: crow::HTTPParser<DummyHandler>::set_connection_parameters() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>> >::set_connection_parameters() Unexecuted instantiation: crow::HTTPParser<crow::Connection<crow::SocketAdaptor, crow::Crow<>> >::set_connection_parameters() |
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) |
188 | | request req; |
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 |