asio: Add server::response::write_trailer()
This commit is contained in:
parent
5b5034f19c
commit
c976a0fcd1
|
@ -101,6 +101,30 @@ int main(int argc, char *argv[]) {
|
|||
res.end("finally!\n");
|
||||
});
|
||||
});
|
||||
server.handle("/trailer", [](const request &req, const response &res) {
|
||||
// send trailer part.
|
||||
res.write_head(200, {{"trailers", {"digest"}}});
|
||||
|
||||
std::string body = "nghttp2 FTW!\n";
|
||||
auto left = std::make_shared<size_t>(body.size());
|
||||
|
||||
res.end([&res, body, left](uint8_t *dst, std::size_t len,
|
||||
uint32_t *data_flags) {
|
||||
auto n = std::min(len, *left);
|
||||
std::copy_n(body.c_str() + (body.size() - *left), n, dst);
|
||||
*left -= n;
|
||||
if (*left == 0) {
|
||||
*data_flags |=
|
||||
NGHTTP2_DATA_FLAG_EOF | NGHTTP2_DATA_FLAG_NO_END_STREAM;
|
||||
// RFC 3230 Instance Digests in HTTP. The digest value is
|
||||
// SHA-256 message digest of body.
|
||||
res.write_trailer(
|
||||
{{"digest",
|
||||
{"SHA-256=qqXqskW7F3ueBSvmZRCiSwl2ym4HRO0M/pvQCBlSDis="}}});
|
||||
}
|
||||
return n;
|
||||
});
|
||||
});
|
||||
|
||||
if (argc >= 6) {
|
||||
boost::asio::ssl::context tls(boost::asio::ssl::context::sslv23);
|
||||
|
|
|
@ -359,6 +359,27 @@ int http2_handler::start_response(stream &strm) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int http2_handler::submit_trailer(stream &strm, header_map h) {
|
||||
int rv;
|
||||
auto nva = std::vector<nghttp2_nv>();
|
||||
nva.reserve(h.size());
|
||||
for (auto &hd : h) {
|
||||
nva.push_back(nghttp2::http2::make_nv(hd.first, hd.second.value,
|
||||
hd.second.sensitive));
|
||||
}
|
||||
|
||||
rv = nghttp2_submit_trailer(session_, strm.get_stream_id(), nva.data(),
|
||||
nva.size());
|
||||
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal_write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http2_handler::enter_callback() {
|
||||
assert(!inside_callback_);
|
||||
inside_callback_ = true;
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
|
||||
int start_response(stream &s);
|
||||
|
||||
int submit_trailer(stream &s, header_map h);
|
||||
|
||||
void stream_error(int32_t stream_id, uint32_t error_code);
|
||||
|
||||
void initiate_write();
|
||||
|
|
|
@ -46,6 +46,10 @@ void response::end(std::string data) const { impl_->end(std::move(data)); }
|
|||
|
||||
void response::end(generator_cb cb) const { impl_->end(std::move(cb)); }
|
||||
|
||||
void response::write_trailer(header_map h) const {
|
||||
impl_->write_trailer(std::move(h));
|
||||
}
|
||||
|
||||
void response::on_close(close_cb cb) const { impl_->on_close(std::move(cb)); }
|
||||
|
||||
void response::cancel(uint32_t error_code) const { impl_->cancel(error_code); }
|
||||
|
|
|
@ -81,6 +81,11 @@ void response_impl::end(generator_cb cb) {
|
|||
state_ = response_state::BODY_STARTED;
|
||||
}
|
||||
|
||||
void response_impl::write_trailer(header_map h) {
|
||||
auto handler = strm_->handler();
|
||||
handler->submit_trailer(*strm_, std::move(h));
|
||||
}
|
||||
|
||||
void response_impl::start_response() {
|
||||
auto handler = strm_->handler();
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
void write_head(unsigned int status_code, header_map h = {});
|
||||
void end(std::string data = "");
|
||||
void end(generator_cb cb);
|
||||
void write_trailer(header_map h);
|
||||
void on_close(close_cb cb);
|
||||
void resume();
|
||||
|
||||
|
|
|
@ -81,6 +81,11 @@ public:
|
|||
// call of end() is allowed.
|
||||
void end(generator_cb cb) const;
|
||||
|
||||
// Write trailer part. This must be called after setting both
|
||||
// NGHTTP2_DATA_FLAG_EOF and NGHTTP2_DATA_FLAG_NO_END_STREAM set in
|
||||
// *data_flag parameter in generator_cb passed to end() function.
|
||||
void write_trailer(header_map h) const;
|
||||
|
||||
// Sets callback which is invoked when this request and response are
|
||||
// finished. After the invocation of this callback, the application
|
||||
// must not access request and response object.
|
||||
|
|
|
@ -76,6 +76,10 @@ template <typename F, typename... T> Defer<F, T...> defer(F &&f, T &&... t) {
|
|||
return Defer<F, T...>(std::forward<F>(f), std::forward<T>(t)...);
|
||||
}
|
||||
|
||||
template <typename T, typename F> bool test_flags(T t, F flags) {
|
||||
return (t & flags) == flags;
|
||||
}
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
#endif // TEMPLATE_H
|
||||
|
|
Loading…
Reference in New Issue