2014-04-01 13:58:52 +00:00
# pragma once
2014-03-31 16:51:50 +00:00
# include <string>
2014-04-01 12:25:16 +00:00
# include <unordered_map>
2014-04-20 08:45:10 +00:00
# include <boost/algorithm/string.hpp>
2014-09-22 20:34:22 +00:00
# include <algorithm>
2014-04-01 12:25:16 +00:00
2016-09-21 14:11:06 +00:00
# include "crow/http_parser_merged.h"
# include "crow/http_request.h"
2014-04-01 13:58:52 +00:00
2014-04-26 17:19:59 +00:00
namespace crow
2014-03-31 16:51:50 +00:00
{
2020-11-18 22:13:57 +00:00
/// A wrapper for `nodejs/http-parser`.
2021-12-03 03:39:23 +00:00
2020-11-18 22:13:57 +00:00
///
2021-11-25 11:45:38 +00:00
/// Used to generate a \ref crow.request from the TCP socket buffer.
template < typename Handler >
2014-03-31 16:51:50 +00:00
struct HTTPParser : public http_parser
{
static int on_message_begin ( http_parser * self_ )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2014-04-01 12:25:16 +00:00
self - > clear ( ) ;
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_url ( http_parser * self_ , const char * at , size_t length )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2021-11-25 11:45:38 +00:00
self - > raw_url . insert ( self - > raw_url . end ( ) , at , at + length ) ;
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_header_field ( http_parser * self_ , const char * at , size_t length )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2014-04-01 12:25:16 +00:00
switch ( self - > header_building_state )
{
case 0 :
if ( ! self - > header_value . empty ( ) )
{
self - > headers . emplace ( std : : move ( self - > header_field ) , std : : move ( self - > header_value ) ) ;
}
2021-11-25 11:45:38 +00:00
self - > header_field . assign ( at , at + length ) ;
2014-04-01 12:25:16 +00:00
self - > header_building_state = 1 ;
break ;
case 1 :
2021-11-25 11:45:38 +00:00
self - > header_field . insert ( self - > header_field . end ( ) , at , at + length ) ;
2014-04-01 12:25:16 +00:00
break ;
}
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_header_value ( http_parser * self_ , const char * at , size_t length )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2014-04-01 12:25:16 +00:00
switch ( self - > header_building_state )
{
case 0 :
2021-11-25 11:45:38 +00:00
self - > header_value . insert ( self - > header_value . end ( ) , at , at + length ) ;
2014-04-01 12:25:16 +00:00
break ;
case 1 :
self - > header_building_state = 0 ;
2021-11-25 11:45:38 +00:00
self - > header_value . assign ( at , at + length ) ;
2014-04-01 12:25:16 +00:00
break ;
}
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_headers_complete ( http_parser * self_ )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2014-04-01 12:25:16 +00:00
if ( ! self - > header_field . empty ( ) )
{
self - > headers . emplace ( std : : move ( self - > header_field ) , std : : move ( self - > header_value ) ) ;
}
2022-02-05 15:15:19 +00:00
2022-02-10 21:56:30 +00:00
self - > set_connection_parameters ( ) ;
2022-02-05 15:15:19 +00:00
2014-05-02 12:54:25 +00:00
self - > process_header ( ) ;
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_body ( http_parser * self_ , const char * at , size_t length )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2021-11-25 11:45:38 +00:00
self - > body . insert ( self - > body . end ( ) , at , at + length ) ;
2014-03-31 16:51:50 +00:00
return 0 ;
}
static int on_message_complete ( http_parser * self_ )
{
HTTPParser * self = static_cast < HTTPParser * > ( self_ ) ;
2014-10-14 08:48:35 +00:00
// url params
2022-02-05 15:15:19 +00:00
self - > url = self - > raw_url . substr ( 0 , self - > qs_point ! = 0 ? self - > qs_point : std : : string : : npos ) ;
2014-10-14 08:48:35 +00:00
self - > url_params = query_string ( self - > raw_url ) ;
2014-04-01 12:25:16 +00:00
self - > process_message ( ) ;
2014-03-31 16:51:50 +00:00
return 0 ;
}
2021-11-25 11:45:38 +00:00
HTTPParser ( Handler * handler ) :
handler_ ( handler )
2014-08-15 02:06:00 +00:00
{
2022-02-05 15:15:19 +00:00
http_parser_init ( this ) ;
2014-08-15 02:06:00 +00:00
}
// return false on error
2020-11-18 22:13:57 +00:00
/// Parse a buffer into the different sections of an HTTP request.
2014-08-15 02:06:00 +00:00
bool feed ( const char * buffer , int length )
{
const static http_parser_settings settings_ {
2021-11-25 11:45:38 +00:00
on_message_begin ,
on_url ,
on_header_field ,
on_header_value ,
on_headers_complete ,
on_body ,
on_message_complete ,
2014-08-15 02:06:00 +00:00
} ;
2014-03-31 16:51:50 +00:00
int nparsed = http_parser_execute ( this , & settings_ , buffer , length ) ;
2022-02-05 15:15:19 +00:00
if ( http_errno ! = CHPE_OK )
2021-11-01 09:02:25 +00:00
{
return false ;
}
2014-04-01 12:25:16 +00:00
return nparsed = = length ;
2014-03-31 16:51:50 +00:00
}
2014-04-01 12:25:16 +00:00
bool done ( )
2014-03-31 16:51:50 +00:00
{
2014-08-15 02:06:00 +00:00
return feed ( nullptr , 0 ) ;
2014-03-31 16:51:50 +00:00
}
2014-04-01 12:25:16 +00:00
void clear ( )
{
url . clear ( ) ;
2014-10-14 08:48:35 +00:00
raw_url . clear ( ) ;
2014-04-01 12:25:16 +00:00
header_building_state = 0 ;
header_field . clear ( ) ;
header_value . clear ( ) ;
headers . clear ( ) ;
2014-09-22 20:34:22 +00:00
url_params . clear ( ) ;
2014-04-01 12:25:16 +00:00
body . clear ( ) ;
}
2022-02-05 15:15:19 +00:00
inline void process_header ( )
2014-05-02 12:54:25 +00:00
{
handler_ - > handle_header ( ) ;
}
2022-02-05 15:15:19 +00:00
inline void process_message ( )
2014-04-01 12:25:16 +00:00
{
handler_ - > handle ( ) ;
}
2022-02-10 21:56:30 +00:00
inline void set_connection_parameters ( )
{
//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"
// HTTP1.1 = always send keep_alive, HTTP1.0 = only send if header exists, HTTP?.? = never send
keep_alive = ( http_major = = 1 & & http_minor = = 0 ) ?
( ( flags & F_CONNECTION_KEEP_ALIVE ) ? true : false ) :
( ( http_major = = 1 & & http_minor = = 1 ) ? true : false ) ;
// HTTP1.1 = only close if close header exists, HTTP1.0 = always close unless keep_alive header exists, HTTP?.?= never close
close_connection = ( http_major = = 1 & & http_minor = = 0 ) ?
( ( flags & F_CONNECTION_KEEP_ALIVE ) ? false : true ) :
( ( http_major = = 1 & & http_minor = = 1 ) ? ( ( flags & F_CONNECTION_CLOSE ) ? true : false ) : false ) ;
}
2020-11-18 22:13:57 +00:00
/// Take the parsed HTTP request data and convert it to a \ref crow.request
2014-05-02 12:54:25 +00:00
request to_request ( ) const
2014-04-01 13:58:52 +00:00
{
2022-02-05 15:15:19 +00:00
return request { static_cast < HTTPMethod > ( method ) , std : : move ( raw_url ) , std : : move ( url ) , std : : move ( url_params ) , std : : move ( headers ) , std : : move ( body ) , http_major , http_minor , keep_alive , close_connection , static_cast < bool > ( upgrade ) } ;
2014-05-02 12:54:25 +00:00
}
2014-10-14 08:48:35 +00:00
std : : string raw_url ;
2014-04-01 12:25:16 +00:00
std : : string url ;
2014-09-22 20:34:22 +00:00
2014-04-01 12:25:16 +00:00
int header_building_state = 0 ;
std : : string header_field ;
std : : string header_value ;
2014-09-10 21:32:41 +00:00
ci_map headers ;
2020-11-18 22:13:57 +00:00
query_string url_params ; ///< What comes after the `?` in the URL.
2014-04-01 12:25:16 +00:00
std : : string body ;
2022-02-05 15:15:19 +00:00
bool keep_alive ; ///< Whether or not the server should send a `connection: Keep-Alive` header to the client.
bool close_connection ; ///< Whether or not the server should shut down the TCP connection once a response is sent.
2014-04-01 12:25:16 +00:00
2020-11-18 22:13:57 +00:00
Handler * handler_ ; ///< This is currently an HTTP connection object (\ref crow.Connection).
2014-03-31 16:51:50 +00:00
} ;
2021-11-25 11:45:38 +00:00
} // namespace crow