Skip to content

Commit 7887cd0

Browse files
committed
http_response::Part now takes template for the sink stream
Mainly so that we can write into a file and still be able to work with file specific API afterwards.
1 parent 793c0b1 commit 7887cd0

File tree

2 files changed

+89
-129
lines changed

2 files changed

+89
-129
lines changed

src/response_part.cpp

Lines changed: 2 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
#include <boost/asio/buffer.hpp>
2-
#include <boost/asio/write.hpp>
3-
#include <boost/beast/http/chunk_encode.hpp>
4-
#include <boost/format.hpp>
5-
#include <boost/container/flat_map.hpp>
6-
71
#include "namespaces.h"
8-
#include "generic_stream.h"
9-
#include "or_throw.h"
102
#include "response_part.h"
11-
#include "util/yield.h"
12-
#include "util/variant.h"
3+
4+
#include <boost/container/flat_map.hpp>
135

146
namespace ouinet { namespace http_response {
157

@@ -29,7 +21,6 @@ fields_to_map(const http::fields& fields) {
2921

3022
using asio::yield_context;
3123

32-
//--------------------------------------------------------------------
3324
bool Head::operator==(const Head& other) const {
3425
if (version() != other.version()) return false;
3526
if (result_int() != other.result_int()) return false;
@@ -40,113 +31,4 @@ bool Trailer::operator==(const Trailer& other) const {
4031
return fields_to_map(*this) == fields_to_map(other);
4132
}
4233

43-
//--------------------------------------------------------------------
44-
static
45-
void async_write(const Head& head, GenericStream& con, yield_context yield)
46-
{
47-
Head::writer headw(head, head.version(), head.result_int());
48-
asio::async_write(con, headw.get(), yield);
49-
}
50-
51-
static
52-
void async_write(const Body& body, GenericStream& con, yield_context yield)
53-
{
54-
asio::async_write(con, asio::buffer(body), yield);
55-
}
56-
57-
static
58-
void async_write(const ChunkHdr& ch_hdr, GenericStream& con, yield_context yield)
59-
{
60-
if (ch_hdr.size > 0)
61-
asio::async_write(con, http::chunk_header{ch_hdr.size, ch_hdr.exts}, yield);
62-
else { // `http::chunk_last` carries a trailer itself, do not use
63-
static const auto hdrf = "0%s\r\n";
64-
auto hdr = (boost::format(hdrf) % ch_hdr.exts).str();
65-
asio::async_write(con, asio::buffer(hdr), yield);
66-
}
67-
}
68-
69-
static
70-
void async_write(const ChunkBody& ch_b, GenericStream& con, yield_context yield)
71-
{
72-
sys::error_code ec;
73-
asio::async_write(con, asio::buffer(ch_b), yield[ec]);
74-
75-
if (ec) return or_throw(yield, ec);
76-
77-
if (ch_b.remain == 0)
78-
asio::async_write(con, http::chunk_crlf{}, yield[ec]);
79-
}
80-
81-
static
82-
void async_write(const Trailer& trailer, GenericStream& con, yield_context yield)
83-
{
84-
Trailer::writer trailerw(trailer);
85-
asio::async_write(con, trailerw.get(), yield);
86-
}
87-
88-
//--------------------------------------------------------------------
89-
template<class T>
90-
static
91-
void async_write_c(const T& t, GenericStream& con, Cancel& cancel, yield_context yield)
92-
{
93-
auto cancelled = cancel.connect([&] { con.close(); });
94-
sys::error_code ec;
95-
async_write(t, con, yield[ec]);
96-
if (cancelled) ec = asio::error::operation_aborted;
97-
return or_throw(yield, ec);
98-
}
99-
100-
//--------------------------------------------------------------------
101-
void
102-
Head::async_write( GenericStream& con
103-
, Cancel cancel
104-
, asio::yield_context yield) const
105-
{
106-
async_write_c(*this, con, cancel, yield);
107-
}
108-
109-
void
110-
Body::async_write( GenericStream& con
111-
, Cancel cancel
112-
, asio::yield_context yield) const
113-
{
114-
async_write_c(*this, con, cancel, yield);
115-
}
116-
117-
void
118-
ChunkHdr::async_write( GenericStream& con
119-
, Cancel cancel
120-
, asio::yield_context yield) const
121-
{
122-
async_write_c(*this, con, cancel, yield);
123-
}
124-
125-
void
126-
ChunkBody::async_write( GenericStream& con
127-
, Cancel cancel
128-
, asio::yield_context yield) const
129-
{
130-
async_write_c(*this, con, cancel, yield);
131-
}
132-
133-
void
134-
Trailer::async_write( GenericStream& con
135-
, Cancel cancel
136-
, asio::yield_context yield) const
137-
{
138-
async_write_c(*this, con, cancel, yield);
139-
}
140-
141-
//--------------------------------------------------------------------
142-
void
143-
Part::async_write( GenericStream& con
144-
, Cancel cancel
145-
, asio::yield_context yield) const
146-
{
147-
util::apply(*this, [&] (const auto& p) {
148-
p.async_write(con, cancel, yield);
149-
});
150-
}
151-
15234
}} // namespace ouinet::http_response

src/response_part.h

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,32 @@
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

1317
namespace ouinet {
1418

15-
class GenericStream;
16-
1719
namespace 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

3356
struct 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

4576
struct 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

62108
struct 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

78139
struct 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

92162
namespace 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

Comments
 (0)