Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/http/http1/legacy_parser_impl.cc
Line
Count
Source (jump to first uncovered line)
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
217k
ParserStatus intToStatus(int rc) {
16
217k
  switch (rc) {
17
145k
  case 0:
18
145k
    return ParserStatus::Ok;
19
59.5k
  case 31:
20
59.5k
    return ParserStatus::Paused;
21
12.3k
  default:
22
12.3k
    return ParserStatus::Error;
23
217k
  }
24
217k
}
25
26
} // namespace
27
28
class LegacyHttpParserImpl::Impl {
29
public:
30
37.1k
  Impl(http_parser_type type) {
31
37.1k
    http_parser_init(&parser_, type);
32
37.1k
    parser_.allow_chunked_length = 1;
33
37.1k
  }
34
35
37.1k
  Impl(http_parser_type type, void* data) : Impl(type) {
36
37.1k
    parser_.data = data;
37
37.1k
    settings_ = {
38
37.1k
        [](http_parser* parser) -> int {
39
33.5k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
40
33.5k
          return static_cast<int>(conn_impl->onMessageBegin());
41
33.5k
        },
42
37.1k
        [](http_parser* parser, const char* at, size_t length) -> int {
43
17.7k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
44
17.7k
          return static_cast<int>(conn_impl->onUrl(at, length));
45
17.7k
        },
46
37.1k
        [](http_parser* parser, const char* at, size_t length) -> int {
47
11.7k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
48
11.7k
          return static_cast<int>(conn_impl->onStatus(at, length));
49
11.7k
        },
50
174k
        [](http_parser* parser, const char* at, size_t length) -> int {
51
174k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
52
174k
          return static_cast<int>(conn_impl->onHeaderField(at, length));
53
174k
        },
54
199k
        [](http_parser* parser, const char* at, size_t length) -> int {
55
199k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
56
199k
          return static_cast<int>(conn_impl->onHeaderValue(at, length));
57
199k
        },
58
37.1k
        [](http_parser* parser) -> int {
59
25.5k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
60
25.5k
          return static_cast<int>(conn_impl->onHeadersComplete());
61
25.5k
        },
62
37.1k
        [](http_parser* parser, const char* at, size_t length) -> int {
63
14.9k
          static_cast<ParserCallbacks*>(parser->data)->bufferBody(at, length);
64
14.9k
          return 0;
65
14.9k
        },
66
37.1k
        [](http_parser* parser) -> int {
67
17.5k
          auto* conn_impl = static_cast<ParserCallbacks*>(parser->data);
68
17.5k
          return static_cast<int>(conn_impl->onMessageComplete());
69
17.5k
        },
70
37.1k
        [](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
15.3k
          const bool is_final_chunk = (parser->content_length == 0);
76
15.3k
          static_cast<ParserCallbacks*>(parser->data)->onChunkHeader(is_final_chunk);
77
15.3k
          return 0;
78
15.3k
        },
79
37.1k
        nullptr // on_chunk_complete
80
37.1k
    };
81
37.1k
  }
82
83
72.5k
  size_t execute(const char* slice, int len) {
84
72.5k
    return http_parser_execute(&parser_, &settings_, slice, len);
85
72.5k
  }
86
87
66.9k
  void resume() { http_parser_pause(&parser_, 0); }
88
89
11.9k
  CallbackResult pause() {
90
11.9k
    http_parser_pause(&parser_, 1);
91
11.9k
    return CallbackResult::Success;
92
11.9k
  }
93
94
229k
  int getErrno() { return HTTP_PARSER_ERRNO(&parser_); }
95
96
111k
  Envoy::Http::Code statusCode() const { return static_cast<Http::Code>(parser_.status_code); }
97
98
25.4k
  bool isHttp11() const { return parser_.http_major == 1 && parser_.http_minor == 1; }
99
100
21.8k
  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
21.8k
    if (parser_.content_length == ULLONG_MAX) {
105
9.80k
      return absl::nullopt;
106
9.80k
    }
107
12.0k
    return parser_.content_length;
108
21.8k
  }
109
110
15.8k
  bool isChunked() const { return parser_.flags & F_CHUNKED; }
111
112
85.3k
  absl::string_view methodName() const {
113
85.3k
    return http_method_str(static_cast<http_method>(parser_.method));
114
85.3k
  }
115
116
25.4k
  int hasTransferEncoding() const { return parser_.uses_transfer_encoding; }
117
118
private:
119
  http_parser parser_;
120
  http_parser_settings settings_;
121
};
122
123
37.1k
LegacyHttpParserImpl::LegacyHttpParserImpl(MessageType type, ParserCallbacks* data) {
124
37.1k
  http_parser_type parser_type;
125
37.1k
  switch (type) {
126
18.7k
  case MessageType::Request:
127
18.7k
    parser_type = HTTP_REQUEST;
128
18.7k
    break;
129
18.3k
  case MessageType::Response:
130
18.3k
    parser_type = HTTP_RESPONSE;
131
18.3k
    break;
132
37.1k
  }
133
134
37.1k
  impl_ = std::make_unique<Impl>(parser_type, data);
135
37.1k
}
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
37.1k
LegacyHttpParserImpl::~LegacyHttpParserImpl() = default;
140
141
72.5k
size_t LegacyHttpParserImpl::execute(const char* slice, int len) {
142
72.5k
  return impl_->execute(slice, len);
143
72.5k
}
144
145
66.9k
void LegacyHttpParserImpl::resume() { impl_->resume(); }
146
147
11.9k
CallbackResult LegacyHttpParserImpl::pause() { return impl_->pause(); }
148
149
217k
ParserStatus LegacyHttpParserImpl::getStatus() const { return intToStatus(impl_->getErrno()); }
150
151
111k
Http::Code LegacyHttpParserImpl::statusCode() const { return impl_->statusCode(); }
152
153
25.4k
bool LegacyHttpParserImpl::isHttp11() const { return impl_->isHttp11(); }
154
155
21.8k
absl::optional<uint64_t> LegacyHttpParserImpl::contentLength() const {
156
21.8k
  return impl_->contentLength();
157
21.8k
}
158
159
15.8k
bool LegacyHttpParserImpl::isChunked() const { return impl_->isChunked(); }
160
161
85.3k
absl::string_view LegacyHttpParserImpl::methodName() const { return impl_->methodName(); }
162
163
12.3k
absl::string_view LegacyHttpParserImpl::errorMessage() const {
164
12.3k
  return http_errno_name(static_cast<http_errno>(impl_->getErrno()));
165
12.3k
}
166
167
25.4k
int LegacyHttpParserImpl::hasTransferEncoding() const { return impl_->hasTransferEncoding(); }
168
169
} // namespace Http1
170
} // namespace Http
171
} // namespace Envoy