55
66#include < boost/beast/http/fields.hpp>
77#include < boost/beast/http/message.hpp>
8+ #include < boost/asio/write.hpp>
89#include < boost/variant.hpp>
10+ #include < boost/format.hpp>
911
1012#include " util/signal.h"
13+ #include " util/variant.h"
1114#include " namespaces.h"
15+ #include " or_throw.h"
1216
1317namespace ouinet {
1418
15- class GenericStream ;
16-
1719namespace http_response {
1820
19- struct Head : public http ::response_header<> {
21+ namespace detail {
22+ template <class P , class S >
23+ void async_write_c (const P* p, S& s, Cancel& c, asio::yield_context y)
24+ {
25+ auto cancelled = c.connect ([&] { s.close (); });
26+ sys::error_code ec;
27+ p->async_write (s, y[ec]);
28+ if (cancelled) ec = asio::error::operation_aborted;
29+ return or_throw (y, ec);
30+ }
31+ }
32+
33+ struct Head : public http ::response_header<> {
2034 using Base = http::response_header<>;
2135 using Base::Base;
2236 Head (const Head&) = default ;
@@ -27,7 +41,16 @@ struct Head : public http::response_header<> {
2741
2842 bool operator ==(const Head& other) const ;
2943
30- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
44+ template <class S >
45+ void async_write (S& s, asio::yield_context yield) const
46+ {
47+ Head::writer headw (*this , Base::version (), Base::result_int ());
48+ asio::async_write (s, headw.get (), yield);
49+ }
50+
51+ template <class S >
52+ void async_write (S& s, Cancel& c, asio::yield_context y) const
53+ { return detail::async_write_c (this , s, c, y); }
3154};
3255
3356struct Body : public std ::vector<uint8_t > {
@@ -39,7 +62,15 @@ struct Body : public std::vector<uint8_t> {
3962 Body (Body&&) = default ;
4063 Body& operator =(const Body&) = default ;
4164
42- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
65+ template <class S >
66+ void async_write (S& s, asio::yield_context yield) const
67+ {
68+ asio::async_write (s, asio::buffer (*this ), yield);
69+ }
70+
71+ template <class S >
72+ void async_write (S& s, Cancel& c, asio::yield_context y) const
73+ { return detail::async_write_c (this , s, c, y); }
4374};
4475
4576struct ChunkHdr {
@@ -56,7 +87,22 @@ struct ChunkHdr {
5687 return size == other.size && exts == other.exts ;
5788 }
5889
59- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
90+ template <class S >
91+ void async_write (S& s, asio::yield_context yield) const
92+ {
93+ if (size > 0 ) {
94+ asio::async_write (s, http::chunk_header{size, exts}, yield);
95+ }
96+ else { // `http::chunk_last` carries a trailer itself, do not use
97+ static const auto hdrf = " 0%s\r\n " ;
98+ auto hdr = (boost::format (hdrf) % exts).str ();
99+ asio::async_write (s, asio::buffer (hdr), yield);
100+ }
101+ }
102+
103+ template <class S >
104+ void async_write (S& s, Cancel& c, asio::yield_context y) const
105+ { return detail::async_write_c (this , s, c, y); }
60106};
61107
62108struct ChunkBody : public std ::vector<uint8_t > {
@@ -72,7 +118,22 @@ struct ChunkBody : public std::vector<uint8_t> {
72118 ChunkBody (ChunkBody&&) = default ;
73119 ChunkBody& operator =(const ChunkBody&) = default ;
74120
75- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
121+ template <class S >
122+ void async_write (S& s, asio::yield_context yield) const
123+ {
124+ sys::error_code ec;
125+ asio::async_write (s, asio::buffer (*this ), yield[ec]);
126+
127+ if (ec) return or_throw (yield, ec);
128+
129+ if (remain == 0 ) {
130+ asio::async_write (s, http::chunk_crlf{}, yield[ec]);
131+ }
132+ }
133+
134+ template <class S >
135+ void async_write (S& s, Cancel& c, asio::yield_context y) const
136+ { return detail::async_write_c (this , s, c, y); }
76137};
77138
78139struct Trailer : public http ::fields {
@@ -86,7 +147,16 @@ struct Trailer : public http::fields {
86147
87148 bool operator ==(const Trailer& other) const ;
88149
89- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
150+ template <class S >
151+ void async_write (S& s, asio::yield_context yield) const
152+ {
153+ Trailer::writer trailerw (*this );
154+ asio::async_write (s, trailerw.get (), yield);
155+ }
156+
157+ template <class S >
158+ void async_write (S& s, Cancel& c, asio::yield_context y) const
159+ { return detail::async_write_c (this , s, c, y); }
90160};
91161
92162namespace detail {
@@ -127,7 +197,15 @@ struct Part : public detail::PartVariant
127197 bool is_chunk_body () const { return as_chunk_body () != nullptr ; }
128198 bool is_trailer () const { return as_trailer () != nullptr ; }
129199
130- void async_write (GenericStream&, Cancel, asio::yield_context) const ;
200+ template <class S >
201+ void async_write (S& s, asio::yield_context y) const
202+ {
203+ util::apply (*this , [&](const auto & p) { p.async_write (s, y); });
204+ }
205+
206+ template <class S >
207+ void async_write (S& s, Cancel& c, asio::yield_context y) const
208+ { return detail::async_write_c (this , s, c, y); }
131209};
132210
133211}} // namespace ouinet::http_response
0 commit comments