Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/source/common/http/http1/codec_impl.cc
Line
Count
Source (jump to first uncovered line)
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
252
const StringUtil::CaseUnorderedSet& caseUnorderdSetContainingUpgradeAndHttp2Settings() {
69
252
  CONSTRUCT_ON_FIRST_USE(StringUtil::CaseUnorderedSet,
70
252
                         Http::Headers::get().ConnectionValues.Upgrade,
71
252
                         Http::Headers::get().ConnectionValues.Http2Settings);
72
252
}
73
74
56.4k
HeaderKeyFormatterConstPtr encodeOnlyFormatterFromSettings(const Http::Http1Settings& settings) {
75
56.4k
  if (settings.header_key_format_ == Http1Settings::HeaderKeyFormat::ProperCase) {
76
67
    return std::make_unique<ProperCaseHeaderKeyFormatter>();
77
67
  }
78
79
56.3k
  return nullptr;
80
56.4k
}
81
82
42.3k
StatefulHeaderKeyFormatterPtr statefulFormatterFromSettings(const Http::Http1Settings& settings) {
83
42.3k
  if (settings.header_key_format_ == Http1Settings::HeaderKeyFormat::StatefulFormatter) {
84
0
    return settings.stateful_header_key_formatter_->create();
85
0
  }
86
42.3k
  return nullptr;
87
42.3k
}
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
39.5k
      is_response_to_connect_request_(false), bytes_meter_(std::move(bytes_meter)) {
105
39.5k
  if (!bytes_meter_) {
106
11.6k
    bytes_meter_ = std::make_shared<StreamInfo::BytesMeter>();
107
11.6k
  }
108
39.5k
  if (connection_.connection().aboveHighWatermark()) {
109
0
    runHighWatermarkCallbacks();
110
0
  }
111
39.5k
}
Envoy::Http::Http1::StreamEncoderImpl::StreamEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&)
Line
Count
Source
104
39.5k
      is_response_to_connect_request_(false), bytes_meter_(std::move(bytes_meter)) {
105
39.5k
  if (!bytes_meter_) {
106
11.6k
    bytes_meter_ = std::make_shared<StreamInfo::BytesMeter>();
107
11.6k
  }
108
39.5k
  if (connection_.connection().aboveHighWatermark()) {
109
0
    runHighWatermarkCallbacks();
110
0
  }
111
39.5k
}
Unexecuted instantiation: Envoy::Http::Http1::StreamEncoderImpl::StreamEncoderImpl(Envoy::Http::Http1::ConnectionImpl&, std::__1::shared_ptr<Envoy::StreamInfo::BytesMeter>&&)
112
113
94.5k
void StreamEncoderImpl::encodeHeader(absl::string_view key, absl::string_view value) {
114
94.5k
  ASSERT(!key.empty());
115
116
94.5k
  const uint64_t header_size = connection_.buffer().addFragments({key, COLON_SPACE, value, CRLF});
117
118
94.5k
  bytes_meter_->addHeaderBytesSent(header_size);
119
94.5k
}
120
121
void StreamEncoderImpl::encodeFormattedHeader(absl::string_view key, absl::string_view value,
122
94.5k
                                              HeaderKeyFormatterOptConstRef formatter) {
123
94.5k
  if (formatter.has_value()) {
124
479
    encodeHeader(formatter->format(key), value);
125
94.1k
  } else {
126
94.1k
    encodeHeader(key, value);
127
94.1k
  }
128
94.5k
}
129
130
7.62k
void ResponseEncoderImpl::encode1xxHeaders(const ResponseHeaderMap& headers) {
131
7.62k
  ASSERT(HeaderUtility::isSpecial1xx(headers));
132
7.62k
  encodeHeaders(headers, false);
133
7.62k
  if (Runtime::runtimeFeatureEnabled(
134
7.62k
          "envoy.reloadable_features.http1_allow_codec_error_response_after_1xx_headers")) {
135
    // Don't consider 100-continue responses as the actual response.
136
7.62k
    started_response_ = false;
137
7.62k
  }
138
7.62k
}
139
140
void StreamEncoderImpl::encodeHeadersBase(const RequestOrResponseHeaderMap& headers,
141
                                          absl::optional<uint64_t> status, bool end_stream,
142
26.1k
                                          bool bodiless_request) {
143
26.1k
  HeaderKeyFormatterOptConstRef formatter(headers.formatter());
144
26.1k
  if (!formatter.has_value()) {
145
26.1k
    formatter = connection_.formatter();
146
26.1k
  }
147
148
26.1k
  const Http::HeaderValues& header_values = Http::Headers::get();
149
26.1k
  bool saw_content_length = false;
150
26.1k
  headers.iterate(
151
121k
      [this, &header_values, formatter](const HeaderEntry& header) -> HeaderMap::Iterate {
152
121k
        absl::string_view key_to_use = header.key().getStringView();
153
121k
        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
121k
        if (key_size_to_use > 1 && key_to_use[0] == ':' && key_to_use[1] == 'a') {
156
11.8k
          key_to_use = absl::string_view(header_values.HostLegacy.get());
157
11.8k
          key_size_to_use = header_values.HostLegacy.get().size();
158
11.8k
        }
159
160
        // Skip all headers starting with ':' that make it here.
161
121k
        if (key_to_use[0] == ':') {
162
41.1k
          return HeaderMap::Iterate::Continue;
163
41.1k
        }
164
165
80.8k
        encodeFormattedHeader(key_to_use, header.value().getStringView(), formatter);
166
167
80.8k
        return HeaderMap::Iterate::Continue;
168
121k
      });
169
170
26.1k
  if (headers.ContentLength()) {
171
1.74k
    saw_content_length = true;
172
1.74k
  }
173
174
26.1k
  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
26.1k
  if (saw_content_length || disable_chunk_encoding_) {
188
2.01k
    chunk_encoding_ = false;
189
24.1k
  } else {
190
24.1k
    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
7.61k
      chunk_encoding_ = false;
194
16.5k
    } 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
3
      chunk_encoding_ = false;
198
16.5k
    } 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
6.21k
      if (!status || (*status >= 200 && *status != 204)) {
206
6.21k
        if (!bodiless_request) {
207
3.44k
          encodeFormattedHeader(header_values.ContentLength.get(), "0", formatter);
208
3.44k
        }
209
6.21k
      }
210
6.21k
      chunk_encoding_ = false;
211
10.3k
    } else if (connection_.protocol() == Protocol::Http10) {
212
15
      chunk_encoding_ = false;
213
10.3k
    } 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
10.3k
      if (!is_response_to_connect_request_) {
217
10.3k
        encodeFormattedHeader(header_values.TransferEncoding.get(),
218
10.3k
                              header_values.TransferEncodingValues.Chunked, formatter);
219
10.3k
      }
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
10.3k
      chunk_encoding_ = !Utility::isUpgrade(headers) && !is_response_to_head_request_ &&
228
10.3k
                        !is_response_to_connect_request_;
229
10.3k
    }
230
24.1k
  }
231
232
26.1k
  connection_.buffer().add(CRLF);
233
234
26.1k
  if (end_stream) {
235
6.29k
    endEncode();
236
19.8k
  } else {
237
19.8k
    flushOutput();
238
19.8k
  }
239
26.1k
}
240
241
8.69k
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
8.69k
  if (data.length() > 0) {
245
8.30k
    if (chunk_encoding_) {
246
5.64k
      std::string chunk_header = absl::StrCat(absl::Hex(data.length()), CRLF);
247
5.64k
      connection_.buffer().add(std::move(chunk_header));
248
5.64k
    }
249
250
8.30k
    connection_.buffer().move(data);
251
252
8.30k
    if (chunk_encoding_) {
253
5.64k
      connection_.buffer().add(CRLF);
254
5.64k
    }
255
8.30k
  }
256
257
8.69k
  if (end_stream) {
258
3.74k
    endEncode();
259
4.95k
  } else {
260
4.95k
    flushOutput();
261
4.95k
  }
262
8.69k
}
263
264
37.3k
void StreamEncoderImpl::flushOutput(bool end_encode) {
265
37.3k
  auto encoded_bytes = connection_.flushOutput(end_encode);
266
37.3k
  bytes_meter_->addWireBytesSent(encoded_bytes);
267
37.3k
}
268
269
2.46k
void StreamEncoderImpl::encodeTrailersBase(const HeaderMap& trailers) {
270
2.46k
  if (!connection_.enableTrailers()) {
271
2.46k
    return endEncode();
272
2.46k
  }
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
182
void StreamEncoderImpl::encodeMetadata(const MetadataMapVector&) {
294
182
  connection_.stats().metadata_not_supported_error_.inc();
295
182
}
296
297
12.5k
void StreamEncoderImpl::endEncode() {
298
12.5k
  if (chunk_encoding_) {
299
5.26k
    connection_.buffer().addFragments({LAST_CHUNK, CRLF});
300
5.26k
  }
301
302
12.5k
  flushOutput(true);
303
12.5k
  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
12.5k
  if (connect_request_ || is_tcp_tunneling_) {
307
13
    connection_.connection().close(
308
13
        Network::ConnectionCloseType::FlushWrite,
309
13
        StreamInfo::LocalCloseReasons::get().CloseForConnectRequestOrTcpTunneling);
310
13
  }
311
12.5k
}
312
313
12.5k
void StreamEncoderImpl::notifyEncodeComplete() {
314
12.5k
  if (codec_callbacks_) {
315
3.58k
    codec_callbacks_->onCodecEncodeComplete();
316
3.58k
  }
317
12.5k
  connection_.onEncodeComplete();
318
12.5k
}
319
320
6.25k
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
6.25k
  auto fragment =
327
6.25k
      Buffer::OwnedBufferFragmentImpl::create(absl::string_view("", 0), response_buffer_releasor_);
328
6.25k
  output_buffer.addBufferFragment(*fragment.release());
329
6.25k
  ASSERT(outbound_responses_ < kMaxOutboundResponses);
330
6.25k
  outbound_responses_++;
331
6.25k
}
332
333
27.9k
Status ServerConnectionImpl::doFloodProtectionChecks() const {
334
27.9k
  ASSERT(dispatching_);
335
  // Before processing another request, make sure that we are below the response flood protection
336
  // threshold.
337
27.9k
  if (outbound_responses_ >= kMaxOutboundResponses) {
338
15
    ENVOY_CONN_LOG(trace, "error accepting request: too many pending responses queued",
339
15
                   connection_);
340
15
    stats_.response_flood_.inc();
341
15
    return bufferFloodError("Too many responses queued.");
342
15
  }
343
27.8k
  return okStatus();
344
27.9k
}
345
346
37.3k
uint64_t ConnectionImpl::flushOutput(bool end_encode) {
347
37.3k
  if (end_encode) {
348
    // If this is an HTTP response in ServerConnectionImpl, track outbound responses for flood
349
    // protection
350
12.5k
    maybeAddSentinelBufferFragment(*output_buffer_);
351
12.5k
  }
352
37.3k
  const uint64_t bytes_encoded = output_buffer_->length();
353
37.3k
  connection().write(*output_buffer_, false);
354
37.3k
  ASSERT(0UL == output_buffer_->length());
355
37.3k
  return bytes_encoded;
356
37.3k
}
357
358
CodecEventCallbacks*
359
7.75k
StreamEncoderImpl::registerCodecEventCallbacks(CodecEventCallbacks* codec_callbacks) {
360
7.75k
  std::swap(codec_callbacks, codec_callbacks_);
361
7.75k
  return codec_callbacks;
362
7.75k
}
363
364
1.84k
void StreamEncoderImpl::resetStream(StreamResetReason reason) {
365
1.84k
  connection_.onResetStreamBase(reason);
366
1.84k
}
367
368
1.32k
void ResponseEncoderImpl::resetStream(StreamResetReason reason) {
369
  // Clear the downstream on the account since we're resetting the downstream.
370
1.32k
  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
1.32k
  StreamEncoderImpl::resetStream(reason);
381
1.32k
}
382
383
8.63k
void StreamEncoderImpl::readDisable(bool disable) {
384
8.63k
  if (disable) {
385
4.31k
    ++read_disable_calls_;
386
4.31k
  } else {
387
4.31k
    ASSERT(read_disable_calls_ != 0);
388
4.31k
    if (read_disable_calls_ != 0) {
389
4.31k
      --read_disable_calls_;
390
4.31k
    }
391
4.31k
  }
392
8.63k
  connection_.readDisable(disable);
393
8.63k
}
394
395
3.87k
uint32_t StreamEncoderImpl::bufferLimit() const { return connection_.bufferLimit(); }
396
397
44
const Network::ConnectionInfoProvider& StreamEncoderImpl::connectionInfoProvider() {
398
44
  return connection_.connection().connectionInfoProvider();
399
44
}
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
14.7k
void ResponseEncoderImpl::encodeHeaders(const ResponseHeaderMap& headers, bool end_stream) {
405
14.7k
  started_response_ = true;
406
407
  // The contract is that client codecs must ensure that :status is present and valid.
408
14.7k
  ASSERT(headers.Status() != nullptr);
409
14.7k
  uint64_t numeric_status = Utility::getResponseStatus(headers);
410
411
14.7k
  absl::string_view response_prefix;
412
14.7k
  if (connection_.protocol() == Protocol::Http10 && connection_.supportsHttp10()) {
413
182
    response_prefix = HTTP_10_RESPONSE_PREFIX;
414
14.5k
  } else {
415
14.5k
    response_prefix = RESPONSE_PREFIX;
416
14.5k
  }
417
418
14.7k
  StatefulHeaderKeyFormatterOptConstRef formatter(headers.formatter());
419
420
14.7k
  absl::string_view reason_phrase;
421
14.7k
  if (formatter.has_value() && !formatter->getReasonPhrase().empty()) {
422
0
    reason_phrase = formatter->getReasonPhrase();
423
14.7k
  } else {
424
14.7k
    const char* status_string = CodeUtility::toString(static_cast<Code>(numeric_status));
425
14.7k
    uint32_t status_string_len = strlen(status_string);
426
14.7k
    reason_phrase = {status_string, status_string_len};
427
14.7k
  }
428
429
14.7k
  connection_.buffer().addFragments(
430
14.7k
      {response_prefix, absl::StrCat(numeric_status), SPACE, reason_phrase, CRLF});
431
432
14.7k
  if (numeric_status >= 300) {
433
    // Don't do special CONNECT logic if the CONNECT was rejected.
434
1.34k
    is_response_to_connect_request_ = false;
435
1.34k
  }
436
437
14.7k
  encodeHeadersBase(headers, absl::make_optional<uint64_t>(numeric_status), end_stream, false);
438
14.7k
}
439
440
static constexpr absl::string_view REQUEST_POSTFIX = " HTTP/1.1\r\n";
441
442
11.6k
Status RequestEncoderImpl::encodeHeaders(const RequestHeaderMap& headers, bool end_stream) {
443
11.6k
#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
11.6k
  RETURN_IF_ERROR(HeaderUtility::checkRequiredRequestHeaders(headers));
450
  // Verify that a filter hasn't added an invalid header key or value.
451
11.6k
  RETURN_IF_ERROR(HeaderUtility::checkValidRequestHeaders(headers));
452
11.4k
#endif
453
454
11.4k
  const HeaderEntry* method = headers.Method();
455
11.4k
  const HeaderEntry* path = headers.Path();
456
11.4k
  const HeaderEntry* host = headers.Host();
457
11.4k
  bool is_connect = HeaderUtility::isConnect(headers);
458
11.4k
  const Http::HeaderValues& header_values = Http::Headers::get();
459
460
11.4k
  if (method->value() == header_values.MethodValues.Head) {
461
141
    head_request_ = true;
462
11.3k
  } else if (method->value() == header_values.MethodValues.Connect) {
463
157
    disableChunkEncoding();
464
157
    connection_.connection().enableHalfClose(true);
465
157
    connect_request_ = true;
466
157
  }
467
11.4k
  if (Utility::isUpgrade(headers)) {
468
117
    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
117
    disableChunkEncoding();
474
117
  }
475
476
11.4k
  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
11.4k
  } else {
495
11.4k
    absl::string_view host_or_path_view;
496
11.4k
    if (is_connect) {
497
157
      host_or_path_view = host->value().getStringView();
498
11.3k
    } else {
499
11.3k
      host_or_path_view = path->value().getStringView();
500
11.3k
    }
501
502
11.4k
    connection_.buffer().addFragments(
503
11.4k
        {method->value().getStringView(), SPACE, host_or_path_view, REQUEST_POSTFIX});
504
11.4k
  }
505
506
11.4k
  encodeHeadersBase(headers, absl::nullopt, end_stream,
507
11.4k
                    HeaderUtility::requestShouldHaveNoBody(headers));
508
11.4k
  return okStatus();
509
11.4k
}
510
511
572k
CallbackResult ConnectionImpl::setAndCheckCallbackStatus(Status&& status) {
512
572k
  ASSERT(codec_status_.ok());
513
572k
  codec_status_ = std::move(status);
514
572k
  return codec_status_.ok() ? CallbackResult::Success : CallbackResult::Error;
515
572k
}
516
517
CallbackResult
518
48.2k
ConnectionImpl::setAndCheckCallbackStatusOr(Envoy::StatusOr<CallbackResult>&& statusor) {
519
48.2k
  ASSERT(codec_status_.ok());
520
48.2k
  if (statusor.ok()) {
521
42.4k
    return statusor.value();
522
42.4k
  } else {
523
5.82k
    codec_status_ = std::move(statusor.status());
524
5.82k
    return CallbackResult::Error;
525
5.82k
  }
526
48.2k
}
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
56.4k
      max_headers_count_(max_headers_count) {
536
56.4k
  if (codec_settings_.use_balsa_parser_) {
537
19.3k
    parser_ = std::make_unique<BalsaParser>(type, this, max_headers_kb_ * 1024, enableTrailers(),
538
19.3k
                                            codec_settings_.allow_custom_methods_);
539
37.1k
  } else {
540
37.1k
    parser_ = std::make_unique<LegacyHttpParserImpl>(type, this);
541
37.1k
  }
542
56.4k
}
543
544
239k
Status ConnectionImpl::completeCurrentHeader() {
545
239k
  ASSERT(dispatching_);
546
239k
  ENVOY_CONN_LOG(trace, "completed header: key={} value={}", connection_,
547
239k
                 current_header_field_.getStringView(), current_header_value_.getStringView());
548
239k
  auto& headers_or_trailers = headersOrTrailers();
549
550
  // Account for ":" and "\r\n" bytes between the header key value pair.
551
239k
  getBytesMeter().addHeaderBytesReceived(CRLF_SIZE + 1);
552
553
  // TODO(10646): Switch to use HeaderUtility::checkHeaderNameForUnderscores().
554
239k
  RETURN_IF_ERROR(checkHeaderNameForUnderscores());
555
239k
  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
216k
    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
216k
    auto formatter = headers_or_trailers.formatter();
564
216k
    if (formatter.has_value()) {
565
0
      formatter->processKey(current_header_field_.getStringView());
566
0
    }
567
4.51M
    current_header_field_.inlineTransform([](char c) { return absl::ascii_tolower(c); });
568
569
216k
    headers_or_trailers.addViaMove(std::move(current_header_field_),
570
216k
                                   std::move(current_header_value_));
571
216k
  }
572
573
  // Check if the number of headers exceeds the limit.
574
239k
  if (headers_or_trailers.size() > max_headers_count_) {
575
97
    error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
576
97
    RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().TooManyHeaders));
577
97
    const absl::string_view header_type =
578
97
        processing_trailers_ ? Http1HeaderTypes::get().Trailers : Http1HeaderTypes::get().Headers;
579
97
    return codecProtocolError(
580
97
        absl::StrCat("http/1.1 protocol error: ", header_type, " count exceeds limit"));
581
97
  }
582
583
239k
  header_parsing_state_ = HeaderParsingState::Field;
584
239k
  ASSERT(current_header_field_.empty());
585
239k
  ASSERT(current_header_value_.empty());
586
239k
  return okStatus();
587
239k
}
588
589
42.3k
Status ConnectionImpl::onMessageBeginImpl() {
590
42.3k
  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
42.3k
  protocol_ = Protocol::Http11;
595
42.3k
  processing_trailers_ = false;
596
42.3k
  header_parsing_state_ = HeaderParsingState::Field;
597
42.3k
  allocHeaders(statefulFormatterFromSettings(codec_settings_));
598
42.3k
  return onMessageBeginBase();
599
42.3k
}
600
601
518k
uint32_t ConnectionImpl::getHeadersSize() {
602
518k
  return current_header_field_.size() + current_header_value_.size() +
603
518k
         headersOrTrailers().byteSize();
604
518k
}
605
606
518k
Status ConnectionImpl::checkMaxHeadersSize() {
607
518k
  const uint32_t total = getHeadersSize();
608
518k
  if (total > (max_headers_kb_ * 1024)) {
609
163
    const absl::string_view header_type =
610
163
        processing_trailers_ ? Http1HeaderTypes::get().Trailers : Http1HeaderTypes::get().Headers;
611
163
    error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
612
163
    RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().HeadersTooLarge));
613
163
    return codecProtocolError(
614
163
        absl::StrCat("http/1.1 protocol error: ", header_type, " size exceeds limit"));
615
163
  }
616
518k
  return okStatus();
617
518k
}
618
619
152k
bool ConnectionImpl::maybeDirectDispatch(Buffer::Instance& data) {
620
152k
  if (!handling_upgrade_) {
621
    // Only direct dispatch for Upgrade requests.
622
152k
    return false;
623
152k
  }
624
625
527
  ENVOY_CONN_LOG(trace, "direct-dispatched {} bytes", connection_, data.length());
626
527
  onBody(data);
627
527
  data.drain(data.length());
628
527
  return true;
629
152k
}
630
631
89.1k
void ConnectionImpl::onDispatch(const Buffer::Instance& data) {
632
89.1k
  getBytesMeter().addWireBytesReceived(data.length());
633
89.1k
}
634
635
30.8k
Http::Status ClientConnectionImpl::dispatch(Buffer::Instance& data) {
636
30.8k
  Http::Status status = ConnectionImpl::dispatch(data);
637
30.8k
  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
9
    return codecProtocolError("http/1.1 protocol error: extraneous data after response complete");
641
9
  }
642
30.8k
  return status;
643
30.8k
}
644
645
89.1k
Http::Status ConnectionImpl::dispatch(Buffer::Instance& data) {
646
  // Add self to the Dispatcher's tracked object stack.
647
89.1k
  ScopeTrackerScopeState scope(this, connection_.dispatcher());
648
89.1k
  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
89.1k
  Cleanup cleanup([this]() { dispatching_ = false; });
652
89.1k
  ASSERT(!dispatching_);
653
89.1k
  ASSERT(codec_status_.ok());
654
89.1k
  ASSERT(buffered_body_.length() == 0);
655
656
89.1k
  dispatching_ = true;
657
89.1k
  onDispatch(data);
658
89.1k
  if (maybeDirectDispatch(data)) {
659
341
    return Http::okStatus();
660
341
  }
661
662
  // Always resume before dispatch.
663
88.8k
  parser_->resume();
664
665
88.8k
  ssize_t total_parsed = 0;
666
88.8k
  if (data.length() > 0) {
667
78.2k
    current_dispatching_buffer_ = &data;
668
125k
    while (data.length() > 0) {
669
85.1k
      auto slice = data.frontSlice();
670
85.1k
      dispatching_slice_already_drained_ = false;
671
85.1k
      auto statusor_parsed = dispatchSlice(static_cast<const char*>(slice.mem_), slice.len_);
672
85.1k
      if (!statusor_parsed.ok()) {
673
25.2k
        return statusor_parsed.status();
674
25.2k
      }
675
59.8k
      if (!dispatching_slice_already_drained_) {
676
57.4k
        ASSERT(statusor_parsed.value() <= slice.len_);
677
57.4k
        data.drain(statusor_parsed.value());
678
57.4k
      }
679
680
59.8k
      total_parsed += statusor_parsed.value();
681
59.8k
      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
12.6k
        ASSERT(parser_->getStatus() == ParserStatus::Paused);
685
12.6k
        break;
686
12.6k
      }
687
59.8k
    }
688
52.9k
    current_dispatching_buffer_ = nullptr;
689
52.9k
    dispatchBufferedBody();
690
52.9k
  } else {
691
10.5k
    auto result = dispatchSlice(nullptr, 0);
692
10.5k
    if (!result.ok()) {
693
66
      return result.status();
694
66
    }
695
10.5k
  }
696
63.4k
  ASSERT(buffered_body_.length() == 0);
697
698
63.4k
  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
63.4k
  maybeDirectDispatch(data);
703
63.4k
  return Http::okStatus();
704
63.4k
}
705
706
95.6k
Envoy::StatusOr<size_t> ConnectionImpl::dispatchSlice(const char* slice, size_t len) {
707
95.6k
  ASSERT(codec_status_.ok() && dispatching_);
708
95.6k
  const size_t nread = parser_->execute(slice, len);
709
95.6k
  if (!codec_status_.ok()) {
710
6.09k
    return codec_status_;
711
6.09k
  }
712
713
89.5k
  const ParserStatus status = parser_->getStatus();
714
89.5k
  if (status != ParserStatus::Ok && status != ParserStatus::Paused) {
715
19.2k
    absl::string_view error = Http1ResponseCodeDetails::get().HttpCodecError;
716
19.2k
    if (codec_settings_.use_balsa_parser_) {
717
6.91k
      if (parser_->errorMessage() == "headers size exceeds limit" ||
718
6.91k
          parser_->errorMessage() == "trailers size exceeds limit") {
719
99
        error_code_ = Http::Code::RequestHeaderFieldsTooLarge;
720
99
        error = Http1ResponseCodeDetails::get().HeadersTooLarge;
721
6.81k
      } else if (parser_->errorMessage() == "header value contains invalid chars") {
722
349
        error = Http1ResponseCodeDetails::get().InvalidCharacters;
723
349
      }
724
6.91k
    }
725
19.2k
    RETURN_IF_ERROR(sendProtocolError(error));
726
    // Avoid overwriting the codec_status_ set in the callbacks.
727
19.2k
    ASSERT(codec_status_.ok());
728
19.2k
    codec_status_ =
729
19.2k
        codecProtocolError(absl::StrCat("http/1.1 protocol error: ", parser_->errorMessage()));
730
19.2k
    return codec_status_;
731
19.2k
  }
732
733
70.3k
  return nread;
734
89.5k
}
735
736
41.4k
CallbackResult ConnectionImpl::onMessageBegin() {
737
41.4k
  return setAndCheckCallbackStatus(onMessageBeginImpl());
738
41.4k
}
739
740
21.8k
CallbackResult ConnectionImpl::onUrl(const char* data, size_t length) {
741
21.8k
  return setAndCheckCallbackStatus(onUrlBase(data, length));
742
21.8k
}
743
744
12.1k
CallbackResult ConnectionImpl::onStatus(const char* data, size_t length) {
745
12.1k
  return setAndCheckCallbackStatus(onStatusBase(data, length));
746
12.1k
}
747
748
236k
CallbackResult ConnectionImpl::onHeaderField(const char* data, size_t length) {
749
236k
  return setAndCheckCallbackStatus(onHeaderFieldImpl(data, length));
750
236k
}
751
752
260k
CallbackResult ConnectionImpl::onHeaderValue(const char* data, size_t length) {
753
260k
  return setAndCheckCallbackStatus(onHeaderValueImpl(data, length));
754
260k
}
755
756
29.8k
CallbackResult ConnectionImpl::onHeadersComplete() {
757
29.8k
  return setAndCheckCallbackStatusOr(onHeadersCompleteImpl());
758
29.8k
}
759
760
31.3k
void ConnectionImpl::bufferBody(const char* data, size_t length) {
761
31.3k
  auto slice = current_dispatching_buffer_->frontSlice();
762
31.3k
  if (data == slice.mem_ && length == slice.len_) {
763
2.40k
    buffered_body_.move(*current_dispatching_buffer_, length);
764
2.40k
    dispatching_slice_already_drained_ = true;
765
28.9k
  } else {
766
28.9k
    buffered_body_.add(data, length);
767
28.9k
  }
768
31.3k
}
769
770
18.3k
CallbackResult ConnectionImpl::onMessageComplete() {
771
18.3k
  return setAndCheckCallbackStatusOr(onMessageCompleteImpl());
772
18.3k
}
773
774
31.7k
void ConnectionImpl::onChunkHeader(bool is_final_chunk) {
775
31.7k
  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
5.41k
    dispatchBufferedBody();
779
5.41k
  }
780
31.7k
}
781
782
236k
Status ConnectionImpl::onHeaderFieldImpl(const char* data, size_t length) {
783
236k
  ASSERT(dispatching_);
784
785
236k
  getBytesMeter().addHeaderBytesReceived(length);
786
787
  // We previously already finished up the headers, these headers are
788
  // now trailers.
789
236k
  if (header_parsing_state_ == HeaderParsingState::Done) {
790
202
    if (!enableTrailers()) {
791
      // Ignore trailers.
792
89
      return okStatus();
793
89
    }
794
113
    processing_trailers_ = true;
795
113
    header_parsing_state_ = HeaderParsingState::Field;
796
113
    allocTrailers();
797
113
  }
798
235k
  if (header_parsing_state_ == HeaderParsingState::Value) {
799
209k
    RETURN_IF_ERROR(completeCurrentHeader());
800
209k
  }
801
802
235k
  current_header_field_.append(data, length);
803
804
235k
  return checkMaxHeadersSize();
805
235k
}
806
807
260k
Status ConnectionImpl::onHeaderValueImpl(const char* data, size_t length) {
808
260k
  ASSERT(dispatching_);
809
810
260k
  getBytesMeter().addHeaderBytesReceived(length);
811
812
260k
  if (header_parsing_state_ == HeaderParsingState::Done && !enableTrailers()) {
813
    // Ignore trailers.
814
101
    return okStatus();
815
101
  }
816
817
260k
  absl::string_view header_value{data, length};
818
260k
  if (!Http::HeaderUtility::headerValueIsValid(header_value)) {
819
56
    ENVOY_CONN_LOG(debug, "invalid header value: {}", connection_, header_value);
820
56
    error_code_ = Http::Code::BadRequest;
821
56
    RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidCharacters));
822
56
    return codecProtocolError("http/1.1 protocol error: header value contains invalid chars");
823
56
  }
824
825
260k
  header_parsing_state_ = HeaderParsingState::Value;
826
260k
  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
234k
    header_value = StringUtil::ltrim(header_value);
832
234k
  }
833
260k
  current_header_value_.append(header_value.data(), header_value.length());
834
835
260k
  return checkMaxHeadersSize();
836
260k
}
837
838
29.8k
StatusOr<CallbackResult> ConnectionImpl::onHeadersCompleteImpl() {
839
29.8k
  ASSERT(!processing_trailers_);
840
29.8k
  ASSERT(dispatching_);
841
29.8k
  ENVOY_CONN_LOG(trace, "onHeadersCompleteImpl", connection_);
842
29.8k
  RETURN_IF_ERROR(completeCurrentHeader());
843
844
29.8k
  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
8.47k
    protocol_ = Protocol::Http10;
848
8.47k
  }
849
29.8k
  RequestOrResponseHeaderMap& request_or_response_headers = requestOrResponseHeaders();
850
29.8k
  const Http::HeaderValues& header_values = Http::Headers::get();
851
29.8k
  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
381
    if (absl::EqualsIgnoreCase(request_or_response_headers.getUpgradeValue(),
855
381
                               header_values.UpgradeValues.H2c)) {
856
252
      ENVOY_CONN_LOG(trace, "removing unsupported h2c upgrade headers.", connection_);
857
252
      request_or_response_headers.removeUpgrade();
858
252
      if (request_or_response_headers.Connection()) {
859
252
        const auto& tokens_to_remove = caseUnorderdSetContainingUpgradeAndHttp2Settings();
860
252
        std::string new_value = StringUtil::removeTokens(
861
252
            request_or_response_headers.getConnectionValue(), ",", tokens_to_remove, ",");
862
252
        if (new_value.empty()) {
863
7
          request_or_response_headers.removeConnection();
864
245
        } else {
865
245
          request_or_response_headers.setConnection(new_value);
866
245
        }
867
252
      }
868
252
      request_or_response_headers.remove(header_values.Http2Settings);
869
252
    } else {
870
129
      ENVOY_CONN_LOG(trace, "codec entering upgrade mode.", connection_);
871
129
      handling_upgrade_ = true;
872
129
    }
873
381
  }
874
29.8k
  if (parser_->methodName() == header_values.MethodValues.Connect) {
875
1.24k
    if (request_or_response_headers.ContentLength()) {
876
577
      if (request_or_response_headers.getContentLengthValue() == "0") {
877
488
        request_or_response_headers.removeContentLength();
878
488
      } 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
89
        error_code_ = Http::Code::BadRequest;
882
89
        RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().BodyDisallowed));
883
89
        return codecProtocolError("http/1.1 protocol error: unsupported content length");
884
89
      }
885
577
    }
886
1.15k
    ENVOY_CONN_LOG(trace, "codec entering upgrade mode for CONNECT request.", connection_);
887
1.15k
    handling_upgrade_ = true;
888
1.15k
  }
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
29.7k
#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
29.7k
  if (parser_->hasTransferEncoding() != 0 && request_or_response_headers.ContentLength()) {
907
48
    if (parser_->isChunked() && codec_settings_.allow_chunked_length_) {
908
0
      request_or_response_headers.removeContentLength();
909
48
    } else {
910
48
      error_code_ = Http::Code::BadRequest;
911
48
      RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().ChunkedContentLength));
912
48
      return codecProtocolError(
913
48
          "http/1.1 protocol error: both 'Content-Length' and 'Transfer-Encoding' are set.");
914
48
    }
915
48
  }
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
29.7k
  if (request_or_response_headers.TransferEncoding()) {
922
10.8k
    const absl::string_view encoding = request_or_response_headers.getTransferEncodingValue();
923
10.8k
    if (!absl::EqualsIgnoreCase(encoding, header_values.TransferEncodingValues.Chunked) ||
924
10.8k
        parser_->methodName() == header_values.MethodValues.Connect) {
925
516
      error_code_ = Http::Code::NotImplemented;
926
516
      RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidTransferEncoding));
927
516
      return codecProtocolError("http/1.1 protocol error: unsupported transfer encoding");
928
516
    }
929
10.8k
  }
930
29.2k
#endif
931
932
29.2k
  auto statusor = onHeadersCompleteBase();
933
29.2k
  if (!statusor.ok()) {
934
5.11k
    RETURN_IF_ERROR(statusor.status());
935
5.11k
  }
936
937
24.0k
  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
24.0k
  return handling_upgrade_ ? CallbackResult::NoBodyData : statusor.value();
942
29.2k
}
943
944
18.3k
StatusOr<CallbackResult> ConnectionImpl::onMessageCompleteImpl() {
945
18.3k
  ENVOY_CONN_LOG(trace, "message complete", connection_);
946
947
18.3k
  dispatchBufferedBody();
948
949
18.3k
  if (handling_upgrade_) {
950
    // If this is an upgrade request, swallow the onMessageComplete. The
951
    // upgrade payload will be treated as stream body.
952
186
    ASSERT(!deferred_end_stream_headers_);
953
186
    ENVOY_CONN_LOG(trace, "Pausing parser due to upgrade.", connection_);
954
186
    return parser_->pause();
955
186
  }
956
957
  // If true, this indicates we were processing trailers and must
958
  // move the last header into current_header_map_
959
18.1k
  if (header_parsing_state_ == HeaderParsingState::Value) {
960
60
    RETURN_IF_ERROR(completeCurrentHeader());
961
60
  }
962
963
18.1k
  return onMessageCompleteBase();
964
18.1k
}
965
966
76.7k
void ConnectionImpl::dispatchBufferedBody() {
967
76.7k
  ASSERT(parser_->getStatus() == ParserStatus::Ok || parser_->getStatus() == ParserStatus::Paused);
968
76.7k
  ASSERT(codec_status_.ok());
969
76.7k
  if (buffered_body_.length() > 0) {
970
7.34k
    onBody(buffered_body_);
971
7.34k
    buffered_body_.drain(buffered_body_.length());
972
7.34k
  }
973
76.7k
}
974
975
1.84k
void ConnectionImpl::onResetStreamBase(StreamResetReason reason) {
976
1.84k
  ASSERT(!reset_stream_called_);
977
1.84k
  reset_stream_called_ = true;
978
1.84k
  onResetStream(reason);
979
1.84k
}
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
6.25k
      response_buffer_releasor_([this](const Buffer::OwnedBufferFragmentImpl* fragment) {
1065
6.25k
        releaseOutboundResponse(fragment);
1066
6.25k
      }),
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
28.7k
          overload_manager.getLoadShedPoint("envoy.load_shed_points.http1_server_abort_dispatch")) {
1074
28.7k
  ENVOY_LOG_ONCE_IF(trace, abort_dispatch_ == nullptr,
1075
28.7k
                    "LoadShedPoint envoy.load_shed_points.http1_server_abort_dispatch is not "
1076
28.7k
                    "found. Is it configured?");
1077
28.7k
  owned_output_buffer_->setWatermarks(connection.bufferLimit());
1078
  // Inform parent
1079
28.7k
  output_buffer_ = owned_output_buffer_.get();
1080
28.7k
}
Unexecuted instantiation: Envoy::Http::Http1::ServerConnectionImpl::ServerConnectionImpl(Envoy::Network::Connection&, Envoy::Http::Http1::CodecStats&, Envoy::Http::ServerConnectionCallbacks&, Envoy::Http::Http1Settings const&, unsigned int, unsigned int, envoy::config::core::v3::HttpProtocolOptions_HeadersWithUnderscoresAction, Envoy::Server::OverloadManager&)
Envoy::Http::Http1::ServerConnectionImpl::ServerConnectionImpl(Envoy::Network::Connection&, Envoy::Http::Http1::CodecStats&, Envoy::Http::ServerConnectionCallbacks&, Envoy::Http::Http1Settings const&, unsigned int, unsigned int, envoy::config::core::v3::HttpProtocolOptions_HeadersWithUnderscoresAction, Envoy::Server::OverloadManager&)
Line
Count
Source
1073
28.7k
          overload_manager.getLoadShedPoint("envoy.load_shed_points.http1_server_abort_dispatch")) {
1074
28.7k
  ENVOY_LOG_ONCE_IF(trace, abort_dispatch_ == nullptr,
1075
28.7k
                    "LoadShedPoint envoy.load_shed_points.http1_server_abort_dispatch is not "
1076
28.7k
                    "found. Is it configured?");
1077
28.7k
  owned_output_buffer_->setWatermarks(connection.bufferLimit());
1078
  // Inform parent
1079
28.7k
  output_buffer_ = owned_output_buffer_.get();
1080
28.7k
}
1081
1082
449k
uint32_t ServerConnectionImpl::getHeadersSize() {
1083
  // Add in the size of the request URL if processing request headers.
1084
449k
  const uint32_t url_size =
1085
449k
      (!processing_trailers_ && active_request_) ? active_request_->request_url_.size() : 0;
1086
449k
  return url_size + ConnectionImpl::getHeadersSize();
1087
449k
}
1088
1089
6.25k
void ServerConnectionImpl::onEncodeComplete() {
1090
6.25k
  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
5.14k
    connection_.dispatcher().deferredDelete(std::move(active_request_));
1095
5.14k
  }
1096
6.25k
}
1097
1098
16.8k
Status ServerConnectionImpl::handlePath(RequestHeaderMap& headers, absl::string_view method) {
1099
16.8k
  const Http::HeaderValues& header_values = Http::Headers::get();
1100
16.8k
  HeaderString path(header_values.Path);
1101
1102
16.8k
  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
16.8k
  if (!is_connect && !active_request_->request_url_.getStringView().empty() &&
1106
16.8k
      (active_request_->request_url_.getStringView()[0] == '/' ||
1107
16.0k
       (method == header_values.MethodValues.Options &&
1108
8.43k
        active_request_->request_url_.getStringView()[0] == '*'))) {
1109
8.43k
    headers.addViaMove(std::move(path), std::move(active_request_->request_url_));
1110
8.43k
    return okStatus();
1111
8.43k
  }
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
8.37k
  if (!codec_settings_.allow_absolute_url_ && !is_connect) {
1123
4.66k
    headers.addViaMove(std::move(path), std::move(active_request_->request_url_));
1124
4.66k
    return okStatus();
1125
4.66k
  }
1126
1127
3.71k
  Utility::Url absolute_url;
1128
3.71k
  if (!absolute_url.initialize(active_request_->request_url_.getStringView(), is_connect)) {
1129
2.98k
    RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidUrl));
1130
2.98k
    return codecProtocolError("http/1.1 protocol error: invalid url in request line");
1131
2.98k
  }
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
728
  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
728
  if (!is_connect) {
1143
674
    if (Runtime::runtimeFeatureEnabled(
1144
674
            "envoy.reloadable_features.allow_absolute_url_with_mixed_scheme")) {
1145
674
      headers.setScheme(absl::AsciiStrToLower(absolute_url.scheme()));
1146
674
    } else {
1147
0
      headers.setScheme(absolute_url.scheme());
1148
0
    }
1149
674
    if (!Utility::schemeIsValid(headers.getSchemeValue())) {
1150
529
      RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidScheme));
1151
529
      return codecProtocolError("http/1.1 protocol error: invalid scheme");
1152
529
    }
1153
145
    if (codec_settings_.validate_scheme_ && Utility::schemeIsHttps(absolute_url.scheme()) &&
1154
145
        !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
145
  }
1160
1161
199
  if (!absolute_url.pathAndQueryParams().empty()) {
1162
147
    headers.setPath(absolute_url.pathAndQueryParams());
1163
147
  }
1164
199
  active_request_->request_url_.clear();
1165
199
  return okStatus();
1166
728
}
1167
1168
13.2k
Status ServerConnectionImpl::checkProtocolVersion(RequestHeaderMap& headers) {
1169
13.2k
  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
4.54k
    if (!codec_settings_.accept_http_10_) {
1176
      // Send "Upgrade Required" if HTTP/1.0 support is not explicitly configured on.
1177
115
      error_code_ = Http::Code::UpgradeRequired;
1178
115
      RETURN_IF_ERROR(sendProtocolError(StreamInfo::ResponseCodeDetails::get().LowVersion));
1179
115
      return codecProtocolError("Upgrade required for HTTP/1.0 or HTTP/0.9");
1180
115
    }
1181
4.42k
    if (!headers.Host() && !codec_settings_.default_host_for_http_10_.empty()) {
1182
      // Add a default host if configured to do so.
1183
3.94k
      headers.setHost(codec_settings_.default_host_for_http_10_);
1184
3.94k
    }
1185
4.42k
  }
1186
13.1k
  return okStatus();
1187
13.2k
}
1188
1189
17.3k
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
17.3k
  if (active_request_) {
1194
17.3k
    auto& headers = absl::get<RequestHeaderMapPtr>(headers_or_trailers_);
1195
17.3k
    ENVOY_CONN_LOG(trace, "Server: onHeadersComplete size={}", connection_, headers->size());
1196
1197
17.3k
    if (!handling_upgrade_ && headers->Connection()) {
1198
      // If we fail to sanitize the request, return a 400 to the client
1199
4.12k
      if (!Utility::sanitizeConnectionHeader(*headers)) {
1200
534
        absl::string_view header_value = headers->getConnectionValue();
1201
534
        ENVOY_CONN_LOG(debug, "Invalid nominated headers in Connection: {}", connection_,
1202
534
                       header_value);
1203
534
        error_code_ = Http::Code::BadRequest;
1204
534
        RETURN_IF_ERROR(
1205
534
            sendProtocolError(Http1ResponseCodeDetails::get().ConnectionHeaderSanitization));
1206
534
        return codecProtocolError("Invalid nominated headers in Connection.");
1207
534
      }
1208
4.12k
    }
1209
1210
    // Inform the response encoder about any HEAD method, so it can set content
1211
    // length and transfer encoding headers correctly.
1212
16.8k
    const Http::HeaderValues& header_values = Http::Headers::get();
1213
16.8k
    active_request_->response_encoder_.setIsResponseToHeadRequest(parser_->methodName() ==
1214
16.8k
                                                                  header_values.MethodValues.Head);
1215
16.8k
    active_request_->response_encoder_.setIsResponseToConnectRequest(
1216
16.8k
        parser_->methodName() == header_values.MethodValues.Connect);
1217
1218
16.8k
    RETURN_IF_ERROR(handlePath(*headers, parser_->methodName()));
1219
13.2k
    ASSERT(active_request_->request_url_.empty());
1220
1221
13.2k
    headers->setMethod(parser_->methodName());
1222
13.2k
    RETURN_IF_ERROR(checkProtocolVersion(*headers));
1223
1224
    // Make sure the host is valid.
1225
13.1k
    auto details = HeaderUtility::requestHeadersValid(*headers);
1226
13.1k
    if (details.has_value()) {
1227
419
      RETURN_IF_ERROR(sendProtocolError(details.value().get()));
1228
419
      return codecProtocolError(
1229
419
          "http/1.1 protocol error: request headers failed spec compliance checks");
1230
419
    }
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
12.7k
    if (parser_->isChunked() ||
1239
12.7k
        (parser_->contentLength().has_value() && parser_->contentLength().value() > 0) ||
1240
12.7k
        handling_upgrade_) {
1241
8.16k
      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
8.16k
      if (connection_.state() != Network::Connection::State::Open) {
1246
1
        return parser_->pause();
1247
1
      }
1248
8.16k
    } else {
1249
4.60k
      deferred_end_stream_headers_ = true;
1250
4.60k
    }
1251
12.7k
  }
1252
1253
12.7k
  return CallbackResult::Success;
1254
17.3k
}
1255
1256
27.9k
Status ServerConnectionImpl::onMessageBeginBase() {
1257
27.9k
  if (!resetStreamCalled()) {
1258
27.9k
    ASSERT(active_request_ == nullptr);
1259
27.9k
    active_request_ = std::make_unique<ActiveRequest>(*this, std::move(bytes_meter_before_stream_));
1260
27.9k
    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
27.9k
    RETURN_IF_ERROR(doFloodProtectionChecks());
1266
27.9k
  }
1267
27.8k
  return okStatus();
1268
27.9k
}
1269
1270
21.8k
Status ServerConnectionImpl::onUrlBase(const char* data, size_t length) {
1271
21.8k
  if (active_request_) {
1272
21.8k
    active_request_->request_url_.append(data, length);
1273
1274
21.8k
    RETURN_IF_ERROR(checkMaxHeadersSize());
1275
21.8k
  }
1276
1277
21.8k
  return okStatus();
1278
21.8k
}
1279
1280
4.80k
void ServerConnectionImpl::onBody(Buffer::Instance& data) {
1281
4.80k
  ASSERT(!deferred_end_stream_headers_);
1282
4.80k
  if (active_request_) {
1283
4.80k
    ENVOY_CONN_LOG(trace, "body size={}", connection_, data.length());
1284
4.80k
    active_request_->request_decoder_->decodeData(data, false);
1285
4.80k
  }
1286
4.80k
}
1287
1288
60.1k
Http::Status ServerConnectionImpl::dispatch(Buffer::Instance& data) {
1289
60.1k
  if (abort_dispatch_ != nullptr && abort_dispatch_->shouldShedLoad()) {
1290
0
    RETURN_IF_ERROR(sendOverloadError());
1291
0
    return envoyOverloadError("Aborting Server Dispatch");
1292
0
  }
1293
1294
60.1k
  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.88k
    active_request_->response_encoder_.readDisable(true);
1299
1.88k
    return okStatus();
1300
1.88k
  }
1301
1302
58.3k
  Http::Status status = ConnectionImpl::dispatch(data);
1303
1304
58.3k
  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
4.03k
    if (data.length() > 0) {
1309
821
      active_request_->response_encoder_.readDisable(true);
1310
821
    }
1311
4.03k
  }
1312
58.3k
  return status;
1313
60.1k
}
1314
1315
7.26k
CallbackResult ServerConnectionImpl::onMessageCompleteBase() {
1316
7.26k
  ASSERT(!handling_upgrade_);
1317
7.26k
  if (active_request_) {
1318
1319
    // The request_decoder should be non-null after we've called the newStream on callbacks.
1320
7.26k
    ASSERT(active_request_->request_decoder_);
1321
7.26k
    active_request_->remote_complete_ = true;
1322
1323
7.26k
    if (deferred_end_stream_headers_) {
1324
4.58k
      active_request_->request_decoder_->decodeHeaders(
1325
4.58k
          std::move(absl::get<RequestHeaderMapPtr>(headers_or_trailers_)), true);
1326
4.58k
      deferred_end_stream_headers_ = false;
1327
4.58k
    } else if (processing_trailers_) {
1328
44
      active_request_->request_decoder_->decodeTrailers(
1329
44
          std::move(absl::get<RequestTrailerMapPtr>(headers_or_trailers_)));
1330
2.63k
    } else {
1331
2.63k
      Buffer::OwnedImpl buffer;
1332
2.63k
      active_request_->request_decoder_->decodeData(buffer, true);
1333
2.63k
    }
1334
1335
    // Reset to ensure no information from one requests persists to the next.
1336
7.26k
    headers_or_trailers_.emplace<RequestHeaderMapPtr>(nullptr);
1337
7.26k
  }
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
7.26k
  return parser_->pause();
1343
7.26k
}
1344
1345
1.32k
void ServerConnectionImpl::onResetStream(StreamResetReason reason) {
1346
1.32k
  if (active_request_) {
1347
1.32k
    active_request_->response_encoder_.runResetCallbacks(reason);
1348
1.32k
    connection_.dispatcher().deferredDelete(std::move(active_request_));
1349
1.32k
  }
1350
1.32k
}
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
13.8k
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
13.8k
  if (active_request_ == nullptr) {
1367
879
    RETURN_IF_ERROR(onMessageBeginImpl());
1368
879
  }
1369
13.8k
  ASSERT(active_request_);
1370
1371
13.8k
  active_request_->response_encoder_.setDetails(details);
1372
13.8k
  if (!active_request_->response_encoder_.startedResponse()) {
1373
13.8k
    active_request_->request_decoder_->sendLocalReply(
1374
13.8k
        error_code_, CodeUtility::toString(error_code_), nullptr, absl::nullopt, details);
1375
13.8k
  }
1376
13.8k
  return okStatus();
1377
13.8k
}
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
6.25k
    const Buffer::OwnedBufferFragmentImpl* fragment) {
1392
6.25k
  ASSERT(outbound_responses_ >= 1);
1393
6.25k
  --outbound_responses_;
1394
6.25k
  delete fragment;
1395
6.25k
}
1396
1397
202k
Status ServerConnectionImpl::checkHeaderNameForUnderscores() {
1398
202k
#ifndef ENVOY_ENABLE_UHV
1399
  // This check has been moved to UHV
1400
202k
  if (headers_with_underscores_action_ != envoy::config::core::v3::HttpProtocolOptions::ALLOW &&
1401
202k
      Http::HeaderUtility::headerNameContainsUnderscore(current_header_field_.getStringView())) {
1402
17.0k
    if (headers_with_underscores_action_ ==
1403
17.0k
        envoy::config::core::v3::HttpProtocolOptions::DROP_HEADER) {
1404
17.0k
      ENVOY_CONN_LOG(debug, "Dropping header with invalid characters in its name: {}", connection_,
1405
17.0k
                     current_header_field_.getStringView());
1406
17.0k
      stats_.incDroppedHeadersWithUnderscores();
1407
17.0k
      current_header_field_.clear();
1408
17.0k
      current_header_value_.clear();
1409
17.0k
    } 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
17.0k
  }
1418
#else
1419
  // Workaround for gcc not understanding [[maybe_unused]] for class members.
1420
  (void)headers_with_underscores_action_;
1421
#endif
1422
202k
  return okStatus();
1423
202k
}
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
27.6k
      passing_through_proxy_(passing_through_proxy) {
1443
27.6k
  owned_output_buffer_->setWatermarks(connection.bufferLimit());
1444
  // Inform parent
1445
27.6k
  output_buffer_ = owned_output_buffer_.get();
1446
27.6k
}
Unexecuted instantiation: Envoy::Http::Http1::ClientConnectionImpl::ClientConnectionImpl(Envoy::Network::Connection&, Envoy::Http::Http1::CodecStats&, Envoy::Http::ConnectionCallbacks&, Envoy::Http::Http1Settings const&, unsigned int, bool)
Envoy::Http::Http1::ClientConnectionImpl::ClientConnectionImpl(Envoy::Network::Connection&, Envoy::Http::Http1::CodecStats&, Envoy::Http::ConnectionCallbacks&, Envoy::Http::Http1Settings const&, unsigned int, bool)
Line
Count
Source
1442
27.6k
      passing_through_proxy_(passing_through_proxy) {
1443
27.6k
  owned_output_buffer_->setWatermarks(connection.bufferLimit());
1444
  // Inform parent
1445
27.6k
  output_buffer_ = owned_output_buffer_.get();
1446
27.6k
}
1447
1448
17.0k
bool ClientConnectionImpl::cannotHaveBody() {
1449
17.0k
  if (pending_response_.has_value() && pending_response_.value().encoder_.headRequest()) {
1450
714
    ASSERT(!pending_response_done_);
1451
714
    return true;
1452
16.3k
  } else if (parser_->statusCode() == Http::Code::NoContent ||
1453
16.3k
             parser_->statusCode() == Http::Code::NotModified ||
1454
16.3k
             (parser_->statusCode() >= Http::Code::OK &&
1455
16.2k
              (parser_->contentLength().has_value() && parser_->contentLength().value() == 0) &&
1456
16.2k
              !parser_->isChunked())) {
1457
4.87k
    return true;
1458
11.4k
  } else {
1459
11.4k
    return false;
1460
11.4k
  }
1461
17.0k
}
1462
1463
11.6k
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
11.6k
  ASSERT(connection_.readEnabled());
1467
1468
11.6k
  ASSERT(!pending_response_.has_value());
1469
11.6k
  ASSERT(pending_response_done_);
1470
11.6k
  pending_response_.emplace(*this, std::move(bytes_meter_before_stream_), &response_decoder);
1471
11.6k
  pending_response_done_ = false;
1472
11.6k
  return pending_response_.value().encoder_;
1473
11.6k
}
1474
1475
12.1k
Status ClientConnectionImpl::onStatusBase(const char* data, size_t length) {
1476
12.1k
  auto& headers = absl::get<ResponseHeaderMapPtr>(headers_or_trailers_);
1477
12.1k
  StatefulHeaderKeyFormatterOptRef formatter(headers->formatter());
1478
12.1k
  if (formatter.has_value()) {
1479
0
    formatter->setReasonPhrase(absl::string_view(data, length));
1480
0
  }
1481
1482
12.1k
  return okStatus();
1483
12.1k
}
1484
1485
11.8k
Envoy::StatusOr<CallbackResult> ClientConnectionImpl::onHeadersCompleteBase() {
1486
11.8k
  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
11.8k
  if (!pending_response_.has_value() && !resetStreamCalled()) {
1492
515
    return prematureResponseError("", parser_->statusCode());
1493
11.3k
  } else if (pending_response_.has_value()) {
1494
11.3k
    ASSERT(!pending_response_done_);
1495
11.3k
    auto& headers = absl::get<ResponseHeaderMapPtr>(headers_or_trailers_);
1496
11.3k
    ENVOY_CONN_LOG(trace, "Client: onHeadersComplete size={}", connection_, headers->size());
1497
11.3k
    headers->setStatus(enumToInt(parser_->statusCode()));
1498
1499
11.3k
    if (parser_->statusCode() >= Http::Code::OK &&
1500
11.3k
        parser_->statusCode() < Http::Code::MultipleChoices &&
1501
11.3k
        pending_response_.value().encoder_.connectRequest()) {
1502
7
      ENVOY_CONN_LOG(trace, "codec entering upgrade mode for CONNECT response.", connection_);
1503
7
      handling_upgrade_ = true;
1504
7
    }
1505
1506
11.3k
    if (parser_->statusCode() < Http::Code::OK || parser_->statusCode() == Http::Code::NoContent) {
1507
5.71k
      if (headers->TransferEncoding()) {
1508
10
        RETURN_IF_ERROR(
1509
10
            sendProtocolError(Http1ResponseCodeDetails::get().TransferEncodingNotAllowed));
1510
10
        return codecProtocolError(
1511
10
            "http/1.1 protocol error: transfer encoding not allowed in 1xx or 204");
1512
10
      }
1513
1514
5.70k
      if (headers->ContentLength()) {
1515
        // Report a protocol error for non-zero Content-Length, but paper over zero Content-Length.
1516
49
        if (headers->ContentLength()->value().getStringView() != "0") {
1517
11
          RETURN_IF_ERROR(
1518
11
              sendProtocolError(Http1ResponseCodeDetails::get().ContentLengthNotAllowed));
1519
11
          return codecProtocolError(
1520
11
              "http/1.1 protocol error: content length not allowed in 1xx or 204");
1521
11
        }
1522
1523
38
        headers->removeContentLength();
1524
38
      }
1525
5.70k
    }
1526
1527
11.3k
    if (HeaderUtility::isSpecial1xx(*headers)) {
1528
5.62k
      pending_response_.value().decoder_->decode1xxHeaders(std::move(headers));
1529
5.69k
    } else if (cannotHaveBody() && !handling_upgrade_) {
1530
2.54k
      deferred_end_stream_headers_ = true;
1531
3.15k
    } else {
1532
3.15k
      pending_response_.value().decoder_->decodeHeaders(std::move(headers), false);
1533
3.15k
    }
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
11.3k
    if (CodeUtility::is1xx(enumToInt(parser_->statusCode())) &&
1540
11.3k
        parser_->statusCode() != Http::Code::SwitchingProtocols) {
1541
5.64k
      ignore_message_complete_for_1xx_ = true;
1542
      // Reset to ensure no information from the 1xx headers is used for the response headers.
1543
5.64k
      headers_or_trailers_.emplace<ResponseHeaderMapPtr>(nullptr);
1544
5.64k
    }
1545
11.3k
  }
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
11.3k
  return cannotHaveBody() ? CallbackResult::NoBody : CallbackResult::Success;
1550
11.8k
}
1551
1552
71
bool ClientConnectionImpl::upgradeAllowed() const {
1553
71
  if (pending_response_.has_value()) {
1554
49
    return pending_response_->encoder_.upgradeRequest();
1555
49
  }
1556
22
  return false;
1557
71
}
1558
1559
3.06k
void ClientConnectionImpl::onBody(Buffer::Instance& data) {
1560
3.06k
  ASSERT(!deferred_end_stream_headers_);
1561
3.06k
  if (pending_response_.has_value()) {
1562
3.06k
    ASSERT(!pending_response_done_);
1563
3.06k
    pending_response_.value().decoder_->decodeData(data, false);
1564
3.06k
  }
1565
3.06k
}
1566
1567
10.8k
CallbackResult ClientConnectionImpl::onMessageCompleteBase() {
1568
10.8k
  ENVOY_CONN_LOG(trace, "message complete", connection_);
1569
10.8k
  if (ignore_message_complete_for_1xx_) {
1570
5.62k
    ignore_message_complete_for_1xx_ = false;
1571
5.62k
    return CallbackResult::Success;
1572
5.62k
  }
1573
5.24k
  if (pending_response_.has_value()) {
1574
5.24k
    ASSERT(!pending_response_done_);
1575
    // After calling decodeData() with end stream set to true, we should no longer be able to reset.
1576
5.24k
    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
5.24k
    pending_response_done_ = true;
1580
1581
5.24k
    if (deferred_end_stream_headers_) {
1582
2.53k
      response.decoder_->decodeHeaders(
1583
2.53k
          std::move(absl::get<ResponseHeaderMapPtr>(headers_or_trailers_)), true);
1584
2.53k
      deferred_end_stream_headers_ = false;
1585
2.71k
    } else if (processing_trailers_) {
1586
0
      response.decoder_->decodeTrailers(
1587
0
          std::move(absl::get<ResponseTrailerMapPtr>(headers_or_trailers_)));
1588
2.71k
    } else {
1589
2.71k
      Buffer::OwnedImpl buffer;
1590
2.71k
      response.decoder_->decodeData(buffer, true);
1591
2.71k
    }
1592
1593
    // Reset to ensure no information from one requests persists to the next.
1594
5.24k
    pending_response_.reset();
1595
5.24k
    headers_or_trailers_.emplace<ResponseHeaderMapPtr>(nullptr);
1596
5.24k
  }
1597
1598
  // Pause the parser after a response is complete. Any remaining data indicates an error.
1599
5.24k
  return parser_->pause();
1600
5.24k
}
1601
1602
520
void ClientConnectionImpl::onResetStream(StreamResetReason reason) {
1603
  // Only raise reset if we did not already dispatch a complete response.
1604
520
  if (pending_response_.has_value() && !pending_response_done_) {
1605
517
    pending_response_.value().encoder_.runResetCallbacks(reason);
1606
517
    pending_response_done_ = true;
1607
517
    pending_response_.reset();
1608
517
  }
1609
520
}
1610
1611
10.9k
Status ClientConnectionImpl::sendProtocolError(absl::string_view details) {
1612
10.9k
  if (pending_response_.has_value()) {
1613
506
    ASSERT(!pending_response_done_);
1614
506
    pending_response_.value().encoder_.setDetails(details);
1615
506
  }
1616
10.9k
  return okStatus();
1617
10.9k
}
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