Merge bitcoin/bitcoin#30321: rest: don't copy data when sending binary response

1556d21599a250297d5f20e5249c970340ab08bc rest: don't copy data when sending binary response (Roman Zeyde)

Pull request description:

  Also, change `HTTPRequest::WriteReply` to accept `std::span`.

ACKs for top commit:
  laanwj:
    re-ACK 1556d21599a250297d5f20e5249c970340ab08bc
  stickies-v:
    ACK 1556d21599a250297d5f20e5249c970340ab08bc

Tree-SHA512: 3e563d8072f0e1b90b00f85adb140d4e5fef169b6882a837b08d1e8391b64c21bea3c4256c4e2a624ac1fb3d374f12a1cc16dc59b2155ec857728162d1daaceb
This commit is contained in:
merge-script 2024-06-26 11:42:06 +01:00
commit b4b9854394
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1
3 changed files with 17 additions and 17 deletions

View File

@ -26,6 +26,7 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <span>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@ -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, * Replies must be sent in the main loop in the main http thread,
* this cannot be done from worker threads. * this cannot be done from worker threads.
*/ */
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) void HTTPRequest::WriteReply(int nStatus, std::span<const std::byte> reply)
{ {
assert(!replySent && req); assert(!replySent && req);
if (m_interrupt) { 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 // Send event to main http thread to send reply message
struct evbuffer* evb = evhttp_request_get_output_buffer(req); struct evbuffer* evb = evhttp_request_get_output_buffer(req);
assert(evb); assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size()); evbuffer_add(evb, reply.data(), reply.size());
auto req_copy = req; auto req_copy = req;
HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);

View File

@ -7,6 +7,7 @@
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <span>
#include <string> #include <string>
namespace util { namespace util {
@ -123,12 +124,16 @@ public:
/** /**
* Write HTTP reply. * Write HTTP reply.
* nStatus is the HTTP status code to send. * 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 * @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. * 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<const std::byte> reply);
}; };
/** Get the query parameter value from request uri for a specified key, or std::nullopt if the key /** Get the query parameter value from request uri for a specified key, or std::nullopt if the key

View File

@ -248,9 +248,8 @@ static bool rest_headers(const std::any& context,
ssHeader << pindex->GetBlockHeader(); ssHeader << pindex->GetBlockHeader();
} }
std::string binaryHeader = ssHeader.str();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, binaryHeader); req->WriteReply(HTTP_OK, ssHeader);
return true; return true;
} }
@ -321,9 +320,8 @@ static bool rest_block(const std::any& context,
switch (rf) { switch (rf) {
case RESTResponseFormat::BINARY: { case RESTResponseFormat::BINARY: {
const std::string binaryBlock{block_data.begin(), block_data.end()};
req->WriteHeader("Content-Type", "application/octet-stream"); 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; return true;
} }
@ -451,9 +449,8 @@ static bool rest_filter_header(const std::any& context, HTTPRequest* req, const
ssHeader << header; ssHeader << header;
} }
std::string binaryHeader = ssHeader.str();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, binaryHeader); req->WriteReply(HTTP_OK, ssHeader);
return true; return true;
} }
case RESTResponseFormat::HEX: { case RESTResponseFormat::HEX: {
@ -548,9 +545,8 @@ static bool rest_block_filter(const std::any& context, HTTPRequest* req, const s
DataStream ssResp{}; DataStream ssResp{};
ssResp << filter; ssResp << filter;
std::string binaryResp = ssResp.str();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, binaryResp); req->WriteReply(HTTP_OK, ssResp);
return true; return true;
} }
case RESTResponseFormat::HEX: { case RESTResponseFormat::HEX: {
@ -729,9 +725,8 @@ static bool rest_tx(const std::any& context, HTTPRequest* req, const std::string
DataStream ssTx; DataStream ssTx;
ssTx << TX_WITH_WITNESS(tx); ssTx << TX_WITH_WITNESS(tx);
std::string binaryTx = ssTx.str();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, binaryTx); req->WriteReply(HTTP_OK, ssTx);
return true; 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 // use exact same output as mentioned in Bip64
DataStream ssGetUTXOResponse{}; DataStream ssGetUTXOResponse{};
ssGetUTXOResponse << active_height << active_hash << bitmap << outs; ssGetUTXOResponse << active_height << active_hash << bitmap << outs;
std::string ssGetUTXOResponseString = ssGetUTXOResponse.str();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, ssGetUTXOResponseString); req->WriteReply(HTTP_OK, ssGetUTXOResponse);
return true; return true;
} }
@ -981,7 +975,7 @@ static bool rest_blockhash_by_height(const std::any& context, HTTPRequest* req,
DataStream ss_blockhash{}; DataStream ss_blockhash{};
ss_blockhash << pblockindex->GetBlockHash(); ss_blockhash << pblockindex->GetBlockHash();
req->WriteHeader("Content-Type", "application/octet-stream"); req->WriteHeader("Content-Type", "application/octet-stream");
req->WriteReply(HTTP_OK, ss_blockhash.str()); req->WriteReply(HTTP_OK, ss_blockhash);
return true; return true;
} }
case RESTResponseFormat::HEX: { case RESTResponseFormat::HEX: {