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