LCOV - code coverage report
Current view: top level - source/common/http/http1 - legacy_parser_impl.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 109 109 100.0 %
Date: 2024-01-05 06:35:25 Functions: 35 35 100.0 %

          Line data    Source code
       1             : #include "source/common/http/http1/legacy_parser_impl.h"
       2             : 
       3             : #include <http_parser.h>
       4             : 
       5             : #include <cstdint>
       6             : 
       7             : #include "source/common/common/assert.h"
       8             : #include "source/common/http/http1/parser.h"
       9             : 
      10             : namespace Envoy {
      11             : namespace Http {
      12             : namespace Http1 {
      13             : namespace {
      14             : 
      15        2140 : ParserStatus intToStatus(int rc) {
      16        2140 :   switch (rc) {
      17         524 :   case 0:
      18         524 :     return ParserStatus::Ok;
      19         480 :   case 31:
      20         480 :     return ParserStatus::Paused;
      21        1136 :   default:
      22        1136 :     return ParserStatus::Error;
      23        2140 :   }
      24        2140 : }
      25             : 
      26             : } // namespace
      27             : 
      28             : class LegacyHttpParserImpl::Impl {
      29             : public:
      30        1541 :   Impl(http_parser_type type) {
      31        1541 :     http_parser_init(&parser_, type);
      32        1541 :     parser_.allow_chunked_length = 1;
      33        1541 :   }
      34             : 
      35        1541 :   Impl(http_parser_type type, void* data) : Impl(type) {
      36        1541 :     parser_.data = data;
      37        1541 :     settings_ = {
      38        1541 :         [](http_parser* parser) -> int {
      39         915 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      40         915 :           return static_cast<int>(conn_impl->onMessageBegin());
      41         915 :         },
      42        1541 :         [](http_parser* parser, const char* at, size_t length) -> int {
      43         559 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      44         559 :           return static_cast<int>(conn_impl->onUrl(at, length));
      45         559 :         },
      46        1541 :         [](http_parser* parser, const char* at, size_t length) -> int {
      47         115 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      48         115 :           return static_cast<int>(conn_impl->onStatus(at, length));
      49         115 :         },
      50        2031 :         [](http_parser* parser, const char* at, size_t length) -> int {
      51        1525 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      52        1525 :           return static_cast<int>(conn_impl->onHeaderField(at, length));
      53        1525 :         },
      54        2031 :         [](http_parser* parser, const char* at, size_t length) -> int {
      55        1500 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      56        1500 :           return static_cast<int>(conn_impl->onHeaderValue(at, length));
      57        1500 :         },
      58        1541 :         [](http_parser* parser) -> int {
      59         295 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      60         295 :           return static_cast<int>(conn_impl->onHeadersComplete());
      61         295 :         },
      62        1541 :         [](http_parser* parser, const char* at, size_t length) -> int {
      63         253 :           static_cast<ParserCallbacks*>(parser->data)->bufferBody(at, length);
      64         253 :           return 0;
      65         253 :         },
      66        1541 :         [](http_parser* parser) -> int {
      67         245 :           auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
      68         245 :           return static_cast<int>(conn_impl->onMessageComplete());
      69         245 :         },
      70        1541 :         [](http_parser* parser) -> int {
      71             :           // A 0-byte chunk header is used to signal the end of the chunked body.
      72             :           // When this function is called, http-parser holds the size of the chunk in
      73             :           // parser->content_length. See
      74             :           // https://github.com/nodejs/http-parser/blob/v2.9.3/http_parser.h#L336
      75         259 :           const bool is_final_chunk = (parser->content_length == 0);
      76         259 :           static_cast<ParserCallbacks*>(parser->data)->onChunkHeader(is_final_chunk);
      77         259 :           return 0;
      78         259 :         },
      79        1541 :         nullptr // on_chunk_complete
      80        1541 :     };
      81        1541 :   }
      82             : 
      83        1680 :   size_t execute(const char* slice, int len) {
      84        1680 :     return http_parser_execute(&parser_, &settings_, slice, len);
      85        1680 :   }
      86             : 
      87        1545 :   void resume() { http_parser_pause(&parser_, 0); }
      88             : 
      89         240 :   CallbackResult pause() {
      90         240 :     http_parser_pause(&parser_, 1);
      91         240 :     return CallbackResult::Success;
      92         240 :   }
      93             : 
      94        3276 :   int getErrno() { return HTTP_PARSER_ERRNO(&parser_); }
      95             : 
      96        1342 :   Envoy::Http::Code statusCode() const { return static_cast<Http::Code>(parser_.status_code); }
      97             : 
      98         295 :   bool isHttp11() const { return parser_.http_major == 1 && parser_.http_minor == 1; }
      99             : 
     100         351 :   absl::optional<uint64_t> contentLength() const {
     101             :     // An unset content length will be have all bits set.
     102             :     // See
     103             :     // https://github.com/nodejs/http-parser/blob/ec8b5ee63f0e51191ea43bb0c6eac7bfbff3141d/http_parser.h#L311
     104         351 :     if (parser_.content_length == ULLONG_MAX) {
     105         313 :       return absl::nullopt;
     106         313 :     }
     107          38 :     return parser_.content_length;
     108         351 :   }
     109             : 
     110         160 :   bool isChunked() const { return parser_.flags & F_CHUNKED; }
     111             : 
     112        1057 :   absl::string_view methodName() const {
     113        1057 :     return http_method_str(static_cast<http_method>(parser_.method));
     114        1057 :   }
     115             : 
     116         294 :   int hasTransferEncoding() const { return parser_.uses_transfer_encoding; }
     117             : 
     118             : private:
     119             :   http_parser parser_;
     120             :   http_parser_settings settings_;
     121             : };
     122             : 
     123        1541 : LegacyHttpParserImpl::LegacyHttpParserImpl(MessageType type, ParserCallbacks* data) {
     124        1541 :   http_parser_type parser_type;
     125        1541 :   switch (type) {
     126         770 :   case MessageType::Request:
     127         770 :     parser_type = HTTP_REQUEST;
     128         770 :     break;
     129         771 :   case MessageType::Response:
     130         771 :     parser_type = HTTP_RESPONSE;
     131         771 :     break;
     132        1541 :   }
     133             : 
     134        1541 :   impl_ = std::make_unique<Impl>(parser_type, data);
     135        1541 : }
     136             : 
     137             : // Because we have a pointer-to-impl using std::unique_ptr, we must place the destructor in the
     138             : // same compilation unit so that the destructor has a complete definition of Impl.
     139        1541 : LegacyHttpParserImpl::~LegacyHttpParserImpl() = default;
     140             : 
     141        1680 : size_t LegacyHttpParserImpl::execute(const char* slice, int len) {
     142        1680 :   return impl_->execute(slice, len);
     143        1680 : }
     144             : 
     145        1545 : void LegacyHttpParserImpl::resume() { impl_->resume(); }
     146             : 
     147         240 : CallbackResult LegacyHttpParserImpl::pause() { return impl_->pause(); }
     148             : 
     149        2140 : ParserStatus LegacyHttpParserImpl::getStatus() const { return intToStatus(impl_->getErrno()); }
     150             : 
     151        1342 : Http::Code LegacyHttpParserImpl::statusCode() const { return impl_->statusCode(); }
     152             : 
     153         295 : bool LegacyHttpParserImpl::isHttp11() const { return impl_->isHttp11(); }
     154             : 
     155         351 : absl::optional<uint64_t> LegacyHttpParserImpl::contentLength() const {
     156         351 :   return impl_->contentLength();
     157         351 : }
     158             : 
     159         160 : bool LegacyHttpParserImpl::isChunked() const { return impl_->isChunked(); }
     160             : 
     161        1057 : absl::string_view LegacyHttpParserImpl::methodName() const { return impl_->methodName(); }
     162             : 
     163        1136 : absl::string_view LegacyHttpParserImpl::errorMessage() const {
     164        1136 :   return http_errno_name(static_cast<http_errno>(impl_->getErrno()));
     165        1136 : }
     166             : 
     167         294 : int LegacyHttpParserImpl::hasTransferEncoding() const { return impl_->hasTransferEncoding(); }
     168             : 
     169             : } // namespace Http1
     170             : } // namespace Http
     171             : } // namespace Envoy

Generated by: LCOV version 1.15