mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-13 06:04:42 +02:00
http: throttle per-connection reads while a request is in flight
A client streaming pipelined requests into a busy connection (or any connection whose replies are slower than the sender) could grow server memory without limit, up to remote OOM. Stop selecting RecvEvent for clients whose request is being processed; pipelined data then backs up in the kernel socket buffer, applying TCP backpressure to the sender. One request per connection is in flight at a time. Functional test streams pipelined submitblock requests into a connection blocked on waitforblockheight. Unpatched builds continue draining the socket buffer indefinitely, patched builds will stall.
This commit is contained in:
@@ -502,6 +502,7 @@ public:
|
||||
const CService& GetPeer() const { return m_addr; }
|
||||
std::shared_ptr<Sock> GetSock() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex) { return WITH_LOCK(m_sock_mutex, return m_sock;); }
|
||||
bool ReadyToSend() const EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex) { return WITH_LOCK(m_send_mutex, return m_send_ready;); }
|
||||
bool ReceiveBufferEmpty() const { return m_recv_buffer.empty(); }
|
||||
|
||||
void Send(const HTTPResponse& res, std::span<const std::byte> reply_body, bool keep_alive) EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex, !m_sock_mutex);
|
||||
void Receive() EXCLUSIVE_LOCKS_REQUIRED(!m_sock_mutex);
|
||||
@@ -522,11 +523,15 @@ public:
|
||||
*/
|
||||
bool MaybeSendBytesFromBuffer() EXCLUSIVE_LOCKS_REQUIRED(!m_send_mutex, !m_sock_mutex);
|
||||
|
||||
//! Used for tests.
|
||||
//! @{
|
||||
const std::string& GetRecvBuffer() const { return m_recv_buffer; }
|
||||
/**
|
||||
* Used to determine if an incomplete request is in progress.
|
||||
* @returns nullptr after a complete request is moved to a worker thread,
|
||||
* but before reading any new data from m_recv_buffer.
|
||||
*/
|
||||
const HTTPRequest* GetRequest() const { return m_req.get(); }
|
||||
//! @}
|
||||
|
||||
//! Used for tests.
|
||||
const std::string& GetRecvBuffer() const { return m_recv_buffer; }
|
||||
|
||||
protected:
|
||||
//! Used for tests.
|
||||
@@ -564,6 +569,7 @@ private:
|
||||
|
||||
//! Set to true by the I/O thread when a request is popped off
|
||||
//! and passed to a worker thread, reset to false by the worker thread.
|
||||
//! Only one request per connection is ever in flight.
|
||||
std::atomic_bool m_req_busy{false};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user