• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "quiche/http2/adapter/test_frame_sequence.h"
2 
3 #include <memory>
4 
5 #include "quiche/http2/adapter/http2_util.h"
6 #include "quiche/http2/adapter/oghttp2_util.h"
7 #include "quiche/spdy/core/hpack/hpack_encoder.h"
8 #include "quiche/spdy/core/spdy_framer.h"
9 
10 namespace http2 {
11 namespace adapter {
12 namespace test {
13 
ToHeaders(absl::Span<const std::pair<absl::string_view,absl::string_view>> headers)14 std::vector<Header> ToHeaders(
15     absl::Span<const std::pair<absl::string_view, absl::string_view>> headers) {
16   std::vector<Header> out;
17   for (auto [name, value] : headers) {
18     out.push_back(std::make_pair(HeaderRep(name), HeaderRep(value)));
19   }
20   return out;
21 }
22 
ClientPreface(absl::Span<const Http2Setting> settings)23 TestFrameSequence& TestFrameSequence::ClientPreface(
24     absl::Span<const Http2Setting> settings) {
25   preface_ = spdy::kHttp2ConnectionHeaderPrefix;
26   return Settings(settings);
27 }
28 
ServerPreface(absl::Span<const Http2Setting> settings)29 TestFrameSequence& TestFrameSequence::ServerPreface(
30     absl::Span<const Http2Setting> settings) {
31   return Settings(settings);
32 }
33 
Data(Http2StreamId stream_id,absl::string_view payload,bool fin,absl::optional<int> padding_length)34 TestFrameSequence& TestFrameSequence::Data(Http2StreamId stream_id,
35                                            absl::string_view payload, bool fin,
36                                            absl::optional<int> padding_length) {
37   auto data = std::make_unique<spdy::SpdyDataIR>(stream_id, payload);
38   data->set_fin(fin);
39   if (padding_length) {
40     data->set_padding_len(padding_length.value());
41   }
42   frames_.push_back(std::move(data));
43   return *this;
44 }
45 
RstStream(Http2StreamId stream_id,Http2ErrorCode error)46 TestFrameSequence& TestFrameSequence::RstStream(Http2StreamId stream_id,
47                                                 Http2ErrorCode error) {
48   frames_.push_back(std::make_unique<spdy::SpdyRstStreamIR>(
49       stream_id, TranslateErrorCode(error)));
50   return *this;
51 }
52 
Settings(absl::Span<const Http2Setting> settings)53 TestFrameSequence& TestFrameSequence::Settings(
54     absl::Span<const Http2Setting> settings) {
55   auto settings_frame = std::make_unique<spdy::SpdySettingsIR>();
56   for (const Http2Setting& setting : settings) {
57     settings_frame->AddSetting(setting.id, setting.value);
58   }
59   frames_.push_back(std::move(settings_frame));
60   return *this;
61 }
62 
SettingsAck()63 TestFrameSequence& TestFrameSequence::SettingsAck() {
64   auto settings = std::make_unique<spdy::SpdySettingsIR>();
65   settings->set_is_ack(true);
66   frames_.push_back(std::move(settings));
67   return *this;
68 }
69 
PushPromise(Http2StreamId stream_id,Http2StreamId promised_stream_id,absl::Span<const Header> headers)70 TestFrameSequence& TestFrameSequence::PushPromise(
71     Http2StreamId stream_id, Http2StreamId promised_stream_id,
72     absl::Span<const Header> headers) {
73   frames_.push_back(std::make_unique<spdy::SpdyPushPromiseIR>(
74       stream_id, promised_stream_id, ToHeaderBlock(headers)));
75   return *this;
76 }
77 
Ping(Http2PingId id)78 TestFrameSequence& TestFrameSequence::Ping(Http2PingId id) {
79   frames_.push_back(std::make_unique<spdy::SpdyPingIR>(id));
80   return *this;
81 }
82 
PingAck(Http2PingId id)83 TestFrameSequence& TestFrameSequence::PingAck(Http2PingId id) {
84   auto ping = std::make_unique<spdy::SpdyPingIR>(id);
85   ping->set_is_ack(true);
86   frames_.push_back(std::move(ping));
87   return *this;
88 }
89 
GoAway(Http2StreamId last_good_stream_id,Http2ErrorCode error,absl::string_view payload)90 TestFrameSequence& TestFrameSequence::GoAway(Http2StreamId last_good_stream_id,
91                                              Http2ErrorCode error,
92                                              absl::string_view payload) {
93   frames_.push_back(std::make_unique<spdy::SpdyGoAwayIR>(
94       last_good_stream_id, TranslateErrorCode(error), std::string(payload)));
95   return *this;
96 }
97 
Headers(Http2StreamId stream_id,absl::Span<const std::pair<absl::string_view,absl::string_view>> headers,bool fin,bool add_continuation)98 TestFrameSequence& TestFrameSequence::Headers(
99     Http2StreamId stream_id,
100     absl::Span<const std::pair<absl::string_view, absl::string_view>> headers,
101     bool fin, bool add_continuation) {
102   return Headers(stream_id, ToHeaders(headers), fin, add_continuation);
103 }
104 
Headers(Http2StreamId stream_id,spdy::Http2HeaderBlock block,bool fin,bool add_continuation)105 TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id,
106                                               spdy::Http2HeaderBlock block,
107                                               bool fin, bool add_continuation) {
108   if (add_continuation) {
109     // The normal intermediate representations don't allow you to represent a
110     // nonterminal HEADERS frame explicitly, so we'll need to use
111     // SpdyUnknownIRs. For simplicity, and in order not to mess up HPACK state,
112     // the payload will be uncompressed.
113     spdy::HpackEncoder encoder;
114     encoder.DisableCompression();
115     std::string encoded_block = encoder.EncodeHeaderBlock(block);
116     const size_t pos = encoded_block.size() / 2;
117     const uint8_t flags = fin ? END_STREAM_FLAG : 0x0;
118     frames_.push_back(std::make_unique<spdy::SpdyUnknownIR>(
119         stream_id, static_cast<uint8_t>(spdy::SpdyFrameType::HEADERS), flags,
120         encoded_block.substr(0, pos)));
121 
122     auto continuation = std::make_unique<spdy::SpdyContinuationIR>(stream_id);
123     continuation->set_end_headers(true);
124     continuation->take_encoding(encoded_block.substr(pos));
125     frames_.push_back(std::move(continuation));
126   } else {
127     auto headers =
128         std::make_unique<spdy::SpdyHeadersIR>(stream_id, std::move(block));
129     headers->set_fin(fin);
130     frames_.push_back(std::move(headers));
131   }
132   return *this;
133 }
134 
Headers(Http2StreamId stream_id,absl::Span<const Header> headers,bool fin,bool add_continuation)135 TestFrameSequence& TestFrameSequence::Headers(Http2StreamId stream_id,
136                                               absl::Span<const Header> headers,
137                                               bool fin, bool add_continuation) {
138   return Headers(stream_id, ToHeaderBlock(headers), fin, add_continuation);
139 }
140 
WindowUpdate(Http2StreamId stream_id,int32_t delta)141 TestFrameSequence& TestFrameSequence::WindowUpdate(Http2StreamId stream_id,
142                                                    int32_t delta) {
143   frames_.push_back(
144       std::make_unique<spdy::SpdyWindowUpdateIR>(stream_id, delta));
145   return *this;
146 }
147 
Priority(Http2StreamId stream_id,Http2StreamId parent_stream_id,int weight,bool exclusive)148 TestFrameSequence& TestFrameSequence::Priority(Http2StreamId stream_id,
149                                                Http2StreamId parent_stream_id,
150                                                int weight, bool exclusive) {
151   frames_.push_back(std::make_unique<spdy::SpdyPriorityIR>(
152       stream_id, parent_stream_id, weight, exclusive));
153   return *this;
154 }
155 
Metadata(Http2StreamId stream_id,absl::string_view payload,bool multiple_frames)156 TestFrameSequence& TestFrameSequence::Metadata(Http2StreamId stream_id,
157                                                absl::string_view payload,
158                                                bool multiple_frames) {
159   if (multiple_frames) {
160     const size_t pos = payload.size() / 2;
161     frames_.push_back(std::make_unique<spdy::SpdyUnknownIR>(
162         stream_id, kMetadataFrameType, 0, std::string(payload.substr(0, pos))));
163     frames_.push_back(std::make_unique<spdy::SpdyUnknownIR>(
164         stream_id, kMetadataFrameType, kMetadataEndFlag,
165         std::string(payload.substr(pos))));
166   } else {
167     frames_.push_back(std::make_unique<spdy::SpdyUnknownIR>(
168         stream_id, kMetadataFrameType, kMetadataEndFlag, std::string(payload)));
169   }
170   return *this;
171 }
172 
Serialize()173 std::string TestFrameSequence::Serialize() {
174   std::string result;
175   if (!preface_.empty()) {
176     result = preface_;
177   }
178   spdy::SpdyFramer framer(spdy::SpdyFramer::ENABLE_COMPRESSION);
179   for (const auto& frame : frames_) {
180     spdy::SpdySerializedFrame f = framer.SerializeFrame(*frame);
181     absl::StrAppend(&result, absl::string_view(f));
182   }
183   return result;
184 }
185 
186 }  // namespace test
187 }  // namespace adapter
188 }  // namespace http2
189