216 lines
12 KiB
C++
216 lines
12 KiB
C++
#include "reply.hpp"
|
|
#include <string>
|
|
|
|
#include "mime_types.hpp"
|
|
|
|
|
|
namespace http::server {
|
|
namespace status_strings {
|
|
const std::string ok = "HTTP/1.1 200 OK\r\n";
|
|
const std::string created = "HTTP/1.1 201 Created\r\n";
|
|
const std::string accepted = "HTTP/1.1 202 Accepted\r\n";
|
|
const std::string no_content = "HTTP/1.1 204 No Content\r\n";
|
|
const std::string multiple_choices = "HTTP/1.1 300 Multiple Choices\r\n";
|
|
const std::string moved_permanently = "HTTP/1.1 301 Moved Permanently\r\n";
|
|
const std::string moved_temporarily = "HTTP/1.1 302 Moved Temporarily\r\n";
|
|
const std::string not_modified = "HTTP/1.1 304 Not Modified\r\n";
|
|
const std::string bad_request = "HTTP/1.1 400 Bad Request\r\n";
|
|
const std::string unauthorized = "HTTP/1.1 401 Unauthorized\r\n";
|
|
const std::string forbidden = "HTTP/1.1 403 Forbidden\r\n";
|
|
const std::string not_found = "HTTP/1.1 404 Not Found\r\n";
|
|
const std::string internal_server_error = "HTTP/1.1 500 Internal Server Error\r\n";
|
|
const std::string not_implemented = "HTTP/1.1 501 Not Implemented\r\n";
|
|
const std::string bad_gateway = "HTTP/1.1 502 Bad Gateway\r\n";
|
|
const std::string service_unavailable = "HTTP/1.1 503 Service Unavailable\r\n";
|
|
|
|
boost::asio::const_buffer to_buffer(status_type status) {
|
|
switch (status) {
|
|
case status_type::ok:
|
|
return boost::asio::buffer(ok);
|
|
case status_type::created:
|
|
return boost::asio::buffer(created);
|
|
case status_type::accepted:
|
|
return boost::asio::buffer(accepted);
|
|
case status_type::no_content:
|
|
return boost::asio::buffer(no_content);
|
|
case status_type::multiple_choices:
|
|
return boost::asio::buffer(multiple_choices);
|
|
case status_type::moved_permanently:
|
|
return boost::asio::buffer(moved_permanently);
|
|
case status_type::moved_temporarily:
|
|
return boost::asio::buffer(moved_temporarily);
|
|
case status_type::not_modified:
|
|
return boost::asio::buffer(not_modified);
|
|
case status_type::bad_request:
|
|
return boost::asio::buffer(bad_request);
|
|
case status_type::unauthorized:
|
|
return boost::asio::buffer(unauthorized);
|
|
case status_type::forbidden:
|
|
return boost::asio::buffer(forbidden);
|
|
case status_type::not_found:
|
|
return boost::asio::buffer(not_found);
|
|
case status_type::internal_server_error:
|
|
return boost::asio::buffer(internal_server_error);
|
|
case status_type::not_implemented:
|
|
return boost::asio::buffer(not_implemented);
|
|
case status_type::bad_gateway:
|
|
return boost::asio::buffer(bad_gateway);
|
|
case status_type::service_unavailable:
|
|
return boost::asio::buffer(service_unavailable);
|
|
default:
|
|
return boost::asio::buffer(internal_server_error);
|
|
}
|
|
}
|
|
} // namespace status_strings
|
|
|
|
namespace misc_strings {
|
|
const char name_value_separator[] = {':', ' '};
|
|
const char crlf[] = {'\r', '\n'};
|
|
} // namespace misc_strings
|
|
|
|
std::vector<boost::asio::const_buffer> Reply::to_buffers() const {
|
|
std::vector<boost::asio::const_buffer> buffers;
|
|
buffers.push_back(status_strings::to_buffer(status));
|
|
for (const auto & h : headers) {
|
|
buffers.emplace_back(boost::asio::buffer(h.name));
|
|
buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator));
|
|
buffers.emplace_back(boost::asio::buffer(h.value));
|
|
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
|
}
|
|
buffers.emplace_back(boost::asio::buffer(misc_strings::crlf));
|
|
buffers.emplace_back(boost::asio::buffer(content));
|
|
return buffers;
|
|
}
|
|
|
|
namespace stock_replies {
|
|
constexpr char ok[] = "";
|
|
constexpr char created[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Created</title></head>"
|
|
"<body><h1>201 Created</h1></body>"
|
|
"</html>";
|
|
constexpr char accepted[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Accepted</title></head>"
|
|
"<body><h1>202 Accepted</h1></body>"
|
|
"</html>";
|
|
constexpr char no_content[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>No Content</title></head>"
|
|
"<body><h1>204 Content</h1></body>"
|
|
"</html>";
|
|
constexpr char multiple_choices[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Multiple Choices</title></head>"
|
|
"<body><h1>300 Multiple Choices</h1></body>"
|
|
"</html>";
|
|
constexpr char moved_permanently[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Moved Permanently</title></head>"
|
|
"<body><h1>301 Moved Permanently</h1></body>"
|
|
"</html>";
|
|
constexpr char moved_temporarily[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Moved Temporarily</title></head>"
|
|
"<body><h1>302 Moved Temporarily</h1></body>"
|
|
"</html>";
|
|
constexpr char not_modified[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Not Modified</title></head>"
|
|
"<body><h1>304 Not Modified</h1></body>"
|
|
"</html>";
|
|
constexpr char bad_request[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Bad Request</title></head>"
|
|
"<body><h1>400 Bad Request</h1></body>"
|
|
"</html>";
|
|
constexpr char unauthorized[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Unauthorized</title></head>"
|
|
"<body><h1>401 Unauthorized</h1></body>"
|
|
"</html>";
|
|
constexpr char forbidden[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Forbidden</title></head>"
|
|
"<body><h1>403 Forbidden</h1></body>"
|
|
"</html>";
|
|
constexpr char not_found[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Not Found</title></head>"
|
|
"<body><h1>404 Not Found</h1></body>"
|
|
"</html>";
|
|
constexpr char internal_server_error[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Internal Server Error</title></head>"
|
|
"<body><h1>500 Internal Server Error</h1></body>"
|
|
"</html>";
|
|
constexpr char not_implemented[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Not Implemented</title></head>"
|
|
"<body><h1>501 Not Implemented</h1></body>"
|
|
"</html>";
|
|
constexpr char bad_gateway[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Bad Gateway</title></head>"
|
|
"<body><h1>502 Bad Gateway</h1></body>"
|
|
"</html>";
|
|
constexpr char service_unavailable[] =
|
|
"<!DOCTYPE html>\n<html>"
|
|
"<head><title>Service Unavailable</title></head>"
|
|
"<body><h1>503 Service Unavailable</h1></body>"
|
|
"</html>";
|
|
|
|
std::vector<char> as_content(status_type status) {
|
|
switch (status) {
|
|
case status_type::ok: return {ok, ok + (sizeof(ok) - 1)};
|
|
case status_type::created: return {created, created + (sizeof(created) - 1)};
|
|
case status_type::accepted: return {accepted, accepted + (sizeof(accepted) - 1)};
|
|
case status_type::no_content: return {no_content, no_content + (sizeof(no_content) - 1)};
|
|
case status_type::multiple_choices: return {multiple_choices, multiple_choices + (sizeof(multiple_choices) - 1)};
|
|
case status_type::moved_permanently: return {moved_permanently, moved_permanently + (sizeof(moved_permanently) - 1)};
|
|
case status_type::moved_temporarily: return {moved_temporarily, moved_temporarily + (sizeof(moved_temporarily) - 1)};
|
|
case status_type::not_modified: return {not_modified, not_modified + (sizeof(not_modified) - 1)};
|
|
case status_type::bad_request: return {bad_request, bad_request + (sizeof(bad_request) - 1)};
|
|
case status_type::unauthorized: return {unauthorized, unauthorized + (sizeof(unauthorized) - 1)};
|
|
case status_type::forbidden: return {forbidden, forbidden + (sizeof(forbidden) - 1)};
|
|
case status_type::not_found: return {not_found, not_found + (sizeof(not_found) - 1)};
|
|
case status_type::not_implemented: return {not_implemented, not_implemented + (sizeof(not_implemented) - 1)};
|
|
case status_type::bad_gateway: return {bad_gateway, bad_gateway + (sizeof(bad_gateway) - 1)};
|
|
case status_type::service_unavailable: return {service_unavailable, service_unavailable + (sizeof(service_unavailable) - 1)};
|
|
case status_type::internal_server_error:
|
|
default: return {internal_server_error, internal_server_error + (sizeof(internal_server_error) - 1)};
|
|
}
|
|
}
|
|
|
|
void as_content(status_type status, std::vector<char>& dest) {
|
|
dest.clear();
|
|
switch (status) {
|
|
case status_type::ok: dest.insert(dest.end(), ok, ok + sizeof(ok) - 1); return;
|
|
case status_type::created: dest.insert(dest.end(), created, created + sizeof(created) - 1); return;
|
|
case status_type::accepted: dest.insert(dest.end(), accepted, accepted + sizeof(accepted) - 1); return;
|
|
case status_type::no_content: dest.insert(dest.end(), no_content, no_content + sizeof(no_content) - 1); return;
|
|
case status_type::multiple_choices: dest.insert(dest.end(), multiple_choices, multiple_choices + sizeof(multiple_choices) - 1); return;
|
|
case status_type::moved_permanently: dest.insert(dest.end(), moved_permanently, moved_permanently + sizeof(moved_permanently) - 1); return;
|
|
case status_type::moved_temporarily: dest.insert(dest.end(), moved_temporarily, moved_temporarily + sizeof(moved_temporarily) - 1); return;
|
|
case status_type::not_modified: dest.insert(dest.end(), not_modified, not_modified + sizeof(not_modified) - 1); return;
|
|
case status_type::bad_request: dest.insert(dest.end(), bad_request, bad_request + sizeof(bad_request) - 1); return;
|
|
case status_type::unauthorized: dest.insert(dest.end(), unauthorized, unauthorized + sizeof(unauthorized) - 1); return;
|
|
case status_type::forbidden: dest.insert(dest.end(), forbidden, forbidden + sizeof(forbidden) - 1); return;
|
|
case status_type::not_found: dest.insert(dest.end(), not_found, not_found + sizeof(not_found) - 1); return;
|
|
case status_type::not_implemented: dest.insert(dest.end(), not_implemented, not_implemented + sizeof(not_implemented) - 1); return;
|
|
case status_type::bad_gateway: dest.insert(dest.end(), bad_gateway, bad_gateway + sizeof(bad_gateway) - 1); return;
|
|
case status_type::service_unavailable: dest.insert(dest.end(), service_unavailable, service_unavailable + sizeof(service_unavailable) - 1); return;
|
|
case status_type::internal_server_error:
|
|
default: dest.insert(dest.end(), internal_server_error, internal_server_error + sizeof(internal_server_error) - 1);
|
|
}
|
|
}
|
|
} // namespace stock_replies
|
|
|
|
void stockReply(status_type status, Reply& rep) {
|
|
rep.status = status;
|
|
rep.headers.clear();
|
|
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_html)});
|
|
stock_replies::as_content(status, rep.content);
|
|
}
|
|
} // namespace http::server
|