Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/test/integration/h2_fuzz.cc
Line
Count
Source (jump to first uncovered line)
1
#include "test/integration/h2_fuzz.h"
2
3
#include <functional>
4
5
#include "source/common/common/assert.h"
6
#include "source/common/common/base64.h"
7
#include "source/common/common/logger.h"
8
9
#include "test/test_common/environment.h"
10
11
namespace Envoy {
12
13
using namespace Envoy::Http::Http2;
14
15
namespace {
16
17
static Http2Frame::HeadersFlags
18
161
unifyHeadersFlags(const Protobuf::RepeatedField<int>& headers_flags) {
19
161
  int unified_flags = 0;
20
161
  for (const auto& flag : headers_flags) {
21
77
    unified_flags |= flag;
22
77
  }
23
161
  return static_cast<Http2Frame::HeadersFlags>(unified_flags);
24
161
}
25
26
} // namespace
27
28
void H2FuzzIntegrationTest::sendFrame(const test::integration::H2TestFrame& proto_frame,
29
6.72k
                                      std::function<void(const Http2Frame&)> write_func) {
30
6.72k
  Http2Frame h2_frame;
31
6.72k
  switch (proto_frame.frame_type_case()) {
32
173
  case test::integration::H2TestFrame::kPing:
33
173
    ENVOY_LOG_MISC(trace, "Sending ping frame");
34
173
    h2_frame = Http2Frame::makePingFrame(proto_frame.ping().data());
35
173
    break;
36
841
  case test::integration::H2TestFrame::kSettings: {
37
841
    const Http2Frame::SettingsFlags settings_flags =
38
841
        static_cast<Http2Frame::SettingsFlags>(proto_frame.settings().flags());
39
841
    ENVOY_LOG_MISC(trace, "Sending settings frame");
40
841
    h2_frame = Http2Frame::makeEmptySettingsFrame(settings_flags);
41
841
    break;
42
0
  }
43
62
  case test::integration::H2TestFrame::kHeaders: {
44
62
    const Http2Frame::HeadersFlags headers_flags = unifyHeadersFlags(proto_frame.headers().flags());
45
62
    const uint32_t stream_idx = proto_frame.headers().stream_index();
46
62
    ENVOY_LOG_MISC(trace, "Sending headers frame");
47
62
    h2_frame = Http2Frame::makeEmptyHeadersFrame(stream_idx, headers_flags);
48
62
    break;
49
0
  }
50
70
  case test::integration::H2TestFrame::kContinuation: {
51
70
    const Http2Frame::HeadersFlags headers_flags =
52
70
        unifyHeadersFlags(proto_frame.continuation().flags());
53
70
    const uint32_t stream_idx = proto_frame.continuation().stream_index();
54
70
    ENVOY_LOG_MISC(trace, "Sending continuation frame");
55
70
    h2_frame = Http2Frame::makeEmptyContinuationFrame(stream_idx, headers_flags);
56
70
    break;
57
0
  }
58
74
  case test::integration::H2TestFrame::kData: {
59
74
    const Http2Frame::DataFlags data_flags =
60
74
        static_cast<Http2Frame::DataFlags>(proto_frame.data().flags());
61
74
    const uint32_t stream_idx = proto_frame.data().stream_index();
62
74
    ENVOY_LOG_MISC(trace, "Sending data frame");
63
74
    h2_frame = Http2Frame::makeEmptyDataFrame(stream_idx, data_flags);
64
74
    break;
65
0
  }
66
190
  case test::integration::H2TestFrame::kPriority: {
67
190
    const uint32_t stream_idx = proto_frame.priority().stream_index();
68
190
    const uint32_t dependent_idx = proto_frame.priority().dependent_index();
69
190
    ENVOY_LOG_MISC(trace, "Sending priority frame");
70
190
    h2_frame = Http2Frame::makePriorityFrame(stream_idx, dependent_idx);
71
190
    break;
72
0
  }
73
29
  case test::integration::H2TestFrame::kPushPromise: {
74
29
    const Http2Frame::HeadersFlags headers_flags =
75
29
        unifyHeadersFlags(proto_frame.push_promise().flags());
76
29
    const uint32_t stream_idx = proto_frame.push_promise().stream_index();
77
29
    const uint32_t promised_stream_idx = proto_frame.push_promise().promised_stream_index();
78
29
    ENVOY_LOG_MISC(trace, "Sending push promise frame");
79
29
    h2_frame =
80
29
        Http2Frame::makeEmptyPushPromiseFrame(stream_idx, promised_stream_idx, headers_flags);
81
29
    break;
82
0
  }
83
89
  case test::integration::H2TestFrame::kResetStream: {
84
89
    const uint32_t stream_idx = proto_frame.reset_stream().stream_index();
85
89
    const Http2Frame::ErrorCode error_code =
86
89
        static_cast<Http2Frame::ErrorCode>(proto_frame.reset_stream().error_code());
87
89
    ENVOY_LOG_MISC(trace, "Sending reset stream frame");
88
89
    h2_frame = Http2Frame::makeResetStreamFrame(stream_idx, error_code);
89
89
    break;
90
0
  }
91
110
  case test::integration::H2TestFrame::kGoAway: {
92
110
    const uint32_t last_stream_idx = proto_frame.go_away().last_stream_index();
93
110
    const Http2Frame::ErrorCode error_code =
94
110
        static_cast<Http2Frame::ErrorCode>(proto_frame.go_away().error_code());
95
110
    ENVOY_LOG_MISC(trace, "Sending go-away frame");
96
110
    h2_frame = Http2Frame::makeEmptyGoAwayFrame(last_stream_idx, error_code);
97
110
    break;
98
0
  }
99
69
  case test::integration::H2TestFrame::kWindowUpdate: {
100
69
    const uint32_t stream_idx = proto_frame.window_update().stream_index();
101
69
    const uint32_t increment = proto_frame.window_update().increment();
102
69
    ENVOY_LOG_MISC(trace, "Sending windows_update frame");
103
69
    h2_frame = Http2Frame::makeWindowUpdateFrame(stream_idx, increment);
104
69
    break;
105
0
  }
106
63
  case test::integration::H2TestFrame::kMalformedRequest: {
107
63
    const uint32_t stream_idx = proto_frame.malformed_request().stream_index();
108
63
    ENVOY_LOG_MISC(trace, "Sending malformed_request frame");
109
63
    h2_frame = Http2Frame::makeMalformedRequest(stream_idx);
110
63
    break;
111
0
  }
112
40
  case test::integration::H2TestFrame::kMalformedRequestWithZerolenHeader: {
113
40
    const uint32_t stream_idx = proto_frame.malformed_request_with_zerolen_header().stream_index();
114
40
    const absl::string_view host = proto_frame.malformed_request_with_zerolen_header().host();
115
40
    const absl::string_view path = proto_frame.malformed_request_with_zerolen_header().path();
116
40
    ENVOY_LOG_MISC(trace, "Sending malformed_request_with_zerolen_header");
117
40
    h2_frame = Http2Frame::makeMalformedRequestWithZerolenHeader(stream_idx, host, path);
118
40
    break;
119
0
  }
120
305
  case test::integration::H2TestFrame::kRequest: {
121
305
    const uint32_t stream_idx = proto_frame.request().stream_index();
122
305
    const absl::string_view host = proto_frame.request().host();
123
305
    const absl::string_view path = proto_frame.request().path();
124
305
    ENVOY_LOG_MISC(trace, "Sending request");
125
305
    h2_frame = Http2Frame::makeRequest(stream_idx, host, path);
126
305
    break;
127
0
  }
128
176
  case test::integration::H2TestFrame::kPostRequest: {
129
176
    const uint32_t stream_idx = proto_frame.post_request().stream_index();
130
176
    const absl::string_view host = proto_frame.post_request().host();
131
176
    const absl::string_view path = proto_frame.post_request().path();
132
176
    ENVOY_LOG_MISC(trace, "Sending post request");
133
176
    h2_frame = Http2Frame::makePostRequest(stream_idx, host, path);
134
176
    break;
135
0
  }
136
2.49k
  case test::integration::H2TestFrame::kMetadata: {
137
2.49k
    const Http2Frame::MetadataFlags metadata_flags =
138
2.49k
        static_cast<Http2Frame::MetadataFlags>(proto_frame.metadata().flags());
139
2.49k
    const uint32_t stream_idx = proto_frame.metadata().stream_index();
140
2.49k
    Http::MetadataMap metadata_map;
141
9.35k
    for (const auto& metadataPair : proto_frame.metadata().metadata().metadata()) {
142
9.35k
      metadata_map.insert(metadataPair);
143
9.35k
    }
144
2.49k
    ENVOY_LOG_MISC(trace, "Sending metadata frame.");
145
2.49k
    h2_frame =
146
2.49k
        Http2Frame::makeMetadataFrameFromMetadataMap(stream_idx, metadata_map, metadata_flags);
147
2.49k
    break;
148
0
  }
149
57
  case test::integration::H2TestFrame::kStatus: {
150
57
    const std::string status = proto_frame.status().status();
151
57
    const uint32_t stream_idx = proto_frame.status().stream_index();
152
57
    ENVOY_LOG_MISC(trace, "Sending status frame");
153
57
    h2_frame = Http2Frame::makeHeadersFrameWithStatus(status, stream_idx);
154
57
    break;
155
0
  }
156
116
  case test::integration::H2TestFrame::kGeneric: {
157
116
    const absl::string_view frame_bytes = proto_frame.generic().frame_bytes();
158
116
    ENVOY_LOG_MISC(trace, "Sending generic frame");
159
116
    h2_frame = Http2Frame::makeGenericFrame(frame_bytes);
160
116
    break;
161
0
  }
162
1.76k
  default:
163
1.76k
    ENVOY_LOG_MISC(debug, "Proto-frame not supported!");
164
1.76k
    break;
165
6.72k
  }
166
167
6.72k
  write_func(h2_frame);
168
6.72k
}
169
170
void H2FuzzIntegrationTest::replay(const test::integration::H2CaptureFuzzTestCase& input,
171
1.22k
                                   bool ignore_response) {
172
1.22k
  struct Init {
173
1.22k
    Init(H2FuzzIntegrationTest* test) { test->initialize(); }
174
1.22k
  };
175
1.22k
  PERSISTENT_FUZZ_VAR(Init, initialized, (this));
176
1.22k
  UNREFERENCED_PARAMETER(initialized);
177
1.22k
  IntegrationTcpClientPtr tcp_client = makeTcpConnection(lookupPort("http"));
178
1.22k
  FakeRawConnectionPtr fake_upstream_connection;
179
1.22k
  bool stop_further_inputs = false;
180
1.22k
  bool preamble_sent = false;
181
5.92k
  for (int i = 0; i < input.events().size(); ++i) {
182
4.76k
    if (stop_further_inputs) {
183
58
      break;
184
58
    }
185
4.71k
    const auto& event = input.events(i);
186
4.71k
    ENVOY_LOG_MISC(debug, "Processing event: {}", event.DebugString());
187
    // If we're disconnected, we fail out.
188
4.71k
    if (!tcp_client->connected()) {
189
6
      ENVOY_LOG_MISC(debug, "Disconnected, no further event processing.");
190
6
      break;
191
6
    }
192
4.70k
    switch (event.event_selector_case()) {
193
543
    case test::integration::Event::kDownstreamSendEvent: {
194
4.71k
      auto downstream_write_func = [&](const Http2Frame& h2_frame) -> void {
195
4.71k
        ASSERT_TRUE(tcp_client->write(std::string(h2_frame), false, false));
196
4.71k
      };
197
543
      if (!preamble_sent) {
198
        // Start H2 session - send hello string
199
309
        ASSERT_TRUE(tcp_client->write(Http2Frame::Preamble, false, false));
200
309
        preamble_sent = true;
201
309
      }
202
4.72k
      for (auto& frame : event.downstream_send_event().h2_frames()) {
203
4.72k
        if (!tcp_client->connected()) {
204
6
          ENVOY_LOG_MISC(debug,
205
6
                         "Disconnected, avoiding sending data, no further event processing.");
206
6
          break;
207
6
        }
208
209
4.71k
        ENVOY_LOG_MISC(trace, "sending downstream frame");
210
4.71k
        sendFrame(frame, downstream_write_func);
211
4.71k
      }
212
543
      break;
213
543
    }
214
351
    case test::integration::Event::kUpstreamSendEvent: {
215
351
      if (ignore_response) {
216
111
        break;
217
111
      }
218
240
      if (fake_upstream_connection == nullptr) {
219
150
        if (!fake_upstreams_[0]->waitForRawConnection(fake_upstream_connection, max_wait_ms_)) {
220
          // If we timed out, we fail out.
221
83
          if (tcp_client->connected()) {
222
83
            tcp_client->close();
223
83
          }
224
83
          stop_further_inputs = true;
225
83
          break;
226
83
        }
227
150
      }
228
      // If we're no longer connected, we're done.
229
157
      if (!fake_upstream_connection->connected()) {
230
6
        if (tcp_client->connected()) {
231
6
          tcp_client->close();
232
6
        }
233
6
        stop_further_inputs = true;
234
6
        break;
235
6
      }
236
151
      {
237
2.01k
        auto upstream_write_func = [&](const Http2Frame& h2_frame) -> void {
238
2.01k
          AssertionResult result = fake_upstream_connection->write(std::string(h2_frame));
239
2.01k
          RELEASE_ASSERT(result, result.message());
240
2.01k
        };
241
2.03k
        for (auto& frame : event.upstream_send_event().h2_frames()) {
242
2.03k
          if (!fake_upstream_connection->connected()) {
243
21
            ENVOY_LOG_MISC(
244
21
                debug,
245
21
                "Upstream disconnected, avoiding sending data, no further event processing.");
246
21
            stop_further_inputs = true;
247
21
            break;
248
21
          }
249
250
2.01k
          ENVOY_LOG_MISC(trace, "sending upstream frame");
251
2.01k
          sendFrame(frame, upstream_write_func);
252
2.01k
        }
253
151
      }
254
151
      break;
255
157
    }
256
3.81k
    default:
257
      // Maybe nothing is set?
258
3.81k
      break;
259
4.70k
    }
260
4.70k
  }
261
1.22k
  if (fake_upstream_connection != nullptr) {
262
67
    if (fake_upstream_connection->connected()) {
263
37
      AssertionResult result = fake_upstream_connection->close();
264
37
      RELEASE_ASSERT(result, result.message());
265
37
    }
266
67
    AssertionResult result = fake_upstream_connection->waitForDisconnect();
267
67
    RELEASE_ASSERT(result, result.message());
268
67
  }
269
1.22k
  if (tcp_client->connected()) {
270
1.20k
    tcp_client->close();
271
1.20k
  }
272
1.22k
}
273
274
} // namespace Envoy