Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/test/common/http/conn_manager_impl_fuzz_test.cc
Line
Count
Source (jump to first uncovered line)
1
// This fuzzer explores the behavior of HCM with replay of trace actions that describe the behavior
2
// of a mocked codec and decoder/encoder filters. It is only partially complete (~60% test coverage
3
// with supplied corpus), since HCM has a lot of behavior to model, requiring investment in building
4
// out modeling actions and a corpus, which is time consuming and may not have significant security
5
// of functional correctness payoff beyond existing tests. Places where we could increase fuzz
6
// coverage include:
7
// * Watermarks
8
// * WebSocket upgrades
9
// * Tracing and stats.
10
// * Encode filter actions (e.g. modeling stop/continue, only done for decoder today).
11
// * SSL
12
// * Idle/drain timeouts.
13
// * HTTP 1.0 special cases
14
// * Fuzz config settings
15
#include <chrono>
16
17
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
18
19
#include "source/common/common/empty_string.h"
20
#include "source/common/http/conn_manager_impl.h"
21
#include "source/common/http/context_impl.h"
22
#include "source/common/http/date_provider_impl.h"
23
#include "source/common/http/exception.h"
24
#include "source/common/http/header_utility.h"
25
#include "source/common/network/address_impl.h"
26
#include "source/common/network/utility.h"
27
28
#include "test/common/http/conn_manager_impl_fuzz.pb.validate.h"
29
#include "test/fuzz/fuzz_runner.h"
30
#include "test/fuzz/utility.h"
31
#include "test/mocks/access_log/mocks.h"
32
#include "test/mocks/common.h"
33
#include "test/mocks/http/mocks.h"
34
#include "test/mocks/local_info/mocks.h"
35
#include "test/mocks/network/mocks.h"
36
#include "test/mocks/router/mocks.h"
37
#include "test/mocks/runtime/mocks.h"
38
#include "test/mocks/server/mocks.h"
39
#include "test/mocks/ssl/mocks.h"
40
#include "test/mocks/tracing/mocks.h"
41
#include "test/mocks/upstream/cluster_manager.h"
42
#include "test/test_common/simulated_time_system.h"
43
44
#include "gmock/gmock.h"
45
46
using testing::InvokeWithoutArgs;
47
using testing::Return;
48
49
namespace Envoy {
50
namespace Http {
51
52
class FuzzConfig : public ConnectionManagerConfig {
53
public:
54
  FuzzConfig(envoy::extensions::filters::network::http_connection_manager::v3::
55
                 HttpConnectionManager::ForwardClientCertDetails forward_client_cert)
56
      : stats_({ALL_HTTP_CONN_MAN_STATS(POOL_COUNTER(*fake_stats_.rootScope()),
57
                                        POOL_GAUGE(fake_stats_),
58
                                        POOL_HISTOGRAM(*fake_stats_.rootScope()))},
59
               "", *fake_stats_.rootScope()),
60
        tracing_stats_{CONN_MAN_TRACING_STATS(POOL_COUNTER(fake_stats_))},
61
        listener_stats_{CONN_MAN_LISTENER_STATS(POOL_COUNTER(fake_stats_))},
62
4.11k
        local_reply_(LocalReply::Factory::createDefault()) {
63
4.11k
    ON_CALL(route_config_provider_, lastUpdated()).WillByDefault(Return(time_system_.systemTime()));
64
4.11k
    ON_CALL(scoped_route_config_provider_, lastUpdated())
65
4.11k
        .WillByDefault(Return(time_system_.systemTime()));
66
4.11k
    access_logs_.emplace_back(std::make_shared<NiceMock<AccessLog::MockInstance>>());
67
4.11k
    request_id_extension_ = Extensions::RequestId::UUIDRequestIDExtension::defaultInstance(random_);
68
4.11k
    forward_client_cert_ = fromClientCert(forward_client_cert);
69
4.11k
  }
70
71
170k
  void newStream() {
72
170k
    if (!codec_) {
73
4.03k
      codec_ = new NiceMock<MockServerConnection>();
74
4.03k
    }
75
170k
    decoder_filter_ = new NiceMock<MockStreamDecoderFilter>();
76
170k
    encoder_filter_ = new NiceMock<MockStreamEncoderFilter>();
77
78
170k
    EXPECT_CALL(filter_factory_, createFilterChain(_))
79
170k
        .WillOnce(Invoke([this](FilterChainManager& manager) -> bool {
80
170k
          FilterFactoryCb decoder_filter_factory = [this](FilterChainFactoryCallbacks& callbacks) {
81
170k
            callbacks.addStreamDecoderFilter(StreamDecoderFilterSharedPtr{decoder_filter_});
82
170k
          };
83
170k
          FilterFactoryCb encoder_filter_factory = [this](FilterChainFactoryCallbacks& callbacks) {
84
170k
            callbacks.addStreamEncoderFilter(StreamEncoderFilterSharedPtr{encoder_filter_});
85
170k
          };
86
87
170k
          manager.applyFilterFactoryCb({}, decoder_filter_factory);
88
170k
          manager.applyFilterFactoryCb({}, encoder_filter_factory);
89
170k
          return true;
90
170k
        }));
91
170k
    EXPECT_CALL(*decoder_filter_, setDecoderFilterCallbacks(_))
92
170k
        .WillOnce(Invoke([this](StreamDecoderFilterCallbacks& callbacks) -> void {
93
170k
          decoder_filter_->callbacks_ = &callbacks;
94
170k
          callbacks.streamInfo().setResponseCodeDetails("");
95
170k
        }));
96
170k
    EXPECT_CALL(*encoder_filter_, setEncoderFilterCallbacks(_));
97
170k
    EXPECT_CALL(filter_factory_, createUpgradeFilterChain("WebSocket", _, _))
98
170k
        .WillRepeatedly(Invoke([&](absl::string_view, const Http::FilterChainFactory::UpgradeMap*,
99
170k
                                   FilterChainManager& manager) -> bool {
100
163
          return filter_factory_.createFilterChain(manager);
101
163
        }));
102
170k
  }
103
104
  Http::ForwardClientCertType
105
  fromClientCert(envoy::extensions::filters::network::http_connection_manager::v3::
106
4.11k
                     HttpConnectionManager::ForwardClientCertDetails forward_client_cert) {
107
4.11k
    switch (forward_client_cert) {
108
3.96k
    case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
109
3.96k
        SANITIZE:
110
3.96k
      return Http::ForwardClientCertType::Sanitize;
111
21
    case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
112
21
        FORWARD_ONLY:
113
21
      return Http::ForwardClientCertType::ForwardOnly;
114
82
    case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
115
82
        APPEND_FORWARD:
116
82
      return Http::ForwardClientCertType::AppendForward;
117
20
    case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
118
20
        SANITIZE_SET:
119
20
      return Http::ForwardClientCertType::SanitizeSet;
120
26
    case envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
121
26
        ALWAYS_FORWARD_ONLY:
122
26
      return Http::ForwardClientCertType::AlwaysForwardOnly;
123
0
    default:
124
0
      return Http::ForwardClientCertType::Sanitize;
125
4.11k
    }
126
4.11k
  }
127
128
  // Http::ConnectionManagerConfig
129
60.7k
  const RequestIDExtensionSharedPtr& requestIDExtension() override { return request_id_extension_; }
130
170k
  const std::list<AccessLog::InstanceSharedPtr>& accessLogs() override { return access_logs_; }
131
60.7k
  bool flushAccessLogOnNewRequest() override { return flush_access_log_on_new_request_; }
132
177
  bool flushAccessLogOnTunnelSuccessfullyEstablished() const override {
133
177
    return flush_access_log_on_tunnel_successfully_established_;
134
177
  }
135
170k
  const absl::optional<std::chrono::milliseconds>& accessLogFlushInterval() override {
136
170k
    return access_log_flush_interval_;
137
170k
  }
138
  ServerConnectionPtr createCodec(Network::Connection&, const Buffer::Instance&,
139
4.03k
                                  ServerConnectionCallbacks&, Server::OverloadManager&) override {
140
4.03k
    return ServerConnectionPtr{codec_};
141
4.03k
  }
142
111k
  DateProvider& dateProvider() override { return date_provider_; }
143
0
  std::chrono::milliseconds drainTimeout() const override { return std::chrono::milliseconds(100); }
144
170k
  FilterChainFactory& filterFactory() override { return filter_factory_; }
145
60.7k
  bool generateRequestId() const override { return true; }
146
60.7k
  bool preserveExternalRequestId() const override { return false; }
147
111k
  bool alwaysSetRequestIdInResponse() const override { return false; }
148
0
  uint32_t maxRequestHeadersKb() const override { return max_request_headers_kb_; }
149
0
  uint32_t maxRequestHeadersCount() const override { return max_request_headers_count_; }
150
4.11k
  absl::optional<std::chrono::milliseconds> idleTimeout() const override { return idle_timeout_; }
151
682k
  bool isRoutable() const override { return true; }
152
4.11k
  absl::optional<std::chrono::milliseconds> maxConnectionDuration() const override {
153
4.11k
    return max_connection_duration_;
154
4.11k
  }
155
341k
  absl::optional<std::chrono::milliseconds> maxStreamDuration() const override {
156
341k
    return max_stream_duration_;
157
341k
  }
158
170k
  std::chrono::milliseconds streamIdleTimeout() const override { return stream_idle_timeout_; }
159
170k
  std::chrono::milliseconds requestTimeout() const override { return request_timeout_; }
160
170k
  std::chrono::milliseconds requestHeadersTimeout() const override {
161
170k
    return request_headers_timeout_;
162
170k
  }
163
4.11k
  std::chrono::milliseconds delayedCloseTimeout() const override { return delayed_close_timeout_; }
164
1.02M
  Router::RouteConfigProvider* routeConfigProvider() override {
165
1.02M
    if (use_srds_) {
166
0
      return nullptr;
167
0
    }
168
1.02M
    return &route_config_provider_;
169
1.02M
  }
170
341k
  Config::ConfigProvider* scopedRouteConfigProvider() override {
171
341k
    if (use_srds_) {
172
0
      return &scoped_route_config_provider_;
173
0
    }
174
341k
    return nullptr;
175
341k
  }
176
170k
  OptRef<const Router::ScopeKeyBuilder> scopeKeyBuilder() override {
177
170k
    if (use_srds_) {
178
0
      return scope_key_builder_;
179
0
    }
180
170k
    return {};
181
170k
  }
182
115k
  const std::string& serverName() const override { return server_name_; }
183
  HttpConnectionManagerProto::ServerHeaderTransformation
184
111k
  serverHeaderTransformation() const override {
185
111k
    return server_transformation_;
186
111k
  }
187
60.7k
  const absl::optional<std::string>& schemeToSet() const override { return scheme_; }
188
4.11k
  ConnectionManagerStats& stats() override { return stats_; }
189
0
  ConnectionManagerTracingStats& tracingStats() override { return tracing_stats_; }
190
121k
  bool useRemoteAddress() const override { return use_remote_address_; }
191
60.5k
  const Http::InternalAddressConfig& internalAddressConfig() const override {
192
60.5k
    return internal_address_config_;
193
60.5k
  }
194
60.7k
  uint32_t xffNumTrustedHops() const override { return 0; }
195
60.7k
  bool skipXffAppend() const override { return false; }
196
171k
  const std::string& via() const override { return EMPTY_STRING; }
197
121k
  Http::ForwardClientCertType forwardClientCert() const override { return forward_client_cert_; }
198
0
  const std::vector<Http::ClientCertDetailsType>& setCurrentClientCertDetails() const override {
199
0
    return set_current_client_cert_details_;
200
0
  }
201
0
  const Network::Address::Instance& localAddress() override { return local_address_; }
202
60.7k
  const absl::optional<std::string>& userAgent() override { return user_agent_; }
203
0
  Tracing::TracerSharedPtr tracer() override { return tracer_; }
204
231k
  const TracingConnectionManagerConfig* tracingConfig() override { return tracing_config_.get(); }
205
4.11k
  ConnectionManagerListenerStats& listenerStats() override { return listener_stats_; }
206
341k
  bool proxy100Continue() const override { return proxy_100_continue_; }
207
0
  bool streamErrorOnInvalidHttpMessaging() const override {
208
0
    return stream_error_on_invalid_http_messaging_;
209
0
  }
210
0
  const Http::Http1Settings& http1Settings() const override { return http1_settings_; }
211
60.6k
  bool shouldNormalizePath() const override { return false; }
212
60.6k
  bool shouldMergeSlashes() const override { return false; }
213
60.7k
  bool shouldStripTrailingHostDot() const override { return false; }
214
121k
  Http::StripPortType stripPortType() const override { return Http::StripPortType::None; }
215
  envoy::config::core::v3::HttpProtocolOptions::HeadersWithUnderscoresAction
216
0
  headersWithUnderscoresAction() const override {
217
0
    return envoy::config::core::v3::HttpProtocolOptions::ALLOW;
218
0
  }
219
170k
  const LocalReply::LocalReply& localReply() const override { return *local_reply_; }
220
  envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
221
      PathWithEscapedSlashesAction
222
60.6k
      pathWithEscapedSlashesAction() const override {
223
60.6k
    return envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager::
224
60.6k
        KEEP_UNCHANGED;
225
60.6k
  }
226
  const std::vector<Http::OriginalIPDetectionSharedPtr>&
227
0
  originalIpDetectionExtensions() const override {
228
0
    return ip_detection_extensions_;
229
0
  }
230
60.7k
  const std::vector<Http::EarlyHeaderMutationPtr>& earlyHeaderMutationExtensions() const override {
231
60.7k
    return early_header_mutations_;
232
60.7k
  }
233
170k
  uint64_t maxRequestsPerConnection() const override { return 0; }
234
115k
  const HttpConnectionManagerProto::ProxyStatusConfig* proxyStatusConfig() const override {
235
115k
    return proxy_status_config_.get();
236
115k
  }
237
170k
  Http::ServerHeaderValidatorPtr makeHeaderValidator(Protocol) override {
238
    // TODO(yanavlasov): fuzz test interface should use the default validator, although this could
239
    // be changed too
240
170k
    return nullptr;
241
170k
  }
242
121k
  bool appendXForwardedPort() const override { return false; }
243
4.11k
  bool addProxyProtocolConnectionState() const override { return true; }
244
245
  const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager
246
      config_;
247
  NiceMock<Random::MockRandomGenerator> random_;
248
  RequestIDExtensionSharedPtr request_id_extension_;
249
  std::list<AccessLog::InstanceSharedPtr> access_logs_;
250
  bool flush_access_log_on_new_request_ = false;
251
  bool flush_access_log_on_tunnel_successfully_established_ = false;
252
  absl::optional<std::chrono::milliseconds> access_log_flush_interval_;
253
  MockServerConnection* codec_{};
254
  MockStreamDecoderFilter* decoder_filter_{};
255
  MockStreamEncoderFilter* encoder_filter_{};
256
  NiceMock<MockFilterChainFactory> filter_factory_;
257
  Event::SimulatedTimeSystem time_system_;
258
  SlowDateProviderImpl date_provider_{time_system_};
259
  bool use_srds_{};
260
  Router::MockRouteConfigProvider route_config_provider_;
261
  Router::MockScopedRouteConfigProvider scoped_route_config_provider_;
262
  Router::MockScopeKeyBuilder scope_key_builder_;
263
  std::string server_name_;
264
  HttpConnectionManagerProto::ServerHeaderTransformation server_transformation_{
265
      HttpConnectionManagerProto::OVERWRITE};
266
  absl::optional<std::string> scheme_;
267
  Stats::IsolatedStoreImpl fake_stats_;
268
  ConnectionManagerStats stats_;
269
  ConnectionManagerTracingStats tracing_stats_;
270
  ConnectionManagerListenerStats listener_stats_;
271
  uint32_t max_request_headers_kb_{Http::DEFAULT_MAX_REQUEST_HEADERS_KB};
272
  uint32_t max_request_headers_count_{Http::DEFAULT_MAX_HEADERS_COUNT};
273
  absl::optional<std::chrono::milliseconds> idle_timeout_;
274
  absl::optional<std::chrono::milliseconds> max_connection_duration_;
275
  absl::optional<std::chrono::milliseconds> max_stream_duration_;
276
  std::chrono::milliseconds stream_idle_timeout_{};
277
  std::chrono::milliseconds request_timeout_{};
278
  std::chrono::milliseconds request_headers_timeout_{};
279
  std::chrono::milliseconds delayed_close_timeout_{};
280
  bool use_remote_address_{true};
281
  Http::ForwardClientCertType forward_client_cert_;
282
  std::vector<Http::ClientCertDetailsType> set_current_client_cert_details_;
283
  Network::Address::Ipv4Instance local_address_{"127.0.0.1"};
284
  absl::optional<std::string> user_agent_;
285
  Tracing::TracerSharedPtr tracer_{std::make_shared<NiceMock<Tracing::MockTracer>>()};
286
  TracingConnectionManagerConfigPtr tracing_config_;
287
  bool proxy_100_continue_{true};
288
  bool stream_error_on_invalid_http_messaging_ = false;
289
  bool preserve_external_request_id_{false};
290
  Http::Http1Settings http1_settings_;
291
  Http::DefaultInternalAddressConfig internal_address_config_;
292
  bool normalize_path_{true};
293
  LocalReply::LocalReplyPtr local_reply_;
294
  std::vector<Http::OriginalIPDetectionSharedPtr> ip_detection_extensions_{};
295
  std::vector<Http::EarlyHeaderMutationPtr> early_header_mutations_;
296
  std::unique_ptr<HttpConnectionManagerProto::ProxyStatusConfig> proxy_status_config_;
297
};
298
299
// Internal representation of stream state. Encapsulates the stream state, mocks
300
// and encoders for both the request/response.
301
class FuzzStream {
302
public:
303
  // We track stream state here to prevent illegal operations, e.g. applying an
304
  // encodeData() to the codec after encodeTrailers(). This is necessary to
305
  // maintain the preconditions for operations on the codec at the API level. Of
306
  // course, it's the codecs must be robust to wire-level violations. We
307
  // explore these violations via MutateAction and SwapAction at the connection
308
  // buffer level.
309
  enum class StreamState {
310
    PendingHeaders,
311
    PendingNonInformationalHeaders,
312
    PendingDataOrTrailers,
313
    Closed
314
  };
315
316
  FuzzStream(ConnectionManagerImpl& conn_manager, FuzzConfig& config,
317
             const HeaderMap& request_headers,
318
             test::common::http::HeaderStatus decode_header_status, bool end_stream)
319
170k
      : conn_manager_(conn_manager), config_(config) {
320
170k
    config_.newStream();
321
170k
    request_state_ = end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers;
322
170k
    response_state_ = StreamState::PendingHeaders;
323
170k
    decoder_filter_ = config.decoder_filter_;
324
170k
    encoder_filter_ = config.encoder_filter_;
325
170k
    EXPECT_CALL(*config_.codec_, dispatch(_))
326
170k
        .WillOnce(InvokeWithoutArgs([this, &request_headers, end_stream] {
327
170k
          decoder_ = &conn_manager_.newStream(encoder_);
328
170k
          auto headers = std::make_unique<TestRequestHeaderMapImpl>(request_headers);
329
170k
          if (headers->Method() == nullptr) {
330
170k
            headers->setReferenceKey(Headers::get().Method, "GET");
331
170k
          }
332
170k
          if (headers->Host() != nullptr &&
333
170k
              !HeaderUtility::authorityIsValid(headers->getHostValue())) {
334
            // Sanitize host header so we don't fail at ASSERTs that verify header sanity checks
335
            // which should have been performed by the codec.
336
151
            headers->setHost(Fuzz::replaceInvalidHostCharacters(headers->getHostValue()));
337
151
          }
338
          // If sendLocalReply is called:
339
170k
          ON_CALL(encoder_, encodeHeaders(_, true))
340
170k
              .WillByDefault(Invoke([this](const ResponseHeaderMap&, bool end_stream) -> void {
341
103k
                response_state_ =
342
103k
                    end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers;
343
103k
              }));
344
170k
          decoder_->decodeHeaders(std::move(headers), end_stream);
345
170k
          return Http::okStatus();
346
170k
        }));
347
170k
    ON_CALL(*decoder_filter_, decodeHeaders(_, _))
348
170k
        .WillByDefault(
349
170k
            InvokeWithoutArgs([this, decode_header_status]() -> Http::FilterHeadersStatus {
350
60.0k
              header_status_ = fromHeaderStatus(decode_header_status);
351
60.0k
              return *header_status_;
352
60.0k
            }));
353
170k
    fakeOnData();
354
170k
    FUZZ_ASSERT(testing::Mock::VerifyAndClearExpectations(config_.codec_));
355
170k
  }
356
357
176k
  void fakeOnData() {
358
176k
    Buffer::OwnedImpl fake_input;
359
176k
    conn_manager_.onData(fake_input, false);
360
176k
  }
361
362
60.0k
  Http::FilterHeadersStatus fromHeaderStatus(test::common::http::HeaderStatus status) {
363
60.0k
    switch (status) {
364
54.9k
    case test::common::http::HeaderStatus::HEADER_CONTINUE:
365
54.9k
      return Http::FilterHeadersStatus::Continue;
366
1.56k
    case test::common::http::HeaderStatus::HEADER_STOP_ITERATION:
367
1.56k
      return Http::FilterHeadersStatus::StopIteration;
368
684
    case test::common::http::HeaderStatus::HEADER_STOP_ALL_ITERATION_AND_BUFFER:
369
684
      return Http::FilterHeadersStatus::StopAllIterationAndBuffer;
370
2.85k
    case test::common::http::HeaderStatus::HEADER_STOP_ALL_ITERATION_AND_WATERMARK:
371
2.85k
      return Http::FilterHeadersStatus::StopAllIterationAndWatermark;
372
0
    default:
373
0
      return Http::FilterHeadersStatus::Continue;
374
60.0k
    }
375
60.0k
  }
376
377
4.29k
  Http::FilterDataStatus fromDataStatus(test::common::http::DataStatus status) {
378
4.29k
    switch (status) {
379
2.66k
    case test::common::http::DataStatus::DATA_CONTINUE:
380
2.66k
      return Http::FilterDataStatus::Continue;
381
956
    case test::common::http::DataStatus::DATA_STOP_ITERATION_AND_BUFFER:
382
956
      return Http::FilterDataStatus::StopIterationAndBuffer;
383
27
    case test::common::http::DataStatus::DATA_STOP_ITERATION_AND_WATERMARK:
384
27
      return Http::FilterDataStatus::StopIterationAndWatermark;
385
652
    case test::common::http::DataStatus::DATA_STOP_ITERATION_NO_BUFFER:
386
652
      return Http::FilterDataStatus::StopIterationNoBuffer;
387
0
    default:
388
0
      return Http::FilterDataStatus::Continue;
389
4.29k
    }
390
4.29k
  }
391
392
307
  Http::FilterTrailersStatus fromTrailerStatus(test::common::http::TrailerStatus status) {
393
307
    switch (status) {
394
256
    case test::common::http::TrailerStatus::TRAILER_CONTINUE:
395
256
      return Http::FilterTrailersStatus::Continue;
396
51
    case test::common::http::TrailerStatus::TRAILER_STOP_ITERATION:
397
51
      return Http::FilterTrailersStatus::StopIteration;
398
0
    default:
399
0
      return Http::FilterTrailersStatus::Continue;
400
307
    }
401
307
  }
402
403
  void decoderFilterCallbackAction(
404
1.00k
      const test::common::http::DecoderFilterCallbackAction& decoder_filter_callback_action) {
405
1.00k
    switch (decoder_filter_callback_action.decoder_filter_callback_action_selector_case()) {
406
880
    case test::common::http::DecoderFilterCallbackAction::kAddDecodedData: {
407
880
      if (request_state_ == StreamState::PendingDataOrTrailers) {
408
877
        Buffer::OwnedImpl buf(std::string(
409
877
            decoder_filter_callback_action.add_decoded_data().size() % (1024 * 1024), 'a'));
410
877
        decoder_filter_->callbacks_->addDecodedData(
411
877
            buf, decoder_filter_callback_action.add_decoded_data().streaming());
412
877
      }
413
880
      break;
414
0
    }
415
121
    default:
416
      // Maybe nothing is set?
417
121
      break;
418
1.00k
    }
419
1.00k
  }
420
421
13.5k
  void requestAction(StreamState& state, const test::common::http::RequestAction& request_action) {
422
13.5k
    switch (request_action.request_action_selector_case()) {
423
6.97k
    case test::common::http::RequestAction::kData: {
424
6.97k
      if (state == StreamState::PendingDataOrTrailers) {
425
5.83k
        const auto& data_action = request_action.data();
426
5.83k
        ON_CALL(*decoder_filter_, decodeData(_, _))
427
5.83k
            .WillByDefault(InvokeWithoutArgs([this, &data_action]() -> Http::FilterDataStatus {
428
4.29k
              if (data_action.has_decoder_filter_callback_action()) {
429
938
                decoderFilterCallbackAction(data_action.decoder_filter_callback_action());
430
938
              }
431
4.29k
              data_status_ = fromDataStatus(data_action.status());
432
4.29k
              return *data_status_;
433
4.29k
            }));
434
5.83k
        EXPECT_CALL(*config_.codec_, dispatch(_)).WillOnce(InvokeWithoutArgs([this, &data_action] {
435
5.83k
          Buffer::OwnedImpl buf(std::string(data_action.size() % (1024 * 1024), 'a'));
436
5.83k
          decoder_->decodeData(buf, data_action.end_stream());
437
5.83k
          return Http::okStatus();
438
5.83k
        }));
439
5.83k
        fakeOnData();
440
5.83k
        FUZZ_ASSERT(testing::Mock::VerifyAndClearExpectations(config_.codec_));
441
5.83k
        state = data_action.end_stream() ? StreamState::Closed : StreamState::PendingDataOrTrailers;
442
5.83k
        decoding_done_ = false;
443
5.83k
      }
444
6.97k
      break;
445
6.97k
    }
446
6.97k
    case test::common::http::RequestAction::kTrailers: {
447
851
      if (state == StreamState::PendingDataOrTrailers) {
448
480
        const auto& trailers_action = request_action.trailers();
449
480
        ON_CALL(*decoder_filter_, decodeTrailers(_))
450
480
            .WillByDefault(
451
480
                InvokeWithoutArgs([this, &trailers_action]() -> Http::FilterTrailersStatus {
452
307
                  if (trailers_action.has_decoder_filter_callback_action()) {
453
63
                    decoderFilterCallbackAction(trailers_action.decoder_filter_callback_action());
454
63
                  }
455
307
                  trailers_status_ = fromTrailerStatus(trailers_action.status());
456
307
                  return *trailers_status_;
457
307
                }));
458
480
        EXPECT_CALL(*config_.codec_, dispatch(_))
459
480
            .WillOnce(InvokeWithoutArgs([this, &trailers_action] {
460
480
              decoder_->decodeTrailers(std::make_unique<TestRequestTrailerMapImpl>(
461
480
                  Fuzz::fromHeaders<TestRequestTrailerMapImpl>(trailers_action.headers())));
462
480
              return Http::okStatus();
463
480
            }));
464
480
        fakeOnData();
465
480
        FUZZ_ASSERT(testing::Mock::VerifyAndClearExpectations(config_.codec_));
466
480
        state = StreamState::Closed;
467
480
        decoding_done_ = false;
468
480
      }
469
851
      break;
470
851
    }
471
1.58k
    case test::common::http::RequestAction::kContinueDecoding: {
472
1.58k
      if (!decoding_done_ &&
473
1.58k
          (header_status_ == FilterHeadersStatus::StopAllIterationAndBuffer ||
474
1.56k
           header_status_ == FilterHeadersStatus::StopAllIterationAndWatermark ||
475
1.56k
           header_status_ == FilterHeadersStatus::StopIteration) &&
476
1.58k
          (!data_status_.has_value() || data_status_ == FilterDataStatus::StopIterationAndBuffer ||
477
255
           data_status_ == FilterDataStatus::StopIterationAndWatermark ||
478
255
           data_status_ == FilterDataStatus::StopIterationNoBuffer) &&
479
1.58k
          (!trailers_status_.has_value() ||
480
186
           trailers_status_ == FilterTrailersStatus::StopIteration)) {
481
186
        decoder_filter_->callbacks_->continueDecoding();
482
186
        decoding_done_ = true;
483
186
      }
484
1.58k
      break;
485
851
    }
486
340
    case test::common::http::RequestAction::kThrowDecoderException:
487
    // Dispatch no longer throws, execute subsequent kReturnDecoderError case.
488
905
    case test::common::http::RequestAction::kReturnDecoderError: {
489
905
      if (state == StreamState::PendingDataOrTrailers) {
490
96
        EXPECT_CALL(*config_.codec_, dispatch(_))
491
96
            .WillOnce(testing::Return(codecProtocolError("blah")));
492
96
        fakeOnData();
493
96
        FUZZ_ASSERT(testing::Mock::VerifyAndClearExpectations(config_.codec_));
494
96
        state = StreamState::Closed;
495
96
        decoding_done_ = true;
496
96
      }
497
905
      break;
498
905
    }
499
3.22k
    default:
500
      // Maybe nothing is set or not a request action?
501
3.22k
      break;
502
13.5k
    }
503
13.5k
  }
504
505
  void responseAction(StreamState& state,
506
7.23k
                      const test::common::http::ResponseAction& response_action) {
507
7.23k
    const bool end_stream = response_action.end_stream();
508
7.23k
    switch (response_action.response_action_selector_case()) {
509
76
    case test::common::http::ResponseAction::kContinueHeaders: {
510
76
      if (state == StreamState::PendingHeaders) {
511
55
        auto headers = std::make_unique<TestResponseHeaderMapImpl>(
512
55
            Fuzz::fromHeaders<TestResponseHeaderMapImpl>(response_action.continue_headers()));
513
55
        headers->setReferenceKey(Headers::get().Status, "100");
514
55
        decoder_filter_->callbacks_->encode1xxHeaders(std::move(headers));
515
        // We don't allow multiple 100-continue headers in HCM, UpstreamRequest is responsible
516
        // for coalescing.
517
55
        state = StreamState::PendingNonInformationalHeaders;
518
55
      }
519
76
      break;
520
0
    }
521
598
    case test::common::http::ResponseAction::kHeaders: {
522
598
      if (state == StreamState::PendingHeaders ||
523
598
          state == StreamState::PendingNonInformationalHeaders) {
524
512
        auto headers = std::make_unique<TestResponseHeaderMapImpl>(
525
512
            Fuzz::fromHeaders<TestResponseHeaderMapImpl>(response_action.headers()));
526
        // The client codec will ensure we always have a valid :status.
527
        // Similarly, local replies should always contain this.
528
512
        const auto status = Utility::getResponseStatusOrNullopt(*headers);
529
        // The only 1xx header that may be provided to encodeHeaders() is a 101 upgrade,
530
        // guaranteed by the codec parsers. See include/envoy/http/filter.h.
531
512
        if (!status.has_value() || (CodeUtility::is1xx(status.value()) &&
532
300
                                    status.value() != enumToInt(Http::Code::SwitchingProtocols))) {
533
213
          headers->setReferenceKey(Headers::get().Status, "200");
534
213
        }
535
512
        decoder_filter_->callbacks_->encodeHeaders(std::move(headers), end_stream, "details");
536
512
        state = end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers;
537
512
      }
538
598
      break;
539
0
    }
540
1.27k
    case test::common::http::ResponseAction::kData: {
541
1.27k
      if (state == StreamState::PendingDataOrTrailers) {
542
423
        Buffer::OwnedImpl buf(std::string(response_action.data() % (1024 * 1024), 'a'));
543
423
        decoder_filter_->callbacks_->encodeData(buf, end_stream);
544
423
        state = end_stream ? StreamState::Closed : StreamState::PendingDataOrTrailers;
545
423
      }
546
1.27k
      break;
547
0
    }
548
215
    case test::common::http::ResponseAction::kTrailers: {
549
215
      if (state == StreamState::PendingDataOrTrailers) {
550
29
        decoder_filter_->callbacks_->encodeTrailers(std::make_unique<TestResponseTrailerMapImpl>(
551
29
            Fuzz::fromHeaders<TestResponseTrailerMapImpl>(response_action.trailers())));
552
29
        state = StreamState::Closed;
553
29
      }
554
215
      break;
555
0
    }
556
5.07k
    default:
557
      // Maybe nothing is set?
558
5.07k
      break;
559
7.23k
    }
560
7.23k
  }
561
562
87.1k
  void streamAction(const test::common::http::StreamAction& stream_action) {
563
87.1k
    switch (stream_action.stream_action_selector_case()) {
564
13.5k
    case test::common::http::StreamAction::kRequest: {
565
13.5k
      requestAction(request_state_, stream_action.request());
566
13.5k
      break;
567
0
    }
568
7.23k
    case test::common::http::StreamAction::kResponse: {
569
7.23k
      responseAction(response_state_, stream_action.response());
570
7.23k
      break;
571
0
    }
572
66.3k
    default:
573
      // Maybe nothing is set?
574
66.3k
      break;
575
87.1k
    }
576
87.1k
  }
577
578
  ConnectionManagerImpl& conn_manager_;
579
  FuzzConfig& config_;
580
  RequestDecoder* decoder_{};
581
  NiceMock<MockResponseEncoder> encoder_;
582
  MockStreamDecoderFilter* decoder_filter_{};
583
  MockStreamEncoderFilter* encoder_filter_{};
584
  StreamState request_state_;
585
  StreamState response_state_;
586
  absl::optional<Http::FilterHeadersStatus> header_status_;
587
  absl::optional<Http::FilterDataStatus> data_status_;
588
  absl::optional<Http::FilterTrailersStatus> trailers_status_;
589
  bool decoding_done_{};
590
};
591
592
using FuzzStreamPtr = std::unique_ptr<FuzzStream>;
593
594
4.11k
DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) {
595
4.11k
  try {
596
4.11k
    TestUtility::validate(input);
597
4.11k
  } catch (const ProtoValidationException& e) {
598
3
    ENVOY_LOG_MISC(debug, "ProtoValidationException: {}", e.what());
599
3
    return;
600
3
  } catch (const Envoy::ProtobufMessage::DeprecatedProtoFieldException& e) {
601
0
    ENVOY_LOG_MISC(debug, "DeprecatedProtoFieldException: {}", e.what());
602
0
    return;
603
0
  }
604
605
4.11k
  FuzzConfig config(input.forward_client_cert());
606
4.11k
  NiceMock<Network::MockDrainDecision> drain_close;
607
4.11k
  NiceMock<Random::MockRandomGenerator> random;
608
4.11k
  Stats::SymbolTableImpl symbol_table;
609
4.11k
  Http::ContextImpl http_context(symbol_table);
610
4.11k
  NiceMock<Runtime::MockLoader> runtime;
611
4.11k
  NiceMock<LocalInfo::MockLocalInfo> local_info;
612
4.11k
  NiceMock<Upstream::MockClusterManager> cluster_manager;
613
4.11k
  NiceMock<Network::MockReadFilterCallbacks> filter_callbacks;
614
4.11k
  NiceMock<Server::MockOverloadManager> overload_manager;
615
4.11k
  auto ssl_connection = std::make_shared<Ssl::MockConnectionInfo>();
616
4.11k
  bool connection_alive = true;
617
618
4.11k
  ON_CALL(filter_callbacks.connection_, ssl()).WillByDefault(Return(ssl_connection));
619
4.11k
  ON_CALL(Const(filter_callbacks.connection_), ssl()).WillByDefault(Return(ssl_connection));
620
4.11k
  ON_CALL(filter_callbacks.connection_, close(_))
621
4.11k
      .WillByDefault(InvokeWithoutArgs([&connection_alive] { connection_alive = false; }));
622
4.11k
  ON_CALL(filter_callbacks.connection_, close(_, _))
623
9.03k
      .WillByDefault(InvokeWithoutArgs([&connection_alive] { connection_alive = false; }));
624
4.11k
  filter_callbacks.connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(
625
4.11k
      std::make_shared<Network::Address::Ipv4Instance>("127.0.0.1"));
626
4.11k
  filter_callbacks.connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(
627
4.11k
      std::make_shared<Network::Address::Ipv4Instance>("0.0.0.0"));
628
629
4.11k
  ConnectionManagerImpl conn_manager(config, drain_close, random, http_context, runtime, local_info,
630
4.11k
                                     cluster_manager, overload_manager, config.time_system_);
631
4.11k
  conn_manager.initializeReadFilterCallbacks(filter_callbacks);
632
633
4.11k
  std::vector<FuzzStreamPtr> streams;
634
635
499k
  for (const auto& action : input.actions()) {
636
499k
    ENVOY_LOG_MISC(trace, "action {} with {} streams", action.DebugString(), streams.size());
637
499k
    if (!connection_alive) {
638
114
      ENVOY_LOG_MISC(trace, "skipping due to dead connection");
639
114
      break;
640
114
    }
641
642
499k
    switch (action.action_selector_case()) {
643
170k
    case test::common::http::Action::kNewStream: {
644
170k
      streams.emplace_back(new FuzzStream(
645
170k
          conn_manager, config,
646
170k
          Fuzz::fromHeaders<TestRequestHeaderMapImpl>(action.new_stream().request_headers(),
647
170k
                                                      /* ignore_headers =*/{}, {":authority"}),
648
170k
          action.new_stream().status(), action.new_stream().end_stream()));
649
170k
      break;
650
0
    }
651
87.2k
    case test::common::http::Action::kStreamAction: {
652
87.2k
      const auto& stream_action = action.stream_action();
653
87.2k
      if (streams.empty()) {
654
119
        break;
655
119
      }
656
87.1k
      (*std::next(streams.begin(), stream_action.stream_id() % streams.size()))
657
87.1k
          ->streamAction(stream_action);
658
87.1k
      break;
659
87.2k
    }
660
241k
    default:
661
      // Maybe nothing is set?
662
241k
      break;
663
499k
    }
664
499k
  }
665
666
4.11k
  filter_callbacks.connection_.raiseEvent(Network::ConnectionEvent::LocalClose);
667
4.11k
  filter_callbacks.connection_.dispatcher_.clearDeferredDeleteList();
668
4.11k
}
669
670
} // namespace Http
671
} // namespace Envoy