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 
16 namespace restinio
17 {
18 
19 namespace impl
20 {
21 
22 //
23 // ct_string_len
24 //
25 
27 template< std::size_t N >
28 inline constexpr std::size_t ct_string_len( const char (&)[N] ) noexcept
29 {
30  return N-1;
31 }
32 
33 enum class content_length_field_presence_t : std::uint8_t
34 {
35  add_content_length,
37 };
38 
39 //
40 // calculate_approx_buffer_size_for_header()
41 //
42 
44 inline 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 
67 inline std::string
69  const http_response_header_t & h,
70  content_length_field_presence_t content_length_field_presence =
71  content_length_field_presence_t::add_content_length,
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  {
106  case http_connection_header_t::keep_alive:
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 
128  if( content_length_field_presence_t::add_content_length ==
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 
155 inline 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 
169 inline 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 */
restinio::impl::create_timeout_resp
auto create_timeout_resp()
Definition: header_helpers.hpp:170
restinio::http_header_common_t::content_length
std::uint64_t content_length() const noexcept
Length of body of an http-message.
Definition: http_headers.hpp:1603
buffers.hpp
restinio::http_header_common_t::http_minor
std::uint16_t http_minor() const noexcept
Definition: http_headers.hpp:1593
restinio::easy_parser::N
constexpr std::size_t N
A special marker that means infinite repetitions.
Definition: easy_parser.hpp:455
restinio::http_response_header_t::status_code
http_status_code_t status_code() const noexcept
Definition: http_headers.hpp:2348
restinio::http_header_fields_t::for_each_field
void for_each_field(Lambda &&lambda) const noexcept(noexcept(lambda(std::declval< const http_header_field_t & >())))
Enumeration of fields.
Definition: http_headers.hpp:1361
restinio::http_response_header_t::reason_phrase
const std::string & reason_phrase() const noexcept
Definition: http_headers.hpp:2356
restinio::impl::content_length_field_presence_t::add_content_length
@ add_content_length
restinio::impl::create_header_string
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.
Definition: header_helpers.hpp:68
restinio::http_connection_header_t::close
@ close
restinio::http_connection_header_t::keep_alive
@ keep_alive
restinio::impl::ct_string_len
constexpr std::size_t ct_string_len(const char(&)[N]) noexcept
Compile time c-string length.
Definition: header_helpers.hpp:28
restinio::impl::calculate_approx_buffer_size_for_header
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.
Definition: header_helpers.hpp:45
restinio::http_header_common_t::connection
http_connection_header_t connection() const
Get the value of 'connection' header field.
Definition: http_headers.hpp:1626
restinio
Definition: asio_include.hpp:21
restinio::http_response_header_t
Resp header.
Definition: http_headers.hpp:2338
restinio::http_status_code_t::raw_code
constexpr auto raw_code() const noexcept
Definition: http_headers.hpp:2003
restinio::impl::create_not_implemented_resp
auto create_not_implemented_resp()
Definition: header_helpers.hpp:156
restinio::writable_items_container_t
std::vector< writable_item_t > writable_items_container_t
Definition: buffers.hpp:668
restinio::impl::content_length_field_presence_t
content_length_field_presence_t
Definition: header_helpers.hpp:34
restinio::http_header_common_t::http_major
std::uint16_t http_major() const noexcept
Http version.
Definition: http_headers.hpp:1585