MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / LoadBody

Method LoadBody

src/httpserver.cpp:420–513  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

418}
419
420bool HTTPRequest::LoadBody(LineReader& reader)
421{
422 // https://httpwg.org/specs/rfc9112.html#message.body
423 auto transfer_encoding_header = m_headers.FindFirst("Transfer-Encoding");
424 if (transfer_encoding_header && ToLower(transfer_encoding_header.value()) == "chunked") {
425 // Transfer-Encoding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-3.3.1
426 // Chunked Transfer Coding: https://datatracker.ietf.org/doc/html/rfc7230.html#section-4.1
427 // see evhttp_handle_chunked_read() in libevent http.c
428 while (reader.Remaining() > 0) {
429 auto maybe_chunk_size = reader.ReadLine();
430 if (!maybe_chunk_size) return false;
431
432 // Allow (but ignore) Chunk Extensions
433 // See https://www.rfc-editor.org/rfc/rfc9112.html#name-chunk-extensions
434 std::string_view chunk_size_noext{maybe_chunk_size.value()};
435 const auto semicolon_pos = chunk_size_noext.find(';');
436 if (semicolon_pos != chunk_size_noext.npos) {
437 chunk_size_noext.remove_suffix(chunk_size_noext.size() - semicolon_pos);
438 }
439
440 const auto chunk_size{ToIntegral<uint64_t>(util::TrimStringView(chunk_size_noext), /*base=*/16)};
441 if (!chunk_size) throw std::runtime_error("Cannot parse chunk length value");
442
443 if ((m_body.size() > MAX_BODY_SIZE) ||
444 (*chunk_size > MAX_BODY_SIZE - m_body.size()))
445 throw ContentTooLargeError("Chunk will exceed max body size");
446
447 // Last chunk has size 0
448 if (*chunk_size == 0) {
449 // Allow (but ignore) Chunked Trailer section, by
450 // reading CRLF-terminated lines until we read an empty line,
451 // which indicates the end of this request.
452 // See https://httpwg.org/specs/rfc9112.html#rfc.section.7.1.2
453 const size_t trailer_start{reader.Consumed()};
454 while (true) {
455 auto maybe_trailer = reader.ReadLine();
456 if (reader.Consumed() - trailer_start > MAX_HEADERS_SIZE) {
457 throw std::runtime_error("HTTP chunked trailer exceeds size limit");
458 }
459 if (!maybe_trailer) return false;
460 if (maybe_trailer->empty()) break;
461 }
462 // Complete request has been parsed, reader is now pointing
463 // to beginning of next request or end of the buffer.
464 return true;
465 }
466
467 // We are still expecting more data for this chunk
468 if (reader.Remaining() < *chunk_size) {
469 return false;
470 }
471
472 // Pack chunk onto body
473 m_body += reader.ReadLength(*chunk_size);
474
475 // Even though every chunk size is explicitly declared,
476 // they are still terminated by a CRLF we don't need,
477 // just consume it here.

Callers 3

ReadRequestMethod · 0.80
BOOST_AUTO_TEST_CASEFunction · 0.80
FUZZ_TARGETFunction · 0.80

Calls 13

TrimStringViewFunction · 0.85
RemainingMethod · 0.80
ReadLineMethod · 0.80
findMethod · 0.80
ConsumedMethod · 0.80
ReadLengthMethod · 0.80
FindAllMethod · 0.80
ToLowerFunction · 0.50
FindFirstMethod · 0.45
valueMethod · 0.45
sizeMethod · 0.45

Tested by 2

BOOST_AUTO_TEST_CASEFunction · 0.64
FUZZ_TARGETFunction · 0.64