asio: Add server::response::write_trailer()

This commit is contained in:
Tatsuhiro Tsujikawa 2015-03-07 19:26:42 +09:00
parent 5b5034f19c
commit c976a0fcd1
8 changed files with 66 additions and 0 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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); }

View File

@ -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();

View File

@ -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();

View File

@ -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.

View File

@ -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