summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/http2/adapter/nghttp2_test_utils.h
blob: 24493d7e164d6db06e3d756247a1284b315c8d75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_
#define QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_

#include <cstdint>
#include <vector>

#include "absl/strings/string_view.h"
#include "http2/adapter/http2_protocol.h"
#include "http2/adapter/nghttp2.h"
#include "common/platform/api/quiche_export.h"
#include "common/platform/api/quiche_test.h"

namespace http2 {
namespace adapter {
namespace test {

// A simple class that can easily be adapted to act as a nghttp2_data_source.
class QUICHE_NO_EXPORT TestDataSource {
 public:
  explicit TestDataSource(absl::string_view data) : data_(std::string(data)) {}

  absl::string_view ReadNext(size_t size) {
    const size_t to_send = std::min(size, remaining_.size());
    auto ret = remaining_.substr(0, to_send);
    remaining_.remove_prefix(to_send);
    return ret;
  }

  size_t SelectPayloadLength(size_t max_length) {
    return std::min(max_length, remaining_.size());
  }

  nghttp2_data_provider MakeDataProvider() {
    return nghttp2_data_provider{
        .source = {.ptr = this},
        .read_callback = [](nghttp2_session*, int32_t, uint8_t*, size_t length,
                            uint32_t* data_flags, nghttp2_data_source* source,
                            void*) -> ssize_t {
          *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
          auto* s = static_cast<TestDataSource*>(source->ptr);
          if (!s->is_data_available()) {
            return NGHTTP2_ERR_DEFERRED;
          }
          const ssize_t ret = s->SelectPayloadLength(length);
          if (ret < static_cast<ssize_t>(length)) {
            *data_flags |= NGHTTP2_DATA_FLAG_EOF;
          }
          return ret;
        }};
  }

  bool is_data_available() const { return is_data_available_; }
  void set_is_data_available(bool value) { is_data_available_ = value; }

 private:
  const std::string data_;
  absl::string_view remaining_ = data_;
  bool is_data_available_ = true;
};

// Matchers for nghttp2 data types.
testing::Matcher<const nghttp2_frame_hd*> HasFrameHeader(
    uint32_t streamid, uint8_t type, const testing::Matcher<int> flags);
testing::Matcher<const nghttp2_frame_hd&> HasFrameHeaderRef(
    uint32_t streamid, uint8_t type, const testing::Matcher<int> flags);

testing::Matcher<const nghttp2_frame*> IsData(
    const testing::Matcher<uint32_t> stream_id,
    const testing::Matcher<size_t> length, const testing::Matcher<int> flags,
    const testing::Matcher<size_t> padding = testing::_);

testing::Matcher<const nghttp2_frame*> IsHeaders(
    const testing::Matcher<uint32_t> stream_id,
    const testing::Matcher<int> flags, const testing::Matcher<int> category);

testing::Matcher<const nghttp2_frame*> IsRstStream(
    const testing::Matcher<uint32_t> stream_id,
    const testing::Matcher<uint32_t> error_code);

testing::Matcher<const nghttp2_frame*> IsSettings(
    const testing::Matcher<std::vector<Http2Setting>> values);

testing::Matcher<const nghttp2_frame*> IsPing(
    const testing::Matcher<uint64_t> id);

testing::Matcher<const nghttp2_frame*> IsPingAck(
    const testing::Matcher<uint64_t> id);

testing::Matcher<const nghttp2_frame*> IsGoAway(
    const testing::Matcher<uint32_t> last_stream_id,
    const testing::Matcher<uint32_t> error_code,
    const testing::Matcher<absl::string_view> opaque_data);

testing::Matcher<const nghttp2_frame*> IsWindowUpdate(
    const testing::Matcher<uint32_t> delta);

}  // namespace test
}  // namespace adapter
}  // namespace http2

#endif  // QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_