RESTinio
parser_callbacks.ipp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9inline int
10restinio_url_cb( http_parser * parser, const char * at, size_t length )
11{
12 try
13 {
14 auto * ctx =
15 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
16 parser->data );
17
18 ctx->m_header.append_request_target( at, length );
19
20 if( ctx->m_header.request_target().length() >
21 ctx->m_limits.max_url_size() )
22 {
23 return -1;
24 }
25 }
26 catch( const std::exception & )
27 {
28 return -1;
29 }
30
31 return 0;
32}
33
34inline int
35restinio_header_field_cb( http_parser * parser, const char *at, size_t length )
36{
37 try
38 {
39 auto * ctx =
40 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
41 parser->data );
42
43 if( ctx->m_last_was_value )
44 {
45 // Maybe there are too many fields?
46 if( ctx->m_total_field_count == ctx->m_limits.max_field_count() )
47 {
48 return -1;
49 }
50
51 ctx->m_current_field_name.assign( at, length );
52 ctx->m_last_was_value = false;
53 }
54 else
55 {
56 ctx->m_current_field_name.append( at, length );
57 }
58
59 if( ctx->m_current_field_name.size() >
60 ctx->m_limits.max_field_name_size() )
61 {
62 return -1;
63 }
64 }
65 catch( const std::exception & )
66 {
67 return -1;
68 }
69
70 return 0;
71}
72
73inline void
74append_last_field_accessor( http_header_fields_t & fields, string_view_t value )
75{
76 fields.append_last_field( value );
77}
78
79inline int
80restinio_header_value_cb( http_parser * parser, const char *at, size_t length )
81{
82 try
83 {
84 auto * ctx =
85 reinterpret_cast< restinio::impl::http_parser_ctx_t * >( parser->data );
86
87 http_header_fields_t & fields = ctx->m_leading_headers_completed
88 ? ctx->m_chunked_info_block.m_trailing_fields
89 : ctx->m_header;
90
91 if( !ctx->m_last_was_value )
92 {
93 fields.add_field(
94 std::move( ctx->m_current_field_name ),
95 std::string{ at, length } );
96
97 ctx->m_last_value_total_size = length;
98 ctx->m_last_was_value = true;
99
100 // At this point the number of parsed fields can be incremented.
101 ctx->m_total_field_count += 1u;
102 }
103 else
104 {
105 append_last_field_accessor( fields, std::string{ at, length } );
106 ctx->m_last_value_total_size += length;
107 }
108
109 if( ctx->m_last_value_total_size >=
110 ctx->m_limits.max_field_value_size() )
111 {
112 return -1;
113 }
114 }
115 catch( const std::exception & )
116 {
117 return -1;
118 }
119
120 return 0;
121}
122
123inline int
124restinio_headers_complete_cb( http_parser * parser )
125{
126 auto * ctx =
127 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
128 parser->data );
129 // Next time header_name/header_value callback should store
130 // values of trailing fields.
131 ctx->m_leading_headers_completed = true;
132
133 if( ULLONG_MAX != parser->content_length &&
134 0 < parser->content_length )
135 {
136 // Maximum body size can be checked right now.
137 if( parser->content_length > ctx->m_limits.max_body_size() )
138 {
139 return -1;
140 }
141
142 try
143 {
144 ctx->m_body.reserve(
146 parser->content_length) );
147 }
148 catch( const std::exception & )
149 {
150 return -1;
151 }
152 }
153
154 return 0;
155}
156
157
158inline int
159restinio_body_cb( http_parser * parser, const char *at, size_t length )
160{
161 try
162 {
163 auto * ctx =
164 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
165 parser->data );
166
167 // The total size of the body should be checked.
168 const auto total_length = static_cast<std::uint64_t>(
169 ctx->m_body.size() ) + length;
170 if( total_length > ctx->m_limits.max_body_size() )
171 {
172 return -1;
173 }
174
175 ctx->m_body.append( at, length );
176 }
177 catch( const std::exception & )
178 {
179 return -1;
180 }
181
182 return 0;
183}
184
185inline int
186restinio_chunk_header_cb( http_parser * parser )
187{
188 try
189 {
190 // In on_chunk_header callback parser->content_length contains
191 // the size of the next chunk.
192 // If that size is 0 then it is the last chunk and it should be
193 // ignored.
194 if( 0u != parser->content_length )
195 {
196 auto * ctx =
197 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
198 parser->data );
199
200 // Store an info about the new chunk.
201 // If there will be an error at the next stage of parsing
202 // the incoming request the whole request's data will be dropped.
203 // So there is no need to care about that new item in m_chunks.
204 ctx->m_chunked_info_block.m_chunks.emplace_back(
205 ctx->m_body.size(),
206 ::restinio::utils::impl::uint64_to_size_t(parser->content_length) );
207 }
208 }
209 catch( const std::exception & )
210 {
211 return -1;
212 }
213
214 return 0;
215}
216
217inline int
218restinio_chunk_complete_cb( http_parser * /*parser*/ )
219{
220 // There is nothing to do.
221 return 0;
222}
223
224template< typename Http_Methods >
225int
226restinio_message_complete_cb( http_parser * parser )
227{
228 // If entire http-message consumed, we need to stop parser.
229 http_parser_pause( parser, 1 );
230
231 auto * ctx =
232 reinterpret_cast< restinio::impl::http_parser_ctx_t * >(
233 parser->data );
234
235 // Maybe the last trailing header is not handled yet.
236 if( !ctx->m_last_was_value && !ctx->m_current_field_name.empty() )
237 {
239 std::move( ctx->m_current_field_name ),
240 std::string{} );
241 }
242
243 ctx->m_message_complete = true;
244 ctx->m_header.method( Http_Methods::from_nodejs( parser->method ) );
245
246 if( 0 == parser->upgrade )
247 ctx->m_header.should_keep_alive( 0 != http_should_keep_alive( parser ) );
248 else
249 ctx->m_header.connection( http_connection_header_t::upgrade );
250
251 return 0;
252}
void add_field(http_field_t field_id, std::string field_value)
Add a field in the form of id-value pair.
std::size_t uint64_to_size_t(std::uint64_t v)
Helper function for truncating uint64 to std::size_t with exception if that truncation will lead to d...
ws_handle_t upgrade(generic_request_type_from_traits_t< Traits > &req, activation_t activation_flag, http_header_fields_t upgrade_response_header_fields, WS_Message_Handler ws_message_handler)
Upgrade http-connection of a current request to a websocket connection.
Definition: websocket.hpp:215
nonstd::string_view string_view_t
Definition: string_view.hpp:19
int restinio_url_cb(http_parser *parser, const char *at, size_t length)
int restinio_header_value_cb(http_parser *parser, const char *at, size_t length)
int restinio_body_cb(http_parser *parser, const char *at, size_t length)
int restinio_message_complete_cb(http_parser *parser)
void append_last_field_accessor(http_header_fields_t &fields, string_view_t value)
int restinio_chunk_complete_cb(http_parser *)
int restinio_headers_complete_cb(http_parser *parser)
int restinio_header_field_cb(http_parser *parser, const char *at, size_t length)
int restinio_chunk_header_cb(http_parser *parser)
void append_request_target(const char *at, size_t length)
Helpfull function for using in parser callback.
std::vector< chunk_info_t > m_chunks
All non-empty chunks from the input.
http_header_fields_t m_trailing_fields
Trailing fields found in the input.
Parsing result context for using in parser callbacks.
Definition: connection.hpp:49
http_request_header_t m_header
Request data.
Definition: connection.hpp:52
chunked_input_info_block_t m_chunked_info_block
Definition: connection.hpp:70
std::string m_current_field_name
Parser context temp values and flags.
Definition: connection.hpp:58