http_reply.cpp
Go to the documentation of this file.
1 //
2 // http_reply.hpp
3 // ~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
12 
13 #include <boost/algorithm/string.hpp>
14 #include <boost/lexical_cast.hpp>
15 
16 #include <fstream>
17 
18 namespace async_web_server_cpp
19 {
20 
21 namespace status_strings
22 {
23 
24 const std::string switching_protocols = "HTTP/1.1 101 Switching Protocols\r\n";
25 const std::string ok = "HTTP/1.0 200 OK\r\n";
26 const std::string created = "HTTP/1.0 201 Created\r\n";
27 const std::string accepted = "HTTP/1.0 202 Accepted\r\n";
28 const std::string no_content = "HTTP/1.0 204 No Content\r\n";
29 const std::string multiple_choices = "HTTP/1.0 300 Multiple Choices\r\n";
30 const std::string moved_permanently = "HTTP/1.0 301 Moved Permanently\r\n";
31 const std::string moved_temporarily = "HTTP/1.0 302 Moved Temporarily\r\n";
32 const std::string not_modified = "HTTP/1.0 304 Not Modified\r\n";
33 const std::string bad_request = "HTTP/1.0 400 Bad Request\r\n";
34 const std::string unauthorized = "HTTP/1.0 401 Unauthorized\r\n";
35 const std::string forbidden = "HTTP/1.0 403 Forbidden\r\n";
36 const std::string not_found = "HTTP/1.0 404 Not Found\r\n";
37 const std::string internal_server_error =
38  "HTTP/1.0 500 Internal Server Error\r\n";
39 const std::string not_implemented = "HTTP/1.0 501 Not Implemented\r\n";
40 const std::string bad_gateway = "HTTP/1.0 502 Bad Gateway\r\n";
41 const std::string service_unavailable = "HTTP/1.0 503 Service Unavailable\r\n";
42 
43 boost::asio::const_buffer to_buffer(HttpReply::status_type status)
44 {
45  switch (status)
46  {
48  return boost::asio::buffer(switching_protocols);
49  case HttpReply::ok:
50  return boost::asio::buffer(ok);
51  case HttpReply::created:
52  return boost::asio::buffer(created);
54  return boost::asio::buffer(accepted);
56  return boost::asio::buffer(no_content);
58  return boost::asio::buffer(multiple_choices);
60  return boost::asio::buffer(moved_permanently);
62  return boost::asio::buffer(moved_temporarily);
64  return boost::asio::buffer(not_modified);
66  return boost::asio::buffer(bad_request);
68  return boost::asio::buffer(unauthorized);
70  return boost::asio::buffer(forbidden);
72  return boost::asio::buffer(not_found);
74  return boost::asio::buffer(internal_server_error);
76  return boost::asio::buffer(not_implemented);
78  return boost::asio::buffer(bad_gateway);
80  return boost::asio::buffer(service_unavailable);
81  default:
82  return boost::asio::buffer(internal_server_error);
83  }
84 }
85 
86 } // namespace status_strings
87 
88 namespace misc_strings
89 {
90 
91 const char name_value_separator[] = {':', ' '};
92 const char crlf[] = {'\r', '\n'};
93 
94 } // namespace misc_strings
95 
96 namespace stock_replies
97 {
98 
99 const char ok[] = "";
100 const char created[] =
101  "<html>"
102  "<head><title>Created</title></head>"
103  "<body><h1>201 Created</h1></body>"
104  "</html>";
105 const char accepted[] =
106  "<html>"
107  "<head><title>Accepted</title></head>"
108  "<body><h1>202 Accepted</h1></body>"
109  "</html>";
110 const char no_content[] =
111  "<html>"
112  "<head><title>No Content</title></head>"
113  "<body><h1>204 Content</h1></body>"
114  "</html>";
115 const char multiple_choices[] =
116  "<html>"
117  "<head><title>Multiple Choices</title></head>"
118  "<body><h1>300 Multiple Choices</h1></body>"
119  "</html>";
120 const char moved_permanently[] =
121  "<html>"
122  "<head><title>Moved Permanently</title></head>"
123  "<body><h1>301 Moved Permanently</h1></body>"
124  "</html>";
125 const char moved_temporarily[] =
126  "<html>"
127  "<head><title>Moved Temporarily</title></head>"
128  "<body><h1>302 Moved Temporarily</h1></body>"
129  "</html>";
130 const char not_modified[] =
131  "<html>"
132  "<head><title>Not Modified</title></head>"
133  "<body><h1>304 Not Modified</h1></body>"
134  "</html>";
135 const char bad_request[] =
136  "<html>"
137  "<head><title>Bad Request</title></head>"
138  "<body><h1>400 Bad Request</h1></body>"
139  "</html>";
140 const char unauthorized[] =
141  "<html>"
142  "<head><title>Unauthorized</title></head>"
143  "<body><h1>401 Unauthorized</h1></body>"
144  "</html>";
145 const char forbidden[] =
146  "<html>"
147  "<head><title>Forbidden</title></head>"
148  "<body><h1>403 Forbidden</h1></body>"
149  "</html>";
150 const char not_found[] =
151  "<html>"
152  "<head><title>Not Found</title></head>"
153  "<body><h1>404 Not Found</h1></body>"
154  "</html>";
155 const char internal_server_error[] =
156  "<html>"
157  "<head><title>Internal Server Error</title></head>"
158  "<body><h1>500 Internal Server Error</h1></body>"
159  "</html>";
160 const char not_implemented[] =
161  "<html>"
162  "<head><title>Not Implemented</title></head>"
163  "<body><h1>501 Not Implemented</h1></body>"
164  "</html>";
165 const char bad_gateway[] =
166  "<html>"
167  "<head><title>Bad Gateway</title></head>"
168  "<body><h1>502 Bad Gateway</h1></body>"
169  "</html>";
170 const char service_unavailable[] =
171  "<html>"
172  "<head><title>Service Unavailable</title></head>"
173  "<body><h1>503 Service Unavailable</h1></body>"
174  "</html>";
175 
177 {
178  switch (status)
179  {
180  case HttpReply::ok:
181  return ok;
182  case HttpReply::created:
183  return created;
184  case HttpReply::accepted:
185  return accepted;
187  return no_content;
189  return multiple_choices;
191  return moved_permanently;
193  return moved_temporarily;
195  return not_modified;
197  return bad_request;
199  return unauthorized;
201  return forbidden;
203  return not_found;
205  return internal_server_error;
207  return not_implemented;
209  return bad_gateway;
211  return service_unavailable;
212  default:
213  return internal_server_error;
214  }
215 }
216 
217 } // namespace stock_replies
218 
219 std::vector<boost::asio::const_buffer>
220 HttpReply::to_buffers(const std::vector<HttpHeader>& headers)
221 {
222  std::vector<boost::asio::const_buffer> buffers;
223  for (std::size_t i = 0; i < headers.size(); ++i)
224  {
225  const HttpHeader& h = headers[i];
226  buffers.push_back(boost::asio::buffer(h.name));
227  buffers.push_back(
228  boost::asio::buffer(misc_strings::name_value_separator));
229  buffers.push_back(boost::asio::buffer(h.value));
230  buffers.push_back(boost::asio::buffer(misc_strings::crlf));
231  }
232  buffers.push_back(boost::asio::buffer(misc_strings::crlf));
233  return buffers;
234 }
235 
238  const std::string& content_type,
239  const std::string& filename,
240  const std::vector<HttpHeader>& additional_headers)
241 {
242  std::vector<HttpHeader> headers;
243  headers.push_back(HttpHeader("Content-Type", content_type));
244  std::copy(additional_headers.begin(), additional_headers.end(),
245  headers.begin());
246 
247  return FileHttpRequestHandler(status, filename, headers);
248 }
250  HttpReply::status_type status, const std::string& filename,
251  const std::vector<HttpHeader>& headers)
252  : status_(status), headers_(headers), filename_(filename)
253 {
254 }
255 
256 static bool hasContentType(const std::vector<HttpHeader>& headers)
257 {
258  for (const auto& h : headers)
259  {
260  if (boost::iequals(h.name, "content-type"))
261  return true;
262  }
263  return false;
264 }
265 
266 static std::string sniffContentType(const std::string& filename)
267 {
268  if (boost::algorithm::ends_with(filename, ".js"))
269  return "application/javascript";
270  if (boost::algorithm::ends_with(filename, ".htm"))
271  return "text/html";
272  if (boost::algorithm::ends_with(filename, ".html"))
273  return "text/html";
274  if (boost::algorithm::ends_with(filename, ".css"))
275  return "text/css";
276  if (boost::algorithm::ends_with(filename, ".png"))
277  return "image/png";
278  if (boost::algorithm::ends_with(filename, ".jpg"))
279  return "image/jpeg";
280  if (boost::algorithm::ends_with(filename, ".jpeg"))
281  return "image/jpeg";
282  if (boost::algorithm::ends_with(filename, ".gif"))
283  return "image/gif";
284  return "application/octet-stream";
285 }
286 
288  const std::string& filename,
289  const std::vector<HttpHeader>& headers,
290  boost::shared_ptr<HttpConnection> connection)
291 {
292  std::ifstream file_stream(filename.c_str());
293  std::stringstream file_buffer;
294  file_buffer << file_stream.rdbuf();
295  std::string content = file_buffer.str();
296 
297  ReplyBuilder reply_builder_(status);
298  reply_builder_.headers(headers);
299  if (!hasContentType(headers))
300  reply_builder_.header("Content-Type", sniffContentType(filename));
301  reply_builder_.header("Content-Length",
302  boost::lexical_cast<std::string>(content.size()));
303  reply_builder_.write(connection);
304  connection->write(content);
305  return true;
306 }
308  const HttpRequest& request, boost::shared_ptr<HttpConnection> connection,
309  const char* begin, const char* end)
310 {
311  return serveFromFile(status_, filename_, headers_, connection);
312 }
313 
315  HttpReply::status_type status, const std::string& path_root,
316  const std::string& filesystem_root, bool list_directories,
317  const std::vector<HttpHeader>& additional_headers)
318 {
319  return FilesystemHttpRequestHandler(status, path_root, filesystem_root,
320  list_directories, additional_headers);
321 }
323  HttpReply::status_type status, const std::string& path_root,
324  const std::string& filesystem_root, bool list_directories,
325  const std::vector<HttpHeader>& headers)
326  : status_(status), headers_(headers), path_root_(path_root),
327  filesystem_root_(filesystem_root), list_directories_(list_directories)
328 {
329 }
330 
332  const HttpRequest& request, boost::shared_ptr<HttpConnection> connection,
333  const char* begin, const char* end)
334 {
335  if (request.path.find(path_root_) == 0)
336  { // request.path startswith path_root
337  std::string rel_path = request.path.substr(path_root_.length());
338  if (rel_path.find_first_of('/') == 0)
339  { // remove leading slash to make path relative
340  rel_path = rel_path.substr(1);
341  }
342 
343  boost::filesystem::path requested_path = filesystem_root_ / rel_path;
344 
345  if (boost::filesystem::exists(requested_path))
346  {
347  if (boost::filesystem::is_directory(requested_path))
348  {
349  if (list_directories_)
350  {
351  std::stringstream content;
352  content << "<html><body>";
353  content << "<h1> Directory Listing: " << request.path
354  << "</h1>";
355  boost::filesystem::directory_iterator end_itr;
356  for (boost::filesystem::directory_iterator itr(
357  requested_path);
358  itr != end_itr; ++itr)
359  {
360  if (boost::filesystem::is_directory(itr->status()))
361  {
362  content << "<a href=\""
363  << itr->path().leaf().generic_string()
364  << "/\">";
365  content << itr->path().leaf().generic_string()
366  << "/";
367  content << "</a>";
368  }
369  else if (boost::filesystem::is_regular_file(
370  itr->status()))
371  {
372  content << "<a href=\""
373  << itr->path().leaf().generic_string()
374  << "\">";
375  content << itr->path().leaf().generic_string();
376  content << "</a>";
377  }
378  content << "<br>";
379  }
380  content << "</body></html>";
382  content.str(), headers_)(
383  request, connection, begin, end);
384  }
385  else
386  {
388  request, connection, begin, end);
389  }
390  return true;
391  }
392  else if (boost::filesystem::is_regular_file(requested_path))
393  {
394  serveFromFile(status_, requested_path.generic_string(),
395  headers_, connection);
396  return true;
397  }
398  else
399  {
400  }
401  }
402  else
403  {
404  return false;
405  }
406  }
407  return false;
408 }
409 
411 {
412  return static_reply(status, "text/html", stock_replies::to_string(status));
413 }
414 
417  const std::string& content_type,
418  const std::string& content,
419  const std::vector<HttpHeader>& additional_headers)
420 {
421  std::vector<HttpHeader> headers;
422  headers.push_back(HttpHeader(
423  "Content-Length", boost::lexical_cast<std::string>(content.size())));
424  headers.push_back(HttpHeader("Content-Type", content_type));
425  std::copy(additional_headers.begin(), additional_headers.end(),
426  headers.begin());
427  return StaticHttpRequestHandler(status, headers, content);
428 }
429 
431  HttpReply::status_type status, const std::vector<HttpHeader>& headers,
432  const std::string& content)
433  : reply_builder_(status), content_string_(content)
434 {
435  reply_builder_.headers(headers);
436 }
437 
439  const HttpRequest& request, boost::shared_ptr<HttpConnection> connection,
440  const char* begin, const char* end)
441 {
442  reply_builder_.write(connection);
443  connection->write(content_string_);
444  return true;
445 }
446 
448 {
449  return ReplyBuilder(status);
450 }
451 
453  : status_(status), headers_(new std::vector<HttpHeader>())
454 {
455 }
456 
457 ReplyBuilder& ReplyBuilder::header(const std::string& name,
458  const std::string& value)
459 {
460  return header(HttpHeader(name, value));
461 }
462 
464 {
465  headers_->push_back(header);
466  return *this;
467 }
468 
469 ReplyBuilder& ReplyBuilder::headers(const std::vector<HttpHeader>& headers)
470 {
471  headers_->insert(headers_->end(), headers.begin(), headers.end());
472  return *this;
473 }
474 
476 {
477  connection->write(status_strings::to_buffer(status_),
479  connection->write(HttpReply::to_buffers(*headers_), headers_);
480 }
481 
482 } // namespace async_web_server_cpp
static bool serveFromFile(HttpReply::status_type status, const std::string &filename, const std::vector< HttpHeader > &headers, boost::shared_ptr< HttpConnection > connection)
Definition: http_reply.cpp:287
static HttpServerRequestHandler static_reply(status_type status, const std::string &content_type, const std::string &content, const std::vector< HttpHeader > &additional_headers=std::vector< HttpHeader >())
Definition: http_reply.cpp:416
static std::string sniffContentType(const std::string &filename)
Definition: http_reply.cpp:266
static ReplyBuilder builder(status_type status)
Definition: http_reply.cpp:447
static HttpServerRequestHandler from_file(HttpReply::status_type status, const std::string &content_type, const std::string &filename, const std::vector< HttpHeader > &additional_headers=std::vector< HttpHeader >())
Definition: http_reply.cpp:237
ReplyBuilder(HttpReply::status_type status)
Definition: http_reply.cpp:452
FileHttpRequestHandler(HttpReply::status_type status, const std::string &filename, const std::vector< HttpHeader > &headers)
Definition: http_reply.cpp:249
bool operator()(const HttpRequest &, boost::shared_ptr< HttpConnection >, const char *begin, const char *end)
Definition: http_reply.cpp:331
ReplyBuilder & headers(const std::vector< HttpHeader > &headers)
Definition: http_reply.cpp:469
bool operator()(const HttpRequest &, boost::shared_ptr< HttpConnection >, const char *begin, const char *end)
Definition: http_reply.cpp:307
static HttpServerRequestHandler from_filesystem(HttpReply::status_type status, const std::string &path_root, const std::string &filesystem_root, bool list_directories, const std::vector< HttpHeader > &additional_headers=std::vector< HttpHeader >())
Definition: http_reply.cpp:314
boost::shared_ptr< HttpConnection > HttpConnectionPtr
static bool hasContentType(const std::vector< HttpHeader > &headers)
Definition: http_reply.cpp:256
boost::shared_ptr< std::vector< HttpHeader > > headers_
Definition: http_reply.hpp:120
HttpReply::status_type status_
Definition: http_reply.hpp:119
void write(HttpConnectionPtr connection)
Definition: http_reply.cpp:475
const std::string internal_server_error
Definition: http_reply.cpp:37
boost::function< bool(const HttpRequest &, boost::shared_ptr< HttpConnection >, const char *begin, const char *end)> HttpServerRequestHandler
static HttpServerRequestHandler stock_reply(status_type status)
Definition: http_reply.cpp:410
bool operator()(const HttpRequest &, boost::shared_ptr< HttpConnection >, const char *begin, const char *end)
Definition: http_reply.cpp:438
FilesystemHttpRequestHandler(HttpReply::status_type status, const std::string &path_root, const std::string &filesystem_root, bool list_directories, const std::vector< HttpHeader > &headers)
Definition: http_reply.cpp:322
boost::asio::const_buffer to_buffer(HttpReply::status_type status)
Definition: http_reply.cpp:43
ReplyBuilder & header(const std::string &name, const std::string &value)
Definition: http_reply.cpp:457
static std::vector< boost::asio::const_buffer > to_buffers(const std::vector< HttpHeader > &headers)
Definition: http_reply.cpp:220
StaticHttpRequestHandler(HttpReply::status_type status, const std::vector< HttpHeader > &headers, const std::string &content)
Definition: http_reply.cpp:430
boost::shared_ptr< const void > ResourcePtr
std::string to_string(HttpReply::status_type status)
Definition: http_reply.cpp:176


async_web_server_cpp
Author(s): Mitchell Wills , Russel Toris
autogenerated on Mon Feb 28 2022 21:54:08