2014-03-31 16:51:50 +00:00
# pragma once
2022-06-22 16:08:13 +00:00
# ifndef ASIO_STANDALONE
2022-06-06 14:38:46 +00:00
# define ASIO_STANDALONE
2022-06-22 16:08:13 +00:00
# endif
2022-06-06 14:38:46 +00:00
# include <asio.hpp>
2014-05-02 05:17:49 +00:00
# include <atomic>
# include <chrono>
2014-10-23 17:45:34 +00:00
# include <vector>
2014-07-29 11:20:50 +00:00
2016-09-21 14:11:06 +00:00
# include "crow/http_parser_merged.h"
2021-10-02 14:11:19 +00:00
# include "crow/common.h"
2016-09-21 14:11:06 +00:00
# include "crow/parser.h"
# include "crow/http_response.h"
# include "crow/logging.h"
# include "crow/settings.h"
2021-11-19 17:42:25 +00:00
# include "crow/task_timer.h"
2016-09-21 14:11:06 +00:00
# include "crow/middleware_context.h"
2022-02-01 13:31:05 +00:00
# include "crow/middleware.h"
2016-09-21 14:11:06 +00:00
# include "crow/socket_adaptors.h"
2021-01-02 19:12:04 +00:00
# include "crow/compression.h"
2022-06-06 15:14:37 +00:00
# include "crow/utility.h"
2014-03-31 16:51:50 +00:00
2014-04-26 17:19:59 +00:00
namespace crow
2014-03-31 16:51:50 +00:00
{
2022-06-06 14:38:46 +00:00
using tcp = asio : : ip : : tcp ;
2015-09-20 13:06:00 +00:00
2014-09-06 19:30:53 +00:00
2014-07-29 11:20:50 +00:00
# ifdef CROW_ENABLE_DEBUG
2016-11-15 15:44:45 +00:00
static std : : atomic < int > connectionCount ;
2014-07-29 11:20:50 +00:00
# endif
2020-11-18 22:13:57 +00:00
/// An HTTP connection.
2021-11-25 11:45:38 +00:00
template < typename Adaptor , typename Handler , typename . . . Middlewares >
2014-08-15 02:06:00 +00:00
class Connection
2014-03-31 16:51:50 +00:00
{
2020-10-19 16:55:40 +00:00
friend struct crow : : response ;
2021-11-25 11:45:38 +00:00
2014-03-31 16:51:50 +00:00
public :
2014-09-06 19:30:53 +00:00
Connection (
2022-06-06 14:38:46 +00:00
asio : : io_service & io_service ,
2021-11-25 11:45:38 +00:00
Handler * handler ,
const std : : string & server_name ,
std : : tuple < Middlewares . . . > * middlewares ,
std : : function < std : : string ( ) > & get_cached_date_str_f ,
detail : : task_timer & task_timer ,
2021-11-29 15:56:12 +00:00
typename Adaptor : : context * adaptor_ctx_ ,
2021-12-03 16:33:40 +00:00
std : : atomic < unsigned int > & queue_length ) :
2021-11-25 11:45:38 +00:00
adaptor_ ( io_service , adaptor_ctx_ ) ,
handler_ ( handler ) ,
parser_ ( this ) ,
2022-07-18 03:33:56 +00:00
req_ ( parser_ . req ) ,
2021-11-25 11:45:38 +00:00
server_name_ ( server_name ) ,
middlewares_ ( middlewares ) ,
get_cached_date_str ( get_cached_date_str_f ) ,
task_timer_ ( task_timer ) ,
2021-11-29 15:56:12 +00:00
res_stream_threshold_ ( handler - > stream_threshold ( ) ) ,
2021-12-03 16:33:40 +00:00
queue_length_ ( queue_length )
2014-07-29 11:20:50 +00:00
{
# ifdef CROW_ENABLE_DEBUG
2021-11-25 11:45:38 +00:00
connectionCount + + ;
2022-02-05 15:15:19 +00:00
CROW_LOG_DEBUG < < " Connection ( " < < this < < " ) allocated, total: " < < connectionCount ;
2014-07-29 11:20:50 +00:00
# endif
}
2021-11-25 11:45:38 +00:00
2014-07-29 11:20:50 +00:00
~ Connection ( )
2014-03-31 16:51:50 +00:00
{
2014-08-05 18:54:38 +00:00
res . complete_request_handler_ = nullptr ;
2014-08-16 02:55:26 +00:00
cancel_deadline_timer ( ) ;
2014-08-05 18:54:38 +00:00
# ifdef CROW_ENABLE_DEBUG
2021-11-25 11:45:38 +00:00
connectionCount - - ;
2022-02-05 15:15:19 +00:00
CROW_LOG_DEBUG < < " Connection ( " < < this < < " ) freed, total: " < < connectionCount ;
2014-07-29 11:20:50 +00:00
# endif
2014-08-05 18:54:38 +00:00
}
2014-03-31 16:51:50 +00:00
2020-11-18 22:13:57 +00:00
/// The TCP socket on top of which the connection is established.
2015-09-20 13:06:00 +00:00
decltype ( std : : declval < Adaptor > ( ) . raw_socket ( ) ) & socket ( )
2014-08-17 09:35:21 +00:00
{
2015-09-20 13:06:00 +00:00
return adaptor_ . raw_socket ( ) ;
2014-08-17 09:35:21 +00:00
}
2014-03-31 16:51:50 +00:00
void start ( )
{
2022-06-07 00:43:53 +00:00
adaptor_ . start ( [ this ] ( const asio : : error_code & ec ) {
2015-09-20 13:06:00 +00:00
if ( ! ec )
{
start_deadline ( ) ;
2014-07-29 11:20:50 +00:00
2015-09-20 13:06:00 +00:00
do_read ( ) ;
}
else
{
2021-04-16 23:33:35 +00:00
CROW_LOG_ERROR < < " Could not start adaptor: " < < ec . message ( ) ;
2015-09-20 13:06:00 +00:00
check_destroy ( ) ;
2021-11-27 17:44:51 +00:00
}
} ) ;
2014-03-31 16:51:50 +00:00
}
2022-07-18 03:33:56 +00:00
void handle_url ( )
{
routing_handle_result_ = handler_ - > handle_initial ( req_ , res ) ;
// if no route is found for the request method, return the response without parsing or processing anything further.
2022-07-20 20:03:42 +00:00
if ( ! routing_handle_result_ - > rule_index )
{
parser_ . done ( ) ;
2022-07-18 03:33:56 +00:00
complete_request ( ) ;
2022-07-20 20:03:42 +00:00
}
2022-07-18 03:33:56 +00:00
}
2014-05-02 12:54:25 +00:00
void handle_header ( )
{
// HTTP 1.1 Expect: 100-continue
2022-07-20 20:03:42 +00:00
if ( req_ . http_ver_major = = 1 & & req_ . http_ver_minor = = 1 & & get_header_value ( req_ . headers , " expect " ) = = " 100-continue " )
2014-05-02 12:54:25 +00:00
{
buffers_ . clear ( ) ;
static std : : string expect_100_continue = " HTTP/1.1 100 Continue \r \n \r \n " ;
buffers_ . emplace_back ( expect_100_continue . data ( ) , expect_100_continue . size ( ) ) ;
do_write ( ) ;
}
}
2014-04-01 12:25:16 +00:00
void handle ( )
{
2022-07-20 20:03:42 +00:00
// TODO(EDev): cancel_deadline_timer should be looked into, it might be a good idea to add it to handle_url() and then restart the timer once everything passes
2014-08-16 16:10:19 +00:00
cancel_deadline_timer ( ) ;
2014-05-02 09:22:02 +00:00
bool is_invalid_request = false ;
2014-09-19 23:20:35 +00:00
add_keep_alive_ = false ;
2014-05-02 09:22:02 +00:00
2022-07-18 03:33:56 +00:00
req_ . remote_ip_address = adaptor_ . remote_endpoint ( ) . address ( ) . to_string ( ) ;
2018-09-28 19:13:52 +00:00
2022-07-18 03:33:56 +00:00
add_keep_alive_ = req_ . keep_alive ;
close_connection_ = req_ . close_connection ;
2022-02-05 15:15:19 +00:00
2022-07-18 03:33:56 +00:00
if ( req_ . check_version ( 1 , 1 ) ) // HTTP/1.1
2014-04-20 08:45:10 +00:00
{
2022-07-18 03:33:56 +00:00
if ( ! req_ . headers . count ( " host " ) )
2014-05-02 09:22:02 +00:00
{
is_invalid_request = true ;
res = response ( 400 ) ;
}
2022-07-18 03:33:56 +00:00
if ( req_ . upgrade )
2021-11-25 11:45:38 +00:00
{
2022-04-07 12:54:50 +00:00
// h2 or h2c headers
2022-07-18 03:33:56 +00:00
if ( req_ . get_header_value ( " upgrade " ) . substr ( 0 , 2 ) = = " h2 " )
2022-02-05 15:15:19 +00:00
{
// TODO(ipkn): HTTP/2
// currently, ignore upgrade header
}
2016-08-28 05:46:31 +00:00
else
{
close_connection_ = true ;
2022-07-18 03:33:56 +00:00
handler_ - > handle_upgrade ( req_ , res , std : : move ( adaptor_ ) ) ;
2016-08-28 05:46:31 +00:00
return ;
}
2021-11-25 11:45:38 +00:00
}
2014-04-20 08:45:10 +00:00
}
2022-07-18 03:33:56 +00:00
CROW_LOG_INFO < < " Request: " < < utility : : lexical_cast < std : : string > ( adaptor_ . remote_endpoint ( ) ) < < " " < < this < < " HTTP/ " < < ( char ) ( req_ . http_ver_major + ' 0 ' ) < < " . " < < ( char ) ( req_ . http_ver_minor + ' 0 ' ) < < ' ' < < method_name ( req_ . method ) < < " " < < req_ . url ;
2014-08-05 18:54:38 +00:00
2014-09-06 19:30:53 +00:00
need_to_call_after_handlers_ = false ;
2014-05-02 09:22:02 +00:00
if ( ! is_invalid_request )
{
2021-11-25 11:45:38 +00:00
res . complete_request_handler_ = [ ] { } ;
2021-11-27 17:44:51 +00:00
res . is_alive_helper_ = [ this ] ( ) - > bool {
return adaptor_ . is_open ( ) ;
} ;
2014-09-06 19:30:53 +00:00
2014-09-07 22:07:53 +00:00
ctx_ = detail : : context < Middlewares . . . > ( ) ;
2022-07-18 03:33:56 +00:00
req_ . middleware_context = static_cast < void * > ( & ctx_ ) ;
req_ . middleware_container = static_cast < void * > ( middlewares_ ) ;
req_ . io_service = & adaptor_ . get_io_service ( ) ;
2022-02-01 13:31:05 +00:00
detail : : middleware_call_helper < detail : : middleware_call_criteria_only_global ,
2022-07-18 03:33:56 +00:00
0 , decltype ( ctx_ ) , decltype ( * middlewares_ ) > ( { } , * middlewares_ , req_ , res , ctx_ ) ;
2014-09-06 19:30:53 +00:00
if ( ! res . completed_ )
{
2021-11-27 17:44:51 +00:00
res . complete_request_handler_ = [ this ] {
this - > complete_request ( ) ;
} ;
2014-09-06 19:30:53 +00:00
need_to_call_after_handlers_ = true ;
2022-07-18 03:33:56 +00:00
handler_ - > handle ( req_ , res , routing_handle_result_ ) ;
2014-09-19 23:20:35 +00:00
if ( add_keep_alive_ )
res . set_header ( " connection " , " Keep-Alive " ) ;
2014-09-06 19:30:53 +00:00
}
2014-09-07 22:07:53 +00:00
else
{
complete_request ( ) ;
}
2014-05-02 09:22:02 +00:00
}
2014-09-19 23:20:35 +00:00
else
{
complete_request ( ) ;
}
2014-08-05 18:54:38 +00:00
}
2020-11-18 22:13:57 +00:00
/// Call the after handle middleware and send the write the response to the connection.
2014-08-05 18:54:38 +00:00
void complete_request ( )
{
2014-10-14 08:48:35 +00:00
CROW_LOG_INFO < < " Response: " < < this < < ' ' < < req_ . raw_url < < ' ' < < res . code < < ' ' < < close_connection_ ;
2014-08-05 18:54:38 +00:00
2014-09-06 19:30:53 +00:00
if ( need_to_call_after_handlers_ )
{
2014-09-14 11:12:18 +00:00
need_to_call_after_handlers_ = false ;
2014-09-07 22:07:53 +00:00
// call all after_handler of middlewares
detail : : after_handlers_call_helper <
2022-02-01 13:31:05 +00:00
detail : : middleware_call_criteria_only_global ,
2021-11-25 11:45:38 +00:00
( static_cast < int > ( sizeof . . . ( Middlewares ) ) - 1 ) ,
decltype ( ctx_ ) ,
2022-04-11 13:01:27 +00:00
decltype ( * middlewares_ ) > ( { } , * middlewares_ , ctx_ , req_ , res ) ;
2014-09-06 19:30:53 +00:00
}
2021-06-03 14:12:20 +00:00
# ifdef CROW_ENABLE_COMPRESSION
2021-11-25 11:45:38 +00:00
if ( handler_ - > compression_used ( ) )
{
2021-08-29 17:54:57 +00:00
std : : string accept_encoding = req_ . get_header_value ( " Accept-Encoding " ) ;
if ( ! accept_encoding . empty ( ) & & res . compressed )
2021-01-02 19:12:04 +00:00
{
2021-08-29 17:54:57 +00:00
switch ( handler_ - > compression_algorithm ( ) )
{
case compression : : DEFLATE :
if ( accept_encoding . find ( " deflate " ) ! = std : : string : : npos )
{
res . body = compression : : compress_string ( res . body , compression : : algorithm : : DEFLATE ) ;
res . set_header ( " Content-Encoding " , " deflate " ) ;
}
break ;
case compression : : GZIP :
if ( accept_encoding . find ( " gzip " ) ! = std : : string : : npos )
{
res . body = compression : : compress_string ( res . body , compression : : algorithm : : GZIP ) ;
res . set_header ( " Content-Encoding " , " gzip " ) ;
}
break ;
default :
break ;
}
2021-01-02 19:12:04 +00:00
}
2021-01-21 18:36:41 +00:00
}
2021-06-03 14:12:20 +00:00
# endif
2020-12-26 16:54:41 +00:00
//if there is a redirection with a partial URL, treat the URL as a route.
std : : string location = res . get_header_value ( " Location " ) ;
2021-01-03 14:56:19 +00:00
if ( ! location . empty ( ) & & location . find ( " :// " , 0 ) = = std : : string : : npos )
2020-12-26 16:54:41 +00:00
{
2021-11-25 11:45:38 +00:00
# ifdef CROW_ENABLE_SSL
2021-11-21 23:29:22 +00:00
if ( handler_ - > ssl_used ( ) )
location . insert ( 0 , " https:// " + req_ . get_header_value ( " Host " ) ) ;
else
2021-11-25 11:45:38 +00:00
# endif
location . insert ( 0 , " http:// " + req_ . get_header_value ( " Host " ) ) ;
2020-12-26 16:54:41 +00:00
res . set_header ( " location " , location ) ;
2021-01-02 19:12:04 +00:00
}
2021-11-25 11:45:38 +00:00
prepare_buffers ( ) ;
2021-04-12 17:11:03 +00:00
2020-11-14 02:28:07 +00:00
if ( res . is_static_type ( ) )
2020-10-04 12:05:26 +00:00
{
do_write_static ( ) ;
2021-11-25 11:45:38 +00:00
}
else
{
2020-10-04 12:05:26 +00:00
do_write_general ( ) ;
}
}
private :
2020-10-21 01:02:09 +00:00
void prepare_buffers ( )
{
2014-08-15 02:06:00 +00:00
//auto self = this->shared_from_this();
2014-08-05 18:54:38 +00:00
res . complete_request_handler_ = nullptr ;
2020-10-04 12:05:26 +00:00
2015-09-20 13:06:00 +00:00
if ( ! adaptor_ . is_open ( ) )
2014-08-15 02:06:00 +00:00
{
2014-08-16 16:10:19 +00:00
//CROW_LOG_DEBUG << this << " delete (socket is closed) " << is_reading << ' ' << is_writing;
//delete this;
2014-09-19 23:20:35 +00:00
return ;
2014-08-15 02:06:00 +00:00
}
2022-02-05 15:15:19 +00:00
// TODO(EDev): HTTP version in status codes should be dynamic
2021-09-30 17:38:23 +00:00
// Keep in sync with common.h/status
2014-08-05 18:54:38 +00:00
static std : : unordered_map < int , std : : string > statusCodes = {
2021-11-25 11:45:38 +00:00
{ status : : CONTINUE , " HTTP/1.1 100 Continue \r \n " } ,
{ status : : SWITCHING_PROTOCOLS , " HTTP/1.1 101 Switching Protocols \r \n " } ,
{ status : : OK , " HTTP/1.1 200 OK \r \n " } ,
{ status : : CREATED , " HTTP/1.1 201 Created \r \n " } ,
{ status : : ACCEPTED , " HTTP/1.1 202 Accepted \r \n " } ,
{ status : : NON_AUTHORITATIVE_INFORMATION , " HTTP/1.1 203 Non-Authoritative Information \r \n " } ,
{ status : : NO_CONTENT , " HTTP/1.1 204 No Content \r \n " } ,
{ status : : RESET_CONTENT , " HTTP/1.1 205 Reset Content \r \n " } ,
{ status : : PARTIAL_CONTENT , " HTTP/1.1 206 Partial Content \r \n " } ,
{ status : : MULTIPLE_CHOICES , " HTTP/1.1 300 Multiple Choices \r \n " } ,
{ status : : MOVED_PERMANENTLY , " HTTP/1.1 301 Moved Permanently \r \n " } ,
{ status : : FOUND , " HTTP/1.1 302 Found \r \n " } ,
{ status : : SEE_OTHER , " HTTP/1.1 303 See Other \r \n " } ,
{ status : : NOT_MODIFIED , " HTTP/1.1 304 Not Modified \r \n " } ,
{ status : : TEMPORARY_REDIRECT , " HTTP/1.1 307 Temporary Redirect \r \n " } ,
{ status : : PERMANENT_REDIRECT , " HTTP/1.1 308 Permanent Redirect \r \n " } ,
{ status : : BAD_REQUEST , " HTTP/1.1 400 Bad Request \r \n " } ,
{ status : : UNAUTHORIZED , " HTTP/1.1 401 Unauthorized \r \n " } ,
{ status : : FORBIDDEN , " HTTP/1.1 403 Forbidden \r \n " } ,
{ status : : NOT_FOUND , " HTTP/1.1 404 Not Found \r \n " } ,
{ status : : METHOD_NOT_ALLOWED , " HTTP/1.1 405 Method Not Allowed \r \n " } ,
{ status : : PROXY_AUTHENTICATION_REQUIRED , " HTTP/1.1 407 Proxy Authentication Required \r \n " } ,
{ status : : CONFLICT , " HTTP/1.1 409 Conflict \r \n " } ,
{ status : : GONE , " HTTP/1.1 410 Gone \r \n " } ,
{ status : : PAYLOAD_TOO_LARGE , " HTTP/1.1 413 Payload Too Large \r \n " } ,
{ status : : UNSUPPORTED_MEDIA_TYPE , " HTTP/1.1 415 Unsupported Media Type \r \n " } ,
{ status : : RANGE_NOT_SATISFIABLE , " HTTP/1.1 416 Range Not Satisfiable \r \n " } ,
{ status : : EXPECTATION_FAILED , " HTTP/1.1 417 Expectation Failed \r \n " } ,
{ status : : PRECONDITION_REQUIRED , " HTTP/1.1 428 Precondition Required \r \n " } ,
{ status : : TOO_MANY_REQUESTS , " HTTP/1.1 429 Too Many Requests \r \n " } ,
{ status : : UNAVAILABLE_FOR_LEGAL_REASONS , " HTTP/1.1 451 Unavailable For Legal Reasons \r \n " } ,
{ status : : INTERNAL_SERVER_ERROR , " HTTP/1.1 500 Internal Server Error \r \n " } ,
{ status : : NOT_IMPLEMENTED , " HTTP/1.1 501 Not Implemented \r \n " } ,
{ status : : BAD_GATEWAY , " HTTP/1.1 502 Bad Gateway \r \n " } ,
{ status : : SERVICE_UNAVAILABLE , " HTTP/1.1 503 Service Unavailable \r \n " } ,
2022-03-20 13:50:52 +00:00
{ status : : GATEWAY_TIMEOUT , " HTTP/1.1 504 Gateway Timeout \r \n " } ,
2021-11-25 11:45:38 +00:00
{ status : : VARIANT_ALSO_NEGOTIATES , " HTTP/1.1 506 Variant Also Negotiates \r \n " } ,
2014-08-05 18:54:38 +00:00
} ;
2014-04-20 08:45:10 +00:00
2022-02-05 15:15:19 +00:00
static const std : : string seperator = " : " ;
2014-04-01 12:25:16 +00:00
2014-04-17 06:50:28 +00:00
buffers_ . clear ( ) ;
2021-11-25 11:45:38 +00:00
buffers_ . reserve ( 4 * ( res . headers . size ( ) + 5 ) + 3 ) ;
2014-04-01 12:25:16 +00:00
2014-04-17 06:50:28 +00:00
if ( ! statusCodes . count ( res . code ) )
{
2022-05-08 11:44:45 +00:00
CROW_LOG_WARNING < < this < < " status code "
< < " ( " < < res . code < < " ) "
< < " not defined, returning 500 instead " ;
res . code = 500 ;
2014-04-17 06:50:28 +00:00
}
2014-04-14 20:11:37 +00:00
2022-05-08 11:44:45 +00:00
auto & status = statusCodes . find ( res . code ) - > second ;
buffers_ . emplace_back ( status . data ( ) , status . size ( ) ) ;
2014-04-17 09:18:02 +00:00
if ( res . code > = 400 & & res . body . empty ( ) )
2014-04-14 20:11:37 +00:00
res . body = statusCodes [ res . code ] . substr ( 9 ) ;
2014-04-01 12:25:16 +00:00
2021-11-25 11:45:38 +00:00
for ( auto & kv : res . headers )
2014-04-01 12:25:16 +00:00
{
2014-04-17 06:50:28 +00:00
buffers_ . emplace_back ( kv . first . data ( ) , kv . first . size ( ) ) ;
buffers_ . emplace_back ( seperator . data ( ) , seperator . size ( ) ) ;
buffers_ . emplace_back ( kv . second . data ( ) , kv . second . size ( ) ) ;
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
2014-04-01 12:25:16 +00:00
}
2021-04-03 10:48:36 +00:00
if ( ! res . manual_length_header & & ! res . headers . count ( " content-length " ) )
2014-04-17 06:50:28 +00:00
{
2014-08-01 21:30:02 +00:00
content_length_ = std : : to_string ( res . body . size ( ) ) ;
2014-05-02 05:17:49 +00:00
static std : : string content_length_tag = " Content-Length: " ;
buffers_ . emplace_back ( content_length_tag . data ( ) , content_length_tag . size ( ) ) ;
buffers_ . emplace_back ( content_length_ . data ( ) , content_length_ . size ( ) ) ;
2014-04-17 06:50:28 +00:00
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
}
2014-09-19 23:20:35 +00:00
if ( ! res . headers . count ( " server " ) )
2014-04-17 06:50:28 +00:00
{
2014-05-02 05:17:49 +00:00
static std : : string server_tag = " Server: " ;
buffers_ . emplace_back ( server_tag . data ( ) , server_tag . size ( ) ) ;
buffers_ . emplace_back ( server_name_ . data ( ) , server_name_ . size ( ) ) ;
2014-04-17 06:50:28 +00:00
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
}
2014-09-19 23:20:35 +00:00
if ( ! res . headers . count ( " date " ) )
2014-04-17 06:50:28 +00:00
{
2014-05-02 05:17:49 +00:00
static std : : string date_tag = " Date: " ;
date_str_ = get_cached_date_str ( ) ;
buffers_ . emplace_back ( date_tag . data ( ) , date_tag . size ( ) ) ;
buffers_ . emplace_back ( date_str_ . data ( ) , date_str_ . size ( ) ) ;
2014-04-18 22:27:05 +00:00
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
2014-04-17 06:50:28 +00:00
}
2014-09-19 23:20:35 +00:00
if ( add_keep_alive_ )
{
2016-03-07 23:30:19 +00:00
static std : : string keep_alive_tag = " Connection: Keep-Alive " ;
2014-09-19 23:20:35 +00:00
buffers_ . emplace_back ( keep_alive_tag . data ( ) , keep_alive_tag . size ( ) ) ;
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
}
2014-04-01 12:25:16 +00:00
2014-04-17 06:50:28 +00:00
buffers_ . emplace_back ( crlf . data ( ) , crlf . size ( ) ) ;
2020-10-04 12:05:26 +00:00
}
2020-11-12 13:27:26 +00:00
2020-10-21 01:02:09 +00:00
void do_write_static ( )
{
2020-10-04 12:05:26 +00:00
is_writing = true ;
2022-06-06 14:38:46 +00:00
asio : : write ( adaptor_ . socket ( ) , buffers_ ) ;
2021-12-02 12:36:52 +00:00
if ( res . file_info . statResult = = 0 )
{
std : : ifstream is ( res . file_info . path . c_str ( ) , std : : ios : : in | std : : ios : : binary ) ;
char buf [ 16384 ] ;
while ( is . read ( buf , sizeof ( buf ) ) . gcount ( ) > 0 )
{
2022-06-06 14:38:46 +00:00
std : : vector < asio : : const_buffer > buffers ;
buffers . push_back ( asio : : buffer ( buf ) ) ;
2021-12-02 12:36:52 +00:00
do_write_sync ( buffers ) ;
}
}
2022-02-05 15:15:19 +00:00
is_writing = false ;
if ( close_connection_ )
{
adaptor_ . shutdown_readwrite ( ) ;
adaptor_ . close ( ) ;
2022-02-10 21:56:30 +00:00
CROW_LOG_DEBUG < < this < < " from write (static) " ;
2022-02-05 15:15:19 +00:00
check_destroy ( ) ;
}
2020-10-12 21:53:27 +00:00
2020-10-04 12:05:26 +00:00
res . end ( ) ;
res . clear ( ) ;
buffers_ . clear ( ) ;
}
2020-11-12 13:27:26 +00:00
2020-10-21 01:02:09 +00:00
void do_write_general ( )
{
2020-10-21 17:54:28 +00:00
if ( res . body . length ( ) < res_stream_threshold_ )
2020-10-21 01:02:09 +00:00
{
res_body_copy_ . swap ( res . body ) ;
buffers_ . emplace_back ( res_body_copy_ . data ( ) , res_body_copy_ . size ( ) ) ;
2014-04-01 12:25:16 +00:00
2020-10-21 01:02:09 +00:00
do_write ( ) ;
2014-09-14 11:12:18 +00:00
2020-10-21 01:02:09 +00:00
if ( need_to_start_read_after_complete_ )
{
need_to_start_read_after_complete_ = false ;
start_deadline ( ) ;
do_read ( ) ;
}
}
else
2014-09-14 11:12:18 +00:00
{
2020-10-21 01:02:09 +00:00
is_writing = true ;
2022-06-06 14:38:46 +00:00
asio : : write ( adaptor_ . socket ( ) , buffers_ ) ; // Write the response start / headers
2022-05-06 17:02:43 +00:00
cancel_deadline_timer ( ) ;
2021-12-02 12:36:52 +00:00
if ( res . body . length ( ) > 0 )
{
std : : string buf ;
2022-06-06 14:38:46 +00:00
std : : vector < asio : : const_buffer > buffers ;
2021-12-02 12:36:52 +00:00
while ( res . body . length ( ) > 16384 )
{
//buf.reserve(16385);
buf = res . body . substr ( 0 , 16384 ) ;
res . body = res . body . substr ( 16384 ) ;
2021-12-02 17:18:34 +00:00
buffers . clear ( ) ;
2022-06-06 14:38:46 +00:00
buffers . push_back ( asio : : buffer ( buf ) ) ;
2021-12-02 12:36:52 +00:00
do_write_sync ( buffers ) ;
}
// Collect whatever is left (less than 16KB) and send it down the socket
// buf.reserve(is.length());
buf = res . body ;
res . body . clear ( ) ;
2021-12-02 17:18:34 +00:00
buffers . clear ( ) ;
2022-06-06 14:38:46 +00:00
buffers . push_back ( asio : : buffer ( buf ) ) ;
2021-12-02 12:36:52 +00:00
do_write_sync ( buffers ) ;
}
2022-02-05 15:15:19 +00:00
is_writing = false ;
if ( close_connection_ )
{
adaptor_ . shutdown_readwrite ( ) ;
adaptor_ . close ( ) ;
2022-02-10 21:56:30 +00:00
CROW_LOG_DEBUG < < this < < " from write (res_stream) " ;
2022-02-05 15:15:19 +00:00
check_destroy ( ) ;
}
2020-10-21 01:02:09 +00:00
res . end ( ) ;
res . clear ( ) ;
buffers_ . clear ( ) ;
2014-09-14 11:12:18 +00:00
}
2014-04-01 12:25:16 +00:00
}
2014-03-31 16:51:50 +00:00
void do_read ( )
{
2014-08-15 02:06:00 +00:00
//auto self = this->shared_from_this();
is_reading = true ;
2021-11-25 11:45:38 +00:00
adaptor_ . socket ( ) . async_read_some (
2022-06-06 14:38:46 +00:00
asio : : buffer ( buffer_ ) ,
2022-06-07 00:43:53 +00:00
[ this ] ( const asio : : error_code & ec , std : : size_t bytes_transferred ) {
2021-11-25 11:45:38 +00:00
bool error_while_reading = true ;
if ( ! ec )
{
bool ret = parser_ . feed ( buffer_ . data ( ) , bytes_transferred ) ;
if ( ret & & adaptor_ . is_open ( ) )
{
error_while_reading = false ;
}
}
if ( error_while_reading )
{
cancel_deadline_timer ( ) ;
parser_ . done ( ) ;
adaptor_ . shutdown_read ( ) ;
adaptor_ . close ( ) ;
is_reading = false ;
2022-02-05 15:15:19 +00:00
CROW_LOG_DEBUG < < this < < " from read(1) with description: \" " < < http_errno_description ( static_cast < http_errno > ( parser_ . http_errno ) ) < < ' \" ' ;
2021-11-25 11:45:38 +00:00
check_destroy ( ) ;
}
else if ( close_connection_ )
{
cancel_deadline_timer ( ) ;
parser_ . done ( ) ;
is_reading = false ;
check_destroy ( ) ;
// adaptor will close after write
}
else if ( ! need_to_call_after_handlers_ )
{
start_deadline ( ) ;
do_read ( ) ;
}
else
{
// res will be completed later by user
need_to_start_read_after_complete_ = true ;
}
} ) ;
2014-04-01 12:25:16 +00:00
}
2014-04-17 06:50:28 +00:00
void do_write ( )
2014-04-01 12:25:16 +00:00
{
2014-08-15 02:06:00 +00:00
//auto self = this->shared_from_this();
is_writing = true ;
2022-06-06 14:38:46 +00:00
asio : : async_write (
2021-11-25 11:45:38 +00:00
adaptor_ . socket ( ) , buffers_ ,
2022-06-07 00:43:53 +00:00
[ & ] ( const asio : : error_code & ec , std : : size_t /*bytes_transferred*/ ) {
2021-11-25 11:45:38 +00:00
is_writing = false ;
res . clear ( ) ;
res_body_copy_ . clear ( ) ;
if ( ! ec )
{
if ( close_connection_ )
{
adaptor_ . shutdown_write ( ) ;
adaptor_ . close ( ) ;
CROW_LOG_DEBUG < < this < < " from write(1) " ;
check_destroy ( ) ;
}
}
else
{
CROW_LOG_DEBUG < < this < < " from write(2) " ;
check_destroy ( ) ;
}
} ) ;
2014-03-31 16:51:50 +00:00
}
2022-06-06 14:38:46 +00:00
inline void do_write_sync ( std : : vector < asio : : const_buffer > & buffers )
2021-12-02 12:36:52 +00:00
{
2022-06-07 00:43:53 +00:00
asio : : write ( adaptor_ . socket ( ) , buffers , [ & ] ( asio : : error_code ec , std : : size_t ) {
2021-12-02 12:36:52 +00:00
if ( ! ec )
{
return false ;
}
else
{
CROW_LOG_ERROR < < ec < < " - happened while sending buffers " ;
CROW_LOG_DEBUG < < this < < " from write (sync)(2) " ;
check_destroy ( ) ;
return true ;
}
} ) ;
2014-03-31 16:51:50 +00:00
}
2014-08-16 16:10:19 +00:00
void check_destroy ( )
2014-08-15 02:06:00 +00:00
{
2014-08-16 02:55:26 +00:00
CROW_LOG_DEBUG < < this < < " is_reading " < < is_reading < < " is_writing " < < is_writing ;
2014-08-15 02:06:00 +00:00
if ( ! is_reading & & ! is_writing )
{
2021-12-03 16:33:40 +00:00
queue_length_ - - ;
2021-12-07 09:58:40 +00:00
CROW_LOG_DEBUG < < this < < " delete (idle) (queue length: " < < queue_length_ < < ' ) ' ;
2014-08-15 02:06:00 +00:00
delete this ;
}
}
2014-08-16 02:55:26 +00:00
void cancel_deadline_timer ( )
{
2021-11-19 17:42:25 +00:00
CROW_LOG_DEBUG < < this < < " timer cancelled: " < < & task_timer_ < < ' ' < < task_id_ ;
task_timer_ . cancel ( task_id_ ) ;
2014-08-16 02:55:26 +00:00
}
2016-08-27 09:03:49 +00:00
void start_deadline ( /*int timeout = 5*/ )
2014-07-29 11:20:50 +00:00
{
2014-08-16 02:55:26 +00:00
cancel_deadline_timer ( ) ;
2021-11-19 17:42:25 +00:00
2021-11-27 12:28:50 +00:00
task_id_ = task_timer_ . schedule ( [ this ] {
2015-09-20 13:06:00 +00:00
if ( ! adaptor_ . is_open ( ) )
2014-07-29 11:20:50 +00:00
{
2014-08-16 02:55:26 +00:00
return ;
2014-07-29 11:20:50 +00:00
}
2020-10-20 08:48:35 +00:00
adaptor_ . shutdown_readwrite ( ) ;
2021-11-27 17:44:51 +00:00
adaptor_ . close ( ) ;
} ) ;
2021-11-19 17:42:25 +00:00
CROW_LOG_DEBUG < < this < < " timer added: " < < & task_timer_ < < ' ' < < task_id_ ;
2014-07-29 11:20:50 +00:00
}
2014-03-31 16:51:50 +00:00
private :
2015-09-20 13:06:00 +00:00
Adaptor adaptor_ ;
2014-03-31 16:51:50 +00:00
Handler * handler_ ;
2022-06-06 15:33:06 +00:00
std : : array < char , 4096 > buffer_ ;
2014-03-31 16:51:50 +00:00
2014-04-01 12:25:16 +00:00
HTTPParser < Connection > parser_ ;
2022-07-18 03:33:56 +00:00
std : : unique_ptr < routing_handle_result > routing_handle_result_ ;
request & req_ ;
2014-04-01 12:25:16 +00:00
response res ;
bool close_connection_ = false ;
2014-04-17 06:50:28 +00:00
const std : : string & server_name_ ;
2022-06-06 14:38:46 +00:00
std : : vector < asio : : const_buffer > buffers_ ;
2014-05-02 05:17:49 +00:00
std : : string content_length_ ;
std : : string date_str_ ;
2015-09-20 13:06:00 +00:00
std : : string res_body_copy_ ;
2014-07-29 11:20:50 +00:00
2021-11-19 17:42:25 +00:00
detail : : task_timer : : identifier_type task_id_ ;
2014-08-15 02:06:00 +00:00
bool is_reading { } ;
bool is_writing { } ;
2015-01-19 09:59:55 +00:00
bool need_to_call_after_handlers_ { } ;
2014-09-14 11:12:18 +00:00
bool need_to_start_read_after_complete_ { } ;
2014-09-19 23:20:35 +00:00
bool add_keep_alive_ { } ;
2014-09-06 19:30:53 +00:00
2014-10-23 17:33:03 +00:00
std : : tuple < Middlewares . . . > * middlewares_ ;
2014-09-06 19:30:53 +00:00
detail : : context < Middlewares . . . > ctx_ ;
2015-02-20 04:44:46 +00:00
std : : function < std : : string ( ) > & get_cached_date_str ;
2021-11-19 17:42:25 +00:00
detail : : task_timer & task_timer_ ;
2021-10-12 12:35:08 +00:00
size_t res_stream_threshold_ ;
2021-11-29 15:56:12 +00:00
2021-12-03 16:33:40 +00:00
std : : atomic < unsigned int > & queue_length_ ;
2014-03-31 16:51:50 +00:00
} ;
2014-07-29 11:20:50 +00:00
2021-11-25 11:45:38 +00:00
} // namespace crow