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

View File

@ -32,8 +32,7 @@ namespace nghttp2 {
namespace asio_http2 {
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);
}

View File

@ -54,32 +54,32 @@ const std::string &request::host() const { return impl_->host(); }
const std::string &request::path() const { return impl_->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));
}
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) { return impl_->on_end(std::move(cb)); }
void request::on_end(void_cb cb) const { return impl_->on_end(std::move(cb)); }
request_impl &request::impl() { return *impl_; }
response::response() : impl_(make_unique<response_impl>()) {}
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));
}
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(); }
@ -87,7 +87,7 @@ bool response::started() const { return impl_->started(); }
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_; }
@ -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,
std::vector<header> headers) {
if (closed()) {
return false;
}
auto handler = handler_.lock();
auto stream = stream_.lock();
auto rv = handler->push_promise(*stream, std::move(method), std::move(path),
auto handler = stream_->handler();
auto rv = handler->push_promise(*stream_, std::move(method), std::move(path),
std::move(headers));
return rv == 0;
}
@ -136,21 +131,11 @@ bool request_impl::pushed() const { return pushed_; }
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_end(void_cb cb) { on_end_cb_ = std::move(cb); }
void request_impl::handler(std::weak_ptr<http2_handler> h) {
handler_ = std::move(h);
}
void request_impl::stream(std::weak_ptr<http2_stream> s) {
stream_ = std::move(s);
}
void request_impl::stream(http2_stream *s) { stream_ = s; }
void request_impl::call_on_data(const uint8_t *data, std::size_t len) {
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_; }
@ -183,18 +169,17 @@ void response_impl::end(std::string data) {
}
void response_impl::end(read_cb cb) {
if (started_ || closed()) {
if (started_) {
return;
}
read_cb_ = std::move(cb);
started_ = true;
auto handler = handler_.lock();
auto stream = stream_.lock();
auto handler = stream_->handler();
if (handler->start_response(*stream) != 0) {
handler->stream_error(stream->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
if (handler->start_response(*stream_) != 0) {
handler->stream_error(stream_->get_stream_id(), NGHTTP2_INTERNAL_ERROR);
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() {
if (closed()) {
return;
}
auto handler = handler_.lock();
auto stream = stream_.lock();
handler->resume(*stream);
auto handler = stream_->handler();
handler->resume(*stream_);
if (!handler->inside_callback()) {
handler->initiate_write();
@ -225,13 +201,7 @@ bool response_impl::started() const { return started_; }
const std::vector<header> &response_impl::headers() const { return headers_; }
void response_impl::handler(std::weak_ptr<http2_handler> h) {
handler_ = std::move(h);
}
void response_impl::stream(std::weak_ptr<http2_stream> s) {
stream_ = std::move(s);
}
void response_impl::stream(http2_stream *s) { stream_ = s; }
std::pair<ssize_t, bool> response_impl::call_read(uint8_t *data,
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);
}
http2_stream::http2_stream(int32_t stream_id)
: request_(std::make_shared<request>()),
response_(std::make_shared<response>()), stream_id_(stream_id) {}
http2_stream::http2_stream(http2_handler *h, int32_t stream_id)
: handler_(h), stream_id_(stream_id) {
request_.impl().stream(this);
response_.impl().stream(this);
}
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() {
return response_;
}
response &http2_stream::response() { return response_; }
http2_handler *http2_stream::handler() const { return handler_; }
namespace {
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;
}
auto &req = stream->get_request()->impl();
auto &req = stream->request().impl();
switch (nghttp2::http2::lookup_token(name, namelen)) {
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) {
stream->get_request()->impl().call_on_end();
stream->request().impl().call_on_end();
}
break;
@ -345,7 +317,7 @@ int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
break;
}
auto &req = stream->get_request()->impl();
auto &req = stream->request().impl();
if (req.host().empty()) {
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);
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
stream->get_request()->impl().call_on_end();
stream->request().impl().call_on_end();
}
break;
@ -376,7 +348,7 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
return 0;
}
stream->get_request()->impl().call_on_data(data, len);
stream->request().impl().call_on_data(data, len);
return 0;
}
@ -485,36 +457,28 @@ int http2_handler::start() {
return 0;
}
std::shared_ptr<http2_stream> http2_handler::create_stream(int32_t stream_id) {
auto stream = std::make_shared<http2_stream>(stream_id);
streams_.emplace(stream_id, stream);
auto self = shared_from_this();
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;
http2_stream *http2_handler::create_stream(int32_t stream_id) {
auto p =
streams_.emplace(stream_id, make_unique<http2_stream>(this, stream_id));
assert(p.second);
return (*p.first).second.get();
}
void http2_handler::close_stream(int32_t 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);
if (i == std::end(streams_)) {
return nullptr;
}
return (*i).second;
return (*i).second.get();
}
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 {
@ -525,7 +489,7 @@ bool http2_handler::should_stop() const {
int http2_handler::start_response(http2_stream &stream) {
int rv;
auto &res = stream.get_response()->impl();
auto &res = stream.response().impl();
auto &headers = res.headers();
auto nva = std::vector<nghttp2_nv>();
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,
void *user_data) -> ssize_t {
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) {
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) {
int rv;
auto &req = stream.get_request()->impl();
auto &req = stream.request().impl();
auto nva = std::vector<nghttp2_nv>();
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_req = promised_stream->get_request()->impl();
auto &promised_req = promised_stream->request().impl();
promised_req.pushed(true);
promised_req.method(std::move(method));
promised_req.scheme(req.scheme());

View File

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

View File

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