diff --git a/src/asio_client_request_impl.cc b/src/asio_client_request_impl.cc index ab92333c..10a17e3f 100644 --- a/src/asio_client_request_impl.cc +++ b/src/asio_client_request_impl.cc @@ -61,11 +61,15 @@ void request_impl::call_on_close(uint32_t error_code) { void request_impl::on_read(read_cb cb) { read_cb_ = std::move(cb); } -read_cb::result_type request_impl::call_on_read(uint8_t *buf, std::size_t len) { +read_cb::result_type request_impl::call_on_read(uint8_t *buf, std::size_t len, + uint32_t *data_flags) { if (read_cb_) { - return read_cb_(buf, len); + return read_cb_(buf, len, data_flags); } - return read_cb::result_type{}; + + *data_flags |= NGHTTP2_DATA_FLAG_EOF; + + return 0; } void request_impl::header(header_map h) { header_ = std::move(h); } diff --git a/src/asio_client_request_impl.h b/src/asio_client_request_impl.h index 5fdf09b7..f9e6b67f 100644 --- a/src/asio_client_request_impl.h +++ b/src/asio_client_request_impl.h @@ -55,7 +55,8 @@ public: void call_on_close(uint32_t error_code); void on_read(read_cb cb); - read_cb::result_type call_on_read(uint8_t *buf, std::size_t len); + read_cb::result_type call_on_read(uint8_t *buf, std::size_t len, + uint32_t *data_flags); void header(header_map h); header_map &header(); diff --git a/src/asio_client_session_impl.cc b/src/asio_client_session_impl.cc index 198827ec..edd8557c 100644 --- a/src/asio_client_session_impl.cc +++ b/src/asio_client_session_impl.cc @@ -409,18 +409,7 @@ const request *session_impl::submit(boost::system::error_code &ec, size_t length, uint32_t *data_flags, nghttp2_data_source *source, void *user_data) -> ssize_t { auto strm = static_cast(source->ptr); - auto rv = strm->request().impl().call_on_read(buf, length); - if (rv.first < 0) { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - - if (rv.second) { - *data_flags |= NGHTTP2_DATA_FLAG_EOF; - } else if (rv.first == 0) { - return NGHTTP2_ERR_DEFERRED; - } - - return rv.first; + return strm->request().impl().call_on_read(buf, length, data_flags); }; prdptr = &prd; } diff --git a/src/asio_common.cc b/src/asio_common.cc index 34efefa5..2f7548dd 100644 --- a/src/asio_common.cc +++ b/src/asio_common.cc @@ -49,11 +49,16 @@ boost::system::error_code make_error_code(nghttp2_error ev) { read_cb string_reader(std::string data) { auto strio = std::make_shared>(std::move(data), data.size()); - return [strio](uint8_t *buf, size_t len) { - auto n = std::min(len, strio->second); - std::copy_n(strio->first.c_str(), n, buf); - strio->second -= n; - return std::make_pair(n, strio->second == 0); + return [strio](uint8_t *buf, size_t len, uint32_t *data_flags) { + auto &data = strio->first; + auto &left = strio->second; + auto n = std::min(len, left); + std::copy_n(data.c_str() + data.size() - left, n, buf); + left -= n; + if (left == 0) { + *data_flags |= NGHTTP2_DATA_FLAG_EOF; + } + return n; }; } diff --git a/src/asio_http2_handler.cc b/src/asio_http2_handler.cc index 8ea9c645..3bf7586e 100644 --- a/src/asio_http2_handler.cc +++ b/src/asio_http2_handler.cc @@ -177,13 +177,15 @@ const header_map &response_impl::header() const { return header_; } void response_impl::stream(http2_stream *s) { stream_ = s; } -std::pair response_impl::call_read(uint8_t *data, - std::size_t len) { +read_cb::result_type response_impl::call_read(uint8_t *data, std::size_t len, + uint32_t *data_flags) { if (read_cb_) { - return read_cb_(data, len); + return read_cb_(data, len, data_flags); } - return std::make_pair(0, true); + *data_flags |= NGHTTP2_DATA_FLAG_EOF; + + return 0; } http2_stream::http2_stream(http2_handler *h, int32_t stream_id) @@ -481,18 +483,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(source->ptr); - auto rv = stream.response().impl().call_read(buf, length); - if (rv.first < 0) { - return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; - } - - if (rv.second) { - *data_flags |= NGHTTP2_DATA_FLAG_EOF; - } else if (rv.first == 0) { - return NGHTTP2_ERR_DEFERRED; - } - - return rv.first; + return stream.response().impl().call_read(buf, length, data_flags); }; rv = nghttp2_submit_response(session_, stream.get_stream_id(), nva.data(), diff --git a/src/asio_http2_handler.h b/src/asio_http2_handler.h index 055fbac6..febf0bf3 100644 --- a/src/asio_http2_handler.h +++ b/src/asio_http2_handler.h @@ -91,7 +91,8 @@ public: const header_map &header() const; bool started() const; void stream(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, + uint32_t *data_flags); private: http2_stream *stream_; diff --git a/src/asio_http2_impl.cc b/src/asio_http2_impl.cc index 4d2c5ddf..17236744 100644 --- a/src/asio_http2_impl.cc +++ b/src/asio_http2_impl.cc @@ -139,20 +139,21 @@ read_cb file_reader(const std::string &path) { read_cb file_reader_from_fd(int fd) { auto d = defer_shared(close, fd); - return [fd, d](uint8_t *buf, size_t len) -> read_cb::result_type { - int rv; - while ((rv = read(fd, buf, len)) == -1 && errno == EINTR) + return [fd, d](uint8_t *buf, size_t len, uint32_t *data_flags) + -> read_cb::result_type { + ssize_t n; + while ((n = read(fd, buf, len)) == -1 && errno == EINTR) ; - if (rv == -1) { - return std::make_pair(-1, false); + if (n == -1) { + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } - if (rv == 0) { - return std::make_pair(rv, true); + if (n == 0) { + *data_flags |= NGHTTP2_DATA_FLAG_EOF; } - return std::make_pair(rv, false); + return n; }; } diff --git a/src/includes/nghttp2/asio_http2.h b/src/includes/nghttp2/asio_http2.h index 6934f00b..2382fe75 100644 --- a/src/includes/nghttp2/asio_http2.h +++ b/src/includes/nghttp2/asio_http2.h @@ -76,18 +76,9 @@ typedef std::function void_cb; typedef std::function error_cb; typedef std::function close_cb; -// Callback function to generate response body. The implementation of -// this callback must fill at most |len| bytes data to |buf|. The -// return value is pair of written bytes and bool value indicating -// that this is the end of the body. If the end of the body was -// reached, return true. If there is error and application wants to -// terminate stream, return std::make_pair(-1, false). Returning -// std::make_pair(0, false) tells the library that don't call this -// callback until application calls response::resume(). This is -// useful when there is no data to send at the moment but there will -// be more to come in near future. -typedef std::function(uint8_t *buf, std::size_t len)> - read_cb; +// Callback function to generate response body. TBD +typedef std::function< + ssize_t(uint8_t *buf, std::size_t len, uint32_t *data_flags)> read_cb; // Convenient function to create function to read file denoted by // |path|. This can be passed to response::end().