Line data Source code
1 : #include "source/common/http/http1/codec_impl.h"
2 :
3 : #include <cstdint>
4 : #include <memory>
5 : #include <string>
6 :
7 : #include "envoy/buffer/buffer.h"
8 : #include "envoy/common/optref.h"
9 : #include "envoy/http/codec.h"
10 : #include "envoy/http/header_map.h"
11 : #include "envoy/network/connection.h"
12 :
13 : #include "source/common/common/cleanup.h"
14 : #include "source/common/common/dump_state_utils.h"
15 : #include "source/common/common/enum_to_int.h"
16 : #include "source/common/common/scope_tracker.h"
17 : #include "source/common/common/statusor.h"
18 : #include "source/common/common/utility.h"
19 : #include "source/common/grpc/common.h"
20 : #include "source/common/http/exception.h"
21 : #include "source/common/http/header_utility.h"
22 : #include "source/common/http/headers.h"
23 : #include "source/common/http/http1/balsa_parser.h"
24 : #include "source/common/http/http1/header_formatter.h"
25 : #include "source/common/http/http1/legacy_parser_impl.h"
26 : #include "source/common/http/utility.h"
27 : #include "source/common/runtime/runtime_features.h"
28 :
29 : #include "absl/container/fixed_array.h"
30 : #include "absl/strings/ascii.h"
31 :
32 : namespace Envoy {
33 : namespace Http {
34 : namespace Http1 {
35 : namespace {
36 :
37 : // Changes or additions to details should be reflected in
38 : // docs/root/configuration/http/http_conn_man/response_code_details.rst
39 : struct Http1ResponseCodeDetailValues {
40 : const absl::string_view TooManyHeaders = "http1.too_many_headers";
41 : const absl::string_view HeadersTooLarge = "http1.headers_too_large";
42 : const absl::string_view HttpCodecError = "http1.codec_error";
43 : const absl::string_view InvalidCharacters = "http1.invalid_characters";
44 : const absl::string_view ConnectionHeaderSanitization = "http1.connection_header_rejected";
45 : const absl::string_view InvalidUrl = "http1.invalid_url";
46 : const absl::string_view InvalidTransferEncoding = "http1.invalid_transfer_encoding";
47 : const absl::string_view BodyDisallowed = "http1.body_disallowed";
48 : const absl::string_view TransferEncodingNotAllowed = "http1.transfer_encoding_not_allowed";
49 : const absl::string_view ContentLengthNotAllowed = "http1.content_length_not_allowed";
50 : const absl::string_view InvalidUnderscore = "http1.unexpected_underscore";
51 : const absl::string_view ChunkedContentLength = "http1.content_length_and_chunked_not_allowed";
52 : const absl::string_view HttpsInPlaintext = "http1.https_url_on_plaintext_connection";
53 : const absl::string_view InvalidScheme = "http1.invalid_scheme";
54 : };
55 :
56 : struct Http1HeaderTypesValues {
57 : const absl::string_view Headers = "headers";
58 : const absl::string_view Trailers = "trailers";
59 : };
60 :
61 : // Pipelining is generally not well supported on the internet and has a series of dangerous
62 : // overflow bugs. As such Envoy disabled it.
63 : static constexpr uint32_t kMaxOutboundResponses = 2;
64 :
65 : using Http1ResponseCodeDetails = ConstSingleton<Http1ResponseCodeDetailValues>;
66 : using Http1HeaderTypes = ConstSingleton<Http1HeaderTypesValues>;
67 :
68 0 : const StringUtil::CaseUnorderedSet& caseUnorderdSetContainingUpgradeAndHttp2Settings() {
69 0 : CONSTRUCT_ON_FIRST_USE(StringUtil::CaseUnorderedSet,
70 0 : Http::Headers::get().ConnectionValues.Upgrade,
71 0 : Http::Headers::get().ConnectionValues.Http2Settings);
72 0 : }
73 :
74 3112 : HeaderKeyFormatterConstPtr encodeOnlyFormatterFromSettings(const Http::Http1Settings& settings) {
75 3112 : if (settings.header_key_format_ == Http1Settings::HeaderKeyFormat::ProperCase) {
76 0 : return std::make_unique<ProperCaseHeaderKeyFormatter>();
77 0 : }
78 :
79 3112 : return nullptr;
80 3112 : }
81 :
82 1975 : StatefulHeaderKeyFormatterPtr statefulFormatterFromSettings(const Http::Http1Settings& settings) {
83 1975 : if (settings.header_key_format_ == Http1Settings::HeaderKeyFormat::StatefulFormatter) {
84 0 : return settings.stateful_header_key_formatter_->create();
85 0 : }
86 1975 : return nullptr;
87 1975 : }
88 :
89 : constexpr size_t CRLF_SIZE = 2;
90 :
91 : } // namespace
92 :
93 : static constexpr absl::string_view CRLF = "\r\n";
94 : // Last chunk as defined here https://tools.ietf.org/html/rfc7230#section-4.1
95 : static constexpr absl::string_view LAST_CHUNK = "0\r\n";
96 :
97 : static constexpr absl::string_view SPACE = " ";
98 : static constexpr absl::string_view COLON_SPACE = ": ";
99 :
100 : StreamEncoderImpl::StreamEncoderImpl(ConnectionImpl& connection,
101 : StreamInfo::BytesMeterSharedPtr&& bytes_meter)
102 : : connection_(connection), disable_chunk_encoding_(false), chunk_encoding_(true),
103 : connect_request_(false), is_tcp_tunneling_(false), is_response_to_head_request_(false),
104 1862 : is_response_to_connect_request_(false), bytes_meter_(std::move(bytes_meter)) {
105 1862 : if (!bytes_meter_) {
106 220 : bytes_meter_ = std::make_shared<StreamInfo::BytesMeter>();
107 220 : }
108 1862 : if (connection_.connection().aboveHighWatermark()) {
109 0 : runHighWatermarkCallbacks();
110 0 : }
111 1862 : }
112 :
113 2637 : void StreamEncoderImpl::encodeHeader(absl::string_view key, absl::string_view value) {
114 2637 : ASSERT(!key.empty());
115 :
116 2637 : const uint64_t header_size = connection_.buffer().addFragments({key, COLON_SPACE, value, CRLF});
117 :
118 2637 : bytes_meter_->addHeaderBytesSent(header_size);
119 2637 : }
120 :
121 : void StreamEncoderImpl::encodeFormattedHeader(absl::string_view key, absl::string_view value,
122 2637 : HeaderKeyFormatterOptConstRef formatter) {
123 2637 : if (formatter.has_value()) {
124 0 : encodeHeader(formatter->format(key), value);
125 2637 : } else {
126 2637 : encodeHeader(key, value);
127 2637 : }
128 2637 : }
129 :
130 13 : void ResponseEncoderImpl::encode1xxHeaders(const ResponseHeaderMap& headers) {
131 13 : ASSERT(HeaderUtility::isSpecial1xx(headers));
132 13 : encodeHeaders(headers, false);
133 13 : if (Runtime::runtimeFeatureEnabled(
134 13 : "envoy.reloadable_features.http1_allow_codec_error_response_after_1xx_headers")) {
135 : // Don't consider 100-continue responses as the actual response.
136 13 : started_response_ = false;
137 13 : }
138 13 : }
139 :
140 : void StreamEncoderImpl::encodeHeadersBase(const RequestOrResponseHeaderMap& headers,
141 : absl::optional<uint64_t> status, bool end_stream,
142 597 : bool bodiless_request) {
143 597 : HeaderKeyFormatterOptConstRef formatter(headers.formatter());
144 597 : if (!formatter.has_value()) {
145 597 : formatter = connection_.formatter();
146 597 : }
147 :
148 597 : const Http::HeaderValues& header_values = Http::Headers::get();
149 597 : bool saw_content_length = false;
150 597 : headers.iterate(
151 3379 : [this, &header_values, formatter](const HeaderEntry& header) -> HeaderMap::Iterate {
152 3379 : absl::string_view key_to_use = header.key().getStringView();
153 3379 : uint32_t key_size_to_use = header.key().size();
154 : // Translate :authority -> host so that upper layers do not need to deal with this.
155 3379 : if (key_size_to_use > 1 && key_to_use[0] == ':' && key_to_use[1] == 'a') {
156 212 : key_to_use = absl::string_view(header_values.HostLegacy.get());
157 212 : key_size_to_use = header_values.HostLegacy.get().size();
158 212 : }
159 :
160 : // Skip all headers starting with ':' that make it here.
161 3379 : if (key_to_use[0] == ':') {
162 995 : return HeaderMap::Iterate::Continue;
163 995 : }
164 :
165 2384 : encodeFormattedHeader(key_to_use, header.value().getStringView(), formatter);
166 :
167 2384 : return HeaderMap::Iterate::Continue;
168 3379 : });
169 :
170 597 : if (headers.ContentLength()) {
171 222 : saw_content_length = true;
172 222 : }
173 :
174 597 : ASSERT(!headers.TransferEncoding());
175 :
176 : // Assume we are chunk encoding unless we are passed a content length or this is a header only
177 : // response. Upper layers generally should strip transfer-encoding since it only applies to
178 : // HTTP/1.1. The codec will infer it based on the type of response.
179 : // for streaming (e.g. SSE stream sent to hystrix dashboard), we do not want
180 : // chunk transfer encoding but we don't have a content-length so disable_chunk_encoding_ is
181 : // consulted before enabling chunk encoding.
182 : //
183 : // Note that for HEAD requests Envoy does best-effort guessing when there is no
184 : // content-length. If a client makes a HEAD request for an upstream resource
185 : // with no bytes but the upstream response doesn't include "Content-length: 0",
186 : // Envoy will incorrectly assume a subsequent response to GET will be chunk encoded.
187 597 : if (saw_content_length || disable_chunk_encoding_) {
188 224 : chunk_encoding_ = false;
189 528 : } else {
190 373 : if (status && (*status < 200 || *status == 204)) {
191 : // For 1xx and 204 responses, do not send the chunked encoding header or enable chunked
192 : // encoding: https://tools.ietf.org/html/rfc7230#section-3.3.1
193 16 : chunk_encoding_ = false;
194 357 : } else if (status && *status == 304) {
195 : // For 304 response, since it should never have a body, we should not need to chunk_encode at
196 : // all.
197 0 : chunk_encoding_ = false;
198 357 : } else if (end_stream && !is_response_to_head_request_) {
199 : // If this is a headers-only stream, append an explicit "Content-Length: 0" unless it's a
200 : // response to a HEAD request.
201 : // For 204s and 1xx where content length is disallowed, don't append the content length but
202 : // also don't chunk encode.
203 : // Also do not add content length for requests which should not have a
204 : // body, per https://tools.ietf.org/html/rfc7230#section-3.3.2
205 116 : if (!status || (*status >= 200 && *status != 204)) {
206 116 : if (!bodiless_request) {
207 13 : encodeFormattedHeader(header_values.ContentLength.get(), "0", formatter);
208 13 : }
209 116 : }
210 116 : chunk_encoding_ = false;
211 243 : } else if (connection_.protocol() == Protocol::Http10) {
212 1 : chunk_encoding_ = false;
213 240 : } else {
214 : // For responses to connect requests, do not send the chunked encoding header:
215 : // https://tools.ietf.org/html/rfc7231#section-4.3.6.
216 240 : if (!is_response_to_connect_request_) {
217 240 : encodeFormattedHeader(header_values.TransferEncoding.get(),
218 240 : header_values.TransferEncodingValues.Chunked, formatter);
219 240 : }
220 : // We do not apply chunk encoding for HTTP upgrades, including CONNECT style upgrades.
221 : // If there is a body in a response on the upgrade path, the chunks will be
222 : // passed through via maybeDirectDispatch so we need to avoid appending
223 : // extra chunk boundaries.
224 : //
225 : // When sending a response to a HEAD request Envoy may send an informational
226 : // "Transfer-Encoding: chunked" header, but should not send a chunk encoded body.
227 240 : chunk_encoding_ = !Utility::isUpgrade(headers) && !is_response_to_head_request_ &&
228 240 : !is_response_to_connect_request_;
229 240 : }
230 373 : }
231 :
232 597 : connection_.buffer().add(CRLF);
233 :
234 597 : if (end_stream) {
235 117 : endEncode();
236 480 : } else {
237 480 : flushOutput();
238 480 : }
239 597 : }
240 :
241 504 : void StreamEncoderImpl::encodeData(Buffer::Instance& data, bool end_stream) {
242 : // end_stream may be indicated with a zero length data buffer. If that is the case, so not
243 : // actually write the zero length buffer out.
244 504 : if (data.length() > 0) {
245 461 : if (chunk_encoding_) {
246 236 : std::string chunk_header = absl::StrCat(absl::Hex(data.length()), CRLF);
247 236 : connection_.buffer().add(std::move(chunk_header));
248 236 : }
249 :
250 461 : connection_.buffer().move(data);
251 :
252 461 : if (chunk_encoding_) {
253 236 : connection_.buffer().add(CRLF);
254 236 : }
255 461 : }
256 :
257 504 : if (end_stream) {
258 401 : endEncode();
259 460 : } else {
260 103 : flushOutput();
261 103 : }
262 504 : }
263 :
264 1118 : void StreamEncoderImpl::flushOutput(bool end_encode) {
265 1118 : auto encoded_bytes = connection_.flushOutput(end_encode);
266 1118 : bytes_meter_->addWireBytesSent(encoded_bytes);
267 1118 : }
268 :
269 17 : void StreamEncoderImpl::encodeTrailersBase(const HeaderMap& trailers) {
270 17 : if (!connection_.enableTrailers()) {
271 17 : return endEncode();
272 17 : }
273 : // Trailers only matter if it is a chunk transfer encoding
274 : // https://tools.ietf.org/html/rfc7230#section-4.4
275 0 : if (chunk_encoding_) {
276 : // Finalize the body
277 0 : connection_.buffer().add(LAST_CHUNK);
278 :
279 : // TODO(mattklein123): Wire up the formatter if someone actually asks for this (very unlikely).
280 0 : trailers.iterate([this](const HeaderEntry& header) -> HeaderMap::Iterate {
281 0 : encodeFormattedHeader(header.key().getStringView(), header.value().getStringView(),
282 0 : HeaderKeyFormatterOptConstRef());
283 0 : return HeaderMap::Iterate::Continue;
284 0 : });
285 :
286 0 : connection_.buffer().add(CRLF);
287 0 : }
288 :
289 0 : flushOutput();
290 0 : notifyEncodeComplete();
291 0 : }
292 :
293 6 : void StreamEncoderImpl::encodeMetadata(const MetadataMapVector&) {
294 6 : connection_.stats().metadata_not_supported_error_.inc();
295 6 : }
296 :
297 535 : void StreamEncoderImpl::endEncode() {
298 535 : if (chunk_encoding_) {
299 196 : connection_.buffer().addFragments({LAST_CHUNK, CRLF});
300 196 : }
301 :
302 535 : flushOutput(true);
303 535 : notifyEncodeComplete();
304 : // With CONNECT or TCP tunneling, half-closing the connection is used to signal end stream so
305 : // don't delay that signal.
306 535 : if (connect_request_ || is_tcp_tunneling_) {
307 0 : connection_.connection().close(
308 0 : Network::ConnectionCloseType::FlushWrite,
309 0 : StreamInfo::LocalCloseReasons::get().CloseForConnectRequestOrTcpTunneling);
310 0 : }
311 535 : }
312 :
313 535 : void StreamEncoderImpl::notifyEncodeComplete() {
314 535 : if (codec_callbacks_) {
315 352 : codec_callbacks_->onCodecEncodeComplete();
316 352 : }
317 535 : connection_.onEncodeComplete();
318 535 : }
319 :
320 367 : void ServerConnectionImpl::maybeAddSentinelBufferFragment(Buffer::Instance& output_buffer) {
321 : // It's messy and complicated to try to tag the final write of an HTTP response for response
322 : // tracking for flood protection. Instead, write an empty buffer fragment after the response,
323 : // to allow for tracking.
324 : // When the response is written out, the fragment will be deleted and the counter will be updated
325 : // by ServerConnectionImpl::releaseOutboundResponse()
326 367 : auto fragment =
327 367 : Buffer::OwnedBufferFragmentImpl::create(absl::string_view("", 0), response_buffer_releasor_);
328 367 : output_buffer.addBufferFragment(*fragment.release());
329 367 : ASSERT(outbound_responses_ < kMaxOutboundResponses);
330 367 : outbound_responses_++;
331 367 : }
332 :
333 1642 : Status ServerConnectionImpl::doFloodProtectionChecks() const {
334 1642 : ASSERT(dispatching_);
335 : // Before processing another request, make sure that we are below the response flood protection
336 : // threshold.
337 1642 : if (outbound_responses_ >= kMaxOutboundResponses) {
338 0 : ENVOY_CONN_LOG(trace, "error accepting request: too many pending responses queued",
339 0 : connection_);
340 0 : stats_.response_flood_.inc();
341 0 : return bufferFloodError("Too many responses queued.");
342 0 : }
343 1642 : return okStatus();
344 1642 : }
345 :
346 1118 : uint64_t ConnectionImpl::flushOutput(bool end_encode) {
347 1118 : if (end_encode) {
348 : // If this is an HTTP response in ServerConnectionImpl, track outbound responses for flood
349 : // protection
350 535 : maybeAddSentinelBufferFragment(*output_buffer_);
351 535 : }
352 1118 : const uint64_t bytes_encoded = output_buffer_->length();
353 1118 : connection().write(*output_buffer_, false);
354 1118 : ASSERT(0UL == output_buffer_->length());
355 1118 : return bytes_encoded;
356 1118 : }
357 :
358 : CodecEventCallbacks*
359 806 : StreamEncoderImpl::registerCodecEventCallbacks(CodecEventCallbacks* codec_callbacks) {
360 806 : std::swap(codec_callbacks, codec_callbacks_);
361 806 : return codec_callbacks;
362 806 : }
363 :
364 247 : void StreamEncoderImpl::resetStream(StreamResetReason reason) {
365 247 : connection_.onResetStreamBase(reason);
366 247 : }
367 :
368 215 : void ResponseEncoderImpl::resetStream(StreamResetReason reason) {
369 : // Clear the downstream on the account since we're resetting the downstream.
370 215 : if (buffer_memory_account_) {
371 0 : buffer_memory_account_->clearDownstream();
372 0 : }
373 :
374 : // For H1, we use idleTimeouts to cancel streams unless there was an
375 : // explicit protocol error prior to sending a response to the downstream
376 : // in which case we send a local reply.
377 : // TODO(kbaichoo): If we want snappier resets of H1 streams we can
378 : // 1) Send local reply if no response data sent yet
379 : // 2) Invoke the idle timeout sooner to close underlying connection
380 215 : StreamEncoderImpl::resetStream(reason);
381 215 : }
382 :
383 142 : void StreamEncoderImpl::readDisable(bool disable) {
384 142 : if (disable) {
385 71 : ++read_disable_calls_;
386 71 : } else {
387 71 : ASSERT(read_disable_calls_ != 0);
388 71 : if (read_disable_calls_ != 0) {
389 71 : --read_disable_calls_;
390 71 : }
391 71 : }
392 142 : connection_.readDisable(disable);
393 142 : }
394 :
395 403 : uint32_t StreamEncoderImpl::bufferLimit() const { return connection_.bufferLimit(); }
396 :
397 54 : const Network::ConnectionInfoProvider& StreamEncoderImpl::connectionInfoProvider() {
398 54 : return connection_.connection().connectionInfoProvider();
399 54 : }
400 :
401 : static constexpr absl::string_view RESPONSE_PREFIX = "HTTP/1.1 ";
402 : static constexpr absl::string_view HTTP_10_RESPONSE_PREFIX = "HTTP/1.0 ";
403 :
404 385 : void ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) {
405 385 : started_response_ = true;
406 :
407 : // The contract is that client codecs must ensure that :status is present and valid.
408 385 : ASSERT(headers.Status() != nullptr);
409 385 : uint64_t numeric_status = Utility::getResponseStatus(headers);
410 :
411 385 : absl::string_view response_prefix;
412 385 : if (connection_.protocol() == Protocol::Http10 && connection_.supportsHttp10()) {
413 1 : response_prefix = HTTP_10_RESPONSE_PREFIX;
414 384 : } else {
415 384 : response_prefix = RESPONSE_PREFIX;
416 384 : }
417 :
418 385 : StatefulHeaderKeyFormatterOptConstRef formatter(headers.formatter());
419 :
420 385 : absl::string_view reason_phrase;
421 385 : if (formatter.has_value() && !formatter->getReasonPhrase().empty()) {
422 0 : reason_phrase = formatter->getReasonPhrase();
423 385 : } else {
424 385 : const char* status_string = CodeUtility::toString(static_cast<Code>(numeric_status));
425 385 : uint32_t status_string_len = strlen(status_string);
426 385 : reason_phrase = {status_string, status_string_len};
427 385 : }
428 :
429 385 : connection_.buffer().addFragments(
430 385 : {response_prefix, absl::StrCat(numeric_status), SPACE, reason_phrase, CRLF});
431 :
432 385 : if (numeric_status >= 300) {
433 : // Don't do special CONNECT logic if the CONNECT was rejected.
434 102 : is_response_to_connect_request_ = false;
435 102 : }
436 :
437 385 : encodeHeadersBase(headers, absl::make_optional<uint64_t>(numeric_status), end_stream, false);
438 385 : }
439 :
440 : static constexpr absl::string_view REQUEST_POSTFIX = " HTTP/1.1\r\n";
441 :
442 220 : Status RequestEncoderImpl::encodeHeaders(const RequestHeaderMap& headers, bool end_stream) {
443 220 : #ifndef ENVOY_ENABLE_UHV
444 : // Headers are now validated by UHV before encoding by the codec. Two checks below are not needed
445 : // when UHV is enabled.
446 : //
447 : // Required headers must be present. This can only happen by some erroneous processing after the
448 : // downstream codecs decode.
449 220 : RETURN_IF_ERROR(HeaderUtility::checkRequiredRequestHeaders(headers));
450 : // Verify that a filter hasn't added an invalid header key or value.
451 217 : RETURN_IF_ERROR(HeaderUtility::checkValidRequestHeaders(headers));
452 212 : #endif
453 :
454 212 : const HeaderEntry* method = headers.Method();
455 212 : const HeaderEntry* path = headers.Path();
456 212 : const HeaderEntry* host = headers.Host();
457 212 : bool is_connect = HeaderUtility::isConnect(headers);
458 212 : const Http::HeaderValues& header_values = Http::Headers::get();
459 :
460 212 : if (method->value() == header_values.MethodValues.Head) {
461 2 : head_request_ = true;
462 210 : } else if (method->value() == header_values.MethodValues.Connect) {
463 0 : disableChunkEncoding();
464 0 : connection_.connection().enableHalfClose(true);
465 0 : connect_request_ = true;
466 0 : }
467 212 : if (Utility::isUpgrade(headers)) {
468 2 : upgrade_request_ = true;
469 : // If the flag is flipped from true to false all outstanding upgrade requests that are waiting
470 : // for upstream connections will become invalid, as Envoy will add chunk encoding to the
471 : // protocol stream. This will likely cause the server to disconnect, since it will be unable to
472 : // parse the protocol.
473 2 : disableChunkEncoding();
474 2 : }
475 :
476 212 : if (connection_.sendFullyQualifiedUrl() && !is_connect) {
477 0 : const HeaderEntry* scheme = headers.Scheme();
478 0 : if (!scheme) {
479 0 : return absl::InvalidArgumentError(
480 0 : absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Scheme.get()));
481 0 : }
482 0 : if (!host) {
483 0 : return absl::InvalidArgumentError(
484 0 : absl::StrCat("missing required header: ", Envoy::Http::Headers::get().Host.get()));
485 0 : }
486 0 : ASSERT(path);
487 0 : ASSERT(host);
488 :
489 0 : std::string url = absl::StrCat(scheme->value().getStringView(), "://",
490 0 : host->value().getStringView(), path->value().getStringView());
491 0 : ENVOY_CONN_LOG(trace, "Sending fully qualified URL: {}", connection_.connection(), url);
492 0 : connection_.buffer().addFragments(
493 0 : {method->value().getStringView(), SPACE, url, REQUEST_POSTFIX});
494 212 : } else {
495 212 : absl::string_view host_or_path_view;
496 212 : if (is_connect) {
497 0 : host_or_path_view = host->value().getStringView();
498 212 : } else {
499 212 : host_or_path_view = path->value().getStringView();
500 212 : }
501 :
502 212 : connection_.buffer().addFragments(
503 212 : {method->value().getStringView(), SPACE, host_or_path_view, REQUEST_POSTFIX});
504 212 : }
505 :
506 212 : encodeHeadersBase(headers, absl::nullopt, end_stream,
507 212 : HeaderUtility::requestShouldHaveNoBody(headers));
508 212 : return okStatus();
509 212 : }
510 :
511 8191 : CallbackResult ConnectionImpl::setAndCheckCallbackStatus(Status&& status) {
512 8191 : ASSERT(codec_status_.ok());
513 8191 : codec_status_ = std::move(status);
514 8191 : return codec_status_.ok() ? CallbackResult::Success : CallbackResult::Error;
515 8191 : }
516 :
517 : CallbackResult
518 1044 : ConnectionImpl::setAndCheckCallbackStatusOr(Envoy::StatusOr<CallbackResult>&& statusor) {
519 1044 : ASSERT(codec_status_.ok());
520 1044 : if (statusor.ok()) {
521 931 : return statusor.value();
522 931 : } else {
523 113 : codec_status_ = std::move(statusor.status());
524 113 : return CallbackResult::Error;
525 113 : }
526 1044 : }
527 :
528 : ConnectionImpl::ConnectionImpl(Network::Connection& connection, CodecStats& stats,
529 : const Http1Settings& settings, MessageType type,
530 : uint32_t max_headers_kb, const uint32_t max_headers_count)
531 : : connection_(connection), stats_(stats), codec_settings_(settings),
532 : encode_only_header_key_formatter_(encodeOnlyFormatterFromSettings(settings)),
533 : processing_trailers_(false), handling_upgrade_(false), reset_stream_called_(false),
534 : deferred_end_stream_headers_(false), dispatching_(false), max_headers_kb_(max_headers_kb),
535 3112 : max_headers_count_(max_headers_count) {
536 3112 : if (codec_settings_.use_balsa_parser_) {
537 1571 : parser_ = std::make_unique<BalsaParser>(type, this, max_headers_kb_ * 1024, enableTrailers(),
538 1571 : codec_settings_.allow_custom_methods_);
539 1849 : } else {
540 1541 : parser_ = std::make_unique<LegacyHttpParserImpl>(type, this);
541 1541 : }
542 3112 : }
543 :
544 2480 : Status ConnectionImpl::completeCurrentHeader() {
545 2480 : ASSERT(dispatching_);
546 2480 : ENVOY_CONN_LOG(trace, "completed header: key={} value={}", connection_,
547 2480 : current_header_field_.getStringView(), current_header_value_.getStringView());
548 2480 : auto& headers_or_trailers = headersOrTrailers();
549 :
550 : // Account for ":" and "\r\n" bytes between the header key value pair.
551 2480 : getBytesMeter().addHeaderBytesReceived(CRLF_SIZE + 1);
552 :
553 : // TODO(10646): Switch to use HeaderUtility::checkHeaderNameForUnderscores().
554 2480 : RETURN_IF_ERROR(checkHeaderNameForUnderscores());
555 2480 : if (!current_header_field_.empty()) {
556 : // Strip trailing whitespace of the current header value if any. Leading whitespace was trimmed
557 : // in ConnectionImpl::onHeaderValue. http_parser does not strip leading or trailing whitespace
558 : // as the spec requires: https://tools.ietf.org/html/rfc7230#section-3.2.4
559 2407 : current_header_value_.rtrim();
560 :
561 : // If there is a stateful formatter installed, remember the original header key before
562 : // converting to lower case.
563 2407 : auto formatter = headers_or_trailers.formatter();
564 2407 : if (formatter.has_value()) {
565 0 : formatter->processKey(current_header_field_.getStringView());
566 0 : }
567 32451 : current_header_field_.inlineTransform([](char c) { return absl::ascii_tolower(c); });
568 :
569 2407 : headers_or_trailers.addViaMove(std::move(current_header_field_),
570 2407 : std::move(current_header_value_));
571 2407 : }
572 :
573 : // Check if the number of headers exceeds the limit.
574 2480 : if (headers_or_trailers.size() > max_headers_count_) {
575 0 : error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
576 0 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().TooManyHeaders));
577 0 : const absl::string_view header_type =
578 0 : processing_trailers_ ? Http1HeaderTypes::get().Trailers : Http1HeaderTypes::get().Headers;
579 0 : return codecProtocolError(
580 0 : absl::StrCat("http/1.1 protocol error: ", header_type, " count exceeds limit"));
581 0 : }
582 :
583 2480 : header_parsing_state_ = HeaderParsingState::Field;
584 2480 : ASSERT(current_header_field_.empty());
585 2480 : ASSERT(current_header_value_.empty());
586 2480 : return okStatus();
587 2480 : }
588 :
589 1975 : Status ConnectionImpl::onMessageBeginImpl() {
590 1975 : ENVOY_CONN_LOG(trace, "message begin", connection_);
591 : // Make sure that if HTTP/1.0 and HTTP/1.1 requests share a connection Envoy correctly sets
592 : // protocol for each request. Envoy defaults to 1.1 but sets the protocol to 1.0 where applicable
593 : // in onHeadersCompleteBase
594 1975 : protocol_ = Protocol::Http11;
595 1975 : processing_trailers_ = false;
596 1975 : header_parsing_state_ = HeaderParsingState::Field;
597 1975 : allocHeaders(statefulFormatterFromSettings(codec_settings_));
598 1975 : return onMessageBeginBase();
599 1975 : }
600 :
601 6237 : uint32_t ConnectionImpl::getHeadersSize() {
602 6237 : return current_header_field_.size() + current_header_value_.size() +
603 6237 : headersOrTrailers().byteSize();
604 6237 : }
605 :
606 6237 : Status ConnectionImpl::checkMaxHeadersSize() {
607 6237 : const uint32_t total = getHeadersSize();
608 6237 : if (total > (max_headers_kb_ * 1024)) {
609 0 : const absl::string_view header_type =
610 0 : processing_trailers_ ? Http1HeaderTypes::get().Trailers : Http1HeaderTypes::get().Headers;
611 0 : error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
612 0 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().HeadersTooLarge));
613 0 : return codecProtocolError(
614 0 : absl::StrCat("http/1.1 protocol error: ", header_type, " size exceeds limit"));
615 0 : }
616 6237 : return okStatus();
617 6237 : }
618 :
619 4038 : bool ConnectionImpl::maybeDirectDispatch(Buffer::Instance& data) {
620 4038 : if (!handling_upgrade_) {
621 : // Only direct dispatch for Upgrade requests.
622 4034 : return false;
623 4034 : }
624 :
625 4 : ENVOY_CONN_LOG(trace, "direct-dispatched {} bytes", connection_, data.length());
626 4 : onBody(data);
627 4 : data.drain(data.length());
628 4 : return true;
629 4038 : }
630 :
631 3126 : void ConnectionImpl::onDispatch(const Buffer::Instance& data) {
632 3126 : getBytesMeter().addWireBytesReceived(data.length());
633 3126 : }
634 :
635 1398 : Http::Status ClientConnectionImpl::dispatch(Buffer::Instance& data) {
636 1398 : Http::Status status = ConnectionImpl::dispatch(data);
637 1398 : if (status.ok() && data.length() > 0) {
638 : // The HTTP/1.1 codec pauses dispatch after a single response is complete. Extraneous data
639 : // after a response is complete indicates an error.
640 0 : return codecProtocolError("http/1.1 protocol error: extraneous data after response complete");
641 0 : }
642 1398 : return status;
643 1398 : }
644 :
645 3126 : Http::Status ConnectionImpl::dispatch(Buffer::Instance& data) {
646 : // Add self to the Dispatcher's tracked object stack.
647 3126 : ScopeTrackerScopeState scope(this, connection_.dispatcher());
648 3126 : ENVOY_CONN_LOG(trace, "parsing {} bytes", connection_, data.length());
649 : // Make sure that dispatching_ is set to false after dispatching, even when
650 : // http_parser exits early with an error code.
651 3126 : Cleanup cleanup([this]() { dispatching_ = false; });
652 3126 : ASSERT(!dispatching_);
653 3126 : ASSERT(codec_status_.ok());
654 3126 : ASSERT(buffered_body_.length() == 0);
655 :
656 3126 : dispatching_ = true;
657 3126 : onDispatch(data);
658 3126 : if (maybeDirectDispatch(data)) {
659 2 : return Http::okStatus();
660 2 : }
661 :
662 : // Always resume before dispatch.
663 3124 : parser_->resume();
664 :
665 3124 : ssize_t total_parsed = 0;
666 3124 : if (data.length() > 0) {
667 2955 : current_dispatching_buffer_ = &data;
668 3434 : while (data.length() > 0) {
669 3198 : auto slice = data.frontSlice();
670 3198 : dispatching_slice_already_drained_ = false;
671 3198 : auto statusor_parsed = dispatchSlice(static_cast<const char*>(slice.mem_), slice.len_);
672 3198 : if (!statusor_parsed.ok()) {
673 2212 : return statusor_parsed.status();
674 2212 : }
675 986 : if (!dispatching_slice_already_drained_) {
676 985 : ASSERT(statusor_parsed.value() <= slice.len_);
677 985 : data.drain(statusor_parsed.value());
678 985 : }
679 :
680 986 : total_parsed += statusor_parsed.value();
681 986 : if (parser_->getStatus() != ParserStatus::Ok) {
682 : // Parse errors trigger an exception in dispatchSlice so we are guaranteed to be paused at
683 : // this point.
684 507 : ASSERT(parser_->getStatus() == ParserStatus::Paused);
685 507 : break;
686 507 : }
687 986 : }
688 743 : current_dispatching_buffer_ = nullptr;
689 743 : dispatchBufferedBody();
690 743 : } else {
691 169 : auto result = dispatchSlice(nullptr, 0);
692 169 : if (!result.ok()) {
693 0 : return result.status();
694 0 : }
695 169 : }
696 912 : ASSERT(buffered_body_.length() == 0);
697 :
698 912 : ENVOY_CONN_LOG(trace, "parsed {} bytes", connection_, total_parsed);
699 :
700 : // If an upgrade has been handled and there is body data or early upgrade
701 : // payload to send on, send it on.
702 912 : maybeDirectDispatch(data);
703 912 : return Http::okStatus();
704 3124 : }
705 :
706 3367 : Envoy::StatusOr<size_t> ConnectionImpl::dispatchSlice(const char* slice, size_t len) {
707 3367 : ASSERT(codec_status_.ok() && dispatching_);
708 3367 : const size_t nread = parser_->execute(slice, len);
709 3367 : if (!codec_status_.ok()) {
710 115 : return codec_status_;
711 115 : }
712 :
713 3252 : const ParserStatus status = parser_->getStatus();
714 3252 : if (status != ParserStatus::Ok && status != ParserStatus::Paused) {
715 2097 : absl::string_view error = Http1ResponseCodeDetails::get().HttpCodecError;
716 2097 : if (codec_settings_.use_balsa_parser_) {
717 961 : if (parser_->errorMessage() == "headers size exceeds limit" ||
718 961 : parser_->errorMessage() == "trailers size exceeds limit") {
719 0 : error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
720 0 : error = Http1ResponseCodeDetails::get().HeadersTooLarge;
721 961 : } else if (parser_->errorMessage() == "header value contains invalid chars") {
722 70 : error = Http1ResponseCodeDetails::get().InvalidCharacters;
723 70 : }
724 961 : }
725 2097 : RETURN_IF_ERROR(sendProtocolError(error));
726 : // Avoid overwriting the codec_status_ set in the callbacks.
727 2097 : ASSERT(codec_status_.ok());
728 2097 : codec_status_ =
729 2097 : codecProtocolError(absl::StrCat("http/1.1 protocol error: ", parser_->errorMessage()));
730 2097 : return codec_status_;
731 2097 : }
732 :
733 1155 : return nread;
734 3252 : }
735 :
736 1796 : CallbackResult ConnectionImpl::onMessageBegin() {
737 1796 : return setAndCheckCallbackStatus(onMessageBeginImpl());
738 1796 : }
739 :
740 1032 : CallbackResult ConnectionImpl::onUrl(const char* data, size_t length) {
741 1032 : return setAndCheckCallbackStatus(onUrlBase(data, length));
742 1032 : }
743 :
744 156 : CallbackResult ConnectionImpl::onStatus(const char* data, size_t length) {
745 156 : return setAndCheckCallbackStatus(onStatusBase(data, length));
746 156 : }
747 :
748 2616 : CallbackResult ConnectionImpl::onHeaderField(const char* data, size_t length) {
749 2616 : return setAndCheckCallbackStatus(onHeaderFieldImpl(data, length));
750 2616 : }
751 :
752 2591 : CallbackResult ConnectionImpl::onHeaderValue(const char* data, size_t length) {
753 2591 : return setAndCheckCallbackStatus(onHeaderValueImpl(data, length));
754 2591 : }
755 :
756 649 : CallbackResult ConnectionImpl::onHeadersComplete() {
757 649 : return setAndCheckCallbackStatusOr(onHeadersCompleteImpl());
758 649 : }
759 :
760 363 : void ConnectionImpl::bufferBody(const char* data, size_t length) {
761 363 : auto slice = current_dispatching_buffer_->frontSlice();
762 363 : if (data == slice.mem_ && length == slice.len_) {
763 1 : buffered_body_.move(*current_dispatching_buffer_, length);
764 1 : dispatching_slice_already_drained_ = true;
765 362 : } else {
766 362 : buffered_body_.add(data, length);
767 362 : }
768 363 : }
769 :
770 395 : CallbackResult ConnectionImpl::onMessageComplete() {
771 395 : return setAndCheckCallbackStatusOr(onMessageCompleteImpl());
772 395 : }
773 :
774 471 : void ConnectionImpl::onChunkHeader(bool is_final_chunk) {
775 471 : if (is_final_chunk) {
776 : // Dispatch body before parsing trailers, so body ends up dispatched even if an error is found
777 : // while processing trailers.
778 216 : dispatchBufferedBody();
779 216 : }
780 471 : }
781 :
782 2616 : Status ConnectionImpl::onHeaderFieldImpl(const char* data, size_t length) {
783 2616 : ASSERT(dispatching_);
784 :
785 2616 : getBytesMeter().addHeaderBytesReceived(length);
786 :
787 : // We previously already finished up the headers, these headers are
788 : // now trailers.
789 2616 : if (header_parsing_state_ == HeaderParsingState::Done) {
790 0 : if (!enableTrailers()) {
791 : // Ignore trailers.
792 0 : return okStatus();
793 0 : }
794 0 : processing_trailers_ = true;
795 0 : header_parsing_state_ = HeaderParsingState::Field;
796 0 : allocTrailers();
797 0 : }
798 2616 : if (header_parsing_state_ == HeaderParsingState::Value) {
799 1831 : RETURN_IF_ERROR(completeCurrentHeader());
800 1831 : }
801 :
802 2616 : current_header_field_.append(data, length);
803 :
804 2616 : return checkMaxHeadersSize();
805 2616 : }
806 :
807 2591 : Status ConnectionImpl::onHeaderValueImpl(const char* data, size_t length) {
808 2591 : ASSERT(dispatching_);
809 :
810 2591 : getBytesMeter().addHeaderBytesReceived(length);
811 :
812 2591 : if (header_parsing_state_ == HeaderParsingState::Done && !enableTrailers()) {
813 : // Ignore trailers.
814 0 : return okStatus();
815 0 : }
816 :
817 2591 : absl::string_view header_value{data, length};
818 2591 : if (!Http::HeaderUtility::headerValueIsValid(header_value)) {
819 2 : ENVOY_CONN_LOG(debug, "invalid header value: {}", connection_, header_value);
820 2 : error_code_ = Http::Code::BadRequest;
821 2 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidCharacters));
822 2 : return codecProtocolError("http/1.1 protocol error: header value contains invalid chars");
823 2 : }
824 :
825 2589 : header_parsing_state_ = HeaderParsingState::Value;
826 2589 : if (current_header_value_.empty()) {
827 : // Strip leading whitespace if the current header value input contains the first bytes of the
828 : // encoded header value. Trailing whitespace is stripped once the full header value is known in
829 : // ConnectionImpl::completeCurrentHeader. http_parser does not strip leading or trailing
830 : // whitespace as the spec requires: https://tools.ietf.org/html/rfc7230#section-3.2.4 .
831 2584 : header_value = StringUtil::ltrim(header_value);
832 2584 : }
833 2589 : current_header_value_.append(header_value.data(), header_value.length());
834 :
835 2589 : return checkMaxHeadersSize();
836 2591 : }
837 :
838 649 : StatusOr<CallbackResult> ConnectionImpl::onHeadersCompleteImpl() {
839 649 : ASSERT(!processing_trailers_);
840 649 : ASSERT(dispatching_);
841 649 : ENVOY_CONN_LOG(trace, "onHeadersCompleteImpl", connection_);
842 649 : RETURN_IF_ERROR(completeCurrentHeader());
843 :
844 649 : if (!parser_->isHttp11()) {
845 : // This is not necessarily true, but it's good enough since higher layers only care if this is
846 : // HTTP/1.1 or not.
847 101 : protocol_ = Protocol::Http10;
848 101 : }
849 649 : RequestOrResponseHeaderMap& request_or_response_headers = requestOrResponseHeaders();
850 649 : const Http::HeaderValues& header_values = Http::Headers::get();
851 649 : if (Utility::isUpgrade(request_or_response_headers) && upgradeAllowed()) {
852 : // Ignore h2c upgrade requests until we support them.
853 : // See https://github.com/envoyproxy/envoy/issues/7161 for details.
854 2 : if (absl::EqualsIgnoreCase(request_or_response_headers.getUpgradeValue(),
855 2 : header_values.UpgradeValues.H2c)) {
856 0 : ENVOY_CONN_LOG(trace, "removing unsupported h2c upgrade headers.", connection_);
857 0 : request_or_response_headers.removeUpgrade();
858 0 : if (request_or_response_headers.Connection()) {
859 0 : const auto& tokens_to_remove = caseUnorderdSetContainingUpgradeAndHttp2Settings();
860 0 : std::string new_value = StringUtil::removeTokens(
861 0 : request_or_response_headers.getConnectionValue(), ",", tokens_to_remove, ",");
862 0 : if (new_value.empty()) {
863 0 : request_or_response_headers.removeConnection();
864 0 : } else {
865 0 : request_or_response_headers.setConnection(new_value);
866 0 : }
867 0 : }
868 0 : request_or_response_headers.remove(header_values.Http2Settings);
869 2 : } else {
870 2 : ENVOY_CONN_LOG(trace, "codec entering upgrade mode.", connection_);
871 2 : handling_upgrade_ = true;
872 2 : }
873 2 : }
874 649 : if (parser_->methodName() == header_values.MethodValues.Connect) {
875 46 : if (request_or_response_headers.ContentLength()) {
876 2 : if (request_or_response_headers.getContentLengthValue() == "0") {
877 0 : request_or_response_headers.removeContentLength();
878 2 : } else {
879 : // Per https://tools.ietf.org/html/rfc7231#section-4.3.6 a payload with a
880 : // CONNECT request has no defined semantics, and may be rejected.
881 2 : error_code_ = Http::Code::BadRequest;
882 2 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().BodyDisallowed));
883 2 : return codecProtocolError("http/1.1 protocol error: unsupported content length");
884 2 : }
885 2 : }
886 44 : ENVOY_CONN_LOG(trace, "codec entering upgrade mode for CONNECT request.", connection_);
887 44 : handling_upgrade_ = true;
888 44 : }
889 :
890 : // https://tools.ietf.org/html/rfc7230#section-3.3.3
891 : // If a message is received with both a Transfer-Encoding and a
892 : // Content-Length header field, the Transfer-Encoding overrides the
893 : // Content-Length. Such a message might indicate an attempt to
894 : // perform request smuggling (Section 9.5) or response splitting
895 : // (Section 9.4) and ought to be handled as an error. A sender MUST
896 : // remove the received Content-Length field prior to forwarding such
897 : // a message.
898 :
899 647 : #ifndef ENVOY_ENABLE_UHV
900 : // This check is moved into default header validator.
901 : // TODO(yanavlasov): use runtime override here when UHV is moved into the main build
902 :
903 : // Reject message with Http::Code::BadRequest if both Transfer-Encoding and Content-Length
904 : // headers are present or if allowed by http1 codec settings and 'Transfer-Encoding'
905 : // is chunked - remove Content-Length and serve request.
906 647 : if (parser_->hasTransferEncoding() != 0 && request_or_response_headers.ContentLength()) {
907 8 : if (parser_->isChunked() && codec_settings_.allow_chunked_length_) {
908 0 : request_or_response_headers.removeContentLength();
909 8 : } else {
910 8 : error_code_ = Http::Code::BadRequest;
911 8 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().ChunkedContentLength));
912 8 : return codecProtocolError(
913 8 : "http/1.1 protocol error: both 'Content-Length' and 'Transfer-Encoding' are set.");
914 8 : }
915 8 : }
916 :
917 : // Per https://tools.ietf.org/html/rfc7230#section-3.3.1 Envoy should reject
918 : // transfer-codings it does not understand.
919 : // Per https://tools.ietf.org/html/rfc7231#section-4.3.6 a payload with a
920 : // CONNECT request has no defined semantics, and may be rejected.
921 639 : if (request_or_response_headers.TransferEncoding()) {
922 412 : const absl::string_view encoding = request_or_response_headers.getTransferEncodingValue();
923 412 : if (!absl::EqualsIgnoreCase(encoding, header_values.TransferEncodingValues.Chunked) ||
924 412 : parser_->methodName() == header_values.MethodValues.Connect) {
925 47 : error_code_ = Http::Code::NotImplemented;
926 47 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidTransferEncoding));
927 47 : return codecProtocolError("http/1.1 protocol error: unsupported transfer encoding");
928 47 : }
929 412 : }
930 592 : #endif
931 :
932 592 : auto statusor = onHeadersCompleteBase();
933 592 : if (!statusor.ok()) {
934 56 : RETURN_IF_ERROR(statusor.status());
935 56 : }
936 :
937 536 : header_parsing_state_ = HeaderParsingState::Done;
938 :
939 : // Returning CallbackResult::NoBodyData informs http_parser to not expect a body or further data
940 : // on this connection.
941 536 : return handling_upgrade_ ? CallbackResult::NoBodyData : statusor.value();
942 592 : }
943 :
944 395 : StatusOr<CallbackResult> ConnectionImpl::onMessageCompleteImpl() {
945 395 : ENVOY_CONN_LOG(trace, "message complete", connection_);
946 :
947 395 : dispatchBufferedBody();
948 :
949 395 : if (handling_upgrade_) {
950 : // If this is an upgrade request, swallow the onMessageComplete. The
951 : // upgrade payload will be treated as stream body.
952 2 : ASSERT(!deferred_end_stream_headers_);
953 2 : ENVOY_CONN_LOG(trace, "Pausing parser due to upgrade.", connection_);
954 2 : return parser_->pause();
955 2 : }
956 :
957 : // If true, this indicates we were processing trailers and must
958 : // move the last header into current_header_map_
959 393 : if (header_parsing_state_ == HeaderParsingState::Value) {
960 0 : RETURN_IF_ERROR(completeCurrentHeader());
961 0 : }
962 :
963 393 : return onMessageCompleteBase();
964 393 : }
965 :
966 1354 : void ConnectionImpl::dispatchBufferedBody() {
967 1354 : ASSERT(parser_->getStatus() == ParserStatus::Ok || parser_->getStatus() == ParserStatus::Paused);
968 1354 : ASSERT(codec_status_.ok());
969 1354 : if (buffered_body_.length() > 0) {
970 265 : onBody(buffered_body_);
971 265 : buffered_body_.drain(buffered_body_.length());
972 265 : }
973 1354 : }
974 :
975 247 : void ConnectionImpl::onResetStreamBase(StreamResetReason reason) {
976 247 : ASSERT(!reset_stream_called_);
977 247 : reset_stream_called_ = true;
978 247 : onResetStream(reason);
979 247 : }
980 :
981 0 : void ConnectionImpl::dumpState(std::ostream& os, int indent_level) const {
982 0 : const char* spaces = spacesForLevel(indent_level);
983 0 : os << spaces << "Http1::ConnectionImpl " << this << DUMP_MEMBER(dispatching_)
984 0 : << DUMP_MEMBER(dispatching_slice_already_drained_) << DUMP_MEMBER(reset_stream_called_)
985 0 : << DUMP_MEMBER(handling_upgrade_) << DUMP_MEMBER(deferred_end_stream_headers_)
986 0 : << DUMP_MEMBER(processing_trailers_) << DUMP_MEMBER(buffered_body_.length());
987 :
988 : // Dump header parsing state, and any progress on headers.
989 0 : os << DUMP_MEMBER(header_parsing_state_);
990 0 : os << DUMP_MEMBER_AS(current_header_field_, current_header_field_.getStringView());
991 0 : os << DUMP_MEMBER_AS(current_header_value_, current_header_value_.getStringView());
992 :
993 : // Dump Child
994 0 : os << '\n';
995 0 : dumpAdditionalState(os, indent_level);
996 :
997 : // Dump the first slice of the dispatching buffer if not drained escaping
998 : // certain characters. We do this last as the slice could be rather large.
999 0 : if (current_dispatching_buffer_ == nullptr || dispatching_slice_already_drained_) {
1000 : // Buffer is either null or already drained (in the body).
1001 : // Use the macro for consistent formatting.
1002 0 : os << DUMP_NULLABLE_MEMBER(current_dispatching_buffer_, "drained");
1003 0 : return;
1004 0 : } else {
1005 0 : absl::string_view front_slice = [](Buffer::RawSlice slice) {
1006 0 : return absl::string_view(static_cast<const char*>(slice.mem_), slice.len_);
1007 0 : }(current_dispatching_buffer_->frontSlice());
1008 :
1009 : // Dump buffer data escaping \r, \n, \t, ", ', and \.
1010 : // This is not the most performant implementation, but we're crashing and
1011 : // cannot allocate memory.
1012 0 : os << spaces << "current_dispatching_buffer_ front_slice length: " << front_slice.length()
1013 0 : << " contents: \"";
1014 0 : StringUtil::escapeToOstream(os, front_slice);
1015 0 : os << "\"\n";
1016 0 : }
1017 0 : }
1018 :
1019 0 : void ServerConnectionImpl::dumpAdditionalState(std::ostream& os, int indent_level) const {
1020 0 : const char* spaces = spacesForLevel(indent_level);
1021 :
1022 0 : DUMP_DETAILS(active_request_);
1023 0 : os << '\n';
1024 :
1025 : // Dump header map, it may be null if it was moved to the request, and
1026 : // request_url.
1027 0 : if (absl::holds_alternative<RequestHeaderMapPtr>(headers_or_trailers_)) {
1028 0 : DUMP_DETAILS(absl::get<RequestHeaderMapPtr>(headers_or_trailers_));
1029 0 : } else {
1030 0 : DUMP_DETAILS(absl::get<RequestTrailerMapPtr>(headers_or_trailers_));
1031 0 : }
1032 0 : }
1033 :
1034 0 : void ClientConnectionImpl::dumpAdditionalState(std::ostream& os, int indent_level) const {
1035 0 : const char* spaces = spacesForLevel(indent_level);
1036 : // Dump header map, it may be null if it was moved to the request.
1037 0 : if (absl::holds_alternative<ResponseHeaderMapPtr>(headers_or_trailers_)) {
1038 0 : DUMP_DETAILS(absl::get<ResponseHeaderMapPtr>(headers_or_trailers_));
1039 0 : } else {
1040 0 : DUMP_DETAILS(absl::get<ResponseTrailerMapPtr>(headers_or_trailers_));
1041 0 : }
1042 :
1043 : // Dump the associated request.
1044 0 : os << spaces << "Dumping corresponding downstream request:";
1045 0 : if (pending_response_.has_value()) {
1046 0 : os << '\n';
1047 0 : const ResponseDecoder* decoder = pending_response_.value().decoder_;
1048 0 : DUMP_DETAILS(decoder);
1049 0 : } else {
1050 0 : os << " null\n";
1051 0 : }
1052 0 : }
1053 :
1054 : ServerConnectionImpl::ServerConnectionImpl(
1055 : Network::Connection& connection, CodecStats& stats, ServerConnectionCallbacks& callbacks,
1056 : const Http1Settings& settings, uint32_t max_request_headers_kb,
1057 : const uint32_t max_request_headers_count,
1058 : envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction
1059 : headers_with_underscores_action,
1060 : Server::OverloadManager& overload_manager)
1061 : : ConnectionImpl(connection, stats, settings, MessageType::Request, max_request_headers_kb,
1062 : max_request_headers_count),
1063 : callbacks_(callbacks),
1064 367 : response_buffer_releasor_([this](const Buffer::OwnedBufferFragmentImpl* fragment) {
1065 367 : releaseOutboundResponse(fragment);
1066 367 : }),
1067 : owned_output_buffer_(connection.dispatcher().getWatermarkFactory().createBuffer(
1068 0 : [&]() -> void { this->onBelowLowWatermark(); },
1069 0 : [&]() -> void { this->onAboveHighWatermark(); },
1070 0 : []() -> void { /* TODO(adisuissa): handle overflow watermark */ })),
1071 : headers_with_underscores_action_(headers_with_underscores_action),
1072 : abort_dispatch_(
1073 1670 : overload_manager.getLoadShedPoint("envoy.load_shed_points.http1_server_abort_dispatch")) {
1074 1670 : ENVOY_LOG_ONCE_IF(trace, abort_dispatch_ == nullptr,
1075 1670 : "LoadShedPoint envoy.load_shed_points.http1_server_abort_dispatch is not "
1076 1670 : "found. Is it configured?");
1077 1670 : owned_output_buffer_->setWatermarks(connection.bufferLimit());
1078 : // Inform parent
1079 1670 : output_buffer_ = owned_output_buffer_.get();
1080 1670 : }
1081 :
1082 4959 : uint32_t ServerConnectionImpl::getHeadersSize() {
1083 : // Add in the size of the request URL if processing request headers.
1084 4959 : const uint32_t url_size =
1085 4959 : (!processing_trailers_ && active_request_) ? active_request_->request_url_.size() : 0;
1086 4959 : return url_size + ConnectionImpl::getHeadersSize();
1087 4959 : }
1088 :
1089 367 : void ServerConnectionImpl::onEncodeComplete() {
1090 367 : if (active_request_->remote_complete_) {
1091 : // Only do this if remote is complete. If we are replying before the request is complete the
1092 : // only logical thing to do is for higher level code to reset() / close the connection so we
1093 : // leave the request around so that it can fire reset callbacks.
1094 155 : connection_.dispatcher().deferredDelete(std::move(active_request_));
1095 155 : }
1096 367 : }
1097 :
1098 436 : Status ServerConnectionImpl::handlePath(RequestHeaderMap& headers, absl::string_view method) {
1099 436 : const Http::HeaderValues& header_values = Http::Headers::get();
1100 436 : HeaderString path(header_values.Path);
1101 :
1102 436 : bool is_connect = (method == header_values.MethodValues.Connect);
1103 :
1104 : // The url is relative or a wildcard when the method is OPTIONS. Nothing to do here.
1105 436 : if (!is_connect && !active_request_->request_url_.getStringView().empty() &&
1106 436 : (active_request_->request_url_.getStringView()[0] == '/' ||
1107 409 : (method == header_values.MethodValues.Options &&
1108 402 : active_request_->request_url_.getStringView()[0] == '*'))) {
1109 402 : headers.addViaMove(std::move(path), std::move(active_request_->request_url_));
1110 402 : return okStatus();
1111 402 : }
1112 :
1113 : // If absolute_urls and/or connect are not going be handled, copy the url and return.
1114 : // This forces the behavior to be backwards compatible with the old codec behavior.
1115 : // CONNECT "urls" are actually host:port so look like absolute URLs to the above checks.
1116 : // Absolute URLS in CONNECT requests will be rejected below by the URL class validation.
1117 :
1118 : /**
1119 : * @param scheme the scheme to validate
1120 : * @return bool true if the scheme is http.
1121 : */
1122 34 : if (!codec_settings_.allow_absolute_url_ && !is_connect) {
1123 5 : headers.addViaMove(std::move(path), std::move(active_request_->request_url_));
1124 5 : return okStatus();
1125 5 : }
1126 :
1127 29 : Utility::Url absolute_url;
1128 29 : if (!absolute_url.initialize(active_request_->request_url_.getStringView(), is_connect)) {
1129 28 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidUrl));
1130 28 : return codecProtocolError("http/1.1 protocol error: invalid url in request line");
1131 28 : }
1132 : // RFC7230#5.7
1133 : // When a proxy receives a request with an absolute-form of
1134 : // request-target, the proxy MUST ignore the received Host header field
1135 : // (if any) and instead replace it with the host information of the
1136 : // request-target. A proxy that forwards such a request MUST generate a
1137 : // new Host field-value based on the received request-target rather than
1138 : // forward the received Host field-value.
1139 1 : headers.setHost(absolute_url.hostAndPort());
1140 : // Add the scheme and validate to ensure no https://
1141 : // requests are accepted over unencrypted connections by front-line Envoys.
1142 1 : if (!is_connect) {
1143 1 : if (Runtime::runtimeFeatureEnabled(
1144 1 : "envoy.reloadable_features.allow_absolute_url_with_mixed_scheme")) {
1145 1 : headers.setScheme(absl::AsciiStrToLower(absolute_url.scheme()));
1146 1 : } else {
1147 0 : headers.setScheme(absolute_url.scheme());
1148 0 : }
1149 1 : if (!Utility::schemeIsValid(headers.getSchemeValue())) {
1150 0 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidScheme));
1151 0 : return codecProtocolError("http/1.1 protocol error: invalid scheme");
1152 0 : }
1153 1 : if (codec_settings_.validate_scheme_ && Utility::schemeIsHttps(absolute_url.scheme()) &&
1154 1 : !connection().ssl()) {
1155 0 : error_code_ = Http::Code::Forbidden;
1156 0 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().HttpsInPlaintext));
1157 0 : return codecProtocolError("http/1.1 protocol error: https in the clear");
1158 0 : }
1159 1 : }
1160 :
1161 1 : if (!absolute_url.pathAndQueryParams().empty()) {
1162 1 : headers.setPath(absolute_url.pathAndQueryParams());
1163 1 : }
1164 1 : active_request_->request_url_.clear();
1165 1 : return okStatus();
1166 1 : }
1167 :
1168 408 : Status ServerConnectionImpl::checkProtocolVersion(RequestHeaderMap& headers) {
1169 408 : if (protocol() == Protocol::Http10) {
1170 : // Assume this is HTTP/1.0. This is fine for HTTP/0.9 but this code will also affect any
1171 : // requests with non-standard version numbers (0.9, 1.3), basically anything which is not
1172 : // HTTP/1.1.
1173 : //
1174 : // The protocol may have shifted in the HTTP/1.0 case so reset it.
1175 44 : if (!codec_settings_.accept_http_10_) {
1176 : // Send "Upgrade Required" if HTTP/1.0 support is not explicitly configured on.
1177 19 : error_code_ = Http::Code::UpgradeRequired;
1178 19 : RETURN_IF_ERROR(sendProtocolError(StreamInfo::ResponseCodeDetails::get().LowVersion));
1179 19 : return codecProtocolError("Upgrade required for HTTP/1.0 or HTTP/0.9");
1180 19 : }
1181 25 : if (!headers.Host() && !codec_settings_.default_host_for_http_10_.empty()) {
1182 : // Add a default host if configured to do so.
1183 24 : headers.setHost(codec_settings_.default_host_for_http_10_);
1184 24 : }
1185 25 : }
1186 389 : return okStatus();
1187 408 : }
1188 :
1189 436 : Envoy::StatusOr<CallbackResult> ServerConnectionImpl::onHeadersCompleteBase() {
1190 : // Handle the case where response happens prior to request complete. It's up to upper layer code
1191 : // to disconnect the connection but we shouldn't fire any more events since it doesn't make
1192 : // sense.
1193 436 : if (active_request_) {
1194 436 : auto& headers = absl::get<RequestHeaderMapPtr>(headers_or_trailers_);
1195 436 : ENVOY_CONN_LOG(trace, "Server: onHeadersComplete size={}", connection_, headers->size());
1196 :
1197 436 : if (!handling_upgrade_ && headers->Connection()) {
1198 : // If we fail to sanitize the request, return a 400 to the client
1199 2 : if (!Utility::sanitizeConnectionHeader(*headers)) {
1200 0 : absl::string_view header_value = headers->getConnectionValue();
1201 0 : ENVOY_CONN_LOG(debug, "Invalid nominated headers in Connection: {}", connection_,
1202 0 : header_value);
1203 0 : error_code_ = Http::Code::BadRequest;
1204 0 : RETURN_IF_ERROR(
1205 0 : sendProtocolError(Http1ResponseCodeDetails::get().ConnectionHeaderSanitization));
1206 0 : return codecProtocolError("Invalid nominated headers in Connection.");
1207 0 : }
1208 2 : }
1209 :
1210 : // Inform the response encoder about any HEAD method, so it can set content
1211 : // length and transfer encoding headers correctly.
1212 436 : const Http::HeaderValues& header_values = Http::Headers::get();
1213 436 : active_request_->response_encoder_.setIsResponseToHeadRequest(parser_->methodName() ==
1214 436 : header_values.MethodValues.Head);
1215 436 : active_request_->response_encoder_.setIsResponseToConnectRequest(
1216 436 : parser_->methodName() == header_values.MethodValues.Connect);
1217 :
1218 436 : RETURN_IF_ERROR(handlePath(*headers, parser_->methodName()));
1219 408 : ASSERT(active_request_->request_url_.empty());
1220 :
1221 408 : headers->setMethod(parser_->methodName());
1222 408 : RETURN_IF_ERROR(checkProtocolVersion(*headers));
1223 :
1224 : // Make sure the host is valid.
1225 389 : auto details = HeaderUtility::requestHeadersValid(*headers);
1226 389 : if (details.has_value()) {
1227 1 : RETURN_IF_ERROR(sendProtocolError(details.value().get()));
1228 1 : return codecProtocolError(
1229 1 : "http/1.1 protocol error: request headers failed spec compliance checks");
1230 1 : }
1231 :
1232 : // Determine here whether we have a body or not. This uses the new RFC semantics where the
1233 : // presence of content-length or chunked transfer-encoding indicates a body vs. a particular
1234 : // method. If there is no body, we defer raising decodeHeaders() until the parser is flushed
1235 : // with message complete. This allows upper layers to behave like HTTP/2 and prevents a proxy
1236 : // scenario where the higher layers stream through and implicitly switch to chunked transfer
1237 : // encoding because end stream with zero body length has not yet been indicated.
1238 388 : if (parser_->isChunked() ||
1239 388 : (parser_->contentLength().has_value() && parser_->contentLength().value() > 0) ||
1240 388 : handling_upgrade_) {
1241 232 : active_request_->request_decoder_->decodeHeaders(std::move(headers), false);
1242 :
1243 : // If the connection has been closed (or is closing) after decoding headers, pause the parser
1244 : // so we return control to the caller.
1245 232 : if (connection_.state() != Network::Connection::State::Open) {
1246 117 : return parser_->pause();
1247 117 : }
1248 343 : } else {
1249 156 : deferred_end_stream_headers_ = true;
1250 156 : }
1251 388 : }
1252 :
1253 271 : return CallbackResult::Success;
1254 436 : }
1255 :
1256 1642 : Status ServerConnectionImpl::onMessageBeginBase() {
1257 1642 : if (!resetStreamCalled()) {
1258 1642 : ASSERT(active_request_ == nullptr);
1259 1642 : active_request_ = std::make_unique<ActiveRequest>(*this, std::move(bytes_meter_before_stream_));
1260 1642 : active_request_->request_decoder_ = &callbacks_.newStream(active_request_->response_encoder_);
1261 :
1262 : // Check for pipelined request flood as we prepare to accept a new request.
1263 : // Parse errors that happen prior to onMessageBegin result in stream termination, it is not
1264 : // possible to overflow output buffers with early parse errors.
1265 1642 : RETURN_IF_ERROR(doFloodProtectionChecks());
1266 1642 : }
1267 1642 : return okStatus();
1268 1642 : }
1269 :
1270 1032 : Status ServerConnectionImpl::onUrlBase(const char* data, size_t length) {
1271 1032 : if (active_request_) {
1272 1032 : active_request_->request_url_.append(data, length);
1273 :
1274 1032 : RETURN_IF_ERROR(checkMaxHeadersSize());
1275 1032 : }
1276 :
1277 1032 : return okStatus();
1278 1032 : }
1279 :
1280 129 : void ServerConnectionImpl::onBody(Buffer::Instance& data) {
1281 129 : ASSERT(!deferred_end_stream_headers_);
1282 129 : if (active_request_) {
1283 129 : ENVOY_CONN_LOG(trace, "body size={}", connection_, data.length());
1284 129 : active_request_->request_decoder_->decodeData(data, false);
1285 129 : }
1286 129 : }
1287 :
1288 1729 : Http::Status ServerConnectionImpl::dispatch(Buffer::Instance& data) {
1289 1729 : if (abort_dispatch_ != nullptr && abort_dispatch_->shouldShedLoad()) {
1290 0 : RETURN_IF_ERROR(sendOverloadError());
1291 0 : return envoyOverloadError("Aborting Server Dispatch");
1292 0 : }
1293 :
1294 1729 : if (active_request_ != nullptr && active_request_->remote_complete_) {
1295 : // Eagerly read disable the connection if the downstream is sending pipelined requests as we
1296 : // serially process them. Reading from the connection will be re-enabled after the active
1297 : // request is completed.
1298 1 : active_request_->response_encoder_.readDisable(true);
1299 1 : return okStatus();
1300 1 : }
1301 :
1302 1728 : Http::Status status = ConnectionImpl::dispatch(data);
1303 :
1304 1728 : if (active_request_ != nullptr && active_request_->remote_complete_) {
1305 : // Read disable the connection if the downstream is sending additional data while we are working
1306 : // on an existing request. Reading from the connection will be re-enabled after the active
1307 : // request is completed.
1308 130 : if (data.length() > 0) {
1309 62 : active_request_->response_encoder_.readDisable(true);
1310 62 : }
1311 130 : }
1312 1728 : return status;
1313 1729 : }
1314 :
1315 247 : CallbackResult ServerConnectionImpl::onMessageCompleteBase() {
1316 247 : ASSERT(!handling_upgrade_);
1317 247 : if (active_request_) {
1318 :
1319 : // The request_decoder should be non-null after we've called the newStream on callbacks.
1320 247 : ASSERT(active_request_->request_decoder_);
1321 247 : active_request_->remote_complete_ = true;
1322 :
1323 247 : if (deferred_end_stream_headers_) {
1324 156 : active_request_->request_decoder_->decodeHeaders(
1325 156 : std::move(absl::get<RequestHeaderMapPtr>(headers_or_trailers_)), true);
1326 156 : deferred_end_stream_headers_ = false;
1327 220 : } else if (processing_trailers_) {
1328 0 : active_request_->request_decoder_->decodeTrailers(
1329 0 : std::move(absl::get<RequestTrailerMapPtr>(headers_or_trailers_)));
1330 91 : } else {
1331 91 : Buffer::OwnedImpl buffer;
1332 91 : active_request_->request_decoder_->decodeData(buffer, true);
1333 91 : }
1334 :
1335 : // Reset to ensure no information from one requests persists to the next.
1336 247 : headers_or_trailers_.emplace<RequestHeaderMapPtr>(nullptr);
1337 247 : }
1338 :
1339 : // Always pause the parser so that the calling code can process 1 request at a time and apply
1340 : // back pressure. However this means that the calling code needs to detect if there is more data
1341 : // in the buffer and dispatch it again.
1342 247 : return parser_->pause();
1343 247 : }
1344 :
1345 215 : void ServerConnectionImpl::onResetStream(StreamResetReason reason) {
1346 215 : if (active_request_) {
1347 213 : active_request_->response_encoder_.runResetCallbacks(reason);
1348 213 : connection_.dispatcher().deferredDelete(std::move(active_request_));
1349 213 : }
1350 215 : }
1351 :
1352 0 : Status ServerConnectionImpl::sendOverloadError() {
1353 0 : const bool latched_dispatching = dispatching_;
1354 :
1355 : // The codec might be in the early stages of server dispatching where this isn't yet
1356 : // flipped to true.
1357 0 : dispatching_ = true;
1358 0 : error_code_ = Http::Code::InternalServerError;
1359 0 : auto status = sendProtocolError(Envoy::StreamInfo::ResponseCodeDetails::get().Overload);
1360 0 : dispatching_ = latched_dispatching;
1361 0 : return status;
1362 0 : }
1363 :
1364 1116 : Status ServerConnectionImpl::sendProtocolError(absl::string_view details) {
1365 : // We do this here because we may get a protocol error before we have a logical stream.
1366 1116 : if (active_request_ == nullptr) {
1367 179 : RETURN_IF_ERROR(onMessageBeginImpl());
1368 179 : }
1369 1116 : ASSERT(active_request_);
1370 :
1371 1116 : active_request_->response_encoder_.setDetails(details);
1372 1116 : if (!active_request_->response_encoder_.startedResponse()) {
1373 1116 : active_request_->request_decoder_->sendLocalReply(
1374 1116 : error_code_, CodeUtility::toString(error_code_), nullptr, absl::nullopt, details);
1375 1116 : }
1376 1116 : return okStatus();
1377 1116 : }
1378 :
1379 0 : void ServerConnectionImpl::onAboveHighWatermark() {
1380 0 : if (active_request_) {
1381 0 : active_request_->response_encoder_.runHighWatermarkCallbacks();
1382 0 : }
1383 0 : }
1384 0 : void ServerConnectionImpl::onBelowLowWatermark() {
1385 0 : if (active_request_) {
1386 0 : active_request_->response_encoder_.runLowWatermarkCallbacks();
1387 0 : }
1388 0 : }
1389 :
1390 : void ServerConnectionImpl::releaseOutboundResponse(
1391 367 : const Buffer::OwnedBufferFragmentImpl* fragment) {
1392 367 : ASSERT(outbound_responses_ >= 1);
1393 367 : --outbound_responses_;
1394 367 : delete fragment;
1395 367 : }
1396 :
1397 1832 : Status ServerConnectionImpl::checkHeaderNameForUnderscores() {
1398 1832 : #ifndef ENVOY_ENABLE_UHV
1399 : // This check has been moved to UHV
1400 1832 : if (headers_with_underscores_action_ != envoy::config::core::v3::HttpProtocolOptions::ALLOW &&
1401 1832 : Http::HeaderUtility::headerNameContainsUnderscore(current_header_field_.getStringView())) {
1402 0 : if (headers_with_underscores_action_ ==
1403 0 : envoy::config::core::v3::HttpProtocolOptions::DROP_HEADER) {
1404 0 : ENVOY_CONN_LOG(debug, "Dropping header with invalid characters in its name: {}", connection_,
1405 0 : current_header_field_.getStringView());
1406 0 : stats_.incDroppedHeadersWithUnderscores();
1407 0 : current_header_field_.clear();
1408 0 : current_header_value_.clear();
1409 0 : } else {
1410 0 : ENVOY_CONN_LOG(debug, "Rejecting request due to header name with underscores: {}",
1411 0 : connection_, current_header_field_.getStringView());
1412 0 : error_code_ = Http::Code::BadRequest;
1413 0 : RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidUnderscore));
1414 0 : stats_.incRequestsRejectedWithUnderscoresInHeaders();
1415 0 : return codecProtocolError("http/1.1 protocol error: header name contains underscores");
1416 0 : }
1417 0 : }
1418 : #else
1419 : // Workaround for gcc not understanding [[maybe_unused]] for class members.
1420 : (void)headers_with_underscores_action_;
1421 : #endif
1422 1832 : return okStatus();
1423 1832 : }
1424 :
1425 0 : void ServerConnectionImpl::ActiveRequest::dumpState(std::ostream& os, int indent_level) const {
1426 0 : (void)indent_level;
1427 0 : os << DUMP_MEMBER_AS(
1428 0 : request_url_, !request_url_.getStringView().empty() ? request_url_.getStringView() : "null");
1429 0 : os << DUMP_MEMBER(response_encoder_.local_end_stream_);
1430 0 : }
1431 :
1432 : ClientConnectionImpl::ClientConnectionImpl(Network::Connection& connection, CodecStats& stats,
1433 : ConnectionCallbacks&, const Http1Settings& settings,
1434 : const uint32_t max_response_headers_count,
1435 : bool passing_through_proxy)
1436 : : ConnectionImpl(connection, stats, settings, MessageType::Response, MAX_RESPONSE_HEADERS_KB,
1437 : max_response_headers_count),
1438 : owned_output_buffer_(connection.dispatcher().getWatermarkFactory().createBuffer(
1439 0 : [&]() -> void { this->onBelowLowWatermark(); },
1440 0 : [&]() -> void { this->onAboveHighWatermark(); },
1441 0 : []() -> void { /* TODO(adisuissa): handle overflow watermark */ })),
1442 1442 : passing_through_proxy_(passing_through_proxy) {
1443 1442 : owned_output_buffer_->setWatermarks(connection.bufferLimit());
1444 : // Inform parent
1445 1442 : output_buffer_ = owned_output_buffer_.get();
1446 1442 : }
1447 :
1448 291 : bool ClientConnectionImpl::cannotHaveBody() {
1449 291 : if (pending_response_.has_value() && pending_response_.value().encoder_.headRequest()) {
1450 2 : ASSERT(!pending_response_done_);
1451 2 : return true;
1452 289 : } else if (parser_->statusCode() == Http::Code::NoContent ||
1453 289 : parser_->statusCode() == Http::Code::NotModified ||
1454 289 : (parser_->statusCode() >= Http::Code::OK &&
1455 283 : (parser_->contentLength().has_value() && parser_->contentLength().value() == 0) &&
1456 283 : !parser_->isChunked())) {
1457 14 : return true;
1458 276 : } else {
1459 275 : return false;
1460 275 : }
1461 291 : }
1462 :
1463 220 : RequestEncoder& ClientConnectionImpl::newStream(ResponseDecoder& response_decoder) {
1464 : // If reads were disabled due to flow control, we expect reads to always be enabled again before
1465 : // reusing this connection. This is done when the response is received.
1466 220 : ASSERT(connection_.readEnabled());
1467 :
1468 220 : ASSERT(!pending_response_.has_value());
1469 220 : ASSERT(pending_response_done_);
1470 220 : pending_response_.emplace(*this, std::move(bytes_meter_before_stream_), &response_decoder);
1471 220 : pending_response_done_ = false;
1472 220 : return pending_response_.value().encoder_;
1473 220 : }
1474 :
1475 156 : Status ClientConnectionImpl::onStatusBase(const char* data, size_t length) {
1476 156 : auto& headers = absl::get<ResponseHeaderMapPtr>(headers_or_trailers_);
1477 156 : StatefulHeaderKeyFormatterOptRef formatter(headers->formatter());
1478 156 : if (formatter.has_value()) {
1479 0 : formatter->setReasonPhrase(absl::string_view(data, length));
1480 0 : }
1481 :
1482 156 : return okStatus();
1483 156 : }
1484 :
1485 156 : Envoy::StatusOr<CallbackResult> ClientConnectionImpl::onHeadersCompleteBase() {
1486 156 : ENVOY_CONN_LOG(trace, "status_code {}", connection_, enumToInt(parser_->statusCode()));
1487 :
1488 : // Handle the case where the client is closing a kept alive connection (by sending a 408
1489 : // with a 'Connection: close' header). In this case we just let response flush out followed
1490 : // by the remote close.
1491 156 : if (!pending_response_.has_value() && !resetStreamCalled()) {
1492 8 : return prematureResponseError("", parser_->statusCode());
1493 148 : } else if (pending_response_.has_value()) {
1494 148 : ASSERT(!pending_response_done_);
1495 148 : auto& headers = absl::get<ResponseHeaderMapPtr>(headers_or_trailers_);
1496 148 : ENVOY_CONN_LOG(trace, "Client: onHeadersComplete size={}", connection_, headers->size());
1497 148 : headers->setStatus(enumToInt(parser_->statusCode()));
1498 :
1499 148 : if (parser_->statusCode() >= Http::Code::OK &&
1500 148 : parser_->statusCode() < Http::Code::MultipleChoices &&
1501 148 : pending_response_.value().encoder_.connectRequest()) {
1502 0 : ENVOY_CONN_LOG(trace, "codec entering upgrade mode for CONNECT response.", connection_);
1503 0 : handling_upgrade_ = true;
1504 0 : }
1505 :
1506 148 : if (parser_->statusCode() < Http::Code::OK || parser_->statusCode() == Http::Code::NoContent) {
1507 8 : if (headers->TransferEncoding()) {
1508 0 : RETURN_IF_ERROR(
1509 0 : sendProtocolError(Http1ResponseCodeDetails::get().TransferEncodingNotAllowed));
1510 0 : return codecProtocolError(
1511 0 : "http/1.1 protocol error: transfer encoding not allowed in 1xx or 204");
1512 0 : }
1513 :
1514 8 : if (headers->ContentLength()) {
1515 : // Report a protocol error for non-zero Content-Length, but paper over zero Content-Length.
1516 0 : if (headers->ContentLength()->value().getStringView() != "0") {
1517 0 : RETURN_IF_ERROR(
1518 0 : sendProtocolError(Http1ResponseCodeDetails::get().ContentLengthNotAllowed));
1519 0 : return codecProtocolError(
1520 0 : "http/1.1 protocol error: content length not allowed in 1xx or 204");
1521 0 : }
1522 :
1523 0 : headers->removeContentLength();
1524 0 : }
1525 8 : }
1526 :
1527 148 : if (HeaderUtility::isSpecial1xx(*headers)) {
1528 5 : pending_response_.value().decoder_->decode1xxHeaders(std::move(headers));
1529 143 : } else if (cannotHaveBody() && !handling_upgrade_) {
1530 8 : deferred_end_stream_headers_ = true;
1531 139 : } else {
1532 135 : pending_response_.value().decoder_->decodeHeaders(std::move(headers), false);
1533 135 : }
1534 :
1535 : // http-parser treats 1xx headers as their own complete response. Swallow the spurious
1536 : // onMessageComplete and continue processing for purely informational headers.
1537 : // 101-SwitchingProtocols is exempt as all data after the header is proxied through after
1538 : // upgrading.
1539 148 : if (CodeUtility::is1xx(enumToInt(parser_->statusCode())) &&
1540 148 : parser_->statusCode() != Http::Code::SwitchingProtocols) {
1541 5 : ignore_message_complete_for_1xx_ = true;
1542 : // Reset to ensure no information from the 1xx headers is used for the response headers.
1543 5 : headers_or_trailers_.emplace<ResponseHeaderMapPtr>(nullptr);
1544 5 : }
1545 148 : }
1546 :
1547 : // Here we deal with cases where the response cannot have a body by returning
1548 : // CallbackResult::NoBody, but http_parser does not deal with it for us.
1549 148 : return cannotHaveBody() ? CallbackResult::NoBody : CallbackResult::Success;
1550 156 : }
1551 :
1552 1 : bool ClientConnectionImpl::upgradeAllowed() const {
1553 1 : if (pending_response_.has_value()) {
1554 1 : return pending_response_->encoder_.upgradeRequest();
1555 1 : }
1556 0 : return false;
1557 1 : }
1558 :
1559 140 : void ClientConnectionImpl::onBody(Buffer::Instance& data) {
1560 140 : ASSERT(!deferred_end_stream_headers_);
1561 140 : if (pending_response_.has_value()) {
1562 140 : ASSERT(!pending_response_done_);
1563 140 : pending_response_.value().decoder_->decodeData(data, false);
1564 140 : }
1565 140 : }
1566 :
1567 146 : CallbackResult ClientConnectionImpl::onMessageCompleteBase() {
1568 146 : ENVOY_CONN_LOG(trace, "message complete", connection_);
1569 146 : if (ignore_message_complete_for_1xx_) {
1570 5 : ignore_message_complete_for_1xx_ = false;
1571 5 : return CallbackResult::Success;
1572 5 : }
1573 141 : if (pending_response_.has_value()) {
1574 141 : ASSERT(!pending_response_done_);
1575 : // After calling decodeData() with end stream set to true, we should no longer be able to reset.
1576 141 : PendingResponse& response = pending_response_.value();
1577 : // Encoder is used as part of decode* calls later in this function so pending_response_ can not
1578 : // be reset just yet. Preserve the state in pending_response_done_ instead.
1579 141 : pending_response_done_ = true;
1580 :
1581 141 : if (deferred_end_stream_headers_) {
1582 8 : response.decoder_->decodeHeaders(
1583 8 : std::move(absl::get<ResponseHeaderMapPtr>(headers_or_trailers_)), true);
1584 8 : deferred_end_stream_headers_ = false;
1585 139 : } else if (processing_trailers_) {
1586 0 : response.decoder_->decodeTrailers(
1587 0 : std::move(absl::get<ResponseTrailerMapPtr>(headers_or_trailers_)));
1588 133 : } else {
1589 133 : Buffer::OwnedImpl buffer;
1590 133 : response.decoder_->decodeData(buffer, true);
1591 133 : }
1592 :
1593 : // Reset to ensure no information from one requests persists to the next.
1594 141 : pending_response_.reset();
1595 141 : headers_or_trailers_.emplace<ResponseHeaderMapPtr>(nullptr);
1596 141 : }
1597 :
1598 : // Pause the parser after a response is complete. Any remaining data indicates an error.
1599 141 : return parser_->pause();
1600 146 : }
1601 :
1602 32 : void ClientConnectionImpl::onResetStream(StreamResetReason reason) {
1603 : // Only raise reset if we did not already dispatch a complete response.
1604 32 : if (pending_response_.has_value() && !pending_response_done_) {
1605 32 : pending_response_.value().encoder_.runResetCallbacks(reason);
1606 32 : pending_response_done_ = true;
1607 32 : pending_response_.reset();
1608 32 : }
1609 32 : }
1610 :
1611 1088 : Status ClientConnectionImpl::sendProtocolError(absl::string_view details) {
1612 1088 : if (pending_response_.has_value()) {
1613 14 : ASSERT(!pending_response_done_);
1614 14 : pending_response_.value().encoder_.setDetails(details);
1615 14 : }
1616 1088 : return okStatus();
1617 1088 : }
1618 :
1619 0 : void ClientConnectionImpl::onAboveHighWatermark() {
1620 : // This should never happen without an active stream/request.
1621 0 : pending_response_.value().encoder_.runHighWatermarkCallbacks();
1622 0 : }
1623 :
1624 0 : void ClientConnectionImpl::onBelowLowWatermark() {
1625 : // This can get called without an active stream/request when the response completion causes us to
1626 : // close the connection, but in doing so go below low watermark.
1627 0 : if (pending_response_.has_value() && !pending_response_done_) {
1628 0 : pending_response_.value().encoder_.runLowWatermarkCallbacks();
1629 0 : }
1630 0 : }
1631 :
1632 : } // namespace Http1
1633 : } // namespace Http
1634 : } // namespace Envoy
|