Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
502client->receive("Host: 127.0.0.1\n"503"Content-Length: 10\n\n");504BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));505BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);507client->receive("I miss you\n");508auto req{HTTPRemoteClient::TryReadRequest(client)};509BOOST_REQUIRE(req);510BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);511}512{513// Read body over multiple data pushes, multiple requests in same push514std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};515BOOST_CHECK(!client->GetRequest());517client->receive("POST / HTTP/1.0\n"518"Host: 127.0.0.1\n"519"Content-Length: 10\n\n"520"I miss");521BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));522// Because of the Content-Length header we know the body is not complete523BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);525// Finish sending first request and include second request in the same buffer526client->receive(" you"527"GET /endpoint HTTP/1.0\n\n");528auto req{HTTPRemoteClient::TryReadRequest(client)};529BOOST_REQUIRE(req);530BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);531BOOST_CHECK_EQUAL(req->GetURI(), "/");532BOOST_CHECK(!client->GetRequest());533BOOST_CHECK_EQUAL(req->ReadBody(), "I miss you");534req->WriteReply(HTTP_OK, ""); // Mark client as no longer busy535// Next request sitting in buffer536BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 24);538// Read second request539req = HTTPRemoteClient::TryReadRequest(client);540BOOST_REQUIRE(req);541BOOST_CHECK(!client->GetRequest());542BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);543BOOST_CHECK_EQUAL(req->GetURI(), "/endpoint");544BOOST_CHECK_EQUAL(req->ReadBody().size(), 0);545// Buffer is cleared546BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 0);547}548{549// A Content-Length body is drained out of the receive buffer as it550// arrives, instead of accumulating there until the request is complete.552std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};553BOOST_CHECK(!client->GetRequest());555client->receive("POST / HTTP/1.0\n"556"Content-Length: 30000\n\n");557HTTPRemoteClient::TryReadRequest(client);558BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);560// Body arrives in 10kB pieces. Each one is copied onto m_body and561// erased from the receive buffer, which never holds more than one piece.562for (int i = 1; i <= 3; ++i) {563client->receive(std::string(10000, 'x'));564BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 10000);565auto req{HTTPRemoteClient::TryReadRequest(client)};566if (i < 3) {567BOOST_CHECK(!req.get());568BOOST_CHECK_EQUAL(client->GetRequest()->ReadBody().size(), 10000 * i);569} else {570BOOST_CHECK(req.get());571BOOST_CHECK_EQUAL(req->ReadBody().size(), 10000 * i);572BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);573BOOST_CHECK(!client->GetRequest());574}575BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 0);576}577}578{579// A body sent in the same push as the next request is split correctly580std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};581BOOST_CHECK(!client->GetRequest());583client->receive("POST / HTTP/1.0\n"584"Content-Length: 4\n\n"585"body"586"GET /next HTTP/1.0\n\n");587auto req{HTTPRemoteClient::TryReadRequest(client)};588BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);589BOOST_CHECK_EQUAL(req->ReadBody(), "body");590// Only the second request is left over591BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 20);592}593{594// Chunked transfer with state595std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};596BOOST_CHECK(!client->GetRequest());598// First chunk is incomplete599client->receive("GET / HTTP/1.0\n"600"Transfer-Encoding: chunked\n"601"\n"602"10\n"603R"({"method)");604BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));605BOOST_REQUIRE(client->GetRequest()->GetChunkSize());606BOOST_CHECK_EQUAL(*client->GetRequest()->GetChunkSize(), 16);607BOOST_CHECK_EQUAL(client->GetRequest()->GetChunkProgress(), 8);608BOOST_CHECK_EQUAL(client->GetRequest()->ReadBody().size(), 8);609BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);611// More data arrives, chunk is completed.612client->receive(R"(":"getbl)""\n");613BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));614// State is reset615BOOST_CHECK(!client->GetRequest()->GetChunkSize());616BOOST_CHECK_EQUAL(client->GetRequest()->GetChunkProgress(), 0);617// New data is added to body but body is still incomplete618BOOST_CHECK_EQUAL(client->GetRequest()->ReadBody().size(), 16);619BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);621// Next chunk arrives without terminal CRLF622client->receive("a\n"623R"(ockcount"})");624BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));625BOOST_CHECK(client->GetRequest()->GetChunkSize());626BOOST_CHECK_EQUAL(*client->GetRequest()->GetChunkSize(), 10);627BOOST_CHECK_EQUAL(client->GetRequest()->GetChunkProgress(), 10);628BOOST_CHECK_EQUAL(client->GetRequest()->ReadBody().size(), 26);629BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);631// Chunk terminal CRLF arrives with final (size 0) chunk632client->receive("\n0\n\n");633auto req{HTTPRemoteClient::TryReadRequest(client)};634// Body size hasn't changed635BOOST_CHECK_EQUAL(req->ReadBody().size(), 26);636// We're done637BOOST_CHECK_EQUAL(req->GetState(), HTTPRequest::State::Complete);638BOOST_CHECK_EQUAL(req->ReadBody(), R"({"method":"getblockcount"})");639}640{641// Invalid headers: error state stops reading642std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};644// Request is in the buffer645client->receive("POST / HTTP/1.0\n"646"Host: 127.0.0.1\n");647BOOST_CHECK(!client->GetRecvBuffer().empty());648BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));649BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsHeaders);650client->receive("Invalid header with no colon\n"651"\n"652"body is not read");653// Reading throws an error, sets state654BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));655BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::Error);657// We read up to the invalid line658BOOST_CHECK_EQUAL(client->GetRequest()->GetHeader("Host"), "127.0.0.1");659// Buffer was cleared, client should just be disconnected now660BOOST_CHECK(client->GetRecvBuffer().empty());662// Even if more data comes in, trying to read again in error state is a no-op663client->receive("Content-Length: 2\n\nok");664BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 21);665BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));666BOOST_CHECK_EQUAL(client->GetRecvBuffer().size(), 21);667}668{669// Headers sent in batches that are below MAX_HEADERS_SIZE but the total is excessive670std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};671BOOST_CHECK(!client->GetRequest());672BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));673BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::Init);675client->receive("POST /huge HTTP/1.0\n");676BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));677BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsHeaders);679for (int i = 0; i < 410; ++i) {680client->receive("key:value\n");681}682BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));683BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsHeaders);685for (int i = 0; i < 409; ++i) {686client->receive("key:value\n");687}688BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));689BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsHeaders);691// We're at 819 x 10-byte headers692// The limit is 8192, three more bytes should throw.693client->receive("k:\n");694BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));695BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::Error);696}697{698// Client sends chunks that are below the limit but the total is excessive699std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};700BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));701BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::Init);703client->receive("POST /huge HTTP/1.0\n");704BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));705BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsHeaders);707client->receive("Transfer-Encoding: chunked\n\n");708BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));709BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);711// Send 16-byte chunk712client->receive("10\nno auto updates!\n");713BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));714BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);716// The next chunk will be of size 32MiB - 16 + 1, below the limit717// on its own but not if it were added to the total cumulative body so far.718// We don't need to actually send or prepare this amount of data.719client->receive("1fffff1\n");720BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));721BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::Error);722}723{724// Ensure chunk trailer is parsed over state lines725std::shared_ptr<DummyClient> client{std::make_shared<DummyClient>()};726BOOST_CHECK(!client->GetRequest());728// Send a 1-byte chunk then send the 0-chunk with a trailer but no terminal CRLF729client->receive("GET / HTTP/1.0\n"730"Transfer-Encoding: chunked\n"731"\n"732"1\n"733"x\n"734"0\n"735"Digest: sha-4=deadbeef\n");736BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));737BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);739// Send first part of another trailer line740client->receive("Expires:");741BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));742BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);744// Finish the trailer line745client->receive("never\n");746BOOST_CHECK(!HTTPRemoteClient::TryReadRequest(client));747BOOST_CHECK_EQUAL(client->GetRequest()->GetState(), HTTPRequest::State::NeedsBody);749// Terminate750client->receive("\n");
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.