/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 |