Skip to content

Commit 4754861

Browse files
committed
refactor http into one mixin
1 parent 52c7f0f commit 4754861

File tree

3 files changed

+273
-304
lines changed

3 files changed

+273
-304
lines changed

example/server/http_responder.hpp

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
//
2+
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail 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/cppalliance/http_io
8+
//
9+
10+
#ifndef BOOST_HTTP_IO_EXAMPLE_SERVER_HTTP_RESPONDER_HPP
11+
#define BOOST_HTTP_IO_EXAMPLE_SERVER_HTTP_RESPONDER_HPP
12+
13+
#include "asio_server.hpp"
14+
#include "handler.hpp"
15+
#include "logger.hpp"
16+
17+
#include <boost/http_io/detail/config.hpp>
18+
#include <boost/http_io/read.hpp>
19+
#include <boost/http_io/write.hpp>
20+
#include <boost/http_io/server/router.hpp>
21+
#include <boost/http_proto/request_parser.hpp>
22+
#include <boost/http_proto/response.hpp>
23+
#include <boost/http_proto/serializer.hpp>
24+
#include <functional> // for _1
25+
26+
namespace boost {
27+
28+
namespace asio {
29+
namespace ip {
30+
class tcp; // forward declaration
31+
} // ip
32+
} // asio
33+
34+
namespace http_io {
35+
36+
//------------------------------------------------
37+
38+
/** Mixin for delivering responses to HTTP requests
39+
*/
40+
template<class Derived>
41+
class http_responder
42+
{
43+
public:
44+
http_responder(
45+
asio_server& srv,
46+
router_type& rr)
47+
: id_(srv.make_unique_id())
48+
, srv_(srv)
49+
, rr_(rr)
50+
, pr_(srv_.services())
51+
, sr_(srv_.services())
52+
{
53+
pr_.reset();
54+
}
55+
56+
void
57+
do_read_request()
58+
{
59+
pr_.start();
60+
61+
using namespace std::placeholders;
62+
http_io::async_read_header(
63+
self().stream(),
64+
pr_,
65+
std::bind(&http_responder::on_read_header,
66+
this, _1, _2));
67+
}
68+
69+
private:
70+
void
71+
on_read_header(
72+
system::error_code const& ec,
73+
std::size_t bytes_transferred)
74+
{
75+
(void)bytes_transferred;
76+
77+
if(ec.failed())
78+
{
79+
reset();
80+
81+
if( ec == asio::error::operation_aborted )
82+
{
83+
LOG_TRC(sect_, id(), "async_accept, error::operation_aborted");
84+
// worker is canceled, exit the I/O loop
85+
return;
86+
}
87+
88+
// errors here are usually recoverable
89+
LOG_DBG(sect_, id(), "async_read_header ", ec.message());
90+
return self().do_accept();
91+
}
92+
93+
// find the route
94+
auto found = rr_.find(rh_,
95+
pr_.get().method(), pr_.get().target());
96+
97+
if(! found)
98+
{
99+
// errors here are usually recoverable
100+
LOG_DBG(sect_, id(), "no route");
101+
reset();
102+
return self().do_accept();
103+
}
104+
105+
using namespace std::placeholders;
106+
http_io::async_read(self().stream(), pr_, std::bind(
107+
&http_responder::on_read_body, this, _1, _2));
108+
}
109+
110+
void
111+
on_read_body(
112+
system::error_code const& ec,
113+
std::size_t bytes_transferred)
114+
{
115+
(void)bytes_transferred;
116+
117+
if( ec.failed() )
118+
{
119+
reset();
120+
121+
if( ec == asio::error::operation_aborted )
122+
{
123+
// worker is canceled, exit the I/O loop
124+
LOG_TRC(sect_, id(), "async_read, error::operation_aborted");
125+
return;
126+
}
127+
128+
// errors here are usually recoverable
129+
LOG_DBG(sect_, id(), "async_read ", ec.message());
130+
return self().do_accept();
131+
}
132+
133+
rh_->on_complete({ pr_.get(), res_, sr_, srv_.is_stopping() });
134+
135+
using namespace std::placeholders;
136+
http_io::async_write(self().stream(), sr_, std::bind(
137+
&http_responder::on_write, this, _1, _2));
138+
}
139+
140+
void
141+
on_write(
142+
system::error_code const& ec,
143+
std::size_t bytes_transferred)
144+
{
145+
(void)bytes_transferred;
146+
147+
if( ec.failed() )
148+
{
149+
reset();
150+
151+
if( ec == asio::error::operation_aborted )
152+
{
153+
// worker is canceled, exit the I/O loop
154+
LOG_TRC(sect_, id(), "async_write, error::operation_aborted");
155+
return;
156+
}
157+
158+
// errors here are usually recoverable
159+
LOG_DBG(sect_, id(), "async_write ", ec.message());
160+
return self().do_accept();
161+
}
162+
163+
if(res_.keep_alive())
164+
return do_read_request();
165+
166+
reset();
167+
return self().do_accept();
168+
}
169+
170+
void
171+
reset()
172+
{
173+
rh_.reset();
174+
pr_.reset();
175+
sr_.reset();
176+
res_.clear();
177+
}
178+
179+
private:
180+
Derived&
181+
self() noexcept
182+
{
183+
return *static_cast<Derived*>(this);
184+
}
185+
186+
Derived const&
187+
self() const noexcept
188+
{
189+
return *static_cast<Derived const*>(this);
190+
}
191+
192+
protected:
193+
std::string id() const
194+
{
195+
return std::string("[") + std::to_string(id_) + "] ";
196+
}
197+
198+
protected:
199+
std::size_t id_ = 0;
200+
section sect_;
201+
asio_server& srv_;
202+
203+
private:
204+
router_type& rr_;
205+
router_type::handler rh_;
206+
http_proto::request_parser pr_;
207+
http_proto::serializer sr_;
208+
http_proto::response res_;
209+
};
210+
211+
} // http_io
212+
} // boost
213+
214+
#endif

0 commit comments

Comments
 (0)