From 1556d21599a250297d5f20e5249c970340ab08bc Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Sat, 22 Jun 2024 11:46:10 +0300 Subject: rest: don't copy data when sending binary response Also, change `HTTPRequest::WriteReply` to accept `std::span`. --- src/httpserver.cpp | 5 +++-- src/httpserver.h | 9 +++++++-- src/rest.cpp | 20 +++++++------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index b1d4dc9234..b6c6db8b35 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -634,7 +635,7 @@ void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value) * Replies must be sent in the main loop in the main http thread, * this cannot be done from worker threads. */ -void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) +void HTTPRequest::WriteReply(int nStatus, std::span reply) { assert(!replySent && req); if (m_interrupt) { @@ -643,7 +644,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) // Send event to main http thread to send reply message struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); - evbuffer_add(evb, strReply.data(), strReply.size()); + evbuffer_add(evb, reply.data(), reply.size()); auto req_copy = req; HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); diff --git a/src/httpserver.h b/src/httpserver.h index 9a49877f09..991081bab8 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -7,6 +7,7 @@ #include #include +#include #include namespace util { @@ -123,12 +124,16 @@ public: /** * Write HTTP reply. * nStatus is the HTTP status code to send. - * strReply is the body of the reply. Keep it empty to send a standard message. + * reply is the body of the reply. Keep it empty to send a standard message. * * @note Can be called only once. As this will give the request back to the * main thread, do not call any other HTTPRequest methods after calling this. */ - void WriteReply(int nStatus, const std::string& strReply = ""); + void WriteReply(int nStatus, std::string_view reply = "") + { + WriteReply(nStatus, std::as_bytes(std::span{reply.data(), reply.size()})); + } + void WriteReply(int nStatus, std::span reply); }; /** Get the query parameter value from request uri for a specified key, or std::nullopt if the key diff --git a/src/rest.cpp b/src/rest.cpp index d43018f5af..4abbc4d2ca 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -248,9 +248,8 @@ static bool rest_headers(const std::any& context, ssHeader << pindex->GetBlockHeader(); } - std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryHeader); + req->WriteReply(HTTP_OK, ssHeader); return true; } @@ -321,9 +320,8 @@ static bool rest_block(const std::any& context, switch (rf) { case RESTResponseFormat::BINARY: { - const std::string binaryBlock{block_data.begin(), block_data.end()}; req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryBlock); + req->WriteReply(HTTP_OK, std::as_bytes(std::span{block_data})); return true; } @@ -451,9 +449,8 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const ssHeader << header; } - std::string binaryHeader = ssHeader.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryHeader); + req->WriteReply(HTTP_OK, ssHeader); return true; } case RESTResponseFormat::HEX: { @@ -548,9 +545,8 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s DataStream ssResp{}; ssResp << filter; - std::string binaryResp = ssResp.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryResp); + req->WriteReply(HTTP_OK, ssResp); return true; } case RESTResponseFormat::HEX: { @@ -729,9 +725,8 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string DataStream ssTx; ssTx << TX_WITH_WITNESS(tx); - std::string binaryTx = ssTx.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, binaryTx); + req->WriteReply(HTTP_OK, ssTx); return true; } @@ -900,10 +895,9 @@ static bool rest_getutxos(const std::any& context, HTTPRequest* req, const std:: // use exact same output as mentioned in Bip64 DataStream ssGetUTXOResponse{}; ssGetUTXOResponse << active_height << active_hash << bitmap << outs; - std::string ssGetUTXOResponseString = ssGetUTXOResponse.str(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, ssGetUTXOResponseString); + req->WriteReply(HTTP_OK, ssGetUTXOResponse); return true; } @@ -981,7 +975,7 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req, DataStream ss_blockhash{}; ss_blockhash << pblockindex->GetBlockHash(); req->WriteHeader("Content-Type", "application/octet-stream"); - req->WriteReply(HTTP_OK, ss_blockhash.str()); + req->WriteReply(HTTP_OK, ss_blockhash); return true; } case RESTResponseFormat::HEX: { -- cgit v1.2.3