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>
2023-12-28 11:06:04 +00:00
# include <algorithm>
2014-05-02 05:17:49 +00:00
# include <atomic>
# include <chrono>
2014-10-23 17:45:34 +00:00
# include <vector>
2023-05-08 08:41:49 +00:00
# include <memory>
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 >
2023-05-08 08:41:49 +00:00
class Connection : public std : : enable_shared_from_this < Connection < Adaptor , Handler , Middlewares . . . > >
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
# 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 ( )
{
2023-05-08 08:41:49 +00:00
auto self = this - > shared_from_this ( ) ;
adaptor_ . start ( [ self ] ( const asio : : error_code & ec ) {
2015-09-20 13:06:00 +00:00
if ( ! ec )
{
2023-05-08 08:41:49 +00:00
self - > start_deadline ( ) ;
self - > parser_ . clear ( ) ;
2014-07-29 11:20:50 +00:00
2023-05-08 08:41:49 +00:00
self - > do_read ( ) ;
2015-09-20 13:06:00 +00:00
}
else
{
2021-04-16 23:33:35 +00:00
CROW_LOG_ERROR < < " Could not start adaptor: " < < ec . message ( ) ;
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
{
2023-12-06 15:34:46 +00:00
continue_requested = true ;
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-08-21 18:33:04 +00:00
else 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 )
{
2023-05-08 08:41:49 +00:00
res . complete_request_handler_ = nullptr ;
auto self = this - > shared_from_this ( ) ;
res . is_alive_helper_ = [ self ] ( ) - > bool {
return self - > adaptor_ . is_open ( ) ;
2021-11-27 17:44:51 +00:00
} ;
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_ )
{
2023-05-08 08:41:49 +00:00
auto self = this - > shared_from_this ( ) ;
res . complete_request_handler_ = [ self ] {
self - > complete_request ( ) ;
2021-11-27 17:44:51 +00:00
} ;
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_ ;
2023-05-08 08:41:49 +00:00
res . is_alive_helper_ = nullptr ;
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-05 18:54:38 +00:00
res . complete_request_handler_ = nullptr ;
2023-05-08 08:41:49 +00:00
res . is_alive_helper_ = 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 ( )
{
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 ) ;
2022-08-21 11:43:57 +00:00
std : : vector < asio : : const_buffer > buffers { 1 } ;
2021-12-02 12:36:52 +00:00
char buf [ 16384 ] ;
2022-08-21 11:43:57 +00:00
is . read ( buf , sizeof ( buf ) ) ;
while ( is . gcount ( ) > 0 )
2021-12-02 12:36:52 +00:00
{
2022-08-21 11:43:57 +00:00
buffers [ 0 ] = asio : : buffer ( buf , is . gcount ( ) ) ;
2021-12-02 12:36:52 +00:00
do_write_sync ( buffers ) ;
2022-08-21 11:43:57 +00:00
is . read ( buf , sizeof ( buf ) ) ;
2021-12-02 12:36:52 +00:00
}
}
2022-02-05 15:15:19 +00:00
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
}
2020-10-12 21:53:27 +00:00
2020-10-04 12:05:26 +00:00
res . end ( ) ;
res . clear ( ) ;
buffers_ . clear ( ) ;
2022-08-21 18:33:04 +00:00
parser_ . clear ( ) ;
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_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
{
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 )
{
2023-12-06 20:37:14 +00:00
std : : vector < asio : : const_buffer > buffers { 1 } ;
const uint8_t * data = reinterpret_cast < const uint8_t * > ( res . body . data ( ) ) ;
size_t length = res . body . length ( ) ;
for ( size_t transferred = 0 ; transferred < length ; )
2021-12-02 12:36:52 +00:00
{
2023-12-29 11:52:10 +00:00
size_t to_transfer = CROW_MIN ( 16384UL , length - transferred ) ;
2023-12-06 20:37:14 +00:00
buffers [ 0 ] = asio : : const_buffer ( data + transferred , to_transfer ) ;
2021-12-02 12:36:52 +00:00
do_write_sync ( buffers ) ;
2023-12-06 20:37:14 +00:00
transferred + = to_transfer ;
2021-12-02 12:36:52 +00:00
}
}
2022-02-05 15:15:19 +00:00
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
}
2020-10-21 01:02:09 +00:00
res . end ( ) ;
res . clear ( ) ;
buffers_ . clear ( ) ;
2022-08-21 18:33:04 +00:00
parser_ . 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 ( )
{
2023-05-08 08:41:49 +00:00
auto self = this - > shared_from_this ( ) ;
2021-11-25 11:45:38 +00:00
adaptor_ . socket ( ) . async_read_some (
2022-06-06 14:38:46 +00:00
asio : : buffer ( buffer_ ) ,
2023-05-08 08:41:49 +00:00
[ self ] ( 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 )
{
2023-05-08 08:41:49 +00:00
bool ret = self - > parser_ . feed ( self - > buffer_ . data ( ) , bytes_transferred ) ;
if ( ret & & self - > adaptor_ . is_open ( ) )
2021-11-25 11:45:38 +00:00
{
error_while_reading = false ;
}
}
if ( error_while_reading )
{
2023-05-08 08:41:49 +00:00
self - > cancel_deadline_timer ( ) ;
self - > parser_ . done ( ) ;
self - > adaptor_ . shutdown_read ( ) ;
self - > adaptor_ . close ( ) ;
CROW_LOG_DEBUG < < self < < " from read(1) with description: \" " < < http_errno_description ( static_cast < http_errno > ( self - > parser_ . http_errno ) ) < < ' \" ' ;
2021-11-25 11:45:38 +00:00
}
2023-05-08 08:41:49 +00:00
else if ( self - > close_connection_ )
2021-11-25 11:45:38 +00:00
{
2023-05-08 08:41:49 +00:00
self - > cancel_deadline_timer ( ) ;
self - > parser_ . done ( ) ;
2021-11-25 11:45:38 +00:00
// adaptor will close after write
}
2023-05-08 08:41:49 +00:00
else if ( ! self - > need_to_call_after_handlers_ )
2021-11-25 11:45:38 +00:00
{
2023-05-08 08:41:49 +00:00
self - > start_deadline ( ) ;
self - > do_read ( ) ;
2021-11-25 11:45:38 +00:00
}
else
{
// res will be completed later by user
2023-05-08 08:41:49 +00:00
self - > need_to_start_read_after_complete_ = true ;
2021-11-25 11:45:38 +00:00
}
} ) ;
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
{
2023-05-08 08:41:49 +00:00
auto self = this - > shared_from_this ( ) ;
2022-06-06 14:38:46 +00:00
asio : : async_write (
2021-11-25 11:45:38 +00:00
adaptor_ . socket ( ) , buffers_ ,
2023-05-08 08:41:49 +00:00
[ self ] ( const asio : : error_code & ec , std : : size_t /*bytes_transferred*/ ) {
self - > res . clear ( ) ;
2023-12-06 15:34:46 +00:00
self - > res_body_copy_ . clear ( ) ;
if ( ! self - > continue_requested )
{
self - > parser_ . clear ( ) ;
}
else
{
self - > continue_requested = false ;
}
2021-11-25 11:45:38 +00:00
if ( ! ec )
{
2023-05-08 08:41:49 +00:00
if ( self - > close_connection_ )
2021-11-25 11:45:38 +00:00
{
2023-05-08 08:41:49 +00:00
self - > adaptor_ . shutdown_write ( ) ;
self - > adaptor_ . close ( ) ;
CROW_LOG_DEBUG < < self < < " from write(1) " ;
2021-11-25 11:45:38 +00:00
}
}
else
{
2023-05-08 08:41:49 +00:00
CROW_LOG_DEBUG < < self < < " from write(2) " ;
2021-11-25 11:45:38 +00:00
}
} ) ;
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) " ;
return true ;
}
} ) ;
2014-03-31 16:51:50 +00:00
}
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
2023-05-08 08:41:49 +00:00
auto self = this - > shared_from_this ( ) ;
task_id_ = task_timer_ . schedule ( [ self ] {
if ( ! self - > 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
}
2023-05-08 08:41:49 +00:00
self - > adaptor_ . shutdown_readwrite ( ) ;
self - > adaptor_ . close ( ) ;
2021-11-27 17:44:51 +00:00
} ) ;
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
2022-10-30 00:43:45 +00:00
detail : : task_timer : : identifier_type task_id_ { } ;
2014-08-15 02:06:00 +00:00
2023-12-06 15:34:46 +00:00
bool continue_requested { } ;
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