asio: Avoid shared_ptr for request and response

This commit is contained in:
Tatsuhiro Tsujikawa 2015-03-04 02:19:38 +09:00
parent 9671eaa850
commit b0c1986a46
6 changed files with 84 additions and 128 deletions

View File

@ -62,10 +62,9 @@ int main(int argc, char *argv[]) {
server.tls(argv[3], argv[4]); server.tls(argv[3], argv[4]);
} }
server.listen("*", port, [](const std::shared_ptr<request> &req, server.listen("*", port, [](const request &req, const response &res) {
const std::shared_ptr<response> &res) { res.write_head(200, {header{"foo", "bar"}});
res->write_head(200, {header{"foo", "bar"}}); res.end("hello, world");
res->end("hello, world");
}); });
} catch (std::exception &e) { } catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n"; std::cerr << "exception: " << e.what() << "\n";

View File

@ -66,12 +66,12 @@ int main(int argc, char *argv[]) {
server.tls(argv[4], argv[5]); server.tls(argv[4], argv[5]);
} }
server.listen("*", port, [&docroot](const std::shared_ptr<request> &req, server.listen("*", port,
const std::shared_ptr<response> &res) { [&docroot](const request &req, const response &res) {
auto path = percent_decode(req->path()); auto path = percent_decode(req.path());
if (!check_path(path)) { if (!check_path(path)) {
res->write_head(404); res.write_head(404);
res->end(); res.end();
return; return;
} }
@ -82,8 +82,8 @@ int main(int argc, char *argv[]) {
path = docroot + path; path = docroot + path;
auto fd = open(path.c_str(), O_RDONLY); auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) { if (fd == -1) {
res->write_head(404); res.write_head(404);
res->end(); res.end();
return; return;
} }
@ -95,8 +95,8 @@ int main(int argc, char *argv[]) {
header{"content-length", std::to_string(stbuf.st_size)}); header{"content-length", std::to_string(stbuf.st_size)});
headers.push_back(header{"last-modified", http_date(stbuf.st_mtime)}); headers.push_back(header{"last-modified", http_date(stbuf.st_mtime)});
} }
res->write_head(200, std::move(headers)); res.write_head(200, std::move(headers));
res->end(file_reader_from_fd(fd)); res.end(file_reader_from_fd(fd));
}); });
} catch (std::exception &e) { } catch (std::exception &e) {
std::cerr << "exception: " << e.what() << "\n"; std::cerr << "exception: " << e.what() << "\n";

View File

@ -32,8 +32,7 @@ namespace nghttp2 {
namespace asio_http2 { namespace asio_http2 {
namespace client { namespace client {
stream::stream(session_impl *sess) : sess_(sess), stream_id_(0) stream::stream(session_impl *sess) : sess_(sess), stream_id_(0) {
{
request_.impl().stream(this); request_.impl().stream(this);
} }

View File

@ -54,32 +54,32 @@ const std::string &request::host() const { return impl_->host(); }
const std::string &request::path() const { return impl_->path(); } const std::string &request::path() const { return impl_->path(); }
bool request::push(std::string method, std::string path, bool request::push(std::string method, std::string path,
std::vector<header> headers) { std::vector<header> headers) const {
return impl_->push(std::move(method), std::move(path), std::move(headers)); return impl_->push(std::move(method), std::move(path), std::move(headers));
} }
bool request::pushed() const { return impl_->pushed(); } bool request::pushed() const { return impl_->pushed(); }
bool request::closed() const { return impl_->closed(); } void request::on_data(data_cb cb) const {
return impl_->on_data(std::move(cb));
}
void request::on_data(data_cb cb) { return impl_->on_data(std::move(cb)); } void request::on_end(void_cb cb) const { return impl_->on_end(std::move(cb)); }
void request::on_end(void_cb cb) { return impl_->on_end(std::move(cb)); }
request_impl &request::impl() { return *impl_; } request_impl &request::impl() { return *impl_; }
response::response() : impl_(make_unique<response_impl>()) {} response::response() : impl_(make_unique<response_impl>()) {}
void response::write_head(unsigned int status_code, void response::write_head(unsigned int status_code,
std::vector<header> headers) { std::vector<header> headers) const {
impl_->write_head(status_code, std::move(headers)); impl_->write_head(status_code, std::move(headers));
} }
void response::end(std::string data) { impl_->end(std::move(data)); } void response::end(std::string data) const { impl_->end(std::move(data)); }
void response::end(read_cb cb) { impl_->end(std::move(cb)); } void response::end(read_cb cb) const { impl_->end(std::move(cb)); }
void response::resume() { impl_->resume(); } void response::resume() const { impl_->resume(); }
unsigned int response::status_code() const { return impl_->status_code(); } unsigned int response::status_code() const { return impl_->status_code(); }
@ -87,7 +87,7 @@ bool response::started() const { return impl_->started(); }
response_impl &response::impl() { return *impl_; } response_impl &response::impl() { return *impl_; }
request_impl::request_impl() : pushed_(false) {} request_impl::request_impl() : stream_(nullptr), pushed_(false) {}
const std::vector<header> &request_impl::headers() const { return headers_; } const std::vector<header> &request_impl::headers() const { return headers_; }
@ -121,13 +121,8 @@ void request_impl::path(std::string arg) { path_ = std::move(arg); }
bool request_impl::push(std::string method, std::string path, bool request_impl::push(std::string method, std::string path,
std::vector<header> headers) { std::vector<header> headers) {
if (closed()) { auto handler = stream_->handler();
return false; auto rv = handler->push_promise(*stream_, std::move(method), std::move(path),
}
auto handler = handler_.lock();
auto stream = stream_.lock();
auto rv = handler->push_promise(*stream, std::move(method), std::move(path),
std::move(headers)); std::move(headers));
return rv == 0; return rv == 0;
} }
@ -136,21 +131,11 @@ bool request_impl::pushed() const { return pushed_; }
void request_impl::pushed(bool f) { pushed_ = f; } void request_impl::pushed(bool f) { pushed_ = f; }
bool request_impl::closed() const {
return handler_.expired() || stream_.expired();
}
void request_impl::on_data(data_cb cb) { on_data_cb_ = std::move(cb); } void request_impl::on_data(data_cb cb) { on_data_cb_ = std::move(cb); }
void request_impl::on_end(void_cb cb) { on_end_cb_ = std::move(cb); } void request_impl::on_end(void_cb cb) { on_end_cb_ = std::move(cb); }
void request_impl::handler(std::weak_ptr<http2_handler> h) { void request_impl::stream(http2_stream *s) { stream_ = s; }
handler_ = std::move(h);
}
void request_impl::stream(std::weak_ptr<http2_stream> s) {
stream_ = std::move(s);
}
void request_impl::call_on_data(const uint8_t *data, std::size_t len) { void request_impl::call_on_data(const uint8_t *data, std::size_t len) {
if (on_data_cb_) { if (on_data_cb_) {
@ -164,7 +149,8 @@ void request_impl::call_on_end() {
} }
} }
response_impl::response_impl() : status_code_(200), started_(false) {} response_impl::response_impl()
: stream_(nullptr), status_code_(200), started_(false) {}
unsigned int response_impl::status_code() const { return status_code_; } unsigned int response_impl::status_code() const { return status_code_; }
@ -183,18 +169,17 @@ void response_impl::end(std::string data) {
} }
void response_impl::end(read_cb cb) { void response_impl::end(read_cb cb) {
if (started_ || closed()) { if (started_) {
return; return;
} }
read_cb_ = std::move(cb); read_cb_ = std::move(cb);
started_ = true; started_ = true;
auto handler = handler_.lock(); auto handler = stream_->handler();
auto stream = stream_.lock();
if (handler->start_response(*stream) != 0) { if (handler->start_response(*stream_) != 0) {
handler->stream_error(stream->get_stream_id(), NGHTTP2_INTERNAL_ERROR); handler->stream_error(stream_->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
return; return;
} }
@ -203,18 +188,9 @@ void response_impl::end(read_cb cb) {
} }
} }
bool response_impl::closed() const {
return handler_.expired() || stream_.expired();
}
void response_impl::resume() { void response_impl::resume() {
if (closed()) { auto handler = stream_->handler();
return; handler->resume(*stream_);
}
auto handler = handler_.lock();
auto stream = stream_.lock();
handler->resume(*stream);
if (!handler->inside_callback()) { if (!handler->inside_callback()) {
handler->initiate_write(); handler->initiate_write();
@ -225,13 +201,7 @@ bool response_impl::started() const { return started_; }
const std::vector<header> &response_impl::headers() const { return headers_; } const std::vector<header> &response_impl::headers() const { return headers_; }
void response_impl::handler(std::weak_ptr<http2_handler> h) { void response_impl::stream(http2_stream *s) { stream_ = s; }
handler_ = std::move(h);
}
void response_impl::stream(std::weak_ptr<http2_stream> s) {
stream_ = std::move(s);
}
std::pair<ssize_t, bool> response_impl::call_read(uint8_t *data, std::pair<ssize_t, bool> response_impl::call_read(uint8_t *data,
std::size_t len) { std::size_t len) {
@ -242,17 +212,19 @@ std::pair<ssize_t, bool> response_impl::call_read(uint8_t *data,
return std::make_pair(0, true); return std::make_pair(0, true);
} }
http2_stream::http2_stream(int32_t stream_id) http2_stream::http2_stream(http2_handler *h, int32_t stream_id)
: request_(std::make_shared<request>()), : handler_(h), stream_id_(stream_id) {
response_(std::make_shared<response>()), stream_id_(stream_id) {} request_.impl().stream(this);
response_.impl().stream(this);
}
int32_t http2_stream::get_stream_id() const { return stream_id_; } int32_t http2_stream::get_stream_id() const { return stream_id_; }
const std::shared_ptr<request> &http2_stream::get_request() { return request_; } request &http2_stream::request() { return request_; }
const std::shared_ptr<response> &http2_stream::get_response() { response &http2_stream::response() { return response_; }
return response_;
} http2_handler *http2_stream::handler() const { return handler_; }
namespace { namespace {
int stream_error(nghttp2_session *session, int32_t stream_id, int stream_error(nghttp2_session *session, int32_t stream_id,
@ -296,7 +268,7 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
return 0; return 0;
} }
auto &req = stream->get_request()->impl(); auto &req = stream->request().impl();
switch (nghttp2::http2::lookup_token(name, namelen)) { switch (nghttp2::http2::lookup_token(name, namelen)) {
case nghttp2::http2::HD__METHOD: case nghttp2::http2::HD__METHOD:
@ -336,7 +308,7 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
} }
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream->get_request()->impl().call_on_end(); stream->request().impl().call_on_end();
} }
break; break;
@ -345,7 +317,7 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
break; break;
} }
auto &req = stream->get_request()->impl(); auto &req = stream->request().impl();
if (req.host().empty()) { if (req.host().empty()) {
req.host(req.authority()); req.host(req.authority());
@ -354,7 +326,7 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
handler->call_on_request(*stream); handler->call_on_request(*stream);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream->get_request()->impl().call_on_end(); stream->request().impl().call_on_end();
} }
break; break;
@ -376,7 +348,7 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
return 0; return 0;
} }
stream->get_request()->impl().call_on_data(data, len); stream->request().impl().call_on_data(data, len);
return 0; return 0;
} }
@ -485,36 +457,28 @@ int http2_handler::start() {
return 0; return 0;
} }
std::shared_ptr<http2_stream> http2_handler::create_stream(int32_t stream_id) { http2_stream *http2_handler::create_stream(int32_t stream_id) {
auto stream = std::make_shared<http2_stream>(stream_id); auto p =
streams_.emplace(stream_id, stream); streams_.emplace(stream_id, make_unique<http2_stream>(this, stream_id));
assert(p.second);
auto self = shared_from_this(); return (*p.first).second.get();
auto &req = stream->get_request()->impl();
auto &res = stream->get_response()->impl();
req.handler(self);
req.stream(stream);
res.handler(self);
res.stream(stream);
return stream;
} }
void http2_handler::close_stream(int32_t stream_id) { void http2_handler::close_stream(int32_t stream_id) {
streams_.erase(stream_id); streams_.erase(stream_id);
} }
std::shared_ptr<http2_stream> http2_handler::find_stream(int32_t stream_id) { http2_stream *http2_handler::find_stream(int32_t stream_id) {
auto i = streams_.find(stream_id); auto i = streams_.find(stream_id);
if (i == std::end(streams_)) { if (i == std::end(streams_)) {
return nullptr; return nullptr;
} }
return (*i).second; return (*i).second.get();
} }
void http2_handler::call_on_request(http2_stream &stream) { void http2_handler::call_on_request(http2_stream &stream) {
request_cb_(stream.get_request(), stream.get_response()); request_cb_(stream.request(), stream.response());
} }
bool http2_handler::should_stop() const { bool http2_handler::should_stop() const {
@ -525,7 +489,7 @@ bool http2_handler::should_stop() const {
int http2_handler::start_response(http2_stream &stream) { int http2_handler::start_response(http2_stream &stream) {
int rv; int rv;
auto &res = stream.get_response()->impl(); auto &res = stream.response().impl();
auto &headers = res.headers(); auto &headers = res.headers();
auto nva = std::vector<nghttp2_nv>(); auto nva = std::vector<nghttp2_nv>();
nva.reserve(2 + headers.size()); nva.reserve(2 + headers.size());
@ -544,7 +508,7 @@ int http2_handler::start_response(http2_stream &stream) {
size_t length, uint32_t *data_flags, nghttp2_data_source *source, size_t length, uint32_t *data_flags, nghttp2_data_source *source,
void *user_data) -> ssize_t { void *user_data) -> ssize_t {
auto &stream = *static_cast<http2_stream *>(source->ptr); auto &stream = *static_cast<http2_stream *>(source->ptr);
auto rv = stream.get_response()->impl().call_read(buf, length); auto rv = stream.response().impl().call_read(buf, length);
if (rv.first < 0) { if (rv.first < 0) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
} }
@ -594,7 +558,7 @@ int http2_handler::push_promise(http2_stream &stream, std::string method,
std::string path, std::vector<header> headers) { std::string path, std::vector<header> headers) {
int rv; int rv;
auto &req = stream.get_request()->impl(); auto &req = stream.request().impl();
auto nva = std::vector<nghttp2_nv>(); auto nva = std::vector<nghttp2_nv>();
nva.reserve(5 + headers.size()); nva.reserve(5 + headers.size());
@ -621,7 +585,7 @@ int http2_handler::push_promise(http2_stream &stream, std::string method,
} }
auto promised_stream = create_stream(rv); auto promised_stream = create_stream(rv);
auto &promised_req = promised_stream->get_request()->impl(); auto &promised_req = promised_stream->request().impl();
promised_req.pushed(true); promised_req.pushed(true);
promised_req.method(std::move(method)); promised_req.method(std::move(method));
promised_req.scheme(req.scheme()); promised_req.scheme(req.scheme());

View File

@ -60,7 +60,6 @@ public:
std::vector<header> headers = {}); std::vector<header> headers = {});
bool pushed() const; bool pushed() const;
bool closed() const;
void on_data(data_cb cb); void on_data(data_cb cb);
void on_end(void_cb cb); void on_end(void_cb cb);
@ -73,12 +72,12 @@ public:
void host(std::string host); void host(std::string host);
void path(std::string path); void path(std::string path);
void pushed(bool f); void pushed(bool f);
void handler(std::weak_ptr<http2_handler> h); void stream(http2_stream *s);
void stream(std::weak_ptr<http2_stream> s);
void call_on_data(const uint8_t *data, std::size_t len); void call_on_data(const uint8_t *data, std::size_t len);
void call_on_end(); void call_on_end();
private: private:
http2_stream *stream_;
std::vector<header> headers_; std::vector<header> headers_;
std::string method_; std::string method_;
std::string scheme_; std::string scheme_;
@ -87,8 +86,6 @@ private:
std::string path_; std::string path_;
data_cb on_data_cb_; data_cb on_data_cb_;
void_cb on_end_cb_; void_cb on_end_cb_;
std::weak_ptr<http2_handler> handler_;
std::weak_ptr<http2_stream> stream_;
bool pushed_; bool pushed_;
}; };
@ -99,35 +96,35 @@ public:
void end(std::string data = ""); void end(std::string data = "");
void end(read_cb cb); void end(read_cb cb);
void resume(); void resume();
bool closed() const;
unsigned int status_code() const; unsigned int status_code() const;
const std::vector<header> &headers() const; const std::vector<header> &headers() const;
bool started() const; bool started() const;
void handler(std::weak_ptr<http2_handler> h); void stream(http2_stream *s);
void stream(std::weak_ptr<http2_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);
private: private:
http2_stream *stream_;
std::vector<header> headers_; std::vector<header> headers_;
read_cb read_cb_; read_cb read_cb_;
std::weak_ptr<http2_handler> handler_;
std::weak_ptr<http2_stream> stream_;
unsigned int status_code_; unsigned int status_code_;
bool started_; bool started_;
}; };
class http2_stream { class http2_stream {
public: public:
http2_stream(int32_t stream_id); http2_stream(http2_handler *h, int32_t stream_id);
int32_t get_stream_id() const; int32_t get_stream_id() const;
const std::shared_ptr<request> &get_request(); request &request();
const std::shared_ptr<response> &get_response(); response &response();
http2_handler *handler() const;
private: private:
std::shared_ptr<request> request_; http2_handler *handler_;
std::shared_ptr<response> response_; class request request_;
class response response_;
int32_t stream_id_; int32_t stream_id_;
}; };
@ -148,9 +145,9 @@ public:
int start(); int start();
std::shared_ptr<http2_stream> create_stream(int32_t stream_id); http2_stream *create_stream(int32_t stream_id);
void close_stream(int32_t stream_id); void close_stream(int32_t stream_id);
std::shared_ptr<http2_stream> find_stream(int32_t stream_id); http2_stream *find_stream(int32_t stream_id);
void call_on_request(http2_stream &stream); void call_on_request(http2_stream &stream);

View File

@ -133,24 +133,21 @@ public:
const std::string &path() const; const std::string &path() const;
// Sets callback when chunk of request body is received. // Sets callback when chunk of request body is received.
void on_data(data_cb cb); void on_data(data_cb cb) const;
// Sets callback when request was completed. // Sets callback when request was completed.
void on_end(void_cb cb); void on_end(void_cb cb) const;
// Pushes resource denoted by |path| using |method|. The additional // Pushes resource denoted by |path| using |method|. The additional
// headers can be given in |headers|. request_cb will be called for // headers can be given in |headers|. request_cb will be called for
// pushed resource later on. This function returns true if it // pushed resource later on. This function returns true if it
// succeeds, or false. // succeeds, or false.
bool push(std::string method, std::string path, bool push(std::string method, std::string path,
std::vector<header> headers = {}); std::vector<header> headers = {}) const;
// Returns true if this is pushed request. // Returns true if this is pushed request.
bool pushed() const; bool pushed() const;
// Returns true if stream has been closed.
bool closed() const;
// Application must not call this directly. // Application must not call this directly.
request_impl &impl(); request_impl &impl();
@ -165,18 +162,19 @@ public:
// Write response header using |status_code| (e.g., 200) and // Write response header using |status_code| (e.g., 200) and
// additional headers in |headers|. // additional headers in |headers|.
void write_head(unsigned int status_code, std::vector<header> headers = {}); void write_head(unsigned int status_code,
std::vector<header> headers = {}) const;
// Sends |data| as request body. No further call of end() is // Sends |data| as request body. No further call of end() is
// allowed. // allowed.
void end(std::string data = ""); void end(std::string data = "") const;
// Sets callback |cb| as a generator of the response body. No // Sets callback |cb| as a generator of the response body. No
// further call of end() is allowed. // further call of end() is allowed.
void end(read_cb cb); void end(read_cb cb) const;
// Resumes deferred response. // Resumes deferred response.
void resume(); void resume() const;
// Returns status code. // Returns status code.
unsigned int status_code() const; unsigned int status_code() const;
@ -193,8 +191,7 @@ private:
// This is so called request callback. Called every time request is // This is so called request callback. Called every time request is
// received. // received.
typedef std::function<void(const std::shared_ptr<request> &, typedef std::function<void(const request &, const response &)> request_cb;
const std::shared_ptr<response> &)> request_cb;
class http2_impl; class http2_impl;