From 354bef5b19b2a27aea4cd7db3c2cea2c3446871f Mon Sep 17 00:00:00 2001 From: fantasy-peak <1356346239@qq.com> Date: Sun, 9 Feb 2025 13:09:57 +0800 Subject: [PATCH] Add setting chunk callback to http request --- examples/client_example/main.cc | 23 +++++++++++++++++++++++ lib/inc/drogon/HttpRequest.h | 29 +++++++++++++++++++++++++++++ lib/src/HttpClientImpl.cc | 3 ++- lib/src/HttpRequestImpl.h | 13 +++++++++++++ lib/src/HttpResponseParser.cc | 10 +++++++++- lib/src/HttpResponseParser.h | 7 ++++++- 6 files changed, 82 insertions(+), 3 deletions(-) diff --git a/examples/client_example/main.cc b/examples/client_example/main.cc index d783f54e0c..5ee7211c02 100644 --- a/examples/client_example/main.cc +++ b/examples/client_example/main.cc @@ -14,6 +14,7 @@ int nth_resp = 0; int main() { +#if 1 trantor::Logger::setLogLevel(trantor::Logger::kTrace); { auto client = HttpClient::newHttpClient("http://www.baidu.com"); @@ -75,6 +76,28 @@ int main() std::cout << "requestsBufferSize:" << client->requestsBufferSize() << std::endl; } +#else + { + auto client = HttpClient::newHttpClient("http://127.0.0.1:8848/stream"); + auto req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/stream"); + req->setChunkCallback([](ResponseChunk ch) { + std::cout << "recv chunk:" << ch.data() << std::endl; + }); + client->sendRequest( + req, [](ReqResult result, const HttpResponsePtr &response) { + if (result != ReqResult::Ok) + { + std::cout + << "error while sending request to server! result: " + << result << std::endl; + return; + } + std::cout << "recv chunk done" << std::endl; + }); + } +#endif app().run(); } diff --git a/lib/inc/drogon/HttpRequest.h b/lib/inc/drogon/HttpRequest.h index 24d8c7579d..97f9359219 100644 --- a/lib/inc/drogon/HttpRequest.h +++ b/lib/inc/drogon/HttpRequest.h @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include #include @@ -37,6 +39,27 @@ namespace drogon class HttpRequest; using HttpRequestPtr = std::shared_ptr; +class DROGON_EXPORT ResponseChunk +{ + public: + ResponseChunk() = default; + + ResponseChunk(const char *s, std::size_t count) + { + data_.append(s, count); + } + + ~ResponseChunk() = default; + + const auto &data() const + { + return data_; + } + + private: + std::string data_; +}; + /** * @brief This template is used to convert a request object to a custom * type object. Users must specialize the template for a particular type. @@ -510,6 +533,12 @@ class DROGON_EXPORT HttpRequest virtual const std::weak_ptr &getConnectionPtr() const noexcept = 0; + virtual void setChunkCallback( + std::function) noexcept = 0; + + virtual const std::function &getChunkCallback() + const noexcept = 0; + virtual ~HttpRequest() { } diff --git a/lib/src/HttpClientImpl.cc b/lib/src/HttpClientImpl.cc index b8cf7596c9..5de6dd498d 100644 --- a/lib/src/HttpClientImpl.cc +++ b/lib/src/HttpClientImpl.cc @@ -618,7 +618,8 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, { responseParser->setForHeadMethod(); } - if (!responseParser->parseResponse(msg)) + if (!responseParser->parseResponse(msg, + firstReq.first->getChunkCallback())) { onError(ReqResult::BadResponse); bytesReceived_ += (msgSize - msg->readableBytes()); diff --git a/lib/src/HttpRequestImpl.h b/lib/src/HttpRequestImpl.h index 966ef92b78..30044bf0ed 100644 --- a/lib/src/HttpRequestImpl.h +++ b/lib/src/HttpRequestImpl.h @@ -579,6 +579,18 @@ class HttpRequestImpl : public HttpRequest return connPtr_; } + void setChunkCallback( + std::function cb) noexcept override + { + chunkCb_ = std::move(cb); + } + + const std::function &getChunkCallback() + const noexcept override + { + return chunkCb_; + } + bool isOnSecureConnection() const noexcept override { return isOnSecureConnection_; @@ -731,6 +743,7 @@ class HttpRequestImpl : public HttpRequest std::exception_ptr streamExceptionPtr_; bool startProcessing_{false}; std::weak_ptr connPtr_; + std::function chunkCb_; protected: std::string content_; diff --git a/lib/src/HttpResponseParser.cc b/lib/src/HttpResponseParser.cc index 4e0d3ad7c1..edbc2ae6f2 100644 --- a/lib/src/HttpResponseParser.cc +++ b/lib/src/HttpResponseParser.cc @@ -17,6 +17,7 @@ #include #include #include +#include using namespace trantor; using namespace drogon; @@ -84,7 +85,9 @@ bool HttpResponseParser::parseResponseOnClose() } // return false if any error -bool HttpResponseParser::parseResponse(MsgBuffer *buf) +bool HttpResponseParser::parseResponse( + MsgBuffer *buf, + const std::function &chunkCallback) { bool ok = true; bool hasMore = true; @@ -277,6 +280,11 @@ bool HttpResponseParser::parseResponse(MsgBuffer *buf) responsePtr_->bodyPtr_ = std::make_shared(); } + if (chunkCallback) + { + chunkCallback( + ResponseChunk(buf->peek(), currentChunkLength_)); + } responsePtr_->bodyPtr_->append(buf->peek(), currentChunkLength_); buf->retrieve(currentChunkLength_ + 2); diff --git a/lib/src/HttpResponseParser.h b/lib/src/HttpResponseParser.h index 6f31c1838f..59050a97b9 100644 --- a/lib/src/HttpResponseParser.h +++ b/lib/src/HttpResponseParser.h @@ -15,9 +15,11 @@ #pragma once #include "impl_forwards.h" +#include #include #include #include +#include #include #include @@ -43,7 +45,10 @@ class HttpResponseParser : public trantor::NonCopyable // default copy-ctor, dtor and assignment are fine // return false if any error - bool parseResponse(trantor::MsgBuffer *buf); + bool parseResponse( + trantor::MsgBuffer *buf, + const std::function &chunkCallback = nullptr); + bool parseResponseOnClose(); bool gotAll() const