37 std::array< char, 64 > buf;
42 "%a, %d %b %Y %H:%M:%S GMT",
45 return std::string{ buf.data() };
58template <
typename Response_Builder >
72 impl::connection_handle_t connection,
74 bool should_keep_alive )
75 :
m_header{ std::move( status_line ) }
79 m_header.should_keep_alive( should_keep_alive );
84 http_response_header_t &
100 std::string field_name,
101 std::string field_value ) &
104 std::move( field_name ),
105 std::move( field_value ) );
112 std::string field_name,
113 std::string field_value ) &&
116 std::move( field_name ),
117 std::move( field_value ) ) );
124 m_header.add_field( std::move( http_header_field ) );
133 std::move( http_header_field ) ) );
140 std::string field_value ) &
144 std::move( field_value ) );
152 std::string field_value ) &&
156 std::move( field_value ) ) );
163 std::chrono::system_clock::time_point tp =
164 std::chrono::system_clock::now() ) &
173 std::chrono::system_clock::time_point tp =
174 std::chrono::system_clock::now() ) &&
183 m_header.should_keep_alive(
false );
214 return 8 + 1 + 3 + 1 +
m_header.status_line().reason_phrase().size();
225 throw exception_t{
"done() cannot be called twice" };
232 return static_cast< Response_Builder &
>( *this );
241template <
typename Response_Output_Strategy >
265 response_builder_t< restinio_controlled_output_t >;
270 using base_type_t::base_type_t;
276 auto size = body.size();
277 return set_body_impl( body, size );
282 set_body( writable_item_t body ) &&
284 return std::move( this->set_body( std::move( body ) ) );
289 append_body( writable_item_t body_part ) &
291 auto size = body_part.size();
292 return append_body_impl( body_part, size );
297 append_body( writable_item_t body_part ) &&
299 return std::move( this->append_body( std::move( body_part ) ) );
308 const response_output_flags_t
309 response_output_flags{
313 m_header.content_length( m_body_size );
315 if_neccessary_reserve_first_element_for_header();
317 m_response_parts[ 0 ] =
320 write_group_t wg{ std::move( m_response_parts ) };
321 wg.status_line_size( calculate_status_line_size() );
325 wg.after_write_notificator( std::move( wscb ) );
328 auto conn = std::move( m_connection );
330 conn->write_response_parts(
332 response_output_flags,
337 throw_done_must_be_called_once();
345 set_body_impl( writable_item_t & body, std::size_t body_size )
347 if_neccessary_reserve_first_element_for_header();
351 m_response_parts.resize( 1 );
355 m_response_parts.emplace_back( std::move( body ) );
358 m_body_size = body_size;
364 append_body_impl( writable_item_t & body_part, std::size_t append_size )
366 if_neccessary_reserve_first_element_for_header();
368 if( 0 < append_size )
370 m_response_parts.emplace_back( std::move( body_part ) );
371 m_body_size += append_size;
378 if_neccessary_reserve_first_element_for_header()
380 if( m_response_parts.empty() )
382 m_response_parts.reserve( 2 );
383 m_response_parts.emplace_back();
387 std::size_t m_body_size{ 0 };
409 response_builder_t< user_controlled_output_t >;
414 using base_type_t::base_type_t;
418 set_content_length( std::size_t content_length ) &
420 m_header.content_length( content_length );
426 set_content_length( std::size_t content_length ) &&
428 return std::move( this->set_content_length( content_length ) );
433 set_body( writable_item_t body ) &
435 auto size = body.size();
436 return set_body_impl( body, size );
441 set_body( writable_item_t body ) &&
443 return std::move( this->set_body( std::move( body ) ) );
448 append_body( writable_item_t body_part ) &
450 auto size = body_part.size();
455 return append_body_impl( body_part );
460 append_body( writable_item_t body_part ) &&
462 return std::move( this->append_body( std::move( body_part ) ) );
487 return std::move( this->flush( std::move( wscb ) ) );
499 std::move(m_connection) };
507 throw_done_must_be_called_once();
520 std::size_t status_line_size{ 0 };
522 if( !m_header_was_sent )
524 m_should_keep_alive_when_header_was_sent =
525 m_header.should_keep_alive();
527 if_neccessary_reserve_first_element_for_header();
529 m_response_parts[ 0 ] =
532 m_header_was_sent =
true;
533 status_line_size = calculate_status_line_size();
536 if( !m_response_parts.empty() ||
540 const response_output_flags_t
541 response_output_flags{
545 write_group_t wg{ std::move( m_response_parts ) };
546 wg.status_line_size( status_line_size );
550 wg.after_write_notificator( std::move( wscb ) );
553 conn->write_response_parts(
555 response_output_flags,
561 set_body_impl( writable_item_t & body, std::size_t body_size )
563 if_neccessary_reserve_first_element_for_header();
567 if( !m_header_was_sent )
568 m_response_parts.resize( 1 );
570 m_response_parts.resize( 0 );
575 m_response_parts.emplace_back( std::move( body ) );
582 append_body_impl( writable_item_t & body_part )
584 if_neccessary_reserve_first_element_for_header();
586 m_response_parts.emplace_back( std::move( body_part ) );
591 if_neccessary_reserve_first_element_for_header()
593 if( !m_header_was_sent && m_response_parts.empty() )
595 m_response_parts.reserve( 2 );
596 m_response_parts.emplace_back();
602 bool m_header_was_sent{
false };
611 bool m_should_keep_alive_when_header_was_sent{
true };
637 response_builder_t< chunked_output_t >;
643 bool should_keep_alive )
645 std::move( status_line ),
646 std::move( connection ),
650 m_chunks.reserve( 4 );
657 append_chunk( writable_item_t chunk ) &
659 auto size = chunk.size();
662 m_chunks.emplace_back( std::move( chunk ) );
669 append_chunk( writable_item_t chunk ) &&
671 return std::move( this->append_chunk( std::move( chunk ) ) );
696 return std::move( this->flush( std::move( wscb ) ) );
708 std::move(m_connection) };
716 throw_done_must_be_called_once();
729 std::size_t status_line_size{ 0 };
730 if( !m_header_was_sent )
732 status_line_size = calculate_status_line_size();
733 prepare_header_for_sending();
737 m_header_was_sent =
true;
739 const response_output_flags_t
740 response_output_flags{
745 if( !bufs.empty() || wscb )
747 write_group_t wg{ std::move( bufs ) };
748 wg.status_line_size( status_line_size );
752 wg.after_write_notificator( std::move( wscb ) );
755 conn->write_response_parts(
757 response_output_flags,
763 prepare_header_for_sending()
765 m_should_keep_alive_when_header_was_sent =
766 m_header.should_keep_alive();
768 constexpr const char value[] =
"chunked";
769 if( !m_header.has_field( restinio::http_field::transfer_encoding ) )
772 restinio::http_field::transfer_encoding,
777 auto & current_value =
778 m_header.get_field( restinio::http_field::transfer_encoding );
779 if( std::string::npos == current_value.find( value ) )
781 constexpr const char comma_value[] =
",chunked";
782 m_header.append_field(
783 restinio::http_field::transfer_encoding,
792 create_bufs(
bool add_zero_chunk )
796 std::size_t reserve_size = 2 * m_chunks.size() + 1;
798 if( !m_header_was_sent )
807 bufs.reserve( reserve_size );
809 if( !m_header_was_sent )
830 auto chunk_it = m_chunks.begin();
831 const auto chunk_end = m_chunks.end();
832 if( chunk_it != chunk_end )
837 asio_ns::buffer_size( chunk_it->buf() ) ) );
838 bufs.emplace_back( std::move( *chunk_it ) );
840 for( ++chunk_it; chunk_it != chunk_end; ++chunk_it )
845 asio_ns::buffer_size( chunk_it->buf() ) ) );
846 bufs.emplace_back( std::move( *chunk_it ) );
850 const char *
const ending_representation =
"\r\n" "0\r\n\r\n";
851 const char * appendix_begin = ending_representation + 2;
852 const char * appendix_end = appendix_begin;
854 if( !m_chunks.empty() )
867 if( appendix_begin != appendix_end )
871 static_cast<std::size_t
>(appendix_end - appendix_begin)
881 bool m_header_was_sent{
false };
890 bool m_should_keep_alive_when_header_was_sent{
true };
Response_Builder & upcast_reference() noexcept
Response_Builder && append_header(http_field_t field_id, std::string field_value) &&
Add header field.
Response_Builder && append_header(http_header_field_t http_header_field) &&
Add header field.
impl::connection_handle_t m_connection
Response_Builder && append_header(std::string field_name, std::string field_value) &&
Add header field.
Response_Builder & append_header(std::string field_name, std::string field_value) &
Add header field.
Response_Builder & connection_close() &noexcept
Set connection close.
std::size_t calculate_status_line_size() const noexcept
base_response_builder_t(base_response_builder_t &&) noexcept=default
Response_Builder & append_header(http_header_field_t http_header_field) &
Add header field.
Response_Builder & append_header(http_field_t field_id, std::string field_value) &
Add header field.
Response_Builder & connection_keep_alive() &noexcept
Set connection keep-alive.
const http_response_header_t & header() const noexcept
Response_Builder & append_header_date_field(std::chrono::system_clock::time_point tp=std::chrono::system_clock::now()) &
Add header Date field.
const request_id_t m_request_id
Response_Builder && append_header_date_field(std::chrono::system_clock::time_point tp=std::chrono::system_clock::now()) &&
Add header Date field.
base_response_builder_t & operator=(const base_response_builder_t &)=delete
base_response_builder_t(const base_response_builder_t &)=delete
http_response_header_t & header() noexcept
Accessors for header.
Response_Builder && connection_close() &&noexcept
Set connection close.
Response_Builder && connection_keep_alive() &&noexcept
http_response_header_t m_header
void throw_done_must_be_called_once() const
Exception class for all exceptions thrown by RESTinio.
HTTP response header status line.
Forbid arbitrary response_builder_t instantiations.
response_builder_t()=delete
Class for storing the buffers used for streaming body (request/response).
A special wrapper around fmtlib include files.
#define RESTINIO_FMT_FORMAT_STRING(s)
std::string create_header_string(const http_response_header_t &h, content_length_field_presence_t content_length_field_presence=content_length_field_presence_t::add_content_length, std::size_t buffer_size=0)
Creates a string for http response header.
std::shared_ptr< connection_base_t > connection_handle_t
Alias for http connection handle.
constexpr std::size_t ct_string_len(const char(&)[N]) noexcept
Compile time c-string length.
unsigned int request_id_t
Request id in scope of single connection.
std::function< void(const asio_ns::error_code &ec) > write_status_cb_t
An alias for a callback to be invoked after the write operation of a particular group of "buffers".
response_connection_attr_t response_connection_attr(bool should_keep_alive)
constexpr request_handling_status_t request_accepted() noexcept
request_handling_status_t
Request handling status.
http_field_t
C++ enum that repeats nodejs c-style enum.
std::string make_date_field_value(std::time_t t)
Format a timepoint to a string of a propper format.
constexpr const_buffer_t const_buffer(const void *str, std::size_t size) noexcept
@ connection_close
This response says to close connection.
std::tm make_gmtime(std::time_t t)
std::vector< writable_item_t > writable_items_container_t
response_parts_attr_t
Attribute for parts.
@ final_parts
Final parts (response ands with these parts).
@ not_final_parts
Intermediate parts (more parts of response to follow).
Tag type for chunked output response builder.
Tag type for RESTinio controlled output response builder.
Tag type for user controlled output response builder.