asio: Start sending response header when write_head is called
This commit is contained in:
parent
a1c937a007
commit
05b8d8c5b7
|
@ -70,6 +70,17 @@ int main(int argc, char *argv[]) {
|
||||||
res.write_head(200);
|
res.write_head(200);
|
||||||
res.end("under construction!");
|
res.end("under construction!");
|
||||||
});
|
});
|
||||||
|
server.handle("/push", [](const request &req, const response &res) {
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto push = res.push(ec, "GET", "/push/1");
|
||||||
|
if (!ec) {
|
||||||
|
push->write_head(200);
|
||||||
|
push->end("server push FTW!");
|
||||||
|
}
|
||||||
|
|
||||||
|
res.write_head(200);
|
||||||
|
res.end("you'll receive server push!");
|
||||||
|
});
|
||||||
server.listen("*", port);
|
server.listen("*", port);
|
||||||
|
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
|
|
|
@ -63,6 +63,11 @@ read_cb string_reader(std::string data) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_cb deferred_reader() {
|
||||||
|
return [](uint8_t *buf, size_t len,
|
||||||
|
uint32_t *data_flags) { return NGHTTP2_ERR_DEFERRED; };
|
||||||
|
}
|
||||||
|
|
||||||
template <typename F, typename... T>
|
template <typename F, typename... T>
|
||||||
std::shared_ptr<Defer<F, T...>> defer_shared(F &&f, T &&... t) {
|
std::shared_ptr<Defer<F, T...>> defer_shared(F &&f, T &&... t) {
|
||||||
return std::make_shared<Defer<F, T...>>(std::forward<F>(f),
|
return std::make_shared<Defer<F, T...>>(std::forward<F>(f),
|
||||||
|
|
|
@ -37,9 +37,12 @@ namespace nghttp2 {
|
||||||
|
|
||||||
namespace asio_http2 {
|
namespace asio_http2 {
|
||||||
|
|
||||||
|
boost::system::error_code make_error_code(nghttp2_error ev);
|
||||||
|
|
||||||
read_cb string_reader(std::string data);
|
read_cb string_reader(std::string data);
|
||||||
|
|
||||||
boost::system::error_code make_error_code(nghttp2_error ev);
|
// Returns read_cb, which just returns NGHTTP2_ERR_DEFERRED
|
||||||
|
read_cb deferred_reader();
|
||||||
|
|
||||||
template <typename InputIt>
|
template <typename InputIt>
|
||||||
void split_path(uri_ref &dst, InputIt first, InputIt last) {
|
void split_path(uri_ref &dst, InputIt first, InputIt last) {
|
||||||
|
|
|
@ -204,8 +204,7 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &res = strm->response().impl();
|
auto &res = strm->response().impl();
|
||||||
res.push_promise_sent(true);
|
res.push_promise_sent();
|
||||||
res.start_response();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,6 @@ boost::asio::io_service &response::io_service() const {
|
||||||
return impl_->io_service();
|
return impl_->io_service();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool response::started() const { return impl_->started(); }
|
|
||||||
|
|
||||||
response_impl &response::impl() const { return *impl_; }
|
response_impl &response::impl() const { return *impl_; }
|
||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
|
|
|
@ -33,33 +33,58 @@ namespace asio_http2 {
|
||||||
namespace server {
|
namespace server {
|
||||||
|
|
||||||
response_impl::response_impl()
|
response_impl::response_impl()
|
||||||
: strm_(nullptr), status_code_(200), started_(false), pushed_(false),
|
: strm_(nullptr), read_cb_(deferred_reader()), status_code_(200),
|
||||||
|
state_(response_state::INITIAL), pushed_(false),
|
||||||
push_promise_sent_(false) {}
|
push_promise_sent_(false) {}
|
||||||
|
|
||||||
unsigned int response_impl::status_code() const { return status_code_; }
|
unsigned int response_impl::status_code() const { return status_code_; }
|
||||||
|
|
||||||
void response_impl::write_head(unsigned int status_code, header_map h) {
|
void response_impl::write_head(unsigned int status_code, header_map h) {
|
||||||
status_code_ = status_code;
|
if (state_ != response_state::INITIAL) {
|
||||||
header_ = std::move(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void response_impl::end(std::string data) {
|
|
||||||
if (started_) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_code_ = status_code;
|
||||||
|
header_ = std::move(h);
|
||||||
|
|
||||||
|
state_ = response_state::HEADER_DONE;
|
||||||
|
|
||||||
|
if (pushed_ && !push_promise_sent_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
void response_impl::end(std::string data) {
|
||||||
end(string_reader(std::move(data)));
|
end(string_reader(std::move(data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void response_impl::end(read_cb cb) {
|
void response_impl::end(read_cb cb) {
|
||||||
if (started_) {
|
if (state_ == response_state::BODY_STARTED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_cb_ = std::move(cb);
|
read_cb_ = std::move(cb);
|
||||||
started_ = true;
|
|
||||||
|
|
||||||
start_response();
|
if (state_ == response_state::INITIAL) {
|
||||||
|
write_head(status_code_);
|
||||||
|
} else {
|
||||||
|
// read_cb is changed, start writing in case it is deferred.
|
||||||
|
auto handler = strm_->handler();
|
||||||
|
handler->resume(*strm_);
|
||||||
|
}
|
||||||
|
|
||||||
|
state_ = response_state::BODY_STARTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void response_impl::start_response() {
|
||||||
|
auto handler = strm_->handler();
|
||||||
|
|
||||||
|
if (handler->start_response(*strm_) != 0) {
|
||||||
|
handler->stream_error(strm_->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void response_impl::on_close(close_cb cb) { close_cb_ = std::move(cb); }
|
void response_impl::on_close(close_cb cb) { close_cb_ = std::move(cb); }
|
||||||
|
@ -75,19 +100,6 @@ void response_impl::cancel(uint32_t error_code) {
|
||||||
handler->stream_error(strm_->get_stream_id(), error_code);
|
handler->stream_error(strm_->get_stream_id(), error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void response_impl::start_response() {
|
|
||||||
if (!started_ || (pushed_ && !push_promise_sent_)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto handler = strm_->handler();
|
|
||||||
|
|
||||||
if (handler->start_response(*strm_) != 0) {
|
|
||||||
handler->stream_error(strm_->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response *response_impl::push(boost::system::error_code &ec, std::string method,
|
response *response_impl::push(boost::system::error_code &ec, std::string method,
|
||||||
std::string raw_path_query, header_map h) const {
|
std::string raw_path_query, header_map h) const {
|
||||||
auto handler = strm_->handler();
|
auto handler = strm_->handler();
|
||||||
|
@ -104,11 +116,18 @@ boost::asio::io_service &response_impl::io_service() {
|
||||||
return strm_->handler()->io_service();
|
return strm_->handler()->io_service();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool response_impl::started() const { return started_; }
|
|
||||||
|
|
||||||
void response_impl::pushed(bool f) { pushed_ = f; }
|
void response_impl::pushed(bool f) { pushed_ = f; }
|
||||||
|
|
||||||
void response_impl::push_promise_sent(bool f) { push_promise_sent_ = f; }
|
void response_impl::push_promise_sent() {
|
||||||
|
if (push_promise_sent_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
push_promise_sent_ = true;
|
||||||
|
if (state_ == response_state::INITIAL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start_response();
|
||||||
|
}
|
||||||
|
|
||||||
const header_map &response_impl::header() const { return header_; }
|
const header_map &response_impl::header() const { return header_; }
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,14 @@ namespace server {
|
||||||
|
|
||||||
class stream;
|
class stream;
|
||||||
|
|
||||||
|
enum class response_state {
|
||||||
|
INITIAL,
|
||||||
|
// response_impl::write_head() was called
|
||||||
|
HEADER_DONE,
|
||||||
|
// response_impl::end() was called
|
||||||
|
BODY_STARTED,
|
||||||
|
};
|
||||||
|
|
||||||
class response_impl {
|
class response_impl {
|
||||||
public:
|
public:
|
||||||
response_impl();
|
response_impl();
|
||||||
|
@ -55,9 +63,8 @@ public:
|
||||||
|
|
||||||
unsigned int status_code() const;
|
unsigned int status_code() const;
|
||||||
const header_map &header() const;
|
const header_map &header() const;
|
||||||
bool started() const;
|
|
||||||
void pushed(bool f);
|
void pushed(bool f);
|
||||||
void push_promise_sent(bool f);
|
void push_promise_sent();
|
||||||
void stream(class stream *s);
|
void stream(class stream *s);
|
||||||
read_cb::result_type call_read(uint8_t *data, std::size_t len,
|
read_cb::result_type call_read(uint8_t *data, std::size_t len,
|
||||||
uint32_t *data_flags);
|
uint32_t *data_flags);
|
||||||
|
@ -69,8 +76,7 @@ private:
|
||||||
read_cb read_cb_;
|
read_cb read_cb_;
|
||||||
close_cb close_cb_;
|
close_cb close_cb_;
|
||||||
unsigned int status_code_;
|
unsigned int status_code_;
|
||||||
// true if response started (end() is called)
|
response_state state_;
|
||||||
bool started_;
|
|
||||||
// true if this is pushed stream's response
|
// true if this is pushed stream's response
|
||||||
bool pushed_;
|
bool pushed_;
|
||||||
// true if PUSH_PROMISE is sent if this is response of a pushed
|
// true if PUSH_PROMISE is sent if this is response of a pushed
|
||||||
|
|
|
@ -97,9 +97,6 @@ public:
|
||||||
// Returns status code.
|
// Returns status code.
|
||||||
unsigned int status_code() const;
|
unsigned int status_code() const;
|
||||||
|
|
||||||
// Returns true if response has been started.
|
|
||||||
bool started() const;
|
|
||||||
|
|
||||||
// Returns boost::asio::io_service this response is running on.
|
// Returns boost::asio::io_service this response is running on.
|
||||||
boost::asio::io_service &io_service() const;
|
boost::asio::io_service &io_service() const;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue