RESTinio
header_helpers.hpp
Go to the documentation of this file.
1 /*
2  restinio
3 */
4 
5 /*!
6  HTTP-Connection handler routine.
7 */
8 
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 
26 //! Compile time c-string length.
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 
34 {
37 };
38 
39 //
40 // calculate_approx_buffer_size_for_header()
41 //
42 
43 //! Calculate buffer size that is enough for serializing the buffer.
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 
66 //! Creates a string for http response header.
67 inline std::string
69  const http_response_header_t & h,
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 
113  case http_connection_header_t::close:
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 
120  case http_connection_header_t::upgrade:
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 
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 
164  writable_items_container_t result;
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 
178  writable_items_container_t result;
179  result.emplace_back( raw_504_response );
180  return result;
181 }
182 
183 } /* namespace impl */
184 
185 } /* namespace restinio */
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::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.
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::enable_if< std::is_same< Parameter_Container, query_string_params_t >::value||std::is_same< Parameter_Container, router::route_params_t >::value, optional_t< Value_Type > >::type opt_value(const Parameter_Container &params, string_view_t key)
Gets the value of a parameter specified by key wrapped in optional_t<Value_Type> if parameter exists ...
Definition: value_or.hpp:64