]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/example/http/server/small/http_server_small.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / beast / example / http / server / small / http_server_small.cpp
CommitLineData
b32b8144
FG
1//
2// Copyright (c) 2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10//------------------------------------------------------------------------------
11//
12// Example: HTTP server, small
13//
14//------------------------------------------------------------------------------
15
16#include <boost/beast/core.hpp>
17#include <boost/beast/http.hpp>
18#include <boost/beast/version.hpp>
19#include <boost/asio.hpp>
20#include <chrono>
21#include <cstdlib>
22#include <ctime>
23#include <iostream>
24#include <memory>
25#include <string>
26
92f5a8d4
TL
27namespace beast = boost::beast; // from <boost/beast.hpp>
28namespace http = beast::http; // from <boost/beast/http.hpp>
29namespace net = boost::asio; // from <boost/asio.hpp>
30using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
b32b8144
FG
31
32namespace my_program_state
33{
34 std::size_t
35 request_count()
36 {
37 static std::size_t count = 0;
38 return ++count;
39 }
40
41 std::time_t
42 now()
43 {
44 return std::time(0);
45 }
46}
47
48class http_connection : public std::enable_shared_from_this<http_connection>
49{
50public:
51 http_connection(tcp::socket socket)
52 : socket_(std::move(socket))
53 {
54 }
55
56 // Initiate the asynchronous operations associated with the connection.
57 void
58 start()
59 {
60 read_request();
61 check_deadline();
62 }
63
64private:
65 // The socket for the currently connected client.
66 tcp::socket socket_;
67
68 // The buffer for performing reads.
92f5a8d4 69 beast::flat_buffer buffer_{8192};
b32b8144
FG
70
71 // The request message.
72 http::request<http::dynamic_body> request_;
73
74 // The response message.
75 http::response<http::dynamic_body> response_;
76
77 // The timer for putting a deadline on connection processing.
92f5a8d4
TL
78 net::steady_timer deadline_{
79 socket_.get_executor(), std::chrono::seconds(60)};
b32b8144
FG
80
81 // Asynchronously receive a complete request message.
82 void
83 read_request()
84 {
85 auto self = shared_from_this();
86
87 http::async_read(
88 socket_,
89 buffer_,
90 request_,
92f5a8d4 91 [self](beast::error_code ec,
b32b8144
FG
92 std::size_t bytes_transferred)
93 {
94 boost::ignore_unused(bytes_transferred);
95 if(!ec)
96 self->process_request();
97 });
98 }
99
100 // Determine what needs to be done with the request message.
101 void
102 process_request()
103 {
104 response_.version(request_.version());
105 response_.keep_alive(false);
106
107 switch(request_.method())
108 {
109 case http::verb::get:
110 response_.result(http::status::ok);
111 response_.set(http::field::server, "Beast");
112 create_response();
113 break;
114
115 default:
116 // We return responses indicating an error if
117 // we do not recognize the request method.
118 response_.result(http::status::bad_request);
119 response_.set(http::field::content_type, "text/plain");
92f5a8d4 120 beast::ostream(response_.body())
b32b8144 121 << "Invalid request-method '"
92f5a8d4 122 << std::string(request_.method_string())
b32b8144
FG
123 << "'";
124 break;
125 }
126
127 write_response();
128 }
129
130 // Construct a response message based on the program state.
131 void
132 create_response()
133 {
134 if(request_.target() == "/count")
135 {
136 response_.set(http::field::content_type, "text/html");
92f5a8d4 137 beast::ostream(response_.body())
b32b8144
FG
138 << "<html>\n"
139 << "<head><title>Request count</title></head>\n"
140 << "<body>\n"
141 << "<h1>Request count</h1>\n"
142 << "<p>There have been "
143 << my_program_state::request_count()
144 << " requests so far.</p>\n"
145 << "</body>\n"
146 << "</html>\n";
147 }
148 else if(request_.target() == "/time")
149 {
150 response_.set(http::field::content_type, "text/html");
92f5a8d4 151 beast::ostream(response_.body())
b32b8144
FG
152 << "<html>\n"
153 << "<head><title>Current time</title></head>\n"
154 << "<body>\n"
155 << "<h1>Current time</h1>\n"
156 << "<p>The current time is "
157 << my_program_state::now()
158 << " seconds since the epoch.</p>\n"
159 << "</body>\n"
160 << "</html>\n";
161 }
162 else
163 {
164 response_.result(http::status::not_found);
165 response_.set(http::field::content_type, "text/plain");
92f5a8d4 166 beast::ostream(response_.body()) << "File not found\r\n";
b32b8144
FG
167 }
168 }
169
170 // Asynchronously transmit the response message.
171 void
172 write_response()
173 {
174 auto self = shared_from_this();
175
176 response_.set(http::field::content_length, response_.body().size());
177
178 http::async_write(
179 socket_,
180 response_,
92f5a8d4 181 [self](beast::error_code ec, std::size_t)
b32b8144
FG
182 {
183 self->socket_.shutdown(tcp::socket::shutdown_send, ec);
184 self->deadline_.cancel();
185 });
186 }
187
188 // Check whether we have spent enough time on this connection.
189 void
190 check_deadline()
191 {
192 auto self = shared_from_this();
193
194 deadline_.async_wait(
92f5a8d4 195 [self](beast::error_code ec)
b32b8144
FG
196 {
197 if(!ec)
198 {
199 // Close socket to cancel any outstanding operation.
200 self->socket_.close(ec);
201 }
202 });
203 }
204};
205
206// "Loop" forever accepting new connections.
207void
208http_server(tcp::acceptor& acceptor, tcp::socket& socket)
209{
210 acceptor.async_accept(socket,
92f5a8d4 211 [&](beast::error_code ec)
b32b8144
FG
212 {
213 if(!ec)
214 std::make_shared<http_connection>(std::move(socket))->start();
215 http_server(acceptor, socket);
216 });
217}
218
219int
220main(int argc, char* argv[])
221{
222 try
223 {
224 // Check command line arguments.
225 if(argc != 3)
226 {
227 std::cerr << "Usage: " << argv[0] << " <address> <port>\n";
228 std::cerr << " For IPv4, try:\n";
229 std::cerr << " receiver 0.0.0.0 80\n";
230 std::cerr << " For IPv6, try:\n";
231 std::cerr << " receiver 0::0 80\n";
232 return EXIT_FAILURE;
233 }
234
92f5a8d4 235 auto const address = net::ip::make_address(argv[1]);
b32b8144
FG
236 unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
237
92f5a8d4 238 net::io_context ioc{1};
b32b8144
FG
239
240 tcp::acceptor acceptor{ioc, {address, port}};
241 tcp::socket socket{ioc};
242 http_server(acceptor, socket);
243
244 ioc.run();
245 }
246 catch(std::exception const& e)
247 {
248 std::cerr << "Error: " << e.what() << std::endl;
249 return EXIT_FAILURE;
250 }
251}