RESTinio
header_helpers.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
11#include <array>
12#include <numeric>
13
14#include <restinio/buffers.hpp>
15
16namespace restinio
17{
18
19namespace impl
20{
21
22//
23// ct_string_len
24//
25
27template< std::size_t N >
28inline constexpr std::size_t ct_string_len( const char (&)[N] ) noexcept
29{
30 return N-1;
31}
32
33enum class content_length_field_presence_t : std::uint8_t
34{
37};
38
39//
40// calculate_approx_buffer_size_for_header()
41//
42
44inline std::size_t
46 const http_response_header_t & h ) noexcept
47{
48 std::size_t result = 13; // "HTTP/1.1 xxx "
49 result += h.reason_phrase().size() + 2; // 2 is for "\r\n".
50 result += 26; // "Connection: keep-alive\r\n" is also enough for "Connection: close\r\n" (21).
51 result += 20 + 18; // "Content-Length: %llu\r\n" assume size is size_t, and 18 is always ok.
52
53 result += 2; // Final "\r\n\r\n".
54
55 h.for_each_field( [&result](const auto & f) noexcept {
56 result += f.name().size() + 2 + f.value().size() + 2;
57 } );
58
59 return result;
60}
61
62//
63// create_header_string()
64//
65
67inline std::string
69 const http_response_header_t & h,
70 content_length_field_presence_t content_length_field_presence =
72 std::size_t buffer_size = 0 )
73{
74 std::string result;
75
76 if( 0 != buffer_size )
77 result.reserve( buffer_size );
78 else
79 result.reserve( calculate_approx_buffer_size_for_header( h ) );
80
81 constexpr const char header_part1[] = "HTTP/";
82 result.append( header_part1, ct_string_len( header_part1 ) );
83
84 result += static_cast<char>( '0' + h.http_major() );
85 result += '.';
86 result += static_cast<char>( '0' + h.http_minor() );
87 result += ' ';
88
89 const auto sc = h.status_code().raw_code();
90
91//FIXME: there should be a check for status_code in range 100..999.
92//May be a special type like bounded_value_t<100,999> must be used in
93//http_response_header_t.
94 result += '0' + ( sc / 100 ) % 10;
95 result += '0' + ( sc / 10 ) % 10;
96 result += '0' + ( sc ) % 10;
97
98 result += ' ';
99 result += h.reason_phrase();
100
101 constexpr const char header_rn[] = "\r\n";
102 result.append( header_rn, ct_string_len( header_rn ) );
103
104 switch( h.connection() )
105 {
107 {
108 constexpr const char header_part2_1[] = "Connection: keep-alive\r\n";
109 result.append( header_part2_1, ct_string_len( header_part2_1 ) );
110 break;
111 }
112
114 {
115 constexpr const char header_part2_2[] = "Connection: close\r\n";
116 result.append( header_part2_2, ct_string_len( header_part2_2 ) );
117 break;
118 }
119
121 {
122 constexpr const char header_part2_3[] = "Connection: Upgrade\r\n";
123 result.append( header_part2_3, ct_string_len( header_part2_3 ) );
124 break;
125 }
126 }
127
129 content_length_field_presence )
130 {
131 std::array< char, 64 > buf;
132 const auto n =
133 std::snprintf(
134 buf.data(),
135 buf.size(),
136 "Content-Length: %llu\r\n",
137 static_cast< unsigned long long >( h.content_length() ) );
138
139 result.append( buf.data(), static_cast<std::string::size_type>(n) );
140 }
141
142 constexpr const char header_field_sep[] = ": ";
143 h.for_each_field( [&result, header_field_sep, header_rn](const auto & f) {
144 result += f.name();
145 result.append( header_field_sep, ct_string_len( header_field_sep ) );
146 result += f.value();
147 result.append( header_rn, ct_string_len( header_rn ) );
148 } );
149
150 result.append( header_rn, ct_string_len( header_rn ) );
151
152 return result;
153}
154
155inline auto
157{
158 constexpr const char raw_501_response[] =
159 "HTTP/1.1 501 Not Implemented\r\n"
160 "Connection: close\r\n"
161 "Content-Length: 0\r\n"
162 "\r\n";
163
165 result.emplace_back( raw_501_response );
166 return result;
167}
168
169inline auto
171{
172 constexpr const char raw_504_response[] =
173 "HTTP/1.1 504 Gateway Time-out\r\n"
174 "Connection: close\r\n"
175 "Content-Length: 0\r\n"
176 "\r\n";
177
179 result.emplace_back( raw_504_response );
180 return result;
181}
182
183} /* namespace impl */
184
185} /* namespace restinio */
void for_each_field(Lambda &&lambda) const noexcept(noexcept(lambda(std::declval< const http_header_field_t & >())))
Enumeration of fields.
constexpr auto raw_code() const noexcept
constexpr std::size_t N
A special marker that means infinite repetitions.
std::size_t calculate_approx_buffer_size_for_header(const http_response_header_t &h) noexcept
Calculate buffer size that is enough for serializing the buffer.
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.
auto create_timeout_resp()
auto create_not_implemented_resp()
constexpr std::size_t ct_string_len(const char(&)[N]) noexcept
Compile time c-string length.
std::vector< writable_item_t > writable_items_container_t
Definition: buffers.hpp:668
std::uint16_t http_major() const noexcept
Http version.
http_connection_header_t connection() const
Get the value of 'connection' header field.
std::uint64_t content_length() const noexcept
Length of body of an http-message.
std::uint16_t http_minor() const noexcept
http_status_code_t status_code() const noexcept
const std::string & reason_phrase() const noexcept