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