RESTinio
parser_callbacks.ipp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  Callbacks used with http parser.
7 */
8 
9 inline int
10 restinio_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 
34 inline int
35 restinio_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 
73 inline void
74 append_last_field_accessor( http_header_fields_t & fields, string_view_t value )
75 {
76  fields.append_last_field( value );
77 }
78 
79 inline int
80 restinio_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 
123 inline int
124 restinio_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(
145  ::restinio::utils::impl::uint64_to_size_t(
146  parser->content_length) );
147  }
148  catch( const std::exception & )
149  {
150  return -1;
151  }
152  }
153 
154  return 0;
155 }
156 
157 
158 inline int
159 restinio_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 
185 inline int
186 restinio_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 
217 inline int
219 {
220  // There is nothing to do.
221  return 0;
222 }
223 
224 template< typename Http_Methods >
225 int
226 restinio_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  {
238  ctx->m_chunked_info_block.m_trailing_fields.add_field(
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 }
int restinio_url_cb(http_parser *parser, const char *at, size_t length)
void append_last_field_accessor(http_header_fields_t &fields, string_view_t value)
int restinio_body_cb(http_parser *parser, const char *at, size_t length)
int restinio_chunk_complete_cb(http_parser *)
int restinio_chunk_header_cb(http_parser *parser)
int restinio_headers_complete_cb(http_parser *parser)
int restinio_header_value_cb(http_parser *parser, const char *at, size_t length)
int restinio_header_field_cb(http_parser *parser, const char *at, size_t length)
int restinio_message_complete_cb(http_parser *parser)