1+ #pragma once
2+ #include " helper.h"
3+ #include " request.h"
4+
5+ // Handles an HTTP server connection
6+ class Session : public std ::enable_shared_from_this<Session>
7+ {
8+ public:
9+ // Take ownership of the stream
10+ explicit Session (tcp::socket &&socket, std::vector<data::person> &person) : m_person(person), m_stream(std::move(socket)), m_lambda(*this ) {}
11+
12+ // Start the asynchronous operation
13+ void run ()
14+ {
15+ // We need to be executing within a strand to perform async operations
16+ // on the I/O objects in this session. Although not strictly necessary
17+ // for single-threaded contexts, this example code is written to be
18+ // thread-safe by default.
19+ net::dispatch (m_stream.get_executor (), beast::bind_front_handler (&Session::doRead, shared_from_this ()));
20+ }
21+
22+ void doRead ()
23+ {
24+ // Make the request empty before reading,
25+ // otherwise the operation behavior is undefined.
26+ m_req = {};
27+
28+ // Set the timeout.
29+ m_stream.expires_after (std::chrono::seconds (30 ));
30+
31+ // Read a request
32+ http::async_read (m_stream, m_buffer, m_req, beast::bind_front_handler (&Session::onRead, shared_from_this ()));
33+ }
34+
35+ void onRead (beast::error_code ec, std::size_t bytes_transferred)
36+ {
37+ boost::ignore_unused (bytes_transferred);
38+
39+ // This means they closed the connection
40+ if (ec == http::error::end_of_stream)
41+ {
42+ return doClose ();
43+ }
44+
45+ if (ec)
46+ {
47+ return fail (ec, " read" );
48+ }
49+
50+ // Send the response
51+ handleRequest (std::move (m_req), m_lambda, m_person);
52+ }
53+
54+ void onWrite (bool close, beast::error_code ec, std::size_t bytes_transferred)
55+ {
56+ boost::ignore_unused (bytes_transferred);
57+
58+ if (ec)
59+ {
60+ return fail (ec, " write" );
61+ }
62+
63+ if (close)
64+ {
65+ // This means we should close the connection, usually because
66+ // the response indicated the "Connection: close" semantic.
67+ return doClose ();
68+ }
69+
70+ // We're done with the response so delete it
71+ m_res = nullptr ;
72+
73+ // Read another request
74+ doRead ();
75+ }
76+
77+ void doClose ()
78+ {
79+ // Send a TCP shutdown
80+ beast::error_code ec;
81+ m_stream.socket ().shutdown (tcp::socket::shutdown_send, ec);
82+
83+ // At this point the connection is closed gracefully
84+ }
85+
86+ private:
87+ std::vector<data::person> &m_person;
88+ // This is the C++11 equivalent of a generic lambda.
89+ // The function object is used to send an HTTP message.
90+ struct sendLambda
91+ {
92+ public:
93+ explicit sendLambda (Session &self) : m_self(self) {}
94+
95+ template <bool isRequest, class Body , class Fields > void operator ()(http::message<isRequest, Body, Fields> &&msg) const
96+ {
97+ // The lifetime of the message has to extend
98+ // for the duration of the async operation so
99+ // we use a shared_ptr to manage it.
100+ auto sp = std::make_shared<http::message<isRequest, Body, Fields>>(std::move (msg));
101+
102+ // Store a type-erased version of the shared
103+ // pointer in the class to keep it alive.
104+ m_self.m_res = sp;
105+
106+ // Write the response
107+ http::async_write (m_self.m_stream , *sp, beast::bind_front_handler (&Session::onWrite, m_self.shared_from_this (), sp->need_eof ()));
108+ }
109+
110+ private:
111+ Session &m_self;
112+ };
113+
114+ beast::tcp_stream m_stream;
115+ beast::flat_buffer m_buffer;
116+ http::request<http::string_body> m_req;
117+ std::shared_ptr<void > m_res;
118+ sendLambda m_lambda;
119+ };
0 commit comments