OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/spdy/spdy_framer.h" | |
6 | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 | |
10 #include <algorithm> | |
11 #include <cstdint> | |
12 #include <limits> | |
13 #include <memory> | |
14 #include <tuple> | |
15 #include <utility> | |
16 #include <vector> | |
17 | |
18 #include "base/compiler_specific.h" | |
19 #include "base/logging.h" | |
20 #include "base/macros.h" | |
21 #include "base/memory/ptr_util.h" | |
22 #include "base/strings/string_number_conversions.h" | |
23 #include "net/quic/platform/api/quic_flags.h" | |
24 #include "net/spdy/array_output_buffer.h" | |
25 #include "net/spdy/hpack/hpack_constants.h" | |
26 #include "net/spdy/mock_spdy_framer_visitor.h" | |
27 #include "net/spdy/spdy_flags.h" | |
28 #include "net/spdy/spdy_frame_builder.h" | |
29 #include "net/spdy/spdy_frame_reader.h" | |
30 #include "net/spdy/spdy_protocol.h" | |
31 #include "net/spdy/spdy_test_utils.h" | |
32 #include "testing/gmock/include/gmock/gmock.h" | |
33 #include "testing/gtest/include/gtest/gtest.h" | |
34 #include "testing/platform_test.h" | |
35 | |
36 using testing::_; | |
37 | |
38 namespace net { | |
39 | |
40 namespace test { | |
41 | |
42 namespace { | |
43 | |
44 const int64_t kSize = 64 * 1024; | |
45 char output_buffer[kSize] = ""; | |
46 | |
47 // frame_list_char is used to hold frames to be compared with output_buffer. | |
48 const int64_t buffer_size = 64 * 1024; | |
49 char frame_list_char[buffer_size] = ""; | |
50 } | |
51 | |
52 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface { | |
53 public: | |
54 MOCK_METHOD4(OnSendCompressedFrame, | |
55 void(SpdyStreamId stream_id, | |
56 SpdyFrameType type, | |
57 size_t payload_len, | |
58 size_t frame_len)); | |
59 | |
60 MOCK_METHOD3(OnReceiveCompressedFrame, | |
61 void(SpdyStreamId stream_id, | |
62 SpdyFrameType type, | |
63 size_t frame_len)); | |
64 }; | |
65 | |
66 class SpdyFramerTestUtil { | |
67 public: | |
68 // Decompress a single frame using the decompression context held by | |
69 // the SpdyFramer. The implemention is meant for use only in tests | |
70 // and will CHECK fail if the input is anything other than a single, | |
71 // well-formed compressed frame. | |
72 // | |
73 // Returns a new decompressed SpdySerializedFrame. | |
74 template <class SpdyFrameType> | |
75 static SpdySerializedFrame DecompressFrame(SpdyFramer* framer, | |
76 const SpdyFrameType& frame) { | |
77 DecompressionVisitor visitor; | |
78 framer->set_visitor(&visitor); | |
79 CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size())); | |
80 CHECK_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer->state()); | |
81 framer->set_visitor(nullptr); | |
82 SpdyFramer serializer(SpdyFramer::DISABLE_COMPRESSION); | |
83 return serializer.SerializeFrame(visitor.GetFrame()); | |
84 } | |
85 | |
86 class DecompressionVisitor : public SpdyFramerVisitorInterface { | |
87 public: | |
88 DecompressionVisitor() : finished_(false) {} | |
89 | |
90 const SpdyFrameIR& GetFrame() const { | |
91 CHECK(finished_); | |
92 return *frame_; | |
93 } | |
94 | |
95 SpdyHeadersHandlerInterface* OnHeaderFrameStart( | |
96 SpdyStreamId stream_id) override { | |
97 if (headers_handler_ == nullptr) { | |
98 headers_handler_ = base::MakeUnique<TestHeadersHandler>(); | |
99 } | |
100 return headers_handler_.get(); | |
101 } | |
102 | |
103 void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override { | |
104 CHECK(!finished_); | |
105 frame_->set_header_block(headers_handler_->decoded_block().Clone()); | |
106 finished_ = true; | |
107 if (end_headers) { | |
108 headers_handler_.reset(); | |
109 } | |
110 } | |
111 | |
112 void OnHeaders(SpdyStreamId stream_id, | |
113 bool has_priority, | |
114 int weight, | |
115 SpdyStreamId parent_stream_id, | |
116 bool exclusive, | |
117 bool fin, | |
118 bool end) override { | |
119 auto headers = base::MakeUnique<SpdyHeadersIR>(stream_id); | |
120 headers->set_has_priority(has_priority); | |
121 headers->set_weight(weight); | |
122 headers->set_parent_stream_id(parent_stream_id); | |
123 headers->set_exclusive(exclusive); | |
124 headers->set_fin(fin); | |
125 frame_ = std::move(headers); | |
126 } | |
127 | |
128 void OnPushPromise(SpdyStreamId stream_id, | |
129 SpdyStreamId promised_stream_id, | |
130 bool end) override { | |
131 frame_ = | |
132 base::MakeUnique<SpdyPushPromiseIR>(stream_id, promised_stream_id); | |
133 } | |
134 | |
135 // TODO(birenroy): Add support for CONTINUATION. | |
136 void OnContinuation(SpdyStreamId stream_id, bool end) override { | |
137 LOG(FATAL); | |
138 } | |
139 | |
140 // All other methods just LOG(FATAL). | |
141 void OnError(SpdyFramer* framer) override { LOG(FATAL); } | |
142 void OnDataFrameHeader(SpdyStreamId stream_id, | |
143 size_t length, | |
144 bool fin) override { | |
145 LOG(FATAL) << "Unexpected data frame header"; | |
146 } | |
147 void OnStreamFrameData(SpdyStreamId stream_id, | |
148 const char* data, | |
149 size_t len) override { | |
150 LOG(FATAL); | |
151 } | |
152 | |
153 void OnStreamEnd(SpdyStreamId stream_id) override { LOG(FATAL); } | |
154 | |
155 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { | |
156 LOG(FATAL); | |
157 } | |
158 | |
159 void OnRstStream(SpdyStreamId stream_id, | |
160 SpdyErrorCode error_code) override { | |
161 LOG(FATAL); | |
162 } | |
163 void OnSetting(SpdySettingsIds id, uint32_t value) override { LOG(FATAL); } | |
164 void OnPing(SpdyPingId unique_id, bool is_ack) override { LOG(FATAL); } | |
165 void OnSettingsEnd() override { LOG(FATAL); } | |
166 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
167 SpdyErrorCode error_code) override { | |
168 LOG(FATAL); | |
169 } | |
170 | |
171 void OnWindowUpdate(SpdyStreamId stream_id, | |
172 int delta_window_size) override { | |
173 LOG(FATAL); | |
174 } | |
175 | |
176 void OnPriority(SpdyStreamId stream_id, | |
177 SpdyStreamId parent_stream_id, | |
178 int weight, | |
179 bool exclusive) override { | |
180 // Do nothing. | |
181 } | |
182 | |
183 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { | |
184 LOG(FATAL); | |
185 return false; | |
186 } | |
187 | |
188 private: | |
189 std::unique_ptr<TestHeadersHandler> headers_handler_; | |
190 std::unique_ptr<SpdyFrameWithHeaderBlockIR> frame_; | |
191 bool finished_; | |
192 | |
193 DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor); | |
194 }; | |
195 | |
196 private: | |
197 DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil); | |
198 }; | |
199 | |
200 MATCHER_P(IsFrameUnionOf, frame_list, "") { | |
201 size_t size_verified = 0; | |
202 for (const auto& frame : *frame_list) { | |
203 if (arg.size() < size_verified + frame.size()) { | |
204 LOG(FATAL) << "Incremental header serialization should not lead to a " | |
205 << "higher total frame length than non-incremental method."; | |
206 return false; | |
207 } | |
208 if (memcmp(arg.data() + size_verified, frame.data(), frame.size())) { | |
209 CompareCharArraysWithHexError( | |
210 "Header serialization methods should be equivalent: ", | |
211 reinterpret_cast<unsigned char*>(arg.data() + size_verified), | |
212 frame.size(), reinterpret_cast<unsigned char*>(frame.data()), | |
213 frame.size()); | |
214 return false; | |
215 } | |
216 size_verified += frame.size(); | |
217 } | |
218 return size_verified == arg.size(); | |
219 } | |
220 | |
221 class SpdyFramerPeer { | |
222 public: | |
223 static size_t ControlFrameBufferSize() { | |
224 return SpdyFramer::kControlFrameBufferSize; | |
225 } | |
226 static size_t GetNumberRequiredContinuationFrames(SpdyFramer* framer, | |
227 size_t size) { | |
228 return framer->GetNumberRequiredContinuationFrames(size); | |
229 } | |
230 static void SetError(SpdyFramer* framer, SpdyFramer::SpdyFramerError error) { | |
231 framer->set_error(error); | |
232 } | |
233 | |
234 // TODO(dahollings): Remove these methods when deprecating non-incremental | |
235 // header serialization path. | |
236 static std::unique_ptr<SpdyHeadersIR> CloneSpdyHeadersIR( | |
237 const SpdyHeadersIR& headers) { | |
238 auto newHeaders = base::MakeUnique<SpdyHeadersIR>( | |
239 headers.stream_id(), headers.header_block().Clone()); | |
240 newHeaders->set_fin(headers.fin()); | |
241 newHeaders->set_has_priority(headers.has_priority()); | |
242 newHeaders->set_weight(headers.weight()); | |
243 newHeaders->set_parent_stream_id(headers.parent_stream_id()); | |
244 newHeaders->set_exclusive(headers.exclusive()); | |
245 if (headers.padded()) { | |
246 newHeaders->set_padding_len(headers.padding_payload_len() + 1); | |
247 } | |
248 newHeaders->set_end_headers(headers.end_headers()); | |
249 return newHeaders; | |
250 } | |
251 | |
252 static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer, | |
253 const SpdyHeadersIR& headers) { | |
254 SpdySerializedFrame serialized_headers_old_version( | |
255 framer->SerializeHeaders(headers)); | |
256 framer->hpack_encoder_.reset(nullptr); | |
257 auto* saved_debug_visitor = framer->debug_visitor_; | |
258 framer->debug_visitor_ = nullptr; | |
259 | |
260 std::vector<SpdySerializedFrame> frame_list; | |
261 ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); | |
262 SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers)); | |
263 while (it.HasNextFrame()) { | |
264 size_t size_before = frame_list_buffer.Size(); | |
265 it.NextFrame(&frame_list_buffer); | |
266 frame_list.emplace_back( | |
267 SpdySerializedFrame(frame_list_buffer.Begin() + size_before, | |
268 frame_list_buffer.Size() - size_before, false)); | |
269 } | |
270 framer->debug_visitor_ = saved_debug_visitor; | |
271 | |
272 EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); | |
273 return serialized_headers_old_version; | |
274 } | |
275 | |
276 static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer, | |
277 const SpdyHeadersIR& headers, | |
278 ArrayOutputBuffer* output) { | |
279 if (output == nullptr) { | |
280 return SerializeHeaders(framer, headers); | |
281 } | |
282 output->Reset(); | |
283 EXPECT_TRUE(framer->SerializeHeaders(headers, output)); | |
284 SpdySerializedFrame serialized_headers_old_version(output->Begin(), | |
285 output->Size(), false); | |
286 framer->hpack_encoder_.reset(nullptr); | |
287 auto* saved_debug_visitor = framer->debug_visitor_; | |
288 framer->debug_visitor_ = nullptr; | |
289 | |
290 std::vector<SpdySerializedFrame> frame_list; | |
291 ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); | |
292 SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers)); | |
293 while (it.HasNextFrame()) { | |
294 size_t size_before = frame_list_buffer.Size(); | |
295 it.NextFrame(&frame_list_buffer); | |
296 frame_list.emplace_back( | |
297 SpdySerializedFrame(frame_list_buffer.Begin() + size_before, | |
298 frame_list_buffer.Size() - size_before, false)); | |
299 } | |
300 framer->debug_visitor_ = saved_debug_visitor; | |
301 | |
302 EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); | |
303 return serialized_headers_old_version; | |
304 } | |
305 | |
306 static std::unique_ptr<SpdyPushPromiseIR> CloneSpdyPushPromiseIR( | |
307 const SpdyPushPromiseIR& push_promise) { | |
308 auto new_push_promise = base::MakeUnique<SpdyPushPromiseIR>( | |
309 push_promise.stream_id(), push_promise.promised_stream_id(), | |
310 push_promise.header_block().Clone()); | |
311 new_push_promise->set_fin(push_promise.fin()); | |
312 if (push_promise.padded()) { | |
313 new_push_promise->set_padding_len(push_promise.padding_payload_len() + 1); | |
314 } | |
315 new_push_promise->set_end_headers(push_promise.end_headers()); | |
316 return new_push_promise; | |
317 } | |
318 | |
319 static SpdySerializedFrame SerializePushPromise( | |
320 SpdyFramer* framer, | |
321 const SpdyPushPromiseIR& push_promise) { | |
322 SpdySerializedFrame serialized_headers_old_version = | |
323 framer->SerializePushPromise(push_promise); | |
324 framer->hpack_encoder_.reset(nullptr); | |
325 auto* saved_debug_visitor = framer->debug_visitor_; | |
326 framer->debug_visitor_ = nullptr; | |
327 | |
328 std::vector<SpdySerializedFrame> frame_list; | |
329 ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); | |
330 frame_list_buffer.Reset(); | |
331 SpdyFramer::SpdyPushPromiseFrameIterator it( | |
332 framer, CloneSpdyPushPromiseIR(push_promise)); | |
333 while (it.HasNextFrame()) { | |
334 size_t size_before = frame_list_buffer.Size(); | |
335 it.NextFrame(&frame_list_buffer); | |
336 frame_list.emplace_back( | |
337 SpdySerializedFrame(frame_list_buffer.Begin() + size_before, | |
338 frame_list_buffer.Size() - size_before, false)); | |
339 } | |
340 framer->debug_visitor_ = saved_debug_visitor; | |
341 | |
342 EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); | |
343 return serialized_headers_old_version; | |
344 } | |
345 | |
346 static SpdySerializedFrame SerializePushPromise( | |
347 SpdyFramer* framer, | |
348 const SpdyPushPromiseIR& push_promise, | |
349 ArrayOutputBuffer* output) { | |
350 if (output == nullptr) { | |
351 return SerializePushPromise(framer, push_promise); | |
352 } | |
353 output->Reset(); | |
354 EXPECT_TRUE(framer->SerializePushPromise(push_promise, output)); | |
355 SpdySerializedFrame serialized_headers_old_version(output->Begin(), | |
356 output->Size(), false); | |
357 framer->hpack_encoder_.reset(nullptr); | |
358 auto* saved_debug_visitor = framer->debug_visitor_; | |
359 framer->debug_visitor_ = nullptr; | |
360 | |
361 std::vector<SpdySerializedFrame> frame_list; | |
362 ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size); | |
363 frame_list_buffer.Reset(); | |
364 SpdyFramer::SpdyPushPromiseFrameIterator it( | |
365 framer, CloneSpdyPushPromiseIR(push_promise)); | |
366 while (it.HasNextFrame()) { | |
367 size_t size_before = frame_list_buffer.Size(); | |
368 it.NextFrame(&frame_list_buffer); | |
369 frame_list.emplace_back( | |
370 SpdySerializedFrame(frame_list_buffer.Begin() + size_before, | |
371 frame_list_buffer.Size() - size_before, false)); | |
372 } | |
373 framer->debug_visitor_ = saved_debug_visitor; | |
374 | |
375 EXPECT_THAT(serialized_headers_old_version, IsFrameUnionOf(&frame_list)); | |
376 return serialized_headers_old_version; | |
377 } | |
378 }; | |
379 | |
380 class TestSpdyVisitor : public SpdyFramerVisitorInterface, | |
381 public SpdyFramerDebugVisitorInterface { | |
382 public: | |
383 // This is larger than our max frame size because header blocks that | |
384 // are too long can spill over into CONTINUATION frames. | |
385 static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024; | |
386 | |
387 explicit TestSpdyVisitor(SpdyFramer::CompressionOption option) | |
388 : framer_(option), | |
389 error_count_(0), | |
390 headers_frame_count_(0), | |
391 push_promise_frame_count_(0), | |
392 goaway_count_(0), | |
393 setting_count_(0), | |
394 settings_ack_sent_(0), | |
395 settings_ack_received_(0), | |
396 continuation_count_(0), | |
397 altsvc_count_(0), | |
398 priority_count_(0), | |
399 test_altsvc_ir_(0), | |
400 on_unknown_frame_result_(false), | |
401 last_window_update_stream_(0), | |
402 last_window_update_delta_(0), | |
403 last_push_promise_stream_(0), | |
404 last_push_promise_promised_stream_(0), | |
405 data_bytes_(0), | |
406 fin_frame_count_(0), | |
407 fin_flag_count_(0), | |
408 end_of_stream_count_(0), | |
409 control_frame_header_data_count_(0), | |
410 zero_length_control_frame_header_data_count_(0), | |
411 data_frame_count_(0), | |
412 last_payload_len_(0), | |
413 last_frame_len_(0), | |
414 header_buffer_(kDefaultHeaderBufferSize), | |
415 header_buffer_length_(0), | |
416 header_stream_id_(static_cast<SpdyStreamId>(-1)), | |
417 header_control_type_(SpdyFrameType::DATA), | |
418 header_buffer_valid_(false) {} | |
419 | |
420 void OnError(SpdyFramer* f) override { | |
421 VLOG(1) << "SpdyFramer Error: " | |
422 << SpdyFramer::SpdyFramerErrorToString(f->spdy_framer_error()); | |
423 ++error_count_; | |
424 } | |
425 | |
426 void OnDataFrameHeader(SpdyStreamId stream_id, | |
427 size_t length, | |
428 bool fin) override { | |
429 VLOG(1) << "OnDataFrameHeader(" << stream_id << ", " << length << ", " | |
430 << fin << ")"; | |
431 ++data_frame_count_; | |
432 header_stream_id_ = stream_id; | |
433 } | |
434 | |
435 void OnStreamFrameData(SpdyStreamId stream_id, | |
436 const char* data, | |
437 size_t len) override { | |
438 VLOG(1) << "OnStreamFrameData(" << stream_id << ", data, " << len << ", " | |
439 << ") data:\n" | |
440 << base::HexEncode(data, len); | |
441 EXPECT_EQ(header_stream_id_, stream_id); | |
442 data_bytes_ += len; | |
443 } | |
444 | |
445 void OnStreamEnd(SpdyStreamId stream_id) override { | |
446 VLOG(1) << "OnStreamEnd(" << stream_id << ")"; | |
447 EXPECT_EQ(header_stream_id_, stream_id); | |
448 ++end_of_stream_count_; | |
449 } | |
450 | |
451 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { | |
452 VLOG(1) << "OnStreamPadding(" << stream_id << ", " << len << ")\n"; | |
453 EXPECT_EQ(header_stream_id_, stream_id); | |
454 data_bytes_ += len; | |
455 } | |
456 | |
457 SpdyHeadersHandlerInterface* OnHeaderFrameStart( | |
458 SpdyStreamId stream_id) override { | |
459 if (headers_handler_ == nullptr) { | |
460 headers_handler_ = base::MakeUnique<TestHeadersHandler>(); | |
461 } | |
462 return headers_handler_.get(); | |
463 } | |
464 | |
465 void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override { | |
466 CHECK(headers_handler_ != nullptr); | |
467 headers_ = headers_handler_->decoded_block().Clone(); | |
468 header_bytes_received_ = headers_handler_->header_bytes_parsed(); | |
469 if (end_headers) { | |
470 headers_handler_.reset(); | |
471 } | |
472 } | |
473 | |
474 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override { | |
475 VLOG(1) << "OnRstStream(" << stream_id << ", " << error_code << ")"; | |
476 ++fin_frame_count_; | |
477 } | |
478 | |
479 void OnSetting(SpdySettingsIds id, uint32_t value) override { | |
480 VLOG(1) << "OnSetting(" << id << ", " << std::hex << ", " << value << ")"; | |
481 ++setting_count_; | |
482 } | |
483 | |
484 void OnSettingsAck() override { | |
485 VLOG(1) << "OnSettingsAck"; | |
486 ++settings_ack_received_; | |
487 } | |
488 | |
489 void OnSettingsEnd() override { | |
490 VLOG(1) << "OnSettingsEnd"; | |
491 ++settings_ack_sent_; | |
492 } | |
493 | |
494 void OnPing(SpdyPingId unique_id, bool is_ack) override { | |
495 LOG(DFATAL) << "OnPing(" << unique_id << ", " << (is_ack ? 1 : 0) << ")"; | |
496 } | |
497 | |
498 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
499 SpdyErrorCode error_code) override { | |
500 VLOG(1) << "OnGoAway(" << last_accepted_stream_id << ", " << error_code | |
501 << ")"; | |
502 ++goaway_count_; | |
503 } | |
504 | |
505 void OnHeaders(SpdyStreamId stream_id, | |
506 bool has_priority, | |
507 int weight, | |
508 SpdyStreamId parent_stream_id, | |
509 bool exclusive, | |
510 bool fin, | |
511 bool end) override { | |
512 VLOG(1) << "OnHeaders(" << stream_id << ", " << has_priority << ", " | |
513 << weight << ", " << parent_stream_id << ", " << exclusive << ", " | |
514 << fin << ", " << end << ")"; | |
515 ++headers_frame_count_; | |
516 InitHeaderStreaming(SpdyFrameType::HEADERS, stream_id); | |
517 if (fin) { | |
518 ++fin_flag_count_; | |
519 } | |
520 header_has_priority_ = has_priority; | |
521 header_parent_stream_id_ = parent_stream_id; | |
522 header_exclusive_ = exclusive; | |
523 } | |
524 | |
525 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { | |
526 VLOG(1) << "OnWindowUpdate(" << stream_id << ", " << delta_window_size | |
527 << ")"; | |
528 last_window_update_stream_ = stream_id; | |
529 last_window_update_delta_ = delta_window_size; | |
530 } | |
531 | |
532 void OnPushPromise(SpdyStreamId stream_id, | |
533 SpdyStreamId promised_stream_id, | |
534 bool end) override { | |
535 VLOG(1) << "OnPushPromise(" << stream_id << ", " << promised_stream_id | |
536 << ", " << end << ")"; | |
537 ++push_promise_frame_count_; | |
538 InitHeaderStreaming(SpdyFrameType::PUSH_PROMISE, stream_id); | |
539 last_push_promise_stream_ = stream_id; | |
540 last_push_promise_promised_stream_ = promised_stream_id; | |
541 } | |
542 | |
543 void OnContinuation(SpdyStreamId stream_id, bool end) override { | |
544 VLOG(1) << "OnContinuation(" << stream_id << ", " << end << ")"; | |
545 ++continuation_count_; | |
546 } | |
547 | |
548 void OnAltSvc(SpdyStreamId stream_id, | |
549 SpdyStringPiece origin, | |
550 const SpdyAltSvcWireFormat::AlternativeServiceVector& | |
551 altsvc_vector) override { | |
552 VLOG(1) << "OnAltSvc(" << stream_id << ", \"" << origin | |
553 << "\", altsvc_vector)"; | |
554 test_altsvc_ir_.set_stream_id(stream_id); | |
555 if (origin.length() > 0) { | |
556 test_altsvc_ir_.set_origin(SpdyString(origin)); | |
557 } | |
558 for (const auto& altsvc : altsvc_vector) { | |
559 test_altsvc_ir_.add_altsvc(altsvc); | |
560 } | |
561 ++altsvc_count_; | |
562 } | |
563 | |
564 void OnPriority(SpdyStreamId stream_id, | |
565 SpdyStreamId parent_stream_id, | |
566 int weight, | |
567 bool exclusive) override { | |
568 VLOG(1) << "OnPriority(" << stream_id << ", " << parent_stream_id << ", " | |
569 << weight << ", " << (exclusive ? 1 : 0) << ")"; | |
570 ++priority_count_; | |
571 } | |
572 | |
573 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { | |
574 VLOG(1) << "OnUnknownFrame(" << stream_id << ", " << frame_type << ")"; | |
575 return on_unknown_frame_result_; | |
576 } | |
577 | |
578 void OnSendCompressedFrame(SpdyStreamId stream_id, | |
579 SpdyFrameType type, | |
580 size_t payload_len, | |
581 size_t frame_len) override { | |
582 VLOG(1) << "OnSendCompressedFrame(" << stream_id << ", " << type << ", " | |
583 << payload_len << ", " << frame_len << ")"; | |
584 last_payload_len_ = payload_len; | |
585 last_frame_len_ = frame_len; | |
586 } | |
587 | |
588 void OnReceiveCompressedFrame(SpdyStreamId stream_id, | |
589 SpdyFrameType type, | |
590 size_t frame_len) override { | |
591 VLOG(1) << "OnReceiveCompressedFrame(" << stream_id << ", " << type << ", " | |
592 << frame_len << ")"; | |
593 last_frame_len_ = frame_len; | |
594 } | |
595 | |
596 // Convenience function which runs a framer simulation with particular input. | |
597 void SimulateInFramer(const unsigned char* input, size_t size) { | |
598 framer_.set_visitor(this); | |
599 size_t input_remaining = size; | |
600 const char* input_ptr = reinterpret_cast<const char*>(input); | |
601 while (input_remaining > 0 && | |
602 framer_.spdy_framer_error() == SpdyFramer::SPDY_NO_ERROR) { | |
603 // To make the tests more interesting, we feed random (and small) chunks | |
604 // into the framer. This simulates getting strange-sized reads from | |
605 // the socket. | |
606 const size_t kMaxReadSize = 32; | |
607 size_t bytes_read = | |
608 (rand() % std::min(input_remaining, kMaxReadSize)) + 1; | |
609 size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read); | |
610 input_remaining -= bytes_processed; | |
611 input_ptr += bytes_processed; | |
612 } | |
613 } | |
614 | |
615 void InitHeaderStreaming(SpdyFrameType header_control_type, | |
616 SpdyStreamId stream_id) { | |
617 if (!IsDefinedFrameType(SerializeFrameType(header_control_type))) { | |
618 DLOG(FATAL) << "Attempted to init header streaming with " | |
619 << "invalid control frame type: " << header_control_type; | |
620 } | |
621 std::fill(header_buffer_.begin(), header_buffer_.end(), 0); | |
622 header_buffer_length_ = 0; | |
623 header_stream_id_ = stream_id; | |
624 header_control_type_ = header_control_type; | |
625 header_buffer_valid_ = true; | |
626 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
627 } | |
628 | |
629 void set_extension_visitor(ExtensionVisitorInterface* extension) { | |
630 framer_.set_extension_visitor(extension); | |
631 } | |
632 | |
633 // Override the default buffer size (16K). Call before using the framer! | |
634 void set_header_buffer_size(size_t header_buffer_size) { | |
635 header_buffer_.resize(header_buffer_size); | |
636 } | |
637 | |
638 // Largest control frame that the SPDY implementation sends, including the | |
639 // size of the header. | |
640 static size_t sent_control_frame_max_size() { | |
641 return SpdyFramer::kMaxControlFrameSize; | |
642 } | |
643 | |
644 // Largest control frame that the SPDY implementation is willing to receive, | |
645 // excluding the size of the header. | |
646 static size_t received_control_frame_max_size() { | |
647 return kSpdyInitialFrameSizeLimit; | |
648 } | |
649 | |
650 static size_t header_data_chunk_max_size() { | |
651 return SpdyFramer::kHeaderDataChunkMaxSize; | |
652 } | |
653 | |
654 SpdyFramer framer_; | |
655 | |
656 // Counters from the visitor callbacks. | |
657 int error_count_; | |
658 int headers_frame_count_; | |
659 int push_promise_frame_count_; | |
660 int goaway_count_; | |
661 int setting_count_; | |
662 int settings_ack_sent_; | |
663 int settings_ack_received_; | |
664 int continuation_count_; | |
665 int altsvc_count_; | |
666 int priority_count_; | |
667 SpdyAltSvcIR test_altsvc_ir_; | |
668 bool on_unknown_frame_result_; | |
669 SpdyStreamId last_window_update_stream_; | |
670 int last_window_update_delta_; | |
671 SpdyStreamId last_push_promise_stream_; | |
672 SpdyStreamId last_push_promise_promised_stream_; | |
673 int data_bytes_; | |
674 int fin_frame_count_; // The count of RST_STREAM type frames received. | |
675 int fin_flag_count_; // The count of frames with the FIN flag set. | |
676 int end_of_stream_count_; // The count of zero-length data frames. | |
677 int control_frame_header_data_count_; // The count of chunks received. | |
678 // The count of zero-length control frame header data chunks received. | |
679 int zero_length_control_frame_header_data_count_; | |
680 int data_frame_count_; | |
681 size_t last_payload_len_; | |
682 size_t last_frame_len_; | |
683 | |
684 // Header block streaming state: | |
685 std::vector<char> header_buffer_; | |
686 size_t header_buffer_length_; | |
687 size_t header_bytes_received_; | |
688 SpdyStreamId header_stream_id_; | |
689 SpdyFrameType header_control_type_; | |
690 bool header_buffer_valid_; | |
691 std::unique_ptr<TestHeadersHandler> headers_handler_; | |
692 SpdyHeaderBlock headers_; | |
693 bool header_has_priority_; | |
694 SpdyStreamId header_parent_stream_id_; | |
695 bool header_exclusive_; | |
696 }; | |
697 | |
698 class TestExtension : public ExtensionVisitorInterface { | |
699 public: | |
700 void OnSetting(uint16_t id, uint32_t value) override { | |
701 settings_received_.push_back({id, value}); | |
702 } | |
703 | |
704 // Called when non-standard frames are received. | |
705 bool OnFrameHeader(SpdyStreamId stream_id, | |
706 size_t length, | |
707 uint8_t type, | |
708 uint8_t flags) override { | |
709 stream_id_ = stream_id; | |
710 length_ = length; | |
711 type_ = type; | |
712 flags_ = flags; | |
713 return true; | |
714 } | |
715 | |
716 // The payload for a single frame may be delivered as multiple calls to | |
717 // OnFramePayload. | |
718 void OnFramePayload(const char* data, size_t len) override { | |
719 payload_.append(data, len); | |
720 } | |
721 | |
722 std::vector<std::pair<uint16_t, uint32_t>> settings_received_; | |
723 SpdyStreamId stream_id_ = 0; | |
724 size_t length_ = 0; | |
725 uint8_t type_ = 0; | |
726 uint8_t flags_ = 0; | |
727 SpdyString payload_; | |
728 }; | |
729 | |
730 // Retrieves serialized headers from a HEADERS frame. | |
731 SpdyStringPiece GetSerializedHeaders(const SpdySerializedFrame& frame, | |
732 const SpdyFramer& framer) { | |
733 SpdyFrameReader reader(frame.data(), frame.size()); | |
734 reader.Seek(3); // Seek past the frame length. | |
735 | |
736 uint8_t serialized_type; | |
737 reader.ReadUInt8(&serialized_type); | |
738 | |
739 SpdyFrameType type = ParseFrameType(serialized_type); | |
740 DCHECK_EQ(SpdyFrameType::HEADERS, type); | |
741 uint8_t flags; | |
742 reader.ReadUInt8(&flags); | |
743 | |
744 return SpdyStringPiece(frame.data() + framer.GetHeadersMinimumSize(), | |
745 frame.size() - framer.GetHeadersMinimumSize()); | |
746 } | |
747 | |
748 enum DecoderChoice { DECODER_SELF, DECODER_NESTED, DECODER_HTTP2 }; | |
749 enum HpackChoice { HPACK_DECODER_1, HPACK_DECODER_3 }; | |
750 enum Output { USE, NOT_USE }; | |
751 | |
752 class SpdyFramerTest : public ::testing::TestWithParam< | |
753 std::tuple<DecoderChoice, HpackChoice, Output>> { | |
754 public: | |
755 SpdyFramerTest() : output_(output_buffer, kSize) {} | |
756 | |
757 protected: | |
758 void SetUp() override { | |
759 auto param = GetParam(); | |
760 switch (std::get<0>(param)) { | |
761 case DECODER_SELF: | |
762 FLAGS_use_nested_spdy_framer_decoder = false; | |
763 FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false; | |
764 break; | |
765 case DECODER_NESTED: | |
766 FLAGS_use_nested_spdy_framer_decoder = true; | |
767 FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = false; | |
768 break; | |
769 case DECODER_HTTP2: | |
770 FLAGS_use_nested_spdy_framer_decoder = false; | |
771 FLAGS_chromium_http2_flag_spdy_use_http2_frame_decoder_adapter = true; | |
772 break; | |
773 } | |
774 switch (std::get<1>(param)) { | |
775 case HPACK_DECODER_1: | |
776 FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = false; | |
777 break; | |
778 case HPACK_DECODER_3: | |
779 FLAGS_chromium_http2_flag_spdy_use_hpack_decoder3 = true; | |
780 break; | |
781 } | |
782 switch (std::get<2>(param)) { | |
783 case USE: | |
784 use_output_ = true; | |
785 break; | |
786 case NOT_USE: | |
787 // TODO(yasong): remove this case after | |
788 // FLAGS_chromium_http2_flag_remove_rewritelength deprecates. | |
789 use_output_ = false; | |
790 break; | |
791 } | |
792 } | |
793 | |
794 void CompareFrame(const SpdyString& description, | |
795 const SpdySerializedFrame& actual_frame, | |
796 const unsigned char* expected, | |
797 const int expected_len) { | |
798 const unsigned char* actual = | |
799 reinterpret_cast<const unsigned char*>(actual_frame.data()); | |
800 CompareCharArraysWithHexError(description, actual, actual_frame.size(), | |
801 expected, expected_len); | |
802 } | |
803 | |
804 void CompareFrames(const SpdyString& description, | |
805 const SpdySerializedFrame& expected_frame, | |
806 const SpdySerializedFrame& actual_frame) { | |
807 CompareCharArraysWithHexError( | |
808 description, | |
809 reinterpret_cast<const unsigned char*>(expected_frame.data()), | |
810 expected_frame.size(), | |
811 reinterpret_cast<const unsigned char*>(actual_frame.data()), | |
812 actual_frame.size()); | |
813 } | |
814 | |
815 bool use_output_ = false; | |
816 ArrayOutputBuffer output_; | |
817 }; | |
818 | |
819 INSTANTIATE_TEST_CASE_P(SpdyFramerTests, | |
820 SpdyFramerTest, | |
821 ::testing::Combine(::testing::Values(DECODER_SELF, | |
822 DECODER_NESTED, | |
823 DECODER_HTTP2), | |
824 ::testing::Values(HPACK_DECODER_1, | |
825 HPACK_DECODER_3), | |
826 ::testing::Values(USE, NOT_USE))); | |
827 | |
828 // Test that we can encode and decode a SpdyHeaderBlock in serialized form. | |
829 TEST_P(SpdyFramerTest, HeaderBlockInBuffer) { | |
830 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
831 | |
832 // Encode the header block into a Headers frame. | |
833 SpdyHeadersIR headers(1); | |
834 headers.SetHeader("alpha", "beta"); | |
835 headers.SetHeader("gamma", "charlie"); | |
836 headers.SetHeader("cookie", "key1=value1; key2=value2"); | |
837 SpdySerializedFrame frame( | |
838 SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); | |
839 | |
840 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
841 visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), | |
842 frame.size()); | |
843 | |
844 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
845 EXPECT_EQ(headers.header_block(), visitor.headers_); | |
846 } | |
847 | |
848 // Test that if there's not a full frame, we fail to parse it. | |
849 TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) { | |
850 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
851 | |
852 // Encode the header block into a Headers frame. | |
853 SpdyHeadersIR headers(1); | |
854 headers.SetHeader("alpha", "beta"); | |
855 headers.SetHeader("gamma", "charlie"); | |
856 SpdySerializedFrame frame( | |
857 SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); | |
858 | |
859 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
860 visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), | |
861 frame.size() - 2); | |
862 | |
863 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
864 EXPECT_EQ(0u, visitor.headers_.size()); | |
865 } | |
866 | |
867 // Test that we treat incoming upper-case or mixed-case header values as | |
868 // malformed. | |
869 TEST_P(SpdyFramerTest, RejectUpperCaseHeaderBlockValue) { | |
870 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
871 | |
872 SpdyFrameBuilder frame(1024); | |
873 frame.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 1); | |
874 frame.WriteUInt32(1); | |
875 frame.WriteStringPiece32("Name1"); | |
876 frame.WriteStringPiece32("value1"); | |
877 frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize()); | |
878 | |
879 SpdyFrameBuilder frame2(1024); | |
880 frame2.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 1); | |
881 frame2.WriteUInt32(2); | |
882 frame2.WriteStringPiece32("name1"); | |
883 frame2.WriteStringPiece32("value1"); | |
884 frame2.WriteStringPiece32("nAmE2"); | |
885 frame2.WriteStringPiece32("value2"); | |
886 frame.OverwriteLength(framer, frame2.length() - framer.GetFrameHeaderSize()); | |
887 | |
888 SpdySerializedFrame control_frame(frame.take()); | |
889 SpdyStringPiece serialized_headers = | |
890 GetSerializedHeaders(control_frame, framer); | |
891 SpdySerializedFrame control_frame2(frame2.take()); | |
892 SpdyStringPiece serialized_headers2 = | |
893 GetSerializedHeaders(control_frame2, framer); | |
894 | |
895 SpdyHeaderBlock new_headers; | |
896 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer( | |
897 serialized_headers.data(), serialized_headers.size(), &new_headers)); | |
898 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer( | |
899 serialized_headers2.data(), serialized_headers2.size(), &new_headers)); | |
900 } | |
901 | |
902 // Test that we can encode and decode stream dependency values in a header | |
903 // frame. | |
904 TEST_P(SpdyFramerTest, HeaderStreamDependencyValues) { | |
905 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
906 | |
907 const SpdyStreamId parent_stream_id_test_array[] = {0, 3}; | |
908 for (SpdyStreamId parent_stream_id : parent_stream_id_test_array) { | |
909 const bool exclusive_test_array[] = {true, false}; | |
910 for (bool exclusive : exclusive_test_array) { | |
911 SpdyHeadersIR headers(1); | |
912 headers.set_has_priority(true); | |
913 headers.set_parent_stream_id(parent_stream_id); | |
914 headers.set_exclusive(exclusive); | |
915 SpdySerializedFrame frame( | |
916 SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); | |
917 | |
918 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
919 visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), | |
920 frame.size()); | |
921 | |
922 EXPECT_TRUE(visitor.header_has_priority_); | |
923 EXPECT_EQ(parent_stream_id, visitor.header_parent_stream_id_); | |
924 EXPECT_EQ(exclusive, visitor.header_exclusive_); | |
925 } | |
926 } | |
927 } | |
928 | |
929 // Test that if we receive a frame with payload length field at the | |
930 // advertised max size, we do not set an error in ProcessInput. | |
931 TEST_P(SpdyFramerTest, AcceptMaxFrameSizeSetting) { | |
932 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
933 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
934 framer.set_visitor(&visitor); | |
935 | |
936 // DATA frame with maximum allowed payload length. | |
937 unsigned char kH2FrameData[] = { | |
938 0x00, 0x40, 0x00, // Length: 2^14 | |
939 0x00, // Type: HEADERS | |
940 0x00, // Flags: None | |
941 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
942 0x00, 0x00, 0x00, 0x00, // Junk payload | |
943 }; | |
944 | |
945 SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), | |
946 sizeof(kH2FrameData), false); | |
947 | |
948 EXPECT_CALL(visitor, OnDataFrameHeader(1, 1 << 14, false)); | |
949 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 4)); | |
950 framer.ProcessInput(frame.data(), frame.size()); | |
951 EXPECT_FALSE(framer.HasError()); | |
952 } | |
953 | |
954 // Test that if we receive a frame with payload length larger than the | |
955 // advertised max size, we set an error of SPDY_INVALID_CONTROL_FRAME_SIZE. | |
956 TEST_P(SpdyFramerTest, ExceedMaxFrameSizeSetting) { | |
957 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
958 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
959 framer.set_visitor(&visitor); | |
960 | |
961 // DATA frame with too large payload length. | |
962 unsigned char kH2FrameData[] = { | |
963 0x00, 0x40, 0x01, // Length: 2^14 + 1 | |
964 0x00, // Type: HEADERS | |
965 0x00, // Flags: None | |
966 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
967 0x00, 0x00, 0x00, 0x00, // Junk payload | |
968 }; | |
969 | |
970 SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), | |
971 sizeof(kH2FrameData), false); | |
972 | |
973 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
974 framer.ProcessInput(frame.data(), frame.size()); | |
975 EXPECT_TRUE(framer.HasError()); | |
976 EXPECT_EQ(SpdyFramer::SPDY_OVERSIZED_PAYLOAD, framer.spdy_framer_error()) | |
977 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
978 } | |
979 | |
980 // Test that if we receive a DATA frame with padding length larger than the | |
981 // payload length, we set an error of SPDY_INVALID_PADDING | |
982 TEST_P(SpdyFramerTest, OversizedDataPaddingError) { | |
983 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
984 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
985 framer.set_visitor(&visitor); | |
986 | |
987 // DATA frame with invalid padding length. | |
988 // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses | |
989 // MSVC, where |char| is signed by default, which would not compile because of | |
990 // the element exceeding 127. | |
991 unsigned char kH2FrameData[] = { | |
992 0x00, 0x00, 0x05, // Length: 5 | |
993 0x00, // Type: DATA | |
994 0x09, // Flags: END_STREAM|PADDED | |
995 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
996 0xff, // PadLen: 255 trailing bytes (Too Long) | |
997 0x00, 0x00, 0x00, 0x00, // Padding | |
998 }; | |
999 | |
1000 SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), | |
1001 sizeof(kH2FrameData), false); | |
1002 | |
1003 { | |
1004 testing::InSequence seq; | |
1005 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, 1)); | |
1006 EXPECT_CALL(visitor, OnStreamPadding(1, 1)); | |
1007 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1008 } | |
1009 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1010 EXPECT_TRUE(framer.HasError()); | |
1011 EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error()) | |
1012 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1013 } | |
1014 | |
1015 // Test that if we receive a DATA frame with padding length not larger than the | |
1016 // payload length, we do not set an error of SPDY_INVALID_PADDING | |
1017 TEST_P(SpdyFramerTest, CorrectlySizedDataPaddingNoError) { | |
1018 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1019 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1020 framer.set_visitor(&visitor); | |
1021 | |
1022 // DATA frame with valid Padding length | |
1023 char kH2FrameData[] = { | |
1024 0x00, 0x00, 0x05, // Length: 5 | |
1025 0x00, // Type: DATA | |
1026 0x08, // Flags: PADDED | |
1027 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1028 0x04, // PadLen: 4 trailing bytes | |
1029 0x00, 0x00, 0x00, 0x00, // Padding | |
1030 }; | |
1031 | |
1032 SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); | |
1033 | |
1034 { | |
1035 testing::InSequence seq; | |
1036 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, false)); | |
1037 EXPECT_CALL(visitor, OnStreamPadding(1, 1)); | |
1038 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))).Times(0); | |
1039 // Note that OnStreamFrameData(1, _, 1)) is never called | |
1040 // since there is no data, only padding | |
1041 EXPECT_CALL(visitor, OnStreamPadding(1, 4)); | |
1042 } | |
1043 | |
1044 EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1045 EXPECT_FALSE(framer.HasError()); | |
1046 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
1047 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1048 } | |
1049 | |
1050 // Test that if we receive a HEADERS frame with padding length larger than the | |
1051 // payload length, we set an error of SPDY_INVALID_PADDING | |
1052 TEST_P(SpdyFramerTest, OversizedHeadersPaddingError) { | |
1053 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1054 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1055 framer.set_visitor(&visitor); | |
1056 | |
1057 // HEADERS frame with invalid padding length. | |
1058 // |kH2FrameData| has to be |unsigned char|, because Chromium on Windows uses | |
1059 // MSVC, where |char| is signed by default, which would not compile because of | |
1060 // the element exceeding 127. | |
1061 unsigned char kH2FrameData[] = { | |
1062 0x00, 0x00, 0x05, // Length: 5 | |
1063 0x01, // Type: HEADERS | |
1064 0x08, // Flags: PADDED | |
1065 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1066 0xff, // PadLen: 255 trailing bytes (Too Long) | |
1067 0x00, 0x00, 0x00, 0x00, // Padding | |
1068 }; | |
1069 | |
1070 SpdySerializedFrame frame(reinterpret_cast<char*>(kH2FrameData), | |
1071 sizeof(kH2FrameData), false); | |
1072 | |
1073 EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false)); | |
1074 EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1); | |
1075 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1076 EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1077 EXPECT_TRUE(framer.HasError()); | |
1078 EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error()) | |
1079 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1080 } | |
1081 | |
1082 // Test that if we receive a HEADERS frame with padding length not larger | |
1083 // than the payload length, we do not set an error of SPDY_INVALID_PADDING | |
1084 TEST_P(SpdyFramerTest, CorrectlySizedHeadersPaddingNoError) { | |
1085 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1086 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1087 framer.set_visitor(&visitor); | |
1088 | |
1089 // HEADERS frame with invalid Padding length | |
1090 char kH2FrameData[] = { | |
1091 0x00, 0x00, 0x05, // Length: 5 | |
1092 0x01, // Type: HEADERS | |
1093 0x08, // Flags: PADDED | |
1094 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1095 0x04, // PadLen: 4 trailing bytes | |
1096 0x00, 0x00, 0x00, 0x00, // Padding | |
1097 }; | |
1098 | |
1099 SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); | |
1100 | |
1101 EXPECT_CALL(visitor, OnHeaders(1, false, 0, 0, false, false, false)); | |
1102 EXPECT_CALL(visitor, OnHeaderFrameStart(1)).Times(1); | |
1103 EXPECT_EQ(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1104 EXPECT_FALSE(framer.HasError()); | |
1105 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
1106 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1107 } | |
1108 | |
1109 // Test that if we receive a DATA with stream ID zero, we signal an error | |
1110 // (but don't crash). | |
1111 TEST_P(SpdyFramerTest, DataWithStreamIdZero) { | |
1112 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1113 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1114 framer.set_visitor(&visitor); | |
1115 | |
1116 const char bytes[] = "hello"; | |
1117 SpdyDataIR data_ir(0, bytes); | |
1118 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1119 | |
1120 // We shouldn't have to read the whole frame before we signal an error. | |
1121 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1122 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1123 EXPECT_TRUE(framer.HasError()); | |
1124 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1125 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1126 } | |
1127 | |
1128 // Test that if we receive a HEADERS with stream ID zero, we signal an error | |
1129 // (but don't crash). | |
1130 TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) { | |
1131 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1132 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1133 framer.set_visitor(&visitor); | |
1134 | |
1135 SpdyHeadersIR headers(0); | |
1136 headers.SetHeader("alpha", "beta"); | |
1137 SpdySerializedFrame frame( | |
1138 SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); | |
1139 | |
1140 // We shouldn't have to read the whole frame before we signal an error. | |
1141 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1142 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1143 EXPECT_TRUE(framer.HasError()); | |
1144 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1145 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1146 } | |
1147 | |
1148 // Test that if we receive a PRIORITY with stream ID zero, we signal an error | |
1149 // (but don't crash). | |
1150 TEST_P(SpdyFramerTest, PriorityWithStreamIdZero) { | |
1151 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1152 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1153 framer.set_visitor(&visitor); | |
1154 | |
1155 SpdyPriorityIR priority_ir(0, 1, 16, true); | |
1156 SpdySerializedFrame frame(framer.SerializeFrame(priority_ir)); | |
1157 if (use_output_) { | |
1158 ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_)); | |
1159 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1160 } | |
1161 | |
1162 // We shouldn't have to read the whole frame before we signal an error. | |
1163 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1164 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1165 EXPECT_TRUE(framer.HasError()); | |
1166 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1167 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1168 } | |
1169 | |
1170 // Test that if we receive a RST_STREAM with stream ID zero, we signal an error | |
1171 // (but don't crash). | |
1172 TEST_P(SpdyFramerTest, RstStreamWithStreamIdZero) { | |
1173 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1174 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1175 framer.set_visitor(&visitor); | |
1176 | |
1177 SpdyRstStreamIR rst_stream_ir(0, ERROR_CODE_PROTOCOL_ERROR); | |
1178 SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream_ir)); | |
1179 if (use_output_) { | |
1180 ASSERT_TRUE(framer.SerializeRstStream(rst_stream_ir, &output_)); | |
1181 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1182 } | |
1183 | |
1184 // We shouldn't have to read the whole frame before we signal an error. | |
1185 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1186 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1187 EXPECT_TRUE(framer.HasError()); | |
1188 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1189 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1190 } | |
1191 | |
1192 // Test that if we receive a SETTINGS with stream ID other than zero, | |
1193 // we signal an error (but don't crash). | |
1194 TEST_P(SpdyFramerTest, SettingsWithStreamIdNotZero) { | |
1195 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1196 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1197 framer.set_visitor(&visitor); | |
1198 | |
1199 // Settings frame with invalid StreamID of 0x01 | |
1200 char kH2FrameData[] = { | |
1201 0x00, 0x00, 0x06, // Length: 6 | |
1202 0x04, // Type: SETTINGS | |
1203 0x00, // Flags: none | |
1204 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1205 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE | |
1206 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141 | |
1207 }; | |
1208 | |
1209 SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); | |
1210 | |
1211 // We shouldn't have to read the whole frame before we signal an error. | |
1212 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1213 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1214 EXPECT_TRUE(framer.HasError()); | |
1215 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1216 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1217 } | |
1218 | |
1219 // Test that if we receive a GOAWAY with stream ID other than zero, | |
1220 // we signal an error (but don't crash). | |
1221 TEST_P(SpdyFramerTest, GoawayWithStreamIdNotZero) { | |
1222 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1223 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1224 framer.set_visitor(&visitor); | |
1225 | |
1226 // GOAWAY frame with invalid StreamID of 0x01 | |
1227 char kH2FrameData[] = { | |
1228 0x00, 0x00, 0x0a, // Length: 10 | |
1229 0x07, // Type: GOAWAY | |
1230 0x00, // Flags: none | |
1231 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1232 0x00, 0x00, 0x00, 0x00, // Last: 0 | |
1233 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR | |
1234 0x47, 0x41, // Description | |
1235 }; | |
1236 | |
1237 SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); | |
1238 | |
1239 // We shouldn't have to read the whole frame before we signal an error. | |
1240 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1241 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1242 EXPECT_TRUE(framer.HasError()); | |
1243 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1244 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1245 } | |
1246 | |
1247 // Test that if we receive a CONTINUATION with stream ID zero, we signal an | |
1248 // SPDY_INVALID_STREAM_ID. | |
1249 TEST_P(SpdyFramerTest, ContinuationWithStreamIdZero) { | |
1250 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1251 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1252 framer.set_visitor(&visitor); | |
1253 | |
1254 SpdyContinuationIR continuation(0); | |
1255 auto some_nonsense_encoding = | |
1256 base::MakeUnique<SpdyString>("some nonsense encoding"); | |
1257 continuation.take_encoding(std::move(some_nonsense_encoding)); | |
1258 continuation.set_end_headers(true); | |
1259 SpdySerializedFrame frame(framer.SerializeContinuation(continuation)); | |
1260 if (use_output_) { | |
1261 ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_)); | |
1262 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1263 } | |
1264 | |
1265 // We shouldn't have to read the whole frame before we signal an error. | |
1266 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1267 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1268 EXPECT_TRUE(framer.HasError()); | |
1269 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1270 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1271 } | |
1272 | |
1273 // Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an | |
1274 // SPDY_INVALID_STREAM_ID. | |
1275 TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) { | |
1276 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1277 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1278 framer.set_visitor(&visitor); | |
1279 | |
1280 SpdyPushPromiseIR push_promise(0, 4); | |
1281 push_promise.SetHeader("alpha", "beta"); | |
1282 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
1283 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
1284 | |
1285 // We shouldn't have to read the whole frame before we signal an error. | |
1286 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1287 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
1288 EXPECT_TRUE(framer.HasError()); | |
1289 EXPECT_EQ(SpdyFramer::SPDY_INVALID_STREAM_ID, framer.spdy_framer_error()) | |
1290 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1291 } | |
1292 | |
1293 // Test that if we receive a PUSH_PROMISE with promised stream ID zero, we | |
1294 // signal SPDY_INVALID_STREAM_ID. | |
1295 TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) { | |
1296 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
1297 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1298 framer.set_visitor(&visitor); | |
1299 | |
1300 SpdyPushPromiseIR push_promise(3, 0); | |
1301 push_promise.SetHeader("alpha", "beta"); | |
1302 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
1303 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
1304 | |
1305 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
1306 framer.ProcessInput(frame.data(), frame.size()); | |
1307 EXPECT_TRUE(framer.HasError()); | |
1308 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error()) | |
1309 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
1310 } | |
1311 | |
1312 TEST_P(SpdyFramerTest, DuplicateHeader) { | |
1313 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
1314 // Frame builder with plentiful buffer size. | |
1315 SpdyFrameBuilder frame(1024); | |
1316 frame.BeginNewFrame(framer, SpdyFrameType::HEADERS, 0, 3); | |
1317 | |
1318 frame.WriteUInt32(2); // Number of headers. | |
1319 frame.WriteStringPiece32("name"); | |
1320 frame.WriteStringPiece32("value1"); | |
1321 frame.WriteStringPiece32("name"); | |
1322 frame.WriteStringPiece32("value2"); | |
1323 // write the length | |
1324 frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize()); | |
1325 | |
1326 SpdyHeaderBlock new_headers; | |
1327 SpdySerializedFrame control_frame(frame.take()); | |
1328 SpdyStringPiece serialized_headers = | |
1329 GetSerializedHeaders(control_frame, framer); | |
1330 // This should fail because duplicate headers are verboten by the spec. | |
1331 EXPECT_FALSE(framer.ParseHeaderBlockInBuffer( | |
1332 serialized_headers.data(), serialized_headers.size(), &new_headers)); | |
1333 } | |
1334 | |
1335 TEST_P(SpdyFramerTest, MultiValueHeader) { | |
1336 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
1337 // Frame builder with plentiful buffer size. | |
1338 SpdyFrameBuilder frame(1024); | |
1339 frame.BeginNewFrame(framer, SpdyFrameType::HEADERS, | |
1340 HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS, 3); | |
1341 frame.WriteUInt32(0); // Priority exclusivity and dependent stream. | |
1342 frame.WriteUInt8(255); // Priority weight. | |
1343 | |
1344 SpdyString value("value1\0value2", 13); | |
1345 // TODO(jgraettinger): If this pattern appears again, move to test class. | |
1346 SpdyHeaderBlock header_set; | |
1347 header_set["name"] = value; | |
1348 SpdyString buffer; | |
1349 HpackEncoder encoder(ObtainHpackHuffmanTable()); | |
1350 encoder.DisableCompression(); | |
1351 encoder.EncodeHeaderSet(header_set, &buffer); | |
1352 frame.WriteBytes(&buffer[0], buffer.size()); | |
1353 // write the length | |
1354 frame.OverwriteLength(framer, frame.length() - framer.GetFrameHeaderSize()); | |
1355 | |
1356 SpdySerializedFrame control_frame(frame.take()); | |
1357 | |
1358 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
1359 visitor.SimulateInFramer( | |
1360 reinterpret_cast<unsigned char*>(control_frame.data()), | |
1361 control_frame.size()); | |
1362 | |
1363 EXPECT_THAT(visitor.headers_, testing::ElementsAre(testing::Pair( | |
1364 "name", SpdyStringPiece(value)))); | |
1365 } | |
1366 | |
1367 TEST_P(SpdyFramerTest, CompressEmptyHeaders) { | |
1368 // See crbug.com/172383 | |
1369 SpdyHeadersIR headers(1); | |
1370 headers.SetHeader("server", "SpdyServer 1.0"); | |
1371 headers.SetHeader("date", "Mon 12 Jan 2009 12:12:12 PST"); | |
1372 headers.SetHeader("status", "200"); | |
1373 headers.SetHeader("version", "HTTP/1.1"); | |
1374 headers.SetHeader("content-type", "text/html"); | |
1375 headers.SetHeader("content-length", "12"); | |
1376 headers.SetHeader("x-empty-header", ""); | |
1377 | |
1378 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1379 SpdySerializedFrame frame1( | |
1380 SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_)); | |
1381 } | |
1382 | |
1383 TEST_P(SpdyFramerTest, Basic) { | |
1384 // Send HEADERS frames with PRIORITY and END_HEADERS set. | |
1385 // frame-format off | |
1386 const unsigned char kH2Input[] = { | |
1387 0x00, 0x00, 0x05, // Length: 5 | |
1388 0x01, // Type: HEADERS | |
1389 0x24, // Flags: END_HEADERS|PRIORITY | |
1390 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1391 0x00, 0x00, 0x00, 0x00, // Parent: 0 | |
1392 0x82, // Weight: 131 | |
1393 | |
1394 0x00, 0x00, 0x01, // Length: 1 | |
1395 0x01, // Type: HEADERS | |
1396 0x04, // Flags: END_HEADERS | |
1397 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1398 0x8c, // :status: 200 | |
1399 | |
1400 0x00, 0x00, 0x0c, // Length: 12 | |
1401 0x00, // Type: DATA | |
1402 0x00, // Flags: none | |
1403 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1404 0xde, 0xad, 0xbe, 0xef, // Payload | |
1405 0xde, 0xad, 0xbe, 0xef, // | |
1406 0xde, 0xad, 0xbe, 0xef, // | |
1407 | |
1408 0x00, 0x00, 0x05, // Length: 5 | |
1409 0x01, // Type: HEADERS | |
1410 0x24, // Flags: END_HEADERS|PRIORITY | |
1411 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
1412 0x00, 0x00, 0x00, 0x00, // Parent: 0 | |
1413 0x82, // Weight: 131 | |
1414 | |
1415 0x00, 0x00, 0x08, // Length: 8 | |
1416 0x00, // Type: DATA | |
1417 0x00, // Flags: none | |
1418 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
1419 0xde, 0xad, 0xbe, 0xef, // Payload | |
1420 0xde, 0xad, 0xbe, 0xef, // | |
1421 | |
1422 0x00, 0x00, 0x04, // Length: 4 | |
1423 0x00, // Type: DATA | |
1424 0x00, // Flags: none | |
1425 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1426 0xde, 0xad, 0xbe, 0xef, // Payload | |
1427 | |
1428 0x00, 0x00, 0x04, // Length: 4 | |
1429 0x03, // Type: RST_STREAM | |
1430 0x00, // Flags: none | |
1431 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1432 0x00, 0x00, 0x00, 0x08, // Error: CANCEL | |
1433 | |
1434 0x00, 0x00, 0x00, // Length: 0 | |
1435 0x00, // Type: DATA | |
1436 0x00, // Flags: none | |
1437 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
1438 | |
1439 0x00, 0x00, 0x04, // Length: 4 | |
1440 0x03, // Type: RST_STREAM | |
1441 0x00, // Flags: none | |
1442 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
1443 0x00, 0x00, 0x00, 0x08, // Error: CANCEL | |
1444 }; | |
1445 // frame-format on | |
1446 | |
1447 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
1448 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); | |
1449 | |
1450 EXPECT_EQ(24, visitor.data_bytes_); | |
1451 EXPECT_EQ(0, visitor.error_count_); | |
1452 EXPECT_EQ(2, visitor.fin_frame_count_); | |
1453 | |
1454 EXPECT_EQ(3, visitor.headers_frame_count_); | |
1455 | |
1456 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1457 EXPECT_EQ(0, visitor.end_of_stream_count_); | |
1458 EXPECT_EQ(4, visitor.data_frame_count_); | |
1459 } | |
1460 | |
1461 // Test that the FIN flag on a data frame signifies EOF. | |
1462 TEST_P(SpdyFramerTest, FinOnDataFrame) { | |
1463 // Send HEADERS frames with END_HEADERS set. | |
1464 // frame-format off | |
1465 const unsigned char kH2Input[] = { | |
1466 0x00, 0x00, 0x05, // Length: 5 | |
1467 0x01, // Type: HEADERS | |
1468 0x24, // Flags: END_HEADERS|PRIORITY | |
1469 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1470 0x00, 0x00, 0x00, 0x00, // Parent: 0 | |
1471 0x82, // Weight: 131 | |
1472 | |
1473 0x00, 0x00, 0x01, // Length: 1 | |
1474 0x01, // Type: HEADERS | |
1475 0x04, // Flags: END_HEADERS | |
1476 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1477 0x8c, // :status: 200 | |
1478 | |
1479 0x00, 0x00, 0x0c, // Length: 12 | |
1480 0x00, // Type: DATA | |
1481 0x00, // Flags: none | |
1482 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1483 0xde, 0xad, 0xbe, 0xef, // Payload | |
1484 0xde, 0xad, 0xbe, 0xef, // | |
1485 0xde, 0xad, 0xbe, 0xef, // | |
1486 | |
1487 0x00, 0x00, 0x04, // Length: 4 | |
1488 0x00, // Type: DATA | |
1489 0x01, // Flags: END_STREAM | |
1490 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1491 0xde, 0xad, 0xbe, 0xef, // Payload | |
1492 }; | |
1493 // frame-format on | |
1494 | |
1495 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
1496 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); | |
1497 | |
1498 EXPECT_EQ(0, visitor.error_count_); | |
1499 EXPECT_EQ(2, visitor.headers_frame_count_); | |
1500 EXPECT_EQ(16, visitor.data_bytes_); | |
1501 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1502 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1503 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
1504 EXPECT_EQ(2, visitor.data_frame_count_); | |
1505 } | |
1506 | |
1507 TEST_P(SpdyFramerTest, FinOnHeadersFrame) { | |
1508 // Send HEADERS frames with END_HEADERS set. | |
1509 // frame-format off | |
1510 const unsigned char kH2Input[] = { | |
1511 0x00, 0x00, 0x05, // Length: 5 | |
1512 0x01, // Type: HEADERS | |
1513 0x24, // Flags: END_HEADERS|PRIORITY | |
1514 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1515 0x00, 0x00, 0x00, 0x00, // Parent: 0 | |
1516 0x82, // Weight: 131 | |
1517 | |
1518 0x00, 0x00, 0x01, // Length: 1 | |
1519 0x01, // Type: HEADERS | |
1520 0x05, // Flags: END_STREAM|END_HEADERS | |
1521 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1522 0x8c, // :status: 200 | |
1523 }; | |
1524 // frame-format on | |
1525 | |
1526 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
1527 visitor.SimulateInFramer(kH2Input, sizeof(kH2Input)); | |
1528 | |
1529 EXPECT_EQ(0, visitor.error_count_); | |
1530 EXPECT_EQ(2, visitor.headers_frame_count_); | |
1531 EXPECT_EQ(0, visitor.data_bytes_); | |
1532 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1533 EXPECT_EQ(1, visitor.fin_flag_count_); | |
1534 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
1535 EXPECT_EQ(0, visitor.data_frame_count_); | |
1536 } | |
1537 | |
1538 // Verify we can decompress the stream even if handed over to the | |
1539 // framer 1 byte at a time. | |
1540 TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) { | |
1541 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1542 | |
1543 const char kHeader1[] = "header1"; | |
1544 const char kHeader2[] = "header2"; | |
1545 const char kValue1[] = "value1"; | |
1546 const char kValue2[] = "value2"; | |
1547 | |
1548 SpdyHeadersIR headers(1); | |
1549 headers.SetHeader(kHeader1, kValue1); | |
1550 headers.SetHeader(kHeader2, kValue2); | |
1551 SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( | |
1552 &framer, headers, use_output_ ? &output_ : nullptr)); | |
1553 | |
1554 const char bytes[] = "this is a test test test test test!"; | |
1555 SpdyDataIR data_ir(1, SpdyStringPiece(bytes, arraysize(bytes))); | |
1556 data_ir.set_fin(true); | |
1557 SpdySerializedFrame send_frame(framer.SerializeData(data_ir)); | |
1558 | |
1559 // Run the inputs through the framer. | |
1560 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
1561 const unsigned char* data; | |
1562 data = reinterpret_cast<const unsigned char*>(headers_frame.data()); | |
1563 for (size_t idx = 0; idx < headers_frame.size(); ++idx) { | |
1564 visitor.SimulateInFramer(data + idx, 1); | |
1565 ASSERT_EQ(0, visitor.error_count_); | |
1566 } | |
1567 data = reinterpret_cast<const unsigned char*>(send_frame.data()); | |
1568 for (size_t idx = 0; idx < send_frame.size(); ++idx) { | |
1569 visitor.SimulateInFramer(data + idx, 1); | |
1570 ASSERT_EQ(0, visitor.error_count_); | |
1571 } | |
1572 | |
1573 EXPECT_EQ(0, visitor.error_count_); | |
1574 EXPECT_EQ(1, visitor.headers_frame_count_); | |
1575 EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); | |
1576 EXPECT_EQ(0, visitor.fin_frame_count_); | |
1577 EXPECT_EQ(0, visitor.fin_flag_count_); | |
1578 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
1579 EXPECT_EQ(1, visitor.data_frame_count_); | |
1580 } | |
1581 | |
1582 TEST_P(SpdyFramerTest, WindowUpdateFrame) { | |
1583 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1584 SpdyWindowUpdateIR window_update(1, 0x12345678); | |
1585 SpdySerializedFrame frame(framer.SerializeWindowUpdate(window_update)); | |
1586 if (use_output_) { | |
1587 ASSERT_TRUE(framer.SerializeWindowUpdate(window_update, &output_)); | |
1588 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1589 } | |
1590 | |
1591 const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678"; | |
1592 const unsigned char kH2FrameData[] = { | |
1593 0x00, 0x00, 0x04, // Length: 4 | |
1594 0x08, // Type: WINDOW_UPDATE | |
1595 0x00, // Flags: none | |
1596 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1597 0x12, 0x34, 0x56, 0x78, // Increment: 305419896 | |
1598 }; | |
1599 | |
1600 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1601 } | |
1602 | |
1603 TEST_P(SpdyFramerTest, CreateDataFrame) { | |
1604 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1605 | |
1606 { | |
1607 const char kDescription[] = "'hello' data frame, no FIN"; | |
1608 // frame-format off | |
1609 const unsigned char kH2FrameData[] = { | |
1610 0x00, 0x00, 0x05, // Length: 5 | |
1611 0x00, // Type: DATA | |
1612 0x00, // Flags: none | |
1613 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1614 'h', 'e', 'l', 'l', // Payload | |
1615 'o', // | |
1616 }; | |
1617 // frame-format on | |
1618 const char bytes[] = "hello"; | |
1619 | |
1620 SpdyDataIR data_ir(1, bytes); | |
1621 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1622 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1623 | |
1624 SpdyDataIR data_header_ir(1); | |
1625 data_header_ir.SetDataShallow(bytes); | |
1626 frame = | |
1627 framer.SerializeDataFrameHeaderWithPaddingLengthField(data_header_ir); | |
1628 CompareCharArraysWithHexError( | |
1629 kDescription, reinterpret_cast<const unsigned char*>(frame.data()), | |
1630 framer.GetDataFrameMinimumSize(), kH2FrameData, | |
1631 framer.GetDataFrameMinimumSize()); | |
1632 } | |
1633 | |
1634 { | |
1635 const char kDescription[] = "'hello' data frame with more padding, no FIN"; | |
1636 const unsigned char kH2FrameData[] = { | |
1637 0x00, 0x00, 0xfd, // Length: 253 | |
1638 0x00, // Type: DATA | |
1639 0x08, // Flags: PADDED | |
1640 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1641 0xf7, // PadLen: 247 trailing bytes | |
1642 'h', 'e', 'l', 'l', // Payload | |
1643 'o', // | |
1644 // Padding of 247 0x00(s). | |
1645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1648 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1649 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1650 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1651 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1652 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1653 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1654 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1655 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1659 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1660 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1661 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1662 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1663 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1664 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1665 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
1666 }; | |
1667 // frame-format on | |
1668 // clang-format on | |
1669 const char bytes[] = "hello"; | |
1670 | |
1671 SpdyDataIR data_ir(1, bytes); | |
1672 // 247 zeros and the pad length field make the overall padding to be 248 | |
1673 // bytes. | |
1674 data_ir.set_padding_len(248); | |
1675 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1676 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1677 | |
1678 frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); | |
1679 CompareCharArraysWithHexError( | |
1680 kDescription, reinterpret_cast<const unsigned char*>(frame.data()), | |
1681 framer.GetDataFrameMinimumSize(), kH2FrameData, | |
1682 framer.GetDataFrameMinimumSize()); | |
1683 } | |
1684 | |
1685 { | |
1686 const char kDescription[] = "'hello' data frame with few padding, no FIN"; | |
1687 // frame-format off | |
1688 const unsigned char kH2FrameData[] = { | |
1689 0x00, 0x00, 0x0d, // Length: 13 | |
1690 0x00, // Type: DATA | |
1691 0x08, // Flags: PADDED | |
1692 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1693 0x07, // PadLen: 7 trailing bytes | |
1694 'h', 'e', 'l', 'l', // Payload | |
1695 'o', // | |
1696 0x00, 0x00, 0x00, 0x00, // Padding | |
1697 0x00, 0x00, 0x00, // Padding | |
1698 }; | |
1699 // frame-format on | |
1700 const char bytes[] = "hello"; | |
1701 | |
1702 SpdyDataIR data_ir(1, bytes); | |
1703 // 7 zeros and the pad length field make the overall padding to be 8 bytes. | |
1704 data_ir.set_padding_len(8); | |
1705 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1706 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1707 } | |
1708 | |
1709 { | |
1710 const char kDescription[] = | |
1711 "'hello' data frame with 1 byte padding, no FIN"; | |
1712 // frame-format off | |
1713 const unsigned char kH2FrameData[] = { | |
1714 0x00, 0x00, 0x06, // Length: 6 | |
1715 0x00, // Type: DATA | |
1716 0x08, // Flags: PADDED | |
1717 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1718 0x00, // PadLen: 0 trailing bytes | |
1719 'h', 'e', 'l', 'l', // Payload | |
1720 'o', // | |
1721 }; | |
1722 // frame-format on | |
1723 const char bytes[] = "hello"; | |
1724 | |
1725 SpdyDataIR data_ir(1, bytes); | |
1726 // The pad length field itself is used for the 1-byte padding and no padding | |
1727 // payload is needed. | |
1728 data_ir.set_padding_len(1); | |
1729 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1730 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1731 | |
1732 frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); | |
1733 CompareCharArraysWithHexError( | |
1734 kDescription, reinterpret_cast<const unsigned char*>(frame.data()), | |
1735 framer.GetDataFrameMinimumSize(), kH2FrameData, | |
1736 framer.GetDataFrameMinimumSize()); | |
1737 } | |
1738 | |
1739 { | |
1740 const char kDescription[] = "Data frame with negative data byte, no FIN"; | |
1741 const unsigned char kH2FrameData[] = { | |
1742 0x00, 0x00, 0x01, // Length: 1 | |
1743 0x00, // Type: DATA | |
1744 0x00, // Flags: none | |
1745 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1746 0xff, // Payload | |
1747 }; | |
1748 SpdyDataIR data_ir(1, "\xff"); | |
1749 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1750 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1751 } | |
1752 | |
1753 { | |
1754 const char kDescription[] = "'hello' data frame, with FIN"; | |
1755 const unsigned char kH2FrameData[] = { | |
1756 0x00, 0x00, 0x05, // Length: 5 | |
1757 0x00, // Type: DATA | |
1758 0x01, // Flags: END_STREAM | |
1759 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1760 0x68, 0x65, 0x6c, 0x6c, // Payload | |
1761 0x6f, // | |
1762 }; | |
1763 SpdyDataIR data_ir(1, "hello"); | |
1764 data_ir.set_fin(true); | |
1765 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1766 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1767 } | |
1768 | |
1769 { | |
1770 const char kDescription[] = "Empty data frame"; | |
1771 const unsigned char kH2FrameData[] = { | |
1772 0x00, 0x00, 0x00, // Length: 0 | |
1773 0x00, // Type: DATA | |
1774 0x00, // Flags: none | |
1775 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1776 }; | |
1777 SpdyDataIR data_ir(1, ""); | |
1778 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1779 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1780 | |
1781 frame = framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir); | |
1782 CompareCharArraysWithHexError( | |
1783 kDescription, reinterpret_cast<const unsigned char*>(frame.data()), | |
1784 framer.GetDataFrameMinimumSize(), kH2FrameData, | |
1785 framer.GetDataFrameMinimumSize()); | |
1786 } | |
1787 | |
1788 { | |
1789 const char kDescription[] = "Data frame with max stream ID"; | |
1790 const unsigned char kH2FrameData[] = { | |
1791 0x00, 0x00, 0x05, // Length: 5 | |
1792 0x00, // Type: DATA | |
1793 0x01, // Flags: END_STREAM | |
1794 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff | |
1795 0x68, 0x65, 0x6c, 0x6c, // Payload | |
1796 0x6f, // | |
1797 }; | |
1798 SpdyDataIR data_ir(0x7fffffff, "hello"); | |
1799 data_ir.set_fin(true); | |
1800 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
1801 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1802 } | |
1803 } | |
1804 | |
1805 TEST_P(SpdyFramerTest, CreateRstStream) { | |
1806 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1807 | |
1808 { | |
1809 const char kDescription[] = "RST_STREAM frame"; | |
1810 const unsigned char kH2FrameData[] = { | |
1811 0x00, 0x00, 0x04, // Length: 4 | |
1812 0x03, // Type: RST_STREAM | |
1813 0x00, // Flags: none | |
1814 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
1815 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR | |
1816 }; | |
1817 SpdyRstStreamIR rst_stream(1, ERROR_CODE_PROTOCOL_ERROR); | |
1818 SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream)); | |
1819 if (use_output_) { | |
1820 ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_)); | |
1821 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1822 } | |
1823 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1824 } | |
1825 | |
1826 { | |
1827 const char kDescription[] = "RST_STREAM frame with max stream ID"; | |
1828 const unsigned char kH2FrameData[] = { | |
1829 0x00, 0x00, 0x04, // Length: 4 | |
1830 0x03, // Type: RST_STREAM | |
1831 0x00, // Flags: none | |
1832 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff | |
1833 0x00, 0x00, 0x00, 0x01, // Error: PROTOCOL_ERROR | |
1834 }; | |
1835 SpdyRstStreamIR rst_stream(0x7FFFFFFF, ERROR_CODE_PROTOCOL_ERROR); | |
1836 SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream)); | |
1837 if (use_output_) { | |
1838 output_.Reset(); | |
1839 ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_)); | |
1840 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1841 } | |
1842 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1843 } | |
1844 | |
1845 { | |
1846 const char kDescription[] = "RST_STREAM frame with max status code"; | |
1847 const unsigned char kH2FrameData[] = { | |
1848 0x00, 0x00, 0x04, // Length: 4 | |
1849 0x03, // Type: RST_STREAM | |
1850 0x00, // Flags: none | |
1851 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff | |
1852 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR | |
1853 }; | |
1854 SpdyRstStreamIR rst_stream(0x7FFFFFFF, ERROR_CODE_INTERNAL_ERROR); | |
1855 SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream)); | |
1856 if (use_output_) { | |
1857 output_.Reset(); | |
1858 ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_)); | |
1859 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1860 } | |
1861 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1862 } | |
1863 } | |
1864 | |
1865 TEST_P(SpdyFramerTest, CreateSettings) { | |
1866 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1867 | |
1868 { | |
1869 const char kDescription[] = "Network byte order SETTINGS frame"; | |
1870 | |
1871 const unsigned char kH2FrameData[] = { | |
1872 0x00, 0x00, 0x06, // Length: 6 | |
1873 0x04, // Type: SETTINGS | |
1874 0x00, // Flags: none | |
1875 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
1876 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE | |
1877 0x0a, 0x0b, 0x0c, 0x0d, // Value: 168496141 | |
1878 }; | |
1879 | |
1880 uint32_t kValue = 0x0a0b0c0d; | |
1881 SpdySettingsIR settings_ir; | |
1882 | |
1883 SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE; | |
1884 settings_ir.AddSetting(kId, kValue); | |
1885 | |
1886 SpdySerializedFrame frame(framer.SerializeSettings(settings_ir)); | |
1887 if (use_output_) { | |
1888 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
1889 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1890 } | |
1891 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1892 } | |
1893 | |
1894 { | |
1895 const char kDescription[] = "Basic SETTINGS frame"; | |
1896 // These end up seemingly out of order because of the way that our internal | |
1897 // ordering for settings_ir works. HTTP2 has no requirement on ordering on | |
1898 // the wire. | |
1899 const unsigned char kH2FrameData[] = { | |
1900 0x00, 0x00, 0x18, // Length: 24 | |
1901 0x04, // Type: SETTINGS | |
1902 0x00, // Flags: none | |
1903 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
1904 0x00, 0x01, // Param: HEADER_TABLE_SIZE | |
1905 0x00, 0x00, 0x00, 0x05, // Value: 5 | |
1906 0x00, 0x02, // Param: ENABLE_PUSH | |
1907 0x00, 0x00, 0x00, 0x06, // Value: 6 | |
1908 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS | |
1909 0x00, 0x00, 0x00, 0x07, // Value: 7 | |
1910 0x00, 0x04, // Param: INITIAL_WINDOW_SIZE | |
1911 0x00, 0x00, 0x00, 0x08, // Value: 8 | |
1912 }; | |
1913 | |
1914 SpdySettingsIR settings_ir; | |
1915 settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); | |
1916 settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); | |
1917 settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); | |
1918 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 8); | |
1919 SpdySerializedFrame frame(framer.SerializeSettings(settings_ir)); | |
1920 if (use_output_) { | |
1921 output_.Reset(); | |
1922 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
1923 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1924 } | |
1925 | |
1926 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1927 } | |
1928 | |
1929 { | |
1930 const char kDescription[] = "Empty SETTINGS frame"; | |
1931 | |
1932 const unsigned char kH2FrameData[] = { | |
1933 0x00, 0x00, 0x00, // Length: 0 | |
1934 0x04, // Type: SETTINGS | |
1935 0x00, // Flags: none | |
1936 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
1937 }; | |
1938 SpdySettingsIR settings_ir; | |
1939 SpdySerializedFrame frame(framer.SerializeSettings(settings_ir)); | |
1940 if (use_output_) { | |
1941 output_.Reset(); | |
1942 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
1943 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1944 } | |
1945 | |
1946 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1947 } | |
1948 } | |
1949 | |
1950 TEST_P(SpdyFramerTest, CreatePingFrame) { | |
1951 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1952 | |
1953 { | |
1954 const char kDescription[] = "PING frame"; | |
1955 const unsigned char kH2FrameData[] = { | |
1956 0x00, 0x00, 0x08, // Length: 8 | |
1957 0x06, // Type: PING | |
1958 0x00, // Flags: none | |
1959 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
1960 0x12, 0x34, 0x56, 0x78, // Opaque | |
1961 0x9a, 0xbc, 0xde, 0xff, // Data | |
1962 }; | |
1963 const unsigned char kH2FrameDataWithAck[] = { | |
1964 0x00, 0x00, 0x08, // Length: 8 | |
1965 0x06, // Type: PING | |
1966 0x01, // Flags: ACK | |
1967 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
1968 0x12, 0x34, 0x56, 0x78, // Opaque | |
1969 0x9a, 0xbc, 0xde, 0xff, // Data | |
1970 }; | |
1971 SpdySerializedFrame frame; | |
1972 const SpdyPingId kPingId = 0x123456789abcdeffULL; | |
1973 SpdyPingIR ping_ir(kPingId); | |
1974 // Tests SpdyPingIR when the ping is not an ack. | |
1975 ASSERT_FALSE(ping_ir.is_ack()); | |
1976 frame = framer.SerializePing(ping_ir); | |
1977 if (use_output_) { | |
1978 ASSERT_TRUE(framer.SerializePing(ping_ir, &output_)); | |
1979 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1980 } | |
1981 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
1982 | |
1983 // Tests SpdyPingIR when the ping is an ack. | |
1984 ping_ir.set_is_ack(true); | |
1985 frame = framer.SerializePing(ping_ir); | |
1986 if (use_output_) { | |
1987 output_.Reset(); | |
1988 ASSERT_TRUE(framer.SerializePing(ping_ir, &output_)); | |
1989 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
1990 } | |
1991 CompareFrame(kDescription, frame, kH2FrameDataWithAck, | |
1992 arraysize(kH2FrameDataWithAck)); | |
1993 } | |
1994 } | |
1995 | |
1996 TEST_P(SpdyFramerTest, CreateGoAway) { | |
1997 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
1998 | |
1999 { | |
2000 const char kDescription[] = "GOAWAY frame"; | |
2001 const unsigned char kH2FrameData[] = { | |
2002 0x00, 0x00, 0x0a, // Length: 10 | |
2003 0x07, // Type: GOAWAY | |
2004 0x00, // Flags: none | |
2005 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
2006 0x00, 0x00, 0x00, 0x00, // Last: 0 | |
2007 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR | |
2008 0x47, 0x41, // Description | |
2009 }; | |
2010 SpdyGoAwayIR goaway_ir(0, ERROR_CODE_NO_ERROR, "GA"); | |
2011 SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir)); | |
2012 if (use_output_) { | |
2013 ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_)); | |
2014 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2015 } | |
2016 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2017 } | |
2018 | |
2019 { | |
2020 const char kDescription[] = "GOAWAY frame with max stream ID, status"; | |
2021 const unsigned char kH2FrameData[] = { | |
2022 0x00, 0x00, 0x0a, // Length: 10 | |
2023 0x07, // Type: GOAWAY | |
2024 0x00, // Flags: none | |
2025 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
2026 0x7f, 0xff, 0xff, 0xff, // Last: 0x7fffffff | |
2027 0x00, 0x00, 0x00, 0x02, // Error: INTERNAL_ERROR | |
2028 0x47, 0x41, // Description | |
2029 }; | |
2030 SpdyGoAwayIR goaway_ir(0x7FFFFFFF, ERROR_CODE_INTERNAL_ERROR, "GA"); | |
2031 SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir)); | |
2032 if (use_output_) { | |
2033 output_.Reset(); | |
2034 ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_)); | |
2035 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2036 } | |
2037 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2038 } | |
2039 } | |
2040 | |
2041 TEST_P(SpdyFramerTest, CreateHeadersUncompressed) { | |
2042 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2043 | |
2044 { | |
2045 const char kDescription[] = "HEADERS frame, no FIN"; | |
2046 // frame-format off | |
2047 const unsigned char kH2FrameData[] = { | |
2048 0x00, 0x00, 0x12, // Length: 18 | |
2049 0x01, // Type: HEADERS | |
2050 0x04, // Flags: END_HEADERS | |
2051 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
2052 | |
2053 0x00, // Unindexed Entry | |
2054 0x03, // Name Len: 3 | |
2055 0x62, 0x61, 0x72, // bar | |
2056 0x03, // Value Len: 3 | |
2057 0x66, 0x6f, 0x6f, // foo | |
2058 | |
2059 0x00, // Unindexed Entry | |
2060 0x03, // Name Len: 3 | |
2061 0x66, 0x6f, 0x6f, // foo | |
2062 0x03, // Value Len: 3 | |
2063 0x62, 0x61, 0x72, // bar | |
2064 }; | |
2065 // frame-format on | |
2066 | |
2067 SpdyHeadersIR headers(1); | |
2068 headers.SetHeader("bar", "foo"); | |
2069 headers.SetHeader("foo", "bar"); | |
2070 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2071 &framer, headers, use_output_ ? &output_ : nullptr)); | |
2072 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2073 } | |
2074 | |
2075 { | |
2076 const char kDescription[] = | |
2077 "HEADERS frame with a 0-length header name, FIN, max stream ID"; | |
2078 // frame-format off | |
2079 const unsigned char kH2FrameData[] = { | |
2080 0x00, 0x00, 0x0f, // Length: 15 | |
2081 0x01, // Type: HEADERS | |
2082 0x05, // Flags: END_STREAM|END_HEADERS | |
2083 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2084 | |
2085 0x00, // Unindexed Entry | |
2086 0x00, // Name Len: 0 | |
2087 0x03, // Value Len: 3 | |
2088 0x66, 0x6f, 0x6f, // foo | |
2089 | |
2090 0x00, // Unindexed Entry | |
2091 0x03, // Name Len: 3 | |
2092 0x66, 0x6f, 0x6f, // foo | |
2093 0x03, // Value Len: 3 | |
2094 0x62, 0x61, 0x72, // bar | |
2095 }; | |
2096 // frame-format on | |
2097 SpdyHeadersIR headers(0x7fffffff); | |
2098 headers.set_fin(true); | |
2099 headers.SetHeader("", "foo"); | |
2100 headers.SetHeader("foo", "bar"); | |
2101 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2102 &framer, headers, use_output_ ? &output_ : nullptr)); | |
2103 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2104 } | |
2105 | |
2106 { | |
2107 const char kDescription[] = | |
2108 "HEADERS frame with a 0-length header val, FIN, max stream ID"; | |
2109 // frame-format off | |
2110 const unsigned char kH2FrameData[] = { | |
2111 0x00, 0x00, 0x0f, // Length: 15 | |
2112 0x01, // Type: HEADERS | |
2113 0x05, // Flags: END_STREAM|END_HEADERS | |
2114 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2115 | |
2116 0x00, // Unindexed Entry | |
2117 0x03, // Name Len: 3 | |
2118 0x62, 0x61, 0x72, // bar | |
2119 0x03, // Value Len: 3 | |
2120 0x66, 0x6f, 0x6f, // foo | |
2121 | |
2122 0x00, // Unindexed Entry | |
2123 0x03, // Name Len: 3 | |
2124 0x66, 0x6f, 0x6f, // foo | |
2125 0x00, // Value Len: 0 | |
2126 }; | |
2127 // frame-format on | |
2128 SpdyHeadersIR headers_ir(0x7fffffff); | |
2129 headers_ir.set_fin(true); | |
2130 headers_ir.SetHeader("bar", "foo"); | |
2131 headers_ir.SetHeader("foo", ""); | |
2132 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2133 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2134 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2135 } | |
2136 | |
2137 { | |
2138 const char kDescription[] = | |
2139 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri"; | |
2140 | |
2141 // frame-format off | |
2142 const unsigned char kH2FrameData[] = { | |
2143 0x00, 0x00, 0x14, // Length: 20 | |
2144 0x01, // Type: HEADERS | |
2145 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY | |
2146 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2147 0x00, 0x00, 0x00, 0x00, // Parent: 0 | |
2148 0xdb, // Weight: 220 | |
2149 | |
2150 0x00, // Unindexed Entry | |
2151 0x03, // Name Len: 3 | |
2152 0x62, 0x61, 0x72, // bar | |
2153 0x03, // Value Len: 3 | |
2154 0x66, 0x6f, 0x6f, // foo | |
2155 | |
2156 0x00, // Unindexed Entry | |
2157 0x03, // Name Len: 3 | |
2158 0x66, 0x6f, 0x6f, // foo | |
2159 0x00, // Value Len: 0 | |
2160 }; | |
2161 // frame-format on | |
2162 SpdyHeadersIR headers_ir(0x7fffffff); | |
2163 headers_ir.set_fin(true); | |
2164 headers_ir.set_has_priority(true); | |
2165 headers_ir.set_weight(220); | |
2166 headers_ir.SetHeader("bar", "foo"); | |
2167 headers_ir.SetHeader("foo", ""); | |
2168 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2169 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2170 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2171 } | |
2172 | |
2173 { | |
2174 const char kDescription[] = | |
2175 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, " | |
2176 "exclusive=true, parent_stream=0"; | |
2177 | |
2178 // frame-format off | |
2179 const unsigned char kV4FrameData[] = { | |
2180 0x00, 0x00, 0x14, // Length: 20 | |
2181 0x01, // Type: HEADERS | |
2182 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY | |
2183 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2184 0x80, 0x00, 0x00, 0x00, // Parent: 0 (Exclusive) | |
2185 0xdb, // Weight: 220 | |
2186 | |
2187 0x00, // Unindexed Entry | |
2188 0x03, // Name Len: 3 | |
2189 0x62, 0x61, 0x72, // bar | |
2190 0x03, // Value Len: 3 | |
2191 0x66, 0x6f, 0x6f, // foo | |
2192 | |
2193 0x00, // Unindexed Entry | |
2194 0x03, // Name Len: 3 | |
2195 0x66, 0x6f, 0x6f, // foo | |
2196 0x00, // Value Len: 0 | |
2197 }; | |
2198 // frame-format on | |
2199 SpdyHeadersIR headers_ir(0x7fffffff); | |
2200 headers_ir.set_fin(true); | |
2201 headers_ir.set_has_priority(true); | |
2202 headers_ir.set_weight(220); | |
2203 headers_ir.set_exclusive(true); | |
2204 headers_ir.set_parent_stream_id(0); | |
2205 headers_ir.SetHeader("bar", "foo"); | |
2206 headers_ir.SetHeader("foo", ""); | |
2207 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2208 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2209 CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData)); | |
2210 } | |
2211 | |
2212 { | |
2213 const char kDescription[] = | |
2214 "HEADERS frame with a 0-length header val, FIN, max stream ID, pri, " | |
2215 "exclusive=false, parent_stream=max stream ID"; | |
2216 | |
2217 // frame-format off | |
2218 const unsigned char kV4FrameData[] = { | |
2219 0x00, 0x00, 0x14, // Length: 20 | |
2220 0x01, // Type: HEADERS | |
2221 0x25, // Flags: END_STREAM|END_HEADERS|PRIORITY | |
2222 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2223 0x7f, 0xff, 0xff, 0xff, // Parent: 2147483647 | |
2224 0xdb, // Weight: 220 | |
2225 | |
2226 0x00, // Unindexed Entry | |
2227 0x03, // Name Len: 3 | |
2228 0x62, 0x61, 0x72, // bar | |
2229 0x03, // Value Len: 3 | |
2230 0x66, 0x6f, 0x6f, // foo | |
2231 | |
2232 0x00, // Unindexed Entry | |
2233 0x03, // Name Len: 3 | |
2234 0x66, 0x6f, 0x6f, // foo | |
2235 0x00, // Value Len: 0 | |
2236 }; | |
2237 // frame-format on | |
2238 SpdyHeadersIR headers_ir(0x7fffffff); | |
2239 headers_ir.set_fin(true); | |
2240 headers_ir.set_has_priority(true); | |
2241 headers_ir.set_weight(220); | |
2242 headers_ir.set_exclusive(false); | |
2243 headers_ir.set_parent_stream_id(0x7fffffff); | |
2244 headers_ir.SetHeader("bar", "foo"); | |
2245 headers_ir.SetHeader("foo", ""); | |
2246 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2247 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2248 CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData)); | |
2249 } | |
2250 | |
2251 { | |
2252 const char kDescription[] = | |
2253 "HEADERS frame with a 0-length header name, FIN, max stream ID, padded"; | |
2254 | |
2255 // frame-format off | |
2256 const unsigned char kH2FrameData[] = { | |
2257 0x00, 0x00, 0x15, // Length: 21 | |
2258 0x01, // Type: HEADERS | |
2259 0x0d, // Flags: END_STREAM|END_HEADERS|PADDED | |
2260 0x7f, 0xff, 0xff, 0xff, // Stream: 2147483647 | |
2261 0x05, // PadLen: 5 trailing bytes | |
2262 | |
2263 0x00, // Unindexed Entry | |
2264 0x00, // Name Len: 0 | |
2265 0x03, // Value Len: 3 | |
2266 0x66, 0x6f, 0x6f, // foo | |
2267 | |
2268 0x00, // Unindexed Entry | |
2269 0x03, // Name Len: 3 | |
2270 0x66, 0x6f, 0x6f, // foo | |
2271 0x03, // Value Len: 3 | |
2272 0x62, 0x61, 0x72, // bar | |
2273 | |
2274 0x00, 0x00, 0x00, 0x00, // Padding | |
2275 0x00, // Padding | |
2276 }; | |
2277 // frame-format on | |
2278 SpdyHeadersIR headers_ir(0x7fffffff); | |
2279 headers_ir.set_fin(true); | |
2280 headers_ir.SetHeader("", "foo"); | |
2281 headers_ir.SetHeader("foo", "bar"); | |
2282 headers_ir.set_padding_len(6); | |
2283 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
2284 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2285 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2286 } | |
2287 } | |
2288 | |
2289 TEST_P(SpdyFramerTest, CreateWindowUpdate) { | |
2290 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2291 | |
2292 { | |
2293 const char kDescription[] = "WINDOW_UPDATE frame"; | |
2294 const unsigned char kH2FrameData[] = { | |
2295 0x00, 0x00, 0x04, // Length: 4 | |
2296 0x08, // Type: WINDOW_UPDATE | |
2297 0x00, // Flags: none | |
2298 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
2299 0x00, 0x00, 0x00, 0x01, // Increment: 1 | |
2300 }; | |
2301 SpdySerializedFrame frame( | |
2302 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1))); | |
2303 if (use_output_) { | |
2304 output_.Reset(); | |
2305 ASSERT_TRUE( | |
2306 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1), &output_)); | |
2307 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2308 } | |
2309 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2310 } | |
2311 | |
2312 { | |
2313 const char kDescription[] = "WINDOW_UPDATE frame with max stream ID"; | |
2314 const unsigned char kH2FrameData[] = { | |
2315 0x00, 0x00, 0x04, // Length: 4 | |
2316 0x08, // Type: WINDOW_UPDATE | |
2317 0x00, // Flags: none | |
2318 0x7f, 0xff, 0xff, 0xff, // Stream: 0x7fffffff | |
2319 0x00, 0x00, 0x00, 0x01, // Increment: 1 | |
2320 }; | |
2321 SpdySerializedFrame frame( | |
2322 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(0x7FFFFFFF, 1))); | |
2323 if (use_output_) { | |
2324 output_.Reset(); | |
2325 ASSERT_TRUE(framer.SerializeWindowUpdate( | |
2326 SpdyWindowUpdateIR(0x7FFFFFFF, 1), &output_)); | |
2327 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2328 } | |
2329 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2330 } | |
2331 | |
2332 { | |
2333 const char kDescription[] = "WINDOW_UPDATE frame with max window delta"; | |
2334 const unsigned char kH2FrameData[] = { | |
2335 0x00, 0x00, 0x04, // Length: 4 | |
2336 0x08, // Type: WINDOW_UPDATE | |
2337 0x00, // Flags: none | |
2338 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
2339 0x7f, 0xff, 0xff, 0xff, // Increment: 0x7fffffff | |
2340 }; | |
2341 SpdySerializedFrame frame( | |
2342 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 0x7FFFFFFF))); | |
2343 if (use_output_) { | |
2344 output_.Reset(); | |
2345 ASSERT_TRUE(framer.SerializeWindowUpdate( | |
2346 SpdyWindowUpdateIR(1, 0x7FFFFFFF), &output_)); | |
2347 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2348 } | |
2349 CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData)); | |
2350 } | |
2351 } | |
2352 | |
2353 TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) { | |
2354 { | |
2355 // Test framing PUSH_PROMISE without padding. | |
2356 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2357 const char kDescription[] = "PUSH_PROMISE frame without padding"; | |
2358 | |
2359 // frame-format off | |
2360 const unsigned char kFrameData[] = { | |
2361 0x00, 0x00, 0x16, // Length: 22 | |
2362 0x05, // Type: PUSH_PROMISE | |
2363 0x04, // Flags: END_HEADERS | |
2364 0x00, 0x00, 0x00, 0x29, // Stream: 41 | |
2365 0x00, 0x00, 0x00, 0x3a, // Promise: 58 | |
2366 | |
2367 0x00, // Unindexed Entry | |
2368 0x03, // Name Len: 3 | |
2369 0x62, 0x61, 0x72, // bar | |
2370 0x03, // Value Len: 3 | |
2371 0x66, 0x6f, 0x6f, // foo | |
2372 | |
2373 0x00, // Unindexed Entry | |
2374 0x03, // Name Len: 3 | |
2375 0x66, 0x6f, 0x6f, // foo | |
2376 0x03, // Value Len: 3 | |
2377 0x62, 0x61, 0x72, // bar | |
2378 }; | |
2379 // frame-format on | |
2380 | |
2381 SpdyPushPromiseIR push_promise(41, 58); | |
2382 push_promise.SetHeader("bar", "foo"); | |
2383 push_promise.SetHeader("foo", "bar"); | |
2384 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
2385 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
2386 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2387 } | |
2388 | |
2389 { | |
2390 // Test framing PUSH_PROMISE with one byte of padding. | |
2391 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2392 const char kDescription[] = "PUSH_PROMISE frame with one byte of padding"; | |
2393 | |
2394 // frame-format off | |
2395 const unsigned char kFrameData[] = { | |
2396 0x00, 0x00, 0x17, // Length: 23 | |
2397 0x05, // Type: PUSH_PROMISE | |
2398 0x0c, // Flags: END_HEADERS|PADDED | |
2399 0x00, 0x00, 0x00, 0x29, // Stream: 41 | |
2400 0x00, // PadLen: 0 trailing bytes | |
2401 0x00, 0x00, 0x00, 0x3a, // Promise: 58 | |
2402 | |
2403 0x00, // Unindexed Entry | |
2404 0x03, // Name Len: 3 | |
2405 0x62, 0x61, 0x72, // bar | |
2406 0x03, // Value Len: 3 | |
2407 0x66, 0x6f, 0x6f, // foo | |
2408 | |
2409 0x00, // Unindexed Entry | |
2410 0x03, // Name Len: 3 | |
2411 0x66, 0x6f, 0x6f, // foo | |
2412 0x03, // Value Len: 3 | |
2413 0x62, 0x61, 0x72, // bar | |
2414 }; | |
2415 // frame-format on | |
2416 | |
2417 SpdyPushPromiseIR push_promise(41, 58); | |
2418 push_promise.set_padding_len(1); | |
2419 push_promise.SetHeader("bar", "foo"); | |
2420 push_promise.SetHeader("foo", "bar"); | |
2421 output_.Reset(); | |
2422 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
2423 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
2424 | |
2425 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2426 } | |
2427 | |
2428 { | |
2429 // Test framing PUSH_PROMISE with 177 bytes of padding. | |
2430 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2431 const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding"; | |
2432 | |
2433 // frame-format off | |
2434 // clang-format off | |
2435 const unsigned char kFrameData[] = { | |
2436 0x00, 0x00, 0xc7, // Length: 199 | |
2437 0x05, // Type: PUSH_PROMISE | |
2438 0x0c, // Flags: END_HEADERS|PADDED | |
2439 0x00, 0x00, 0x00, 0x2a, // Stream: 42 | |
2440 0xb0, // PadLen: 176 trailing bytes | |
2441 0x00, 0x00, 0x00, 0x39, // Promise: 57 | |
2442 | |
2443 0x00, // Unindexed Entry | |
2444 0x03, // Name Len: 3 | |
2445 0x62, 0x61, 0x72, // bar | |
2446 0x03, // Value Len: 3 | |
2447 0x66, 0x6f, 0x6f, // foo | |
2448 | |
2449 0x00, // Unindexed Entry | |
2450 0x03, // Name Len: 3 | |
2451 0x66, 0x6f, 0x6f, // foo | |
2452 0x03, // Value Len: 3 | |
2453 0x62, 0x61, 0x72, // bar | |
2454 | |
2455 // Padding of 176 0x00(s). | |
2456 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2457 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2462 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2463 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2464 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2465 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2466 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2469 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2471 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
2472 }; | |
2473 // clang-format on | |
2474 // frame-format on | |
2475 | |
2476 SpdyPushPromiseIR push_promise(42, 57); | |
2477 push_promise.set_padding_len(177); | |
2478 push_promise.SetHeader("bar", "foo"); | |
2479 push_promise.SetHeader("foo", "bar"); | |
2480 output_.Reset(); | |
2481 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
2482 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
2483 | |
2484 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2485 } | |
2486 } | |
2487 | |
2488 // Regression test for https://crbug.com/464748. | |
2489 TEST_P(SpdyFramerTest, GetNumberRequiredContinuationFrames) { | |
2490 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2491 EXPECT_EQ(1u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( | |
2492 &framer, 16383 + 16374)); | |
2493 EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( | |
2494 &framer, 16383 + 16374 + 1)); | |
2495 EXPECT_EQ(2u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( | |
2496 &framer, 16383 + 2 * 16374)); | |
2497 EXPECT_EQ(3u, SpdyFramerPeer::GetNumberRequiredContinuationFrames( | |
2498 &framer, 16383 + 2 * 16374 + 1)); | |
2499 } | |
2500 | |
2501 TEST_P(SpdyFramerTest, CreateContinuationUncompressed) { | |
2502 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2503 const char kDescription[] = "CONTINUATION frame"; | |
2504 | |
2505 // frame-format off | |
2506 const unsigned char kFrameData[] = { | |
2507 0x00, 0x00, 0x12, // Length: 18 | |
2508 0x09, // Type: CONTINUATION | |
2509 0x04, // Flags: END_HEADERS | |
2510 0x00, 0x00, 0x00, 0x2a, // Stream: 42 | |
2511 | |
2512 0x00, // Unindexed Entry | |
2513 0x03, // Name Len: 3 | |
2514 0x62, 0x61, 0x72, // bar | |
2515 0x03, // Value Len: 3 | |
2516 0x66, 0x6f, 0x6f, // foo | |
2517 | |
2518 0x00, // Unindexed Entry | |
2519 0x03, // Name Len: 3 | |
2520 0x66, 0x6f, 0x6f, // foo | |
2521 0x03, // Value Len: 3 | |
2522 0x62, 0x61, 0x72, // bar | |
2523 }; | |
2524 // frame-format on | |
2525 | |
2526 SpdyHeaderBlock header_block; | |
2527 header_block["bar"] = "foo"; | |
2528 header_block["foo"] = "bar"; | |
2529 auto buffer = base::MakeUnique<SpdyString>(); | |
2530 HpackEncoder encoder(ObtainHpackHuffmanTable()); | |
2531 encoder.DisableCompression(); | |
2532 encoder.EncodeHeaderSet(header_block, buffer.get()); | |
2533 | |
2534 SpdyContinuationIR continuation(42); | |
2535 continuation.take_encoding(std::move(buffer)); | |
2536 continuation.set_end_headers(true); | |
2537 | |
2538 SpdySerializedFrame frame(framer.SerializeContinuation(continuation)); | |
2539 if (use_output_) { | |
2540 ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_)); | |
2541 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2542 } | |
2543 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2544 } | |
2545 | |
2546 // Test that if we send an unexpected CONTINUATION | |
2547 // we signal an error (but don't crash). | |
2548 TEST_P(SpdyFramerTest, SendUnexpectedContinuation) { | |
2549 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
2550 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2551 framer.set_visitor(&visitor); | |
2552 | |
2553 // frame-format off | |
2554 char kH2FrameData[] = { | |
2555 0x00, 0x00, 0x12, // Length: 18 | |
2556 0x09, // Type: CONTINUATION | |
2557 0x04, // Flags: END_HEADERS | |
2558 0x00, 0x00, 0x00, 0x2a, // Stream: 42 | |
2559 | |
2560 0x00, // Unindexed Entry | |
2561 0x03, // Name Len: 3 | |
2562 0x62, 0x61, 0x72, // bar | |
2563 0x03, // Value Len: 3 | |
2564 0x66, 0x6f, 0x6f, // foo | |
2565 | |
2566 0x00, // Unindexed Entry | |
2567 0x03, // Name Len: 3 | |
2568 0x66, 0x6f, 0x6f, // foo | |
2569 0x03, // Value Len: 3 | |
2570 0x62, 0x61, 0x72, // bar | |
2571 }; | |
2572 // frame-format on | |
2573 | |
2574 SpdySerializedFrame frame(kH2FrameData, sizeof(kH2FrameData), false); | |
2575 | |
2576 // We shouldn't have to read the whole frame before we signal an error. | |
2577 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
2578 EXPECT_GT(frame.size(), framer.ProcessInput(frame.data(), frame.size())); | |
2579 EXPECT_TRUE(framer.HasError()); | |
2580 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, framer.spdy_framer_error()) | |
2581 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
2582 } | |
2583 | |
2584 TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) { | |
2585 { | |
2586 // Test framing in a case such that a PUSH_PROMISE frame, with one byte of | |
2587 // padding, cannot hold all the data payload, which is overflowed to the | |
2588 // consecutive CONTINUATION frame. | |
2589 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2590 const char kDescription[] = | |
2591 "PUSH_PROMISE and CONTINUATION frames with one byte of padding"; | |
2592 | |
2593 // frame-format off | |
2594 const unsigned char kPartialPushPromiseFrameData[] = { | |
2595 0x00, 0x3f, 0xf6, // Length: 16374 | |
2596 0x05, // Type: PUSH_PROMISE | |
2597 0x08, // Flags: PADDED | |
2598 0x00, 0x00, 0x00, 0x2a, // Stream: 42 | |
2599 0x00, // PadLen: 0 trailing bytes | |
2600 0x00, 0x00, 0x00, 0x39, // Promise: 57 | |
2601 | |
2602 0x00, // Unindexed Entry | |
2603 0x03, // Name Len: 3 | |
2604 0x78, 0x78, 0x78, // xxx | |
2605 0x7f, 0x80, 0x7f, // Value Len: 16361 | |
2606 0x78, 0x78, 0x78, 0x78, // xxxx | |
2607 0x78, 0x78, 0x78, 0x78, // xxxx | |
2608 0x78, 0x78, 0x78, 0x78, // xxxx | |
2609 0x78, 0x78, 0x78, 0x78, // xxxx | |
2610 0x78, 0x78, 0x78, 0x78, // xxxx | |
2611 0x78, 0x78, 0x78, 0x78, // xxxx | |
2612 0x78, 0x78, 0x78, 0x78, // xxxx | |
2613 0x78, 0x78, 0x78, 0x78, // xxxx | |
2614 0x78, 0x78, 0x78, 0x78, // xxxx | |
2615 0x78, 0x78, 0x78, 0x78, // xxxx | |
2616 0x78, 0x78, 0x78, 0x78, // xxxx | |
2617 0x78, 0x78, 0x78, 0x78, // xxxx | |
2618 0x78, 0x78, 0x78, 0x78, // xxxx | |
2619 0x78, 0x78, 0x78, 0x78, // xxxx | |
2620 0x78, 0x78, 0x78, 0x78, // xxxx | |
2621 0x78, 0x78, 0x78, 0x78, // xxxx | |
2622 0x78, 0x78, 0x78, 0x78, // xxxx | |
2623 0x78, 0x78, 0x78, 0x78, // xxxx | |
2624 0x78, 0x78, 0x78, 0x78, // xxxx | |
2625 0x78, 0x78, 0x78, 0x78, // xxxx | |
2626 0x78, 0x78, 0x78, 0x78, // xxxx | |
2627 }; | |
2628 const unsigned char kContinuationFrameData[] = { | |
2629 0x00, 0x00, 0x16, // Length: 22 | |
2630 0x09, // Type: CONTINUATION | |
2631 0x04, // Flags: END_HEADERS | |
2632 0x00, 0x00, 0x00, 0x2a, // Stream: 42 | |
2633 0x78, 0x78, 0x78, 0x78, // xxxx | |
2634 0x78, 0x78, 0x78, 0x78, // xxxx | |
2635 0x78, 0x78, 0x78, 0x78, // xxxx | |
2636 0x78, 0x78, 0x78, 0x78, // xxxx | |
2637 0x78, 0x78, 0x78, 0x78, // xxxx | |
2638 0x78, // x | |
2639 }; | |
2640 // frame-format on | |
2641 | |
2642 SpdyPushPromiseIR push_promise(42, 57); | |
2643 push_promise.set_padding_len(1); | |
2644 SpdyString big_value(TestSpdyVisitor::sent_control_frame_max_size(), 'x'); | |
2645 push_promise.SetHeader("xxx", big_value); | |
2646 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
2647 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
2648 | |
2649 // The entire frame should look like below: | |
2650 // Name Length in Byte | |
2651 // ------------------------------------------- Begin of PUSH_PROMISE frame | |
2652 // PUSH_PROMISE header 9 | |
2653 // Pad length field 1 | |
2654 // Promised stream 4 | |
2655 // Length field of key 2 | |
2656 // Content of key 3 | |
2657 // Length field of value 3 | |
2658 // Part of big_value 16361 | |
2659 // ------------------------------------------- Begin of CONTINUATION frame | |
2660 // CONTINUATION header 9 | |
2661 // Remaining of big_value 22 | |
2662 // ------------------------------------------- End | |
2663 | |
2664 // Length of everything listed above except big_value. | |
2665 int len_non_data_payload = 31; | |
2666 EXPECT_EQ( | |
2667 TestSpdyVisitor::sent_control_frame_max_size() + len_non_data_payload, | |
2668 frame.size()); | |
2669 | |
2670 // Partially compare the PUSH_PROMISE frame against the template. | |
2671 const unsigned char* frame_data = | |
2672 reinterpret_cast<const unsigned char*>(frame.data()); | |
2673 CompareCharArraysWithHexError( | |
2674 kDescription, frame_data, arraysize(kPartialPushPromiseFrameData), | |
2675 kPartialPushPromiseFrameData, arraysize(kPartialPushPromiseFrameData)); | |
2676 | |
2677 // Compare the CONTINUATION frame against the template. | |
2678 frame_data += TestSpdyVisitor::sent_control_frame_max_size(); | |
2679 CompareCharArraysWithHexError( | |
2680 kDescription, frame_data, arraysize(kContinuationFrameData), | |
2681 kContinuationFrameData, arraysize(kContinuationFrameData)); | |
2682 } | |
2683 } | |
2684 | |
2685 TEST_P(SpdyFramerTest, CreateAltSvc) { | |
2686 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2687 | |
2688 const char kDescription[] = "ALTSVC frame"; | |
2689 const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC); | |
2690 const unsigned char kFrameData[] = { | |
2691 0x00, 0x00, 0x49, kType, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 'o', | |
2692 'r', 'i', 'g', 'i', 'n', 'p', 'i', 'd', '1', '=', '"', 'h', | |
2693 'o', 's', 't', ':', '4', '4', '3', '"', ';', ' ', 'm', 'a', | |
2694 '=', '5', ',', 'p', '%', '2', '2', '%', '3', 'D', 'i', '%', | |
2695 '3', 'A', 'd', '=', '"', 'h', '_', '\\', '\\', 'o', '\\', '"', | |
2696 's', 't', ':', '1', '2', '3', '"', ';', ' ', 'm', 'a', '=', | |
2697 '4', '2', ';', ' ', 'v', '=', '"', '2', '4', '"'}; | |
2698 SpdyAltSvcIR altsvc_ir(3); | |
2699 altsvc_ir.set_origin("origin"); | |
2700 altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( | |
2701 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector())); | |
2702 altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( | |
2703 "p\"=i:d", "h_\\o\"st", 123, 42, | |
2704 SpdyAltSvcWireFormat::VersionVector{24})); | |
2705 SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir)); | |
2706 if (use_output_) { | |
2707 ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_)); | |
2708 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2709 } | |
2710 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2711 } | |
2712 | |
2713 TEST_P(SpdyFramerTest, CreatePriority) { | |
2714 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2715 | |
2716 const char kDescription[] = "PRIORITY frame"; | |
2717 const unsigned char kFrameData[] = { | |
2718 0x00, 0x00, 0x05, // Length: 5 | |
2719 0x02, // Type: PRIORITY | |
2720 0x00, // Flags: none | |
2721 0x00, 0x00, 0x00, 0x02, // Stream: 2 | |
2722 0x80, 0x00, 0x00, 0x01, // Parent: 1 (Exclusive) | |
2723 0x10, // Weight: 17 | |
2724 }; | |
2725 SpdyPriorityIR priority_ir(2, 1, 17, true); | |
2726 SpdySerializedFrame frame(framer.SerializeFrame(priority_ir)); | |
2727 if (use_output_) { | |
2728 ASSERT_TRUE(framer.SerializeFrame(priority_ir, &output_)); | |
2729 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2730 } | |
2731 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2732 SpdyPriorityIR priority2(2); | |
2733 priority2.set_parent_stream_id(1); | |
2734 priority2.set_weight(17); | |
2735 priority2.set_exclusive(true); | |
2736 if (use_output_) { | |
2737 output_.Reset(); | |
2738 ASSERT_TRUE(framer.SerializeFrame(priority2, &output_)); | |
2739 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
2740 } else { | |
2741 frame = framer.SerializeFrame(priority2); | |
2742 } | |
2743 CompareFrame(kDescription, frame, kFrameData, arraysize(kFrameData)); | |
2744 } | |
2745 | |
2746 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) { | |
2747 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2748 SpdyHeadersIR headers_ir(1); | |
2749 headers_ir.SetHeader("alpha", "beta"); | |
2750 headers_ir.SetHeader("gamma", "delta"); | |
2751 SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( | |
2752 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2753 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
2754 visitor.SimulateInFramer( | |
2755 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2756 control_frame.size()); | |
2757 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2758 EXPECT_EQ(0, visitor.control_frame_header_data_count_); | |
2759 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2760 EXPECT_EQ(0, visitor.end_of_stream_count_); | |
2761 EXPECT_EQ(headers_ir.header_block(), visitor.headers_); | |
2762 } | |
2763 | |
2764 TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) { | |
2765 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2766 SpdyHeadersIR headers_ir(1); | |
2767 headers_ir.set_fin(true); | |
2768 headers_ir.SetHeader("alpha", "beta"); | |
2769 headers_ir.SetHeader("gamma", "delta"); | |
2770 SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( | |
2771 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
2772 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
2773 visitor.SimulateInFramer( | |
2774 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2775 control_frame.size()); | |
2776 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2777 EXPECT_EQ(0, visitor.control_frame_header_data_count_); | |
2778 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2779 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
2780 EXPECT_EQ(headers_ir.header_block(), visitor.headers_); | |
2781 } | |
2782 | |
2783 TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) { | |
2784 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2785 SpdyHeadersIR headers(1); | |
2786 headers.set_padding_len(256); | |
2787 | |
2788 // Exact payload length will change with HPACK, but this should be long | |
2789 // enough to cause an overflow. | |
2790 const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size(); | |
2791 SpdyString big_value(kBigValueSize, 'x'); | |
2792 headers.SetHeader("aa", big_value); | |
2793 SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( | |
2794 &framer, headers, use_output_ ? &output_ : nullptr)); | |
2795 EXPECT_GT(control_frame.size(), | |
2796 TestSpdyVisitor::sent_control_frame_max_size()); | |
2797 | |
2798 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
2799 visitor.SimulateInFramer( | |
2800 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2801 control_frame.size()); | |
2802 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2803 EXPECT_EQ(0, visitor.error_count_); | |
2804 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2805 EXPECT_EQ(1, visitor.continuation_count_); | |
2806 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2807 } | |
2808 | |
2809 TEST_P(SpdyFramerTest, MultipleContinuationFramesWithIterator) { | |
2810 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2811 auto headers = base::MakeUnique<SpdyHeadersIR>(1); | |
2812 headers->set_padding_len(256); | |
2813 | |
2814 // Exact payload length will change with HPACK, but this should be long | |
2815 // enough to cause an overflow. | |
2816 const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size(); | |
2817 SpdyString big_valuex(kBigValueSize, 'x'); | |
2818 headers->SetHeader("aa", big_valuex); | |
2819 SpdyString big_valuez(kBigValueSize, 'z'); | |
2820 headers->SetHeader("bb", big_valuez); | |
2821 | |
2822 SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers)); | |
2823 | |
2824 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2825 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2826 SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false); | |
2827 EXPECT_EQ(headers_frame.size(), | |
2828 TestSpdyVisitor::sent_control_frame_max_size()); | |
2829 | |
2830 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
2831 visitor.SimulateInFramer( | |
2832 reinterpret_cast<unsigned char*>(headers_frame.data()), | |
2833 headers_frame.size()); | |
2834 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2835 EXPECT_EQ(0, visitor.error_count_); | |
2836 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2837 EXPECT_EQ(0, visitor.continuation_count_); | |
2838 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2839 | |
2840 output_.Reset(); | |
2841 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2842 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2843 SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); | |
2844 EXPECT_EQ(first_cont_frame.size(), | |
2845 TestSpdyVisitor::sent_control_frame_max_size()); | |
2846 | |
2847 visitor.SimulateInFramer( | |
2848 reinterpret_cast<unsigned char*>(first_cont_frame.data()), | |
2849 first_cont_frame.size()); | |
2850 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2851 EXPECT_EQ(0, visitor.error_count_); | |
2852 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2853 EXPECT_EQ(1, visitor.continuation_count_); | |
2854 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2855 | |
2856 output_.Reset(); | |
2857 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2858 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2859 SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); | |
2860 EXPECT_LT(second_cont_frame.size(), | |
2861 TestSpdyVisitor::sent_control_frame_max_size()); | |
2862 | |
2863 visitor.SimulateInFramer( | |
2864 reinterpret_cast<unsigned char*>(second_cont_frame.data()), | |
2865 second_cont_frame.size()); | |
2866 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2867 EXPECT_EQ(0, visitor.error_count_); | |
2868 EXPECT_EQ(1, visitor.headers_frame_count_); | |
2869 EXPECT_EQ(2, visitor.continuation_count_); | |
2870 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2871 | |
2872 EXPECT_FALSE(frame_it.HasNextFrame()); | |
2873 } | |
2874 | |
2875 TEST_P(SpdyFramerTest, PushPromiseFramesWithIterator) { | |
2876 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2877 auto push_promise = base::MakeUnique<SpdyPushPromiseIR>(1, 2); | |
2878 push_promise->set_padding_len(256); | |
2879 | |
2880 // Exact payload length will change with HPACK, but this should be long | |
2881 // enough to cause an overflow. | |
2882 const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size(); | |
2883 SpdyString big_valuex(kBigValueSize, 'x'); | |
2884 push_promise->SetHeader("aa", big_valuex); | |
2885 SpdyString big_valuez(kBigValueSize, 'z'); | |
2886 push_promise->SetHeader("bb", big_valuez); | |
2887 | |
2888 SpdyFramer::SpdyPushPromiseFrameIterator frame_it(&framer, | |
2889 std::move(push_promise)); | |
2890 | |
2891 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2892 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2893 SpdySerializedFrame push_promise_frame(output_.Begin(), output_.Size(), | |
2894 false); | |
2895 EXPECT_EQ(push_promise_frame.size(), | |
2896 TestSpdyVisitor::sent_control_frame_max_size()); | |
2897 | |
2898 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
2899 visitor.SimulateInFramer( | |
2900 reinterpret_cast<unsigned char*>(push_promise_frame.data()), | |
2901 push_promise_frame.size()); | |
2902 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2903 EXPECT_EQ(0, visitor.error_count_); | |
2904 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
2905 EXPECT_EQ(0, visitor.continuation_count_); | |
2906 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2907 | |
2908 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2909 output_.Reset(); | |
2910 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2911 SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false); | |
2912 | |
2913 EXPECT_EQ(first_cont_frame.size(), | |
2914 TestSpdyVisitor::sent_control_frame_max_size()); | |
2915 visitor.SimulateInFramer( | |
2916 reinterpret_cast<unsigned char*>(first_cont_frame.data()), | |
2917 first_cont_frame.size()); | |
2918 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2919 EXPECT_EQ(0, visitor.error_count_); | |
2920 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
2921 EXPECT_EQ(1, visitor.continuation_count_); | |
2922 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2923 | |
2924 EXPECT_TRUE(frame_it.HasNextFrame()); | |
2925 output_.Reset(); | |
2926 EXPECT_TRUE(frame_it.NextFrame(&output_)); | |
2927 SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false); | |
2928 EXPECT_LT(second_cont_frame.size(), | |
2929 TestSpdyVisitor::sent_control_frame_max_size()); | |
2930 | |
2931 visitor.SimulateInFramer( | |
2932 reinterpret_cast<unsigned char*>(second_cont_frame.data()), | |
2933 second_cont_frame.size()); | |
2934 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2935 EXPECT_EQ(0, visitor.error_count_); | |
2936 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
2937 EXPECT_EQ(2, visitor.continuation_count_); | |
2938 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2939 | |
2940 EXPECT_FALSE(frame_it.HasNextFrame()); | |
2941 } | |
2942 | |
2943 TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) { | |
2944 SpdyFramer framer(SpdyFramer::DISABLE_COMPRESSION); | |
2945 SpdyPushPromiseIR push_promise(1, 2); | |
2946 push_promise.set_padding_len(256); | |
2947 | |
2948 // Exact payload length will change with HPACK, but this should be long | |
2949 // enough to cause an overflow. | |
2950 const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size(); | |
2951 SpdyString big_value(kBigValueSize, 'x'); | |
2952 push_promise.SetHeader("aa", big_value); | |
2953 SpdySerializedFrame control_frame(SpdyFramerPeer::SerializePushPromise( | |
2954 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
2955 EXPECT_GT(control_frame.size(), | |
2956 TestSpdyVisitor::sent_control_frame_max_size()); | |
2957 | |
2958 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
2959 visitor.SimulateInFramer( | |
2960 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2961 control_frame.size()); | |
2962 EXPECT_TRUE(visitor.header_buffer_valid_); | |
2963 EXPECT_EQ(0, visitor.error_count_); | |
2964 EXPECT_EQ(1, visitor.push_promise_frame_count_); | |
2965 EXPECT_EQ(1, visitor.continuation_count_); | |
2966 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
2967 } | |
2968 | |
2969 // Check that the framer stops delivering header data chunks once the visitor | |
2970 // declares it doesn't want any more. This is important to guard against | |
2971 // "zip bomb" types of attacks. | |
2972 TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) { | |
2973 const size_t kHeaderBufferChunks = 4; | |
2974 const size_t kHeaderBufferSize = | |
2975 TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks; | |
2976 const size_t kBigValueSize = kHeaderBufferSize * 2; | |
2977 SpdyString big_value(kBigValueSize, 'x'); | |
2978 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2979 SpdyHeadersIR headers(1); | |
2980 headers.set_fin(true); | |
2981 headers.SetHeader("aa", big_value); | |
2982 SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders( | |
2983 &framer, headers, use_output_ ? &output_ : nullptr)); | |
2984 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
2985 visitor.set_header_buffer_size(kHeaderBufferSize); | |
2986 visitor.SimulateInFramer( | |
2987 reinterpret_cast<unsigned char*>(control_frame.data()), | |
2988 control_frame.size()); | |
2989 // It's up to the visitor to ignore extraneous header data; the framer | |
2990 // won't throw an error. | |
2991 EXPECT_GT(visitor.header_bytes_received_, visitor.header_buffer_.size()); | |
2992 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
2993 } | |
2994 | |
2995 TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) { | |
2996 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
2997 // Create a GoAway frame that has a few extra bytes at the end. | |
2998 // We create enough overhead to overflow the framer's control frame buffer. | |
2999 ASSERT_LE(SpdyFramerPeer::ControlFrameBufferSize(), 250u); | |
3000 const size_t length = SpdyFramerPeer::ControlFrameBufferSize() + 1; | |
3001 | |
3002 // HTTP/2 GOAWAY frames are only bound by a minimal length, since they may | |
3003 // carry opaque data. Verify that minimal length is tested. | |
3004 ASSERT_GT(framer.GetGoAwayMinimumSize(), kFrameHeaderSize); | |
3005 const size_t less_than_min_length = | |
3006 framer.GetGoAwayMinimumSize() - kFrameHeaderSize - 1; | |
3007 ASSERT_LE(less_than_min_length, std::numeric_limits<unsigned char>::max()); | |
3008 const unsigned char kH2Len = static_cast<unsigned char>(less_than_min_length); | |
3009 const unsigned char kH2FrameData[] = { | |
3010 0x00, 0x00, kH2Len, // Length: min length - 1 | |
3011 0x07, // Type: GOAWAY | |
3012 0x00, // Flags: none | |
3013 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3014 0x00, 0x00, 0x00, 0x00, // Last: 0 | |
3015 0x00, 0x00, 0x00, // Truncated Status Field | |
3016 }; | |
3017 const size_t pad_length = length + kFrameHeaderSize - sizeof(kH2FrameData); | |
3018 SpdyString pad(pad_length, 'A'); | |
3019 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3020 | |
3021 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); | |
3022 visitor.SimulateInFramer(reinterpret_cast<const unsigned char*>(pad.c_str()), | |
3023 pad.length()); | |
3024 | |
3025 EXPECT_EQ(1, visitor.error_count_); // This generated an error. | |
3026 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
3027 visitor.framer_.spdy_framer_error()) | |
3028 << SpdyFramer::SpdyFramerErrorToString( | |
3029 visitor.framer_.spdy_framer_error()); | |
3030 EXPECT_EQ(0, visitor.goaway_count_); // Frame not parsed. | |
3031 } | |
3032 | |
3033 TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) { | |
3034 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3035 SpdySettingsIR settings_ir; | |
3036 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
3037 if (use_output_) { | |
3038 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
3039 control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3040 } | |
3041 SetFrameLength(&control_frame, 0); | |
3042 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3043 visitor.SimulateInFramer( | |
3044 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3045 framer.GetFrameHeaderSize()); | |
3046 // Zero-len settings frames are permitted as of HTTP/2. | |
3047 EXPECT_EQ(0, visitor.error_count_); | |
3048 } | |
3049 | |
3050 // Tests handling of SETTINGS frames with invalid length. | |
3051 TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) { | |
3052 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3053 SpdySettingsIR settings_ir; | |
3054 | |
3055 // Add settings to more than fill the frame so that we don't get a buffer | |
3056 // overflow when calling SimulateInFramer() below. These settings must be | |
3057 // distinct parameters because SpdySettingsIR has a map for settings, and will | |
3058 // collapse multiple copies of the same parameter. | |
3059 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 0x00000002); | |
3060 settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 0x00000002); | |
3061 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
3062 if (use_output_) { | |
3063 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
3064 control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3065 } | |
3066 const size_t kNewLength = 8; | |
3067 SetFrameLength(&control_frame, kNewLength); | |
3068 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3069 visitor.SimulateInFramer( | |
3070 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3071 framer.GetFrameHeaderSize() + kNewLength); | |
3072 // Should generate an error, since its not possible to have a | |
3073 // settings frame of length kNewLength. | |
3074 EXPECT_EQ(1, visitor.error_count_); | |
3075 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
3076 visitor.framer_.spdy_framer_error()) | |
3077 << SpdyFramer::SpdyFramerErrorToString( | |
3078 visitor.framer_.spdy_framer_error()); | |
3079 } | |
3080 | |
3081 // Tests handling of SETTINGS frames larger than the frame buffer size. | |
3082 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) { | |
3083 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3084 SpdySettingsIR settings_ir; | |
3085 settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 5); | |
3086 settings_ir.AddSetting(SETTINGS_ENABLE_PUSH, 6); | |
3087 settings_ir.AddSetting(SETTINGS_MAX_CONCURRENT_STREAMS, 7); | |
3088 | |
3089 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
3090 if (use_output_) { | |
3091 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
3092 control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3093 } | |
3094 | |
3095 EXPECT_LT(SpdyFramerPeer::ControlFrameBufferSize(), control_frame.size()); | |
3096 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3097 | |
3098 // Read all at once. | |
3099 visitor.SimulateInFramer( | |
3100 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3101 control_frame.size()); | |
3102 EXPECT_EQ(0, visitor.error_count_); | |
3103 EXPECT_EQ(3, visitor.setting_count_); | |
3104 EXPECT_EQ(1, visitor.settings_ack_sent_); | |
3105 | |
3106 // Read data in small chunks. | |
3107 size_t framed_data = 0; | |
3108 size_t unframed_data = control_frame.size(); | |
3109 size_t kReadChunkSize = 5; // Read five bytes at a time. | |
3110 while (unframed_data > 0) { | |
3111 size_t to_read = std::min(kReadChunkSize, unframed_data); | |
3112 visitor.SimulateInFramer( | |
3113 reinterpret_cast<unsigned char*>(control_frame.data() + framed_data), | |
3114 to_read); | |
3115 unframed_data -= to_read; | |
3116 framed_data += to_read; | |
3117 } | |
3118 EXPECT_EQ(0, visitor.error_count_); | |
3119 EXPECT_EQ(3 * 2, visitor.setting_count_); | |
3120 EXPECT_EQ(2, visitor.settings_ack_sent_); | |
3121 } | |
3122 | |
3123 // Tests handling of SETTINGS frame with duplicate entries. | |
3124 TEST_P(SpdyFramerTest, ReadDuplicateSettings) { | |
3125 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3126 | |
3127 const unsigned char kH2FrameData[] = { | |
3128 0x00, 0x00, 0x12, // Length: 18 | |
3129 0x04, // Type: SETTINGS | |
3130 0x00, // Flags: none | |
3131 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3132 0x00, 0x01, // Param: HEADER_TABLE_SIZE | |
3133 0x00, 0x00, 0x00, 0x02, // Value: 2 | |
3134 0x00, 0x01, // Param: HEADER_TABLE_SIZE | |
3135 0x00, 0x00, 0x00, 0x03, // Value: 3 | |
3136 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS | |
3137 0x00, 0x00, 0x00, 0x03, // Value: 3 | |
3138 }; | |
3139 | |
3140 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3141 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); | |
3142 | |
3143 // In HTTP/2, duplicate settings are allowed; | |
3144 // each setting replaces the previous value for that setting. | |
3145 EXPECT_EQ(3, visitor.setting_count_); | |
3146 EXPECT_EQ(0, visitor.error_count_); | |
3147 EXPECT_EQ(1, visitor.settings_ack_sent_); | |
3148 } | |
3149 | |
3150 // Tests handling of SETTINGS frame with a setting we don't recognize. | |
3151 TEST_P(SpdyFramerTest, ReadUnknownSettingsId) { | |
3152 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3153 const unsigned char kH2FrameData[] = { | |
3154 0x00, 0x00, 0x06, // Length: 6 | |
3155 0x04, // Type: SETTINGS | |
3156 0x00, // Flags: none | |
3157 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3158 0x00, 0x10, // Param: 16 | |
3159 0x00, 0x00, 0x00, 0x02, // Value: 2 | |
3160 }; | |
3161 | |
3162 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3163 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); | |
3164 | |
3165 // In HTTP/2, we ignore unknown settings because of extensions. | |
3166 EXPECT_EQ(0, visitor.setting_count_); | |
3167 EXPECT_EQ(0, visitor.error_count_); | |
3168 } | |
3169 | |
3170 TEST_P(SpdyFramerTest, ReadUnknownSettingsWithExtension) { | |
3171 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3172 const unsigned char kH2FrameData[] = { | |
3173 0x00, 0x00, 0x0c, // Length: 12 | |
3174 0x04, // Type: SETTINGS | |
3175 0x00, // Flags: none | |
3176 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3177 0x00, 0x10, // Param: 16 | |
3178 0x00, 0x00, 0x00, 0x02, // Value: 2 | |
3179 0x00, 0x5f, // Param: 95 | |
3180 0x00, 0x01, 0x00, 0x02, // Value: 65538 | |
3181 }; | |
3182 | |
3183 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3184 TestExtension extension; | |
3185 visitor.set_extension_visitor(&extension); | |
3186 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); | |
3187 | |
3188 // In HTTP/2, we ignore unknown settings because of extensions. | |
3189 EXPECT_EQ(0, visitor.setting_count_); | |
3190 EXPECT_EQ(0, visitor.error_count_); | |
3191 | |
3192 EXPECT_THAT( | |
3193 extension.settings_received_, | |
3194 testing::ElementsAre(testing::Pair(16, 2), testing::Pair(95, 65538))); | |
3195 } | |
3196 | |
3197 // Tests handling of SETTINGS frame with entries out of order. | |
3198 TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) { | |
3199 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3200 const unsigned char kH2FrameData[] = { | |
3201 0x00, 0x00, 0x12, // Length: 18 | |
3202 0x04, // Type: SETTINGS | |
3203 0x00, // Flags: none | |
3204 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3205 0x00, 0x02, // Param: ENABLE_PUSH | |
3206 0x00, 0x00, 0x00, 0x02, // Value: 2 | |
3207 0x00, 0x01, // Param: HEADER_TABLE_SIZE | |
3208 0x00, 0x00, 0x00, 0x03, // Value: 3 | |
3209 0x00, 0x03, // Param: MAX_CONCURRENT_STREAMS | |
3210 0x00, 0x00, 0x00, 0x03, // Value: 3 | |
3211 }; | |
3212 | |
3213 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3214 visitor.SimulateInFramer(kH2FrameData, sizeof(kH2FrameData)); | |
3215 | |
3216 // In HTTP/2, settings are allowed in any order. | |
3217 EXPECT_EQ(3, visitor.setting_count_); | |
3218 EXPECT_EQ(0, visitor.error_count_); | |
3219 } | |
3220 | |
3221 TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) { | |
3222 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3223 | |
3224 const unsigned char kFrameData[] = { | |
3225 0x00, 0x00, 0x00, // Length: 0 | |
3226 0x04, // Type: SETTINGS | |
3227 0x01, // Flags: ACK | |
3228 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
3229 }; | |
3230 | |
3231 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3232 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
3233 | |
3234 EXPECT_EQ(0, visitor.error_count_); | |
3235 EXPECT_EQ(0, visitor.setting_count_); | |
3236 EXPECT_EQ(1, visitor.settings_ack_received_); | |
3237 } | |
3238 | |
3239 TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) { | |
3240 const int kPaddingLen = 119; | |
3241 const char data_payload[] = "hello"; | |
3242 | |
3243 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
3244 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3245 framer.set_visitor(&visitor); | |
3246 | |
3247 SpdyDataIR data_ir(1, data_payload); | |
3248 data_ir.set_padding_len(kPaddingLen); | |
3249 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
3250 | |
3251 int bytes_consumed = 0; | |
3252 | |
3253 // Send the frame header. | |
3254 EXPECT_CALL(visitor, | |
3255 OnDataFrameHeader(1, kPaddingLen + strlen(data_payload), false)); | |
3256 CHECK_EQ(framer.GetDataFrameMinimumSize(), | |
3257 framer.ProcessInput(frame.data(), framer.GetDataFrameMinimumSize())); | |
3258 CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_DATA_FRAME_PADDING_LENGTH); | |
3259 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3260 bytes_consumed += framer.GetDataFrameMinimumSize(); | |
3261 | |
3262 // Send the padding length field. | |
3263 EXPECT_CALL(visitor, OnStreamPadding(1, 1)); | |
3264 CHECK_EQ(1u, framer.ProcessInput(frame.data() + bytes_consumed, 1)); | |
3265 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME); | |
3266 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3267 bytes_consumed += 1; | |
3268 | |
3269 // Send the first two bytes of the data payload, i.e., "he". | |
3270 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2)); | |
3271 CHECK_EQ(2u, framer.ProcessInput(frame.data() + bytes_consumed, 2)); | |
3272 CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME); | |
3273 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3274 bytes_consumed += 2; | |
3275 | |
3276 // Send the rest three bytes of the data payload, i.e., "llo". | |
3277 EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3)); | |
3278 CHECK_EQ(3u, framer.ProcessInput(frame.data() + bytes_consumed, 3)); | |
3279 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING); | |
3280 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3281 bytes_consumed += 3; | |
3282 | |
3283 // Send the first 100 bytes of the padding payload. | |
3284 EXPECT_CALL(visitor, OnStreamPadding(1, 100)); | |
3285 CHECK_EQ(100u, framer.ProcessInput(frame.data() + bytes_consumed, 100)); | |
3286 CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING); | |
3287 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3288 bytes_consumed += 100; | |
3289 | |
3290 // Send rest of the padding payload. | |
3291 EXPECT_CALL(visitor, OnStreamPadding(1, 18)); | |
3292 CHECK_EQ(18u, framer.ProcessInput(frame.data() + bytes_consumed, 18)); | |
3293 CHECK_EQ(framer.state(), SpdyFramer::SPDY_READY_FOR_FRAME); | |
3294 CHECK_EQ(framer.spdy_framer_error(), SpdyFramer::SPDY_NO_ERROR); | |
3295 } | |
3296 | |
3297 TEST_P(SpdyFramerTest, ReadWindowUpdate) { | |
3298 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3299 SpdySerializedFrame control_frame( | |
3300 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2))); | |
3301 if (use_output_) { | |
3302 ASSERT_TRUE( | |
3303 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2), &output_)); | |
3304 control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3305 } | |
3306 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3307 visitor.SimulateInFramer( | |
3308 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3309 control_frame.size()); | |
3310 EXPECT_EQ(1u, visitor.last_window_update_stream_); | |
3311 EXPECT_EQ(2, visitor.last_window_update_delta_); | |
3312 } | |
3313 | |
3314 TEST_P(SpdyFramerTest, ReadCompressedPushPromise) { | |
3315 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3316 SpdyPushPromiseIR push_promise(42, 57); | |
3317 push_promise.SetHeader("foo", "bar"); | |
3318 push_promise.SetHeader("bar", "foofoo"); | |
3319 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
3320 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
3321 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
3322 visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()), | |
3323 frame.size()); | |
3324 EXPECT_EQ(42u, visitor.last_push_promise_stream_); | |
3325 EXPECT_EQ(57u, visitor.last_push_promise_promised_stream_); | |
3326 EXPECT_EQ(push_promise.header_block(), visitor.headers_); | |
3327 } | |
3328 | |
3329 TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) { | |
3330 // frame-format off | |
3331 const unsigned char kInput[] = { | |
3332 0x00, 0x00, 0x14, // Length: 20 | |
3333 0x01, // Type: HEADERS | |
3334 0x08, // Flags: PADDED | |
3335 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3336 0x03, // PadLen: 3 trailing bytes | |
3337 0x00, // Unindexed Entry | |
3338 0x06, // Name Len: 6 | |
3339 'c', 'o', 'o', 'k', 'i', 'e', // Name | |
3340 0x07, // Value Len: 7 | |
3341 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value | |
3342 0x00, 0x00, 0x00, // Padding | |
3343 | |
3344 0x00, 0x00, 0x14, // Length: 20 | |
3345 0x09, // Type: CONTINUATION | |
3346 0x00, // Flags: none | |
3347 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3348 0x00, // Unindexed Entry | |
3349 0x06, // Name Len: 6 | |
3350 'c', 'o', 'o', 'k', 'i', 'e', // Name | |
3351 0x08, // Value Len: 7 | |
3352 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value | |
3353 0x00, // Unindexed Entry | |
3354 0x06, // Name Len: 6 | |
3355 'c', // Name (split) | |
3356 | |
3357 0x00, 0x00, 0x12, // Length: 18 | |
3358 0x09, // Type: CONTINUATION | |
3359 0x04, // Flags: END_HEADERS | |
3360 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3361 'o', 'o', 'k', 'i', 'e', // Name (continued) | |
3362 0x00, // Value Len: 0 | |
3363 0x00, // Unindexed Entry | |
3364 0x04, // Name Len: 4 | |
3365 'n', 'a', 'm', 'e', // Name | |
3366 0x05, // Value Len: 5 | |
3367 'v', 'a', 'l', 'u', 'e', // Value | |
3368 }; | |
3369 // frame-format on | |
3370 | |
3371 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3372 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3373 | |
3374 EXPECT_EQ(0, visitor.error_count_); | |
3375 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3376 EXPECT_EQ(2, visitor.continuation_count_); | |
3377 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
3378 EXPECT_EQ(0, visitor.end_of_stream_count_); | |
3379 | |
3380 EXPECT_THAT( | |
3381 visitor.headers_, | |
3382 testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), | |
3383 testing::Pair("name", "value"))); | |
3384 } | |
3385 | |
3386 TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) { | |
3387 // frame-format off | |
3388 const unsigned char kInput[] = { | |
3389 0x00, 0x00, 0x10, // Length: 20 | |
3390 0x01, // Type: HEADERS | |
3391 0x01, // Flags: END_STREAM | |
3392 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3393 0x00, // Unindexed Entry | |
3394 0x06, // Name Len: 6 | |
3395 'c', 'o', 'o', 'k', 'i', 'e', // Name | |
3396 0x07, // Value Len: 7 | |
3397 'f', 'o', 'o', '=', 'b', 'a', 'r', // Value | |
3398 | |
3399 0x00, 0x00, 0x14, // Length: 20 | |
3400 0x09, // Type: CONTINUATION | |
3401 0x00, // Flags: none | |
3402 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3403 0x00, // Unindexed Entry | |
3404 0x06, // Name Len: 6 | |
3405 'c', 'o', 'o', 'k', 'i', 'e', // Name | |
3406 0x08, // Value Len: 7 | |
3407 'b', 'a', 'z', '=', 'b', 'i', 'n', 'g', // Value | |
3408 0x00, // Unindexed Entry | |
3409 0x06, // Name Len: 6 | |
3410 'c', // Name (split) | |
3411 | |
3412 0x00, 0x00, 0x12, // Length: 18 | |
3413 0x09, // Type: CONTINUATION | |
3414 0x04, // Flags: END_HEADERS | |
3415 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3416 'o', 'o', 'k', 'i', 'e', // Name (continued) | |
3417 0x00, // Value Len: 0 | |
3418 0x00, // Unindexed Entry | |
3419 0x04, // Name Len: 4 | |
3420 'n', 'a', 'm', 'e', // Name | |
3421 0x05, // Value Len: 5 | |
3422 'v', 'a', 'l', 'u', 'e', // Value | |
3423 }; | |
3424 // frame-format on | |
3425 | |
3426 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3427 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3428 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3429 | |
3430 EXPECT_EQ(0, visitor.error_count_); | |
3431 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3432 EXPECT_EQ(2, visitor.continuation_count_); | |
3433 EXPECT_EQ(1, visitor.fin_flag_count_); | |
3434 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
3435 EXPECT_EQ(1, visitor.end_of_stream_count_); | |
3436 | |
3437 EXPECT_THAT( | |
3438 visitor.headers_, | |
3439 testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), | |
3440 testing::Pair("name", "value"))); | |
3441 } | |
3442 | |
3443 TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) { | |
3444 // frame-format off | |
3445 const unsigned char kInput[] = { | |
3446 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE | |
3447 0x08, 0x00, 0x00, 0x00, // PADDED | |
3448 0x01, 0x02, 0x00, 0x00, // Stream 1, Pad length field | |
3449 0x00, 0x2A, 0x00, 0x06, // Promised stream 42 | |
3450 'c', 'o', 'o', 'k', | |
3451 'i', 'e', 0x07, 'f', | |
3452 'o', 'o', '=', 'b', | |
3453 'a', 'r', 0x00, 0x00, | |
3454 | |
3455 0x00, 0x00, 0x14, 0x09, // CONTINUATION | |
3456 0x00, 0x00, 0x00, 0x00, | |
3457 0x01, 0x00, 0x06, 'c', // Stream 1 | |
3458 'o', 'o', 'k', 'i', | |
3459 'e', 0x08, 'b', 'a', | |
3460 'z', '=', 'b', 'i', | |
3461 'n', 'g', 0x00, 0x06, | |
3462 'c', | |
3463 | |
3464 0x00, 0x00, 0x12, 0x09, // CONTINUATION | |
3465 0x04, 0x00, 0x00, 0x00, // END_HEADERS | |
3466 0x01, 'o', 'o', 'k', // Stream 1 | |
3467 'i', 'e', 0x00, 0x00, | |
3468 0x04, 'n', 'a', 'm', | |
3469 'e', 0x05, 'v', 'a', | |
3470 'l', 'u', 'e', | |
3471 }; | |
3472 // frame-format on | |
3473 | |
3474 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3475 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3476 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3477 | |
3478 EXPECT_EQ(0, visitor.error_count_); | |
3479 EXPECT_EQ(1u, visitor.last_push_promise_stream_); | |
3480 EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_); | |
3481 EXPECT_EQ(2, visitor.continuation_count_); | |
3482 EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); | |
3483 EXPECT_EQ(0, visitor.end_of_stream_count_); | |
3484 | |
3485 EXPECT_THAT( | |
3486 visitor.headers_, | |
3487 testing::ElementsAre(testing::Pair("cookie", "foo=bar; baz=bing; "), | |
3488 testing::Pair("name", "value"))); | |
3489 } | |
3490 | |
3491 // Receiving an unknown frame when a continuation is expected should | |
3492 // result in a SPDY_UNEXPECTED_FRAME error | |
3493 TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuation) { | |
3494 const unsigned char kInput[] = { | |
3495 0x00, 0x00, 0x10, // Length: 16 | |
3496 0x01, // Type: HEADERS | |
3497 0x00, // Flags: none | |
3498 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3499 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3500 0x6f, 0x6b, 0x69, 0x65, // | |
3501 0x07, 0x66, 0x6f, 0x6f, // | |
3502 0x3d, 0x62, 0x61, 0x72, // | |
3503 | |
3504 0x00, 0x00, 0x14, // Length: 20 | |
3505 0xa9, // Type: UnknownFrameType(169) | |
3506 0x00, // Flags: none | |
3507 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3508 0x00, 0x06, 0x63, 0x6f, // Payload | |
3509 0x6f, 0x6b, 0x69, 0x65, // | |
3510 0x08, 0x62, 0x61, 0x7a, // | |
3511 0x3d, 0x62, 0x69, 0x6e, // | |
3512 0x67, 0x00, 0x06, 0x63, // | |
3513 }; | |
3514 | |
3515 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3516 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3517 // Assume the unknown frame is allowed | |
3518 visitor.on_unknown_frame_result_ = true; | |
3519 framer.set_visitor(&visitor); | |
3520 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3521 | |
3522 EXPECT_EQ(1, visitor.error_count_); | |
3523 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3524 visitor.framer_.spdy_framer_error()) | |
3525 << SpdyFramer::SpdyFramerErrorToString( | |
3526 visitor.framer_.spdy_framer_error()); | |
3527 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3528 EXPECT_EQ(0, visitor.continuation_count_); | |
3529 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3530 } | |
3531 | |
3532 // Receiving an unknown frame when a continuation is expected should | |
3533 // result in a SPDY_UNEXPECTED_FRAME error | |
3534 TEST_P(SpdyFramerTest, ReceiveUnknownMidContinuationWithExtension) { | |
3535 const unsigned char kInput[] = { | |
3536 0x00, 0x00, 0x10, // Length: 16 | |
3537 0x01, // Type: HEADERS | |
3538 0x00, // Flags: none | |
3539 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3540 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3541 0x6f, 0x6b, 0x69, 0x65, // | |
3542 0x07, 0x66, 0x6f, 0x6f, // | |
3543 0x3d, 0x62, 0x61, 0x72, // | |
3544 | |
3545 0x00, 0x00, 0x14, // Length: 20 | |
3546 0xa9, // Type: UnknownFrameType(169) | |
3547 0x00, // Flags: none | |
3548 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3549 0x00, 0x06, 0x63, 0x6f, // Payload | |
3550 0x6f, 0x6b, 0x69, 0x65, // | |
3551 0x08, 0x62, 0x61, 0x7a, // | |
3552 0x3d, 0x62, 0x69, 0x6e, // | |
3553 0x67, 0x00, 0x06, 0x63, // | |
3554 }; | |
3555 | |
3556 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3557 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3558 TestExtension extension; | |
3559 visitor.set_extension_visitor(&extension); | |
3560 framer.set_visitor(&visitor); | |
3561 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3562 | |
3563 EXPECT_EQ(1, visitor.error_count_); | |
3564 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3565 visitor.framer_.spdy_framer_error()) | |
3566 << SpdyFramer::SpdyFramerErrorToString( | |
3567 visitor.framer_.spdy_framer_error()); | |
3568 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3569 EXPECT_EQ(0, visitor.continuation_count_); | |
3570 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3571 } | |
3572 | |
3573 TEST_P(SpdyFramerTest, ReceiveContinuationOnWrongStream) { | |
3574 const unsigned char kInput[] = { | |
3575 0x00, 0x00, 0x10, // Length: 16 | |
3576 0x01, // Type: HEADERS | |
3577 0x00, // Flags: none | |
3578 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3579 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3580 0x6f, 0x6b, 0x69, 0x65, // | |
3581 0x07, 0x66, 0x6f, 0x6f, // | |
3582 0x3d, 0x62, 0x61, 0x72, // | |
3583 | |
3584 0x00, 0x00, 0x14, // Length: 20 | |
3585 0x09, // Type: CONTINUATION | |
3586 0x00, // Flags: none | |
3587 0x00, 0x00, 0x00, 0x02, // Stream: 2 | |
3588 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3589 0x6f, 0x6b, 0x69, 0x65, // | |
3590 0x08, 0x62, 0x61, 0x7a, // | |
3591 0x3d, 0x62, 0x69, 0x6e, // | |
3592 0x67, 0x00, 0x06, 0x63, // | |
3593 }; | |
3594 | |
3595 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3596 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3597 framer.set_visitor(&visitor); | |
3598 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3599 | |
3600 EXPECT_EQ(1, visitor.error_count_); | |
3601 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3602 visitor.framer_.spdy_framer_error()) | |
3603 << SpdyFramer::SpdyFramerErrorToString( | |
3604 visitor.framer_.spdy_framer_error()); | |
3605 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3606 EXPECT_EQ(0, visitor.continuation_count_); | |
3607 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3608 } | |
3609 | |
3610 TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) { | |
3611 const unsigned char kInput[] = { | |
3612 0x00, 0x00, 0x18, // Length: 24 | |
3613 0x09, // Type: CONTINUATION | |
3614 0x00, // Flags: none | |
3615 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3616 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3617 0x6f, 0x6b, 0x69, 0x65, // | |
3618 0x07, 0x66, 0x6f, 0x6f, // | |
3619 0x3d, 0x62, 0x61, 0x72, // | |
3620 }; | |
3621 | |
3622 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3623 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3624 framer.set_visitor(&visitor); | |
3625 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3626 | |
3627 EXPECT_EQ(1, visitor.error_count_); | |
3628 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3629 visitor.framer_.spdy_framer_error()) | |
3630 << SpdyFramer::SpdyFramerErrorToString( | |
3631 visitor.framer_.spdy_framer_error()); | |
3632 EXPECT_EQ(0, visitor.continuation_count_); | |
3633 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3634 } | |
3635 | |
3636 TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) { | |
3637 const unsigned char kInput[] = { | |
3638 0x00, 0x00, 0x10, // Length: 16 | |
3639 0x01, // Type: HEADERS | |
3640 0x00, // Flags: none | |
3641 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3642 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3643 0x6f, 0x6b, 0x69, 0x65, // | |
3644 0x07, 0x66, 0x6f, 0x6f, // | |
3645 0x3d, 0x62, 0x61, 0x72, // | |
3646 | |
3647 0x00, 0x00, 0x00, // Length: 0 | |
3648 0x00, // Type: DATA | |
3649 0x01, // Flags: END_STREAM | |
3650 0x00, 0x00, 0x00, 0x04, // Stream: 4 | |
3651 | |
3652 0xde, 0xad, 0xbe, 0xef, // Truncated Frame Header | |
3653 }; | |
3654 | |
3655 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3656 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3657 framer.set_visitor(&visitor); | |
3658 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3659 | |
3660 EXPECT_EQ(1, visitor.error_count_); | |
3661 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3662 visitor.framer_.spdy_framer_error()) | |
3663 << SpdyFramer::SpdyFramerErrorToString( | |
3664 visitor.framer_.spdy_framer_error()); | |
3665 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3666 EXPECT_EQ(0, visitor.continuation_count_); | |
3667 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3668 EXPECT_EQ(0, visitor.data_frame_count_); | |
3669 } | |
3670 | |
3671 TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) { | |
3672 const unsigned char kInput[] = { | |
3673 0x00, 0x00, 0x10, // Length: 16 | |
3674 0x01, // Type: HEADERS | |
3675 0x00, // Flags: none | |
3676 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3677 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3678 0x6f, 0x6b, 0x69, 0x65, // | |
3679 0x07, 0x66, 0x6f, 0x6f, // | |
3680 0x3d, 0x62, 0x61, 0x72, // | |
3681 | |
3682 0x00, 0x00, 0x10, // Length: 16 | |
3683 0x01, // Type: HEADERS | |
3684 0x00, // Flags: none | |
3685 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
3686 0x00, 0x06, 0x63, 0x6f, // HPACK | |
3687 0x6f, 0x6b, 0x69, 0x65, // | |
3688 0x07, 0x66, 0x6f, 0x6f, // | |
3689 0x3d, 0x62, 0x61, 0x72, // | |
3690 }; | |
3691 | |
3692 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3693 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3694 framer.set_visitor(&visitor); | |
3695 visitor.SimulateInFramer(kInput, sizeof(kInput)); | |
3696 | |
3697 EXPECT_EQ(1, visitor.error_count_); | |
3698 EXPECT_EQ(SpdyFramer::SPDY_UNEXPECTED_FRAME, | |
3699 visitor.framer_.spdy_framer_error()) | |
3700 << SpdyFramer::SpdyFramerErrorToString( | |
3701 visitor.framer_.spdy_framer_error()); | |
3702 EXPECT_EQ(1, visitor.headers_frame_count_); | |
3703 EXPECT_EQ(0, visitor.continuation_count_); | |
3704 EXPECT_EQ(0u, visitor.header_buffer_length_); | |
3705 EXPECT_EQ(0, visitor.data_frame_count_); | |
3706 } | |
3707 | |
3708 TEST_P(SpdyFramerTest, ReadGarbage) { | |
3709 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3710 unsigned char garbage_frame[256]; | |
3711 memset(garbage_frame, ~0, sizeof(garbage_frame)); | |
3712 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3713 visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame)); | |
3714 EXPECT_EQ(1, visitor.error_count_); | |
3715 } | |
3716 | |
3717 TEST_P(SpdyFramerTest, ReadUnknownExtensionFrame) { | |
3718 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3719 | |
3720 // The unrecognized frame type should still have a valid length. | |
3721 const unsigned char unknown_frame[] = { | |
3722 0x00, 0x00, 0x08, // Length: 8 | |
3723 0xff, // Type: UnknownFrameType(255) | |
3724 0xff, // Flags: 0xff | |
3725 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) | |
3726 0xff, 0xff, 0xff, 0xff, // Payload | |
3727 0xff, 0xff, 0xff, 0xff, // | |
3728 }; | |
3729 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3730 | |
3731 // Simulate the case where the stream id validation checks out. | |
3732 visitor.on_unknown_frame_result_ = true; | |
3733 visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame)); | |
3734 EXPECT_EQ(0, visitor.error_count_); | |
3735 | |
3736 // Follow it up with a valid control frame to make sure we handle | |
3737 // subsequent frames correctly. | |
3738 SpdySettingsIR settings_ir; | |
3739 settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10); | |
3740 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
3741 if (use_output_) { | |
3742 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
3743 control_frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3744 } | |
3745 visitor.SimulateInFramer( | |
3746 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3747 control_frame.size()); | |
3748 EXPECT_EQ(0, visitor.error_count_); | |
3749 EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_)); | |
3750 EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_)); | |
3751 } | |
3752 | |
3753 TEST_P(SpdyFramerTest, ReadUnknownExtensionFrameWithExtension) { | |
3754 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3755 | |
3756 // The unrecognized frame type should still have a valid length. | |
3757 const unsigned char unknown_frame[] = { | |
3758 0x00, 0x00, 0x14, // Length: 20 | |
3759 0xff, // Type: UnknownFrameType(255) | |
3760 0xff, // Flags: 0xff | |
3761 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) | |
3762 0xff, 0xff, 0xff, 0xff, // Payload | |
3763 0xff, 0xff, 0xff, 0xff, // | |
3764 0xff, 0xff, 0xff, 0xff, // | |
3765 0xff, 0xff, 0xff, 0xff, // | |
3766 0xff, 0xff, 0xff, 0xff, // | |
3767 }; | |
3768 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3769 TestExtension extension; | |
3770 visitor.set_extension_visitor(&extension); | |
3771 visitor.SimulateInFramer(unknown_frame, arraysize(unknown_frame)); | |
3772 EXPECT_EQ(0, visitor.error_count_); | |
3773 EXPECT_EQ(0x7fffffffu, extension.stream_id_); | |
3774 EXPECT_EQ(20u, extension.length_); | |
3775 EXPECT_EQ(255, extension.type_); | |
3776 EXPECT_EQ(0xff, extension.flags_); | |
3777 EXPECT_EQ(SpdyString(20, '\xff'), extension.payload_); | |
3778 | |
3779 // Follow it up with a valid control frame to make sure we handle | |
3780 // subsequent frames correctly. | |
3781 SpdySettingsIR settings_ir; | |
3782 settings_ir.AddSetting(SETTINGS_HEADER_TABLE_SIZE, 10); | |
3783 SpdySerializedFrame control_frame(framer.SerializeSettings(settings_ir)); | |
3784 visitor.SimulateInFramer( | |
3785 reinterpret_cast<unsigned char*>(control_frame.data()), | |
3786 control_frame.size()); | |
3787 EXPECT_EQ(0, visitor.error_count_); | |
3788 EXPECT_EQ(1u, static_cast<unsigned>(visitor.setting_count_)); | |
3789 EXPECT_EQ(1u, static_cast<unsigned>(visitor.settings_ack_sent_)); | |
3790 } | |
3791 | |
3792 TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) { | |
3793 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3794 const unsigned char kFrameData[] = { | |
3795 0x00, 0x00, 0x08, // Length: 8 | |
3796 0xff, // Type: UnknownFrameType(255) | |
3797 0xff, // Flags: 0xff | |
3798 0xff, 0xff, 0xff, 0xff, // Stream: 0x7fffffff (R-bit set) | |
3799 0xff, 0xff, 0xff, 0xff, // Payload | |
3800 0xff, 0xff, 0xff, 0xff, // | |
3801 }; | |
3802 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3803 visitor.SimulateInFramer(kFrameData, arraysize(kFrameData)); | |
3804 EXPECT_EQ(1, visitor.error_count_); | |
3805 } | |
3806 | |
3807 TEST_P(SpdyFramerTest, ReadGarbageHPACKEncoding) { | |
3808 const unsigned char kInput[] = { | |
3809 0x00, 0x12, 0x01, // Length: 4609 | |
3810 0x04, // Type: SETTINGS | |
3811 0x00, // Flags: none | |
3812 0x00, 0x00, 0x01, 0xef, // Stream: 495 | |
3813 0xef, 0xff, // Param: 61439 | |
3814 0xff, 0xff, 0xff, 0xff, // Value: 4294967295 | |
3815 0xff, 0xff, // Param: 0xffff | |
3816 0xff, 0xff, 0xff, 0xff, // Value: 4294967295 | |
3817 0xff, 0xff, 0xff, 0xff, // Settings (Truncated) | |
3818 0xff, // | |
3819 }; | |
3820 | |
3821 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
3822 visitor.SimulateInFramer(kInput, arraysize(kInput)); | |
3823 EXPECT_EQ(1, visitor.error_count_); | |
3824 } | |
3825 | |
3826 TEST_P(SpdyFramerTest, SizesTest) { | |
3827 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3828 EXPECT_EQ(9u, framer.GetDataFrameMinimumSize()); | |
3829 EXPECT_EQ(9u, framer.GetFrameHeaderSize()); | |
3830 EXPECT_EQ(13u, framer.GetRstStreamSize()); | |
3831 EXPECT_EQ(9u, framer.GetSettingsMinimumSize()); | |
3832 EXPECT_EQ(17u, framer.GetPingSize()); | |
3833 EXPECT_EQ(17u, framer.GetGoAwayMinimumSize()); | |
3834 EXPECT_EQ(9u, framer.GetHeadersMinimumSize()); | |
3835 EXPECT_EQ(13u, framer.GetWindowUpdateSize()); | |
3836 EXPECT_EQ(13u, framer.GetPushPromiseMinimumSize()); | |
3837 EXPECT_EQ(11u, framer.GetAltSvcMinimumSize()); | |
3838 EXPECT_EQ(9u, framer.GetFrameMinimumSize()); | |
3839 EXPECT_EQ(16393u, framer.GetFrameMaximumSize()); | |
3840 EXPECT_EQ(16384u, framer.GetDataFrameMaximumPayload()); | |
3841 } | |
3842 | |
3843 TEST_P(SpdyFramerTest, StateToStringTest) { | |
3844 EXPECT_STREQ("ERROR", SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR)); | |
3845 EXPECT_STREQ("FRAME_COMPLETE", | |
3846 SpdyFramer::StateToString(SpdyFramer::SPDY_FRAME_COMPLETE)); | |
3847 EXPECT_STREQ("READY_FOR_FRAME", | |
3848 SpdyFramer::StateToString(SpdyFramer::SPDY_READY_FOR_FRAME)); | |
3849 EXPECT_STREQ( | |
3850 "READING_COMMON_HEADER", | |
3851 SpdyFramer::StateToString(SpdyFramer::SPDY_READING_COMMON_HEADER)); | |
3852 EXPECT_STREQ( | |
3853 "CONTROL_FRAME_PAYLOAD", | |
3854 SpdyFramer::StateToString(SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD)); | |
3855 EXPECT_STREQ( | |
3856 "IGNORE_REMAINING_PAYLOAD", | |
3857 SpdyFramer::StateToString(SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD)); | |
3858 EXPECT_STREQ( | |
3859 "FORWARD_STREAM_FRAME", | |
3860 SpdyFramer::StateToString(SpdyFramer::SPDY_FORWARD_STREAM_FRAME)); | |
3861 EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK", | |
3862 SpdyFramer::StateToString( | |
3863 SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK)); | |
3864 EXPECT_STREQ( | |
3865 "SPDY_CONTROL_FRAME_HEADER_BLOCK", | |
3866 SpdyFramer::StateToString(SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK)); | |
3867 EXPECT_STREQ( | |
3868 "SPDY_SETTINGS_FRAME_PAYLOAD", | |
3869 SpdyFramer::StateToString(SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD)); | |
3870 EXPECT_STREQ( | |
3871 "SPDY_ALTSVC_FRAME_PAYLOAD", | |
3872 SpdyFramer::StateToString(SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD)); | |
3873 EXPECT_STREQ("UNKNOWN_STATE", SpdyFramer::StateToString( | |
3874 SpdyFramer::SPDY_ALTSVC_FRAME_PAYLOAD + 1)); | |
3875 } | |
3876 | |
3877 TEST_P(SpdyFramerTest, SpdyFramerErrorToStringTest) { | |
3878 EXPECT_STREQ("NO_ERROR", | |
3879 SpdyFramer::SpdyFramerErrorToString(SpdyFramer::SPDY_NO_ERROR)); | |
3880 EXPECT_STREQ("INVALID_STREAM_ID", SpdyFramer::SpdyFramerErrorToString( | |
3881 SpdyFramer::SPDY_INVALID_STREAM_ID)); | |
3882 EXPECT_STREQ("INVALID_CONTROL_FRAME", | |
3883 SpdyFramer::SpdyFramerErrorToString( | |
3884 SpdyFramer::SPDY_INVALID_CONTROL_FRAME)); | |
3885 EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE", | |
3886 SpdyFramer::SpdyFramerErrorToString( | |
3887 SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE)); | |
3888 EXPECT_STREQ("ZLIB_INIT_FAILURE", SpdyFramer::SpdyFramerErrorToString( | |
3889 SpdyFramer::SPDY_ZLIB_INIT_FAILURE)); | |
3890 EXPECT_STREQ("UNSUPPORTED_VERSION", | |
3891 SpdyFramer::SpdyFramerErrorToString( | |
3892 SpdyFramer::SPDY_UNSUPPORTED_VERSION)); | |
3893 EXPECT_STREQ("DECOMPRESS_FAILURE", SpdyFramer::SpdyFramerErrorToString( | |
3894 SpdyFramer::SPDY_DECOMPRESS_FAILURE)); | |
3895 EXPECT_STREQ("COMPRESS_FAILURE", SpdyFramer::SpdyFramerErrorToString( | |
3896 SpdyFramer::SPDY_COMPRESS_FAILURE)); | |
3897 EXPECT_STREQ("GOAWAY_FRAME_CORRUPT", | |
3898 SpdyFramer::SpdyFramerErrorToString( | |
3899 SpdyFramer::SPDY_GOAWAY_FRAME_CORRUPT)); | |
3900 EXPECT_STREQ("RST_STREAM_FRAME_CORRUPT", | |
3901 SpdyFramer::SpdyFramerErrorToString( | |
3902 SpdyFramer::SPDY_RST_STREAM_FRAME_CORRUPT)); | |
3903 EXPECT_STREQ("INVALID_PADDING", SpdyFramer::SpdyFramerErrorToString( | |
3904 SpdyFramer::SPDY_INVALID_PADDING)); | |
3905 EXPECT_STREQ("INVALID_DATA_FRAME_FLAGS", | |
3906 SpdyFramer::SpdyFramerErrorToString( | |
3907 SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS)); | |
3908 EXPECT_STREQ("INVALID_CONTROL_FRAME_FLAGS", | |
3909 SpdyFramer::SpdyFramerErrorToString( | |
3910 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS)); | |
3911 EXPECT_STREQ("UNEXPECTED_FRAME", SpdyFramer::SpdyFramerErrorToString( | |
3912 SpdyFramer::SPDY_UNEXPECTED_FRAME)); | |
3913 EXPECT_STREQ("INTERNAL_FRAMER_ERROR", | |
3914 SpdyFramer::SpdyFramerErrorToString( | |
3915 SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR)); | |
3916 EXPECT_STREQ("INVALID_CONTROL_FRAME_SIZE", | |
3917 SpdyFramer::SpdyFramerErrorToString( | |
3918 SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE)); | |
3919 EXPECT_STREQ("OVERSIZED_PAYLOAD", SpdyFramer::SpdyFramerErrorToString( | |
3920 SpdyFramer::SPDY_OVERSIZED_PAYLOAD)); | |
3921 EXPECT_STREQ("UNKNOWN_ERROR", | |
3922 SpdyFramer::SpdyFramerErrorToString(SpdyFramer::LAST_ERROR)); | |
3923 EXPECT_STREQ("UNKNOWN_ERROR", SpdyFramer::SpdyFramerErrorToString( | |
3924 static_cast<SpdyFramer::SpdyFramerError>( | |
3925 SpdyFramer::LAST_ERROR + 1))); | |
3926 } | |
3927 | |
3928 TEST_P(SpdyFramerTest, DataFrameFlagsV4) { | |
3929 uint8_t valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_PADDED; | |
3930 | |
3931 uint8_t flags = 0; | |
3932 do { | |
3933 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
3934 << static_cast<int>(flags)); | |
3935 | |
3936 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
3937 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3938 framer.set_visitor(&visitor); | |
3939 | |
3940 SpdyDataIR data_ir(1, "hello"); | |
3941 SpdySerializedFrame frame(framer.SerializeData(data_ir)); | |
3942 SetFrameFlags(&frame, flags); | |
3943 | |
3944 if (flags & ~valid_data_flags) { | |
3945 EXPECT_CALL(visitor, OnError(_)); | |
3946 } else { | |
3947 EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); | |
3948 if (flags & DATA_FLAG_PADDED) { | |
3949 // The first byte of payload is parsed as padding length, but 'h' | |
3950 // (0x68) is too large a padding length for a 5 byte payload. | |
3951 EXPECT_CALL(visitor, OnStreamPadding(_, 1)); | |
3952 // Expect Error since the frame ends prematurely. | |
3953 EXPECT_CALL(visitor, OnError(_)); | |
3954 } else { | |
3955 EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5)); | |
3956 if (flags & DATA_FLAG_FIN) { | |
3957 EXPECT_CALL(visitor, OnStreamEnd(_)); | |
3958 } | |
3959 } | |
3960 } | |
3961 | |
3962 framer.ProcessInput(frame.data(), frame.size()); | |
3963 if (flags & ~valid_data_flags) { | |
3964 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
3965 EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, | |
3966 framer.spdy_framer_error()) | |
3967 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
3968 } else if (flags & DATA_FLAG_PADDED) { | |
3969 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
3970 EXPECT_EQ(SpdyFramer::SPDY_INVALID_PADDING, framer.spdy_framer_error()) | |
3971 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
3972 } else { | |
3973 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
3974 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
3975 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
3976 } | |
3977 } while (++flags != 0); | |
3978 } | |
3979 | |
3980 TEST_P(SpdyFramerTest, RstStreamFrameFlags) { | |
3981 uint8_t flags = 0; | |
3982 do { | |
3983 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
3984 << static_cast<int>(flags)); | |
3985 | |
3986 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
3987 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
3988 framer.set_visitor(&visitor); | |
3989 | |
3990 SpdyRstStreamIR rst_stream(13, ERROR_CODE_CANCEL); | |
3991 SpdySerializedFrame frame(framer.SerializeRstStream(rst_stream)); | |
3992 if (use_output_) { | |
3993 output_.Reset(); | |
3994 ASSERT_TRUE(framer.SerializeRstStream(rst_stream, &output_)); | |
3995 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
3996 } | |
3997 SetFrameFlags(&frame, flags); | |
3998 | |
3999 EXPECT_CALL(visitor, OnRstStream(13, ERROR_CODE_CANCEL)); | |
4000 | |
4001 framer.ProcessInput(frame.data(), frame.size()); | |
4002 | |
4003 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4004 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4005 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4006 } while (++flags != 0); | |
4007 } | |
4008 | |
4009 TEST_P(SpdyFramerTest, SettingsFrameFlags) { | |
4010 uint8_t flags = 0; | |
4011 do { | |
4012 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4013 << static_cast<int>(flags)); | |
4014 | |
4015 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4016 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4017 framer.set_visitor(&visitor); | |
4018 | |
4019 SpdySettingsIR settings_ir; | |
4020 settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16); | |
4021 SpdySerializedFrame frame(framer.SerializeSettings(settings_ir)); | |
4022 if (use_output_) { | |
4023 output_.Reset(); | |
4024 ASSERT_TRUE(framer.SerializeSettings(settings_ir, &output_)); | |
4025 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4026 } | |
4027 SetFrameFlags(&frame, flags); | |
4028 | |
4029 if (flags & SETTINGS_FLAG_ACK) { | |
4030 EXPECT_CALL(visitor, OnError(_)); | |
4031 } else { | |
4032 EXPECT_CALL(visitor, OnSettings(flags & SETTINGS_FLAG_ACK)); | |
4033 EXPECT_CALL(visitor, OnSetting(SETTINGS_INITIAL_WINDOW_SIZE, 16)); | |
4034 EXPECT_CALL(visitor, OnSettingsEnd()); | |
4035 } | |
4036 | |
4037 framer.ProcessInput(frame.data(), frame.size()); | |
4038 if (flags & SETTINGS_FLAG_ACK) { | |
4039 // The frame is invalid because ACK frames should have no payload. | |
4040 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4041 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4042 framer.spdy_framer_error()) | |
4043 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4044 } else { | |
4045 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4046 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4047 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4048 } | |
4049 } while (++flags != 0); | |
4050 } | |
4051 | |
4052 TEST_P(SpdyFramerTest, GoawayFrameFlags) { | |
4053 uint8_t flags = 0; | |
4054 do { | |
4055 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4056 << static_cast<int>(flags)); | |
4057 | |
4058 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4059 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4060 framer.set_visitor(&visitor); | |
4061 | |
4062 SpdyGoAwayIR goaway_ir(97, ERROR_CODE_NO_ERROR, "test"); | |
4063 SpdySerializedFrame frame(framer.SerializeGoAway(goaway_ir)); | |
4064 if (use_output_) { | |
4065 output_.Reset(); | |
4066 ASSERT_TRUE(framer.SerializeGoAway(goaway_ir, &output_)); | |
4067 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4068 } | |
4069 SetFrameFlags(&frame, flags); | |
4070 | |
4071 EXPECT_CALL(visitor, OnGoAway(97, ERROR_CODE_NO_ERROR)); | |
4072 | |
4073 framer.ProcessInput(frame.data(), frame.size()); | |
4074 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4075 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4076 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4077 } while (++flags != 0); | |
4078 } | |
4079 | |
4080 TEST_P(SpdyFramerTest, HeadersFrameFlags) { | |
4081 uint8_t flags = 0; | |
4082 do { | |
4083 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4084 << static_cast<int>(flags)); | |
4085 | |
4086 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4087 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4088 framer.set_visitor(&visitor); | |
4089 | |
4090 SpdyHeadersIR headers_ir(57); | |
4091 if (flags & HEADERS_FLAG_PRIORITY) { | |
4092 headers_ir.set_weight(3); | |
4093 headers_ir.set_has_priority(true); | |
4094 headers_ir.set_parent_stream_id(5); | |
4095 headers_ir.set_exclusive(true); | |
4096 } | |
4097 headers_ir.SetHeader("foo", "bar"); | |
4098 SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders( | |
4099 &framer, headers_ir, use_output_ ? &output_ : nullptr)); | |
4100 uint8_t set_flags = flags & ~HEADERS_FLAG_PADDED; | |
4101 SetFrameFlags(&frame, set_flags); | |
4102 | |
4103 // Expected callback values | |
4104 SpdyStreamId stream_id = 57; | |
4105 bool has_priority = false; | |
4106 SpdyPriority priority = 0; | |
4107 SpdyStreamId parent_stream_id = 0; | |
4108 bool exclusive = false; | |
4109 bool fin = flags & CONTROL_FLAG_FIN; | |
4110 bool end = flags & HEADERS_FLAG_END_HEADERS; | |
4111 if (flags & HEADERS_FLAG_PRIORITY) { | |
4112 has_priority = true; | |
4113 priority = 3; | |
4114 parent_stream_id = 5; | |
4115 exclusive = true; | |
4116 } | |
4117 EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, priority, | |
4118 parent_stream_id, exclusive, fin, end)); | |
4119 EXPECT_CALL(visitor, OnHeaderFrameStart(57)).Times(1); | |
4120 if (end) { | |
4121 EXPECT_CALL(visitor, OnHeaderFrameEnd(57, _)).Times(1); | |
4122 } | |
4123 if (flags & DATA_FLAG_FIN && end) { | |
4124 EXPECT_CALL(visitor, OnStreamEnd(_)); | |
4125 } else { | |
4126 // Do not close the stream if we are expecting a CONTINUATION frame. | |
4127 EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0); | |
4128 } | |
4129 | |
4130 framer.ProcessInput(frame.data(), frame.size()); | |
4131 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4132 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4133 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4134 } while (++flags != 0); | |
4135 } | |
4136 | |
4137 TEST_P(SpdyFramerTest, PingFrameFlags) { | |
4138 uint8_t flags = 0; | |
4139 do { | |
4140 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4141 << static_cast<int>(flags)); | |
4142 | |
4143 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4144 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4145 framer.set_visitor(&visitor); | |
4146 | |
4147 SpdySerializedFrame frame(framer.SerializePing(SpdyPingIR(42))); | |
4148 SetFrameFlags(&frame, flags); | |
4149 | |
4150 EXPECT_CALL(visitor, OnPing(42, flags & PING_FLAG_ACK)); | |
4151 | |
4152 framer.ProcessInput(frame.data(), frame.size()); | |
4153 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4154 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4155 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4156 } while (++flags != 0); | |
4157 } | |
4158 | |
4159 TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) { | |
4160 uint8_t flags = 0; | |
4161 do { | |
4162 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4163 << static_cast<int>(flags)); | |
4164 | |
4165 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4166 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4167 framer.set_visitor(&visitor); | |
4168 | |
4169 SpdySerializedFrame frame( | |
4170 framer.SerializeWindowUpdate(SpdyWindowUpdateIR(4, 1024))); | |
4171 SetFrameFlags(&frame, flags); | |
4172 | |
4173 EXPECT_CALL(visitor, OnWindowUpdate(4, 1024)); | |
4174 | |
4175 framer.ProcessInput(frame.data(), frame.size()); | |
4176 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4177 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4178 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4179 } while (++flags != 0); | |
4180 } | |
4181 | |
4182 TEST_P(SpdyFramerTest, PushPromiseFrameFlags) { | |
4183 const SpdyStreamId client_id = 123; // Must be odd. | |
4184 const SpdyStreamId promised_id = 22; // Must be even. | |
4185 uint8_t flags = 0; | |
4186 do { | |
4187 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4188 << static_cast<int>(flags)); | |
4189 | |
4190 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4191 testing::StrictMock<test::MockDebugVisitor> debug_visitor; | |
4192 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4193 framer.set_visitor(&visitor); | |
4194 framer.set_debug_visitor(&debug_visitor); | |
4195 | |
4196 EXPECT_CALL( | |
4197 debug_visitor, | |
4198 OnSendCompressedFrame(client_id, SpdyFrameType::PUSH_PROMISE, _, _)); | |
4199 | |
4200 SpdyPushPromiseIR push_promise(client_id, promised_id); | |
4201 push_promise.SetHeader("foo", "bar"); | |
4202 SpdySerializedFrame frame(SpdyFramerPeer::SerializePushPromise( | |
4203 &framer, push_promise, use_output_ ? &output_ : nullptr)); | |
4204 // TODO(jgraettinger): Add padding to SpdyPushPromiseIR, | |
4205 // and implement framing. | |
4206 SetFrameFlags(&frame, flags & ~HEADERS_FLAG_PADDED); | |
4207 | |
4208 bool end = flags & PUSH_PROMISE_FLAG_END_PUSH_PROMISE; | |
4209 EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame( | |
4210 client_id, SpdyFrameType::PUSH_PROMISE, _)); | |
4211 EXPECT_CALL(visitor, OnPushPromise(client_id, promised_id, end)); | |
4212 EXPECT_CALL(visitor, OnHeaderFrameStart(client_id)).Times(1); | |
4213 if (end) { | |
4214 EXPECT_CALL(visitor, OnHeaderFrameEnd(client_id, _)).Times(1); | |
4215 } | |
4216 | |
4217 framer.ProcessInput(frame.data(), frame.size()); | |
4218 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4219 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4220 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4221 } while (++flags != 0); | |
4222 } | |
4223 | |
4224 TEST_P(SpdyFramerTest, ContinuationFrameFlags) { | |
4225 uint8_t flags = 0; | |
4226 do { | |
4227 if (use_output_) { | |
4228 output_.Reset(); | |
4229 } | |
4230 SCOPED_TRACE(testing::Message() << "Flags " << flags << std::hex | |
4231 << static_cast<int>(flags)); | |
4232 | |
4233 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4234 testing::StrictMock<test::MockDebugVisitor> debug_visitor; | |
4235 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4236 framer.set_visitor(&visitor); | |
4237 framer.set_debug_visitor(&debug_visitor); | |
4238 | |
4239 EXPECT_CALL(debug_visitor, | |
4240 OnSendCompressedFrame(42, SpdyFrameType::HEADERS, _, _)); | |
4241 EXPECT_CALL(debug_visitor, | |
4242 OnReceiveCompressedFrame(42, SpdyFrameType::HEADERS, _)); | |
4243 EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false, false, false)); | |
4244 EXPECT_CALL(visitor, OnHeaderFrameStart(42)).Times(1); | |
4245 | |
4246 SpdyHeadersIR headers_ir(42); | |
4247 headers_ir.SetHeader("foo", "bar"); | |
4248 SpdySerializedFrame frame0; | |
4249 if (use_output_) { | |
4250 EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_)); | |
4251 frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4252 } else { | |
4253 frame0 = framer.SerializeHeaders(headers_ir); | |
4254 } | |
4255 SetFrameFlags(&frame0, 0); | |
4256 | |
4257 SpdyContinuationIR continuation(42); | |
4258 SpdySerializedFrame frame1; | |
4259 if (use_output_) { | |
4260 char* begin = output_.Begin() + output_.Size(); | |
4261 ASSERT_TRUE(framer.SerializeContinuation(continuation, &output_)); | |
4262 frame1 = | |
4263 SpdySerializedFrame(begin, output_.Size() - frame0.size(), false); | |
4264 } else { | |
4265 frame1 = framer.SerializeContinuation(continuation); | |
4266 } | |
4267 SetFrameFlags(&frame1, flags); | |
4268 | |
4269 EXPECT_CALL(debug_visitor, | |
4270 OnReceiveCompressedFrame(42, SpdyFrameType::CONTINUATION, _)); | |
4271 EXPECT_CALL(visitor, OnContinuation(42, flags & HEADERS_FLAG_END_HEADERS)); | |
4272 bool end = flags & HEADERS_FLAG_END_HEADERS; | |
4273 if (end) { | |
4274 EXPECT_CALL(visitor, OnHeaderFrameEnd(42, _)).Times(1); | |
4275 } | |
4276 | |
4277 framer.ProcessInput(frame0.data(), frame0.size()); | |
4278 framer.ProcessInput(frame1.data(), frame1.size()); | |
4279 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4280 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4281 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4282 } while (++flags != 0); | |
4283 } | |
4284 | |
4285 // TODO(mlavan): Add TEST_F(SpdyFramerTest, AltSvcFrameFlags) | |
4286 | |
4287 // Test handling of a RST_STREAM with out-of-bounds status codes. | |
4288 TEST_P(SpdyFramerTest, RstStreamStatusBounds) { | |
4289 const unsigned char kH2RstStreamInvalid[] = { | |
4290 0x00, 0x00, 0x04, // Length: 4 | |
4291 0x03, // Type: RST_STREAM | |
4292 0x00, // Flags: none | |
4293 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
4294 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR | |
4295 }; | |
4296 const unsigned char kH2RstStreamNumStatusCodes[] = { | |
4297 0x00, 0x00, 0x04, // Length: 4 | |
4298 0x03, // Type: RST_STREAM | |
4299 0x00, // Flags: none | |
4300 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
4301 0x00, 0x00, 0x00, 0xff, // Error: 255 | |
4302 }; | |
4303 | |
4304 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4305 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4306 framer.set_visitor(&visitor); | |
4307 | |
4308 EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_NO_ERROR)); | |
4309 framer.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamInvalid), | |
4310 arraysize(kH2RstStreamInvalid)); | |
4311 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4312 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4313 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4314 | |
4315 framer.Reset(); | |
4316 | |
4317 EXPECT_CALL(visitor, OnRstStream(1, ERROR_CODE_INTERNAL_ERROR)); | |
4318 framer.ProcessInput(reinterpret_cast<const char*>(kH2RstStreamNumStatusCodes), | |
4319 arraysize(kH2RstStreamNumStatusCodes)); | |
4320 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4321 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4322 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4323 } | |
4324 | |
4325 // Test handling of GOAWAY frames with out-of-bounds status code. | |
4326 TEST_P(SpdyFramerTest, GoAwayStatusBounds) { | |
4327 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4328 const unsigned char kH2FrameData[] = { | |
4329 0x00, 0x00, 0x0a, // Length: 10 | |
4330 0x07, // Type: GOAWAY | |
4331 0x00, // Flags: none | |
4332 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
4333 0x00, 0x00, 0x00, 0x01, // Last: 1 | |
4334 0xff, 0xff, 0xff, 0xff, // Error: 0xffffffff | |
4335 0x47, 0x41, // Description | |
4336 }; | |
4337 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4338 framer.set_visitor(&visitor); | |
4339 | |
4340 EXPECT_CALL(visitor, OnGoAway(1, ERROR_CODE_INTERNAL_ERROR)); | |
4341 framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData), | |
4342 arraysize(kH2FrameData)); | |
4343 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4344 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4345 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4346 } | |
4347 | |
4348 // Tests handling of a GOAWAY frame with out-of-bounds stream ID. | |
4349 TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) { | |
4350 const unsigned char kH2FrameData[] = { | |
4351 0x00, 0x00, 0x08, // Length: 8 | |
4352 0x07, // Type: GOAWAY | |
4353 0x00, // Flags: none | |
4354 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
4355 0xff, 0xff, 0xff, 0xff, // Last: 0x7fffffff (R-bit set) | |
4356 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR | |
4357 }; | |
4358 | |
4359 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4360 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4361 framer.set_visitor(&visitor); | |
4362 | |
4363 EXPECT_CALL(visitor, OnGoAway(0x7fffffff, ERROR_CODE_NO_ERROR)); | |
4364 framer.ProcessInput(reinterpret_cast<const char*>(kH2FrameData), | |
4365 arraysize(kH2FrameData)); | |
4366 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4367 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4368 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4369 } | |
4370 | |
4371 TEST_P(SpdyFramerTest, OnAltSvcWithOrigin) { | |
4372 const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given. | |
4373 | |
4374 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4375 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4376 framer.set_visitor(&visitor); | |
4377 | |
4378 SpdyAltSvcWireFormat::AlternativeService altsvc1( | |
4379 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); | |
4380 SpdyAltSvcWireFormat::AlternativeService altsvc2( | |
4381 "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); | |
4382 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; | |
4383 altsvc_vector.push_back(altsvc1); | |
4384 altsvc_vector.push_back(altsvc2); | |
4385 EXPECT_CALL(visitor, | |
4386 OnAltSvc(kStreamId, SpdyStringPiece("o_r|g!n"), altsvc_vector)); | |
4387 | |
4388 SpdyAltSvcIR altsvc_ir(kStreamId); | |
4389 altsvc_ir.set_origin("o_r|g!n"); | |
4390 altsvc_ir.add_altsvc(altsvc1); | |
4391 altsvc_ir.add_altsvc(altsvc2); | |
4392 SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir)); | |
4393 if (use_output_) { | |
4394 output_.Reset(); | |
4395 ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_)); | |
4396 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4397 } | |
4398 framer.ProcessInput(frame.data(), frame.size()); | |
4399 | |
4400 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4401 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4402 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4403 } | |
4404 | |
4405 TEST_P(SpdyFramerTest, OnAltSvcNoOrigin) { | |
4406 const SpdyStreamId kStreamId = 1; | |
4407 | |
4408 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4409 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4410 framer.set_visitor(&visitor); | |
4411 | |
4412 SpdyAltSvcWireFormat::AlternativeService altsvc1( | |
4413 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); | |
4414 SpdyAltSvcWireFormat::AlternativeService altsvc2( | |
4415 "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); | |
4416 SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector; | |
4417 altsvc_vector.push_back(altsvc1); | |
4418 altsvc_vector.push_back(altsvc2); | |
4419 EXPECT_CALL(visitor, OnAltSvc(kStreamId, SpdyStringPiece(""), altsvc_vector)); | |
4420 | |
4421 SpdyAltSvcIR altsvc_ir(kStreamId); | |
4422 altsvc_ir.add_altsvc(altsvc1); | |
4423 altsvc_ir.add_altsvc(altsvc2); | |
4424 SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir)); | |
4425 framer.ProcessInput(frame.data(), frame.size()); | |
4426 | |
4427 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4428 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4429 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4430 } | |
4431 | |
4432 TEST_P(SpdyFramerTest, OnAltSvcEmptyProtocolId) { | |
4433 const SpdyStreamId kStreamId = 0; // Stream id must be zero if origin given. | |
4434 | |
4435 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4436 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4437 framer.set_visitor(&visitor); | |
4438 | |
4439 EXPECT_CALL(visitor, OnError(testing::Eq(&framer))); | |
4440 | |
4441 SpdyAltSvcIR altsvc_ir(kStreamId); | |
4442 altsvc_ir.set_origin("o1"); | |
4443 altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( | |
4444 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector())); | |
4445 altsvc_ir.add_altsvc(SpdyAltSvcWireFormat::AlternativeService( | |
4446 "", "h1", 443, 10, SpdyAltSvcWireFormat::VersionVector())); | |
4447 SpdySerializedFrame frame(framer.SerializeFrame(altsvc_ir)); | |
4448 if (use_output_) { | |
4449 output_.Reset(); | |
4450 ASSERT_TRUE(framer.SerializeFrame(altsvc_ir, &output_)); | |
4451 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4452 } | |
4453 framer.ProcessInput(frame.data(), frame.size()); | |
4454 | |
4455 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4456 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error()) | |
4457 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4458 } | |
4459 | |
4460 TEST_P(SpdyFramerTest, OnAltSvcBadLengths) { | |
4461 const unsigned char kType = SerializeFrameType(SpdyFrameType::ALTSVC); | |
4462 const unsigned char kFrameDataOriginLenLargerThanFrame[] = { | |
4463 0x00, 0x00, 0x05, kType, 0x00, 0x00, 0x00, | |
4464 0x00, 0x03, 0x42, 0x42, 'f', 'o', 'o', | |
4465 }; | |
4466 | |
4467 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4468 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4469 framer.set_visitor(&visitor); | |
4470 visitor.SimulateInFramer(kFrameDataOriginLenLargerThanFrame, | |
4471 sizeof(kFrameDataOriginLenLargerThanFrame)); | |
4472 | |
4473 EXPECT_EQ(1, visitor.error_count_); | |
4474 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, | |
4475 visitor.framer_.spdy_framer_error()); | |
4476 } | |
4477 | |
4478 // Tests handling of ALTSVC frames delivered in small chunks. | |
4479 TEST_P(SpdyFramerTest, ReadChunkedAltSvcFrame) { | |
4480 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4481 SpdyAltSvcIR altsvc_ir(1); | |
4482 SpdyAltSvcWireFormat::AlternativeService altsvc1( | |
4483 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); | |
4484 SpdyAltSvcWireFormat::AlternativeService altsvc2( | |
4485 "p\"=i:d", "h_\\o\"st", 123, 42, SpdyAltSvcWireFormat::VersionVector{24}); | |
4486 altsvc_ir.add_altsvc(altsvc1); | |
4487 altsvc_ir.add_altsvc(altsvc2); | |
4488 | |
4489 SpdySerializedFrame control_frame(framer.SerializeAltSvc(altsvc_ir)); | |
4490 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4491 | |
4492 // Read data in small chunks. | |
4493 size_t framed_data = 0; | |
4494 size_t unframed_data = control_frame.size(); | |
4495 size_t kReadChunkSize = 5; // Read five bytes at a time. | |
4496 while (unframed_data > 0) { | |
4497 size_t to_read = std::min(kReadChunkSize, unframed_data); | |
4498 visitor.SimulateInFramer( | |
4499 reinterpret_cast<unsigned char*>(control_frame.data() + framed_data), | |
4500 to_read); | |
4501 unframed_data -= to_read; | |
4502 framed_data += to_read; | |
4503 } | |
4504 EXPECT_EQ(0, visitor.error_count_); | |
4505 EXPECT_EQ(1, visitor.altsvc_count_); | |
4506 ASSERT_EQ(2u, visitor.test_altsvc_ir_.altsvc_vector().size()); | |
4507 EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[0] == altsvc1); | |
4508 EXPECT_TRUE(visitor.test_altsvc_ir_.altsvc_vector()[1] == altsvc2); | |
4509 } | |
4510 | |
4511 // While RFC7838 Section 4 says that an ALTSVC frame on stream 0 with empty | |
4512 // origin MUST be ignored, it is not implemented at the framer level: instead, | |
4513 // such frames are passed on to the consumer. | |
4514 TEST_P(SpdyFramerTest, ReadAltSvcFrame) { | |
4515 constexpr struct { | |
4516 uint32_t stream_id; | |
4517 const char* origin; | |
4518 } test_cases[] = {{0, ""}, | |
4519 {1, ""}, | |
4520 {0, "https://www.example.com"}, | |
4521 {1, "https://www.example.com"}}; | |
4522 for (const auto& test_case : test_cases) { | |
4523 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4524 SpdyAltSvcIR altsvc_ir(test_case.stream_id); | |
4525 SpdyAltSvcWireFormat::AlternativeService altsvc( | |
4526 "pid1", "host", 443, 5, SpdyAltSvcWireFormat::VersionVector()); | |
4527 altsvc_ir.add_altsvc(altsvc); | |
4528 altsvc_ir.set_origin(test_case.origin); | |
4529 SpdySerializedFrame frame(framer.SerializeAltSvc(altsvc_ir)); | |
4530 | |
4531 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
4532 framer.set_visitor(&visitor); | |
4533 framer.ProcessInput(frame.data(), frame.size()); | |
4534 | |
4535 EXPECT_EQ(0, visitor.error_count_); | |
4536 EXPECT_EQ(1, visitor.altsvc_count_); | |
4537 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4538 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4539 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4540 } | |
4541 } | |
4542 | |
4543 // An ALTSVC frame with invalid Alt-Svc-Field-Value results in an error. | |
4544 TEST_P(SpdyFramerTest, ErrorOnAltSvcFrameWithInvalidValue) { | |
4545 // Alt-Svc-Field-Value must be "clear" or must contain an "=" character | |
4546 // per RFC7838 Section 3. | |
4547 const char kFrameData[] = { | |
4548 0x00, 0x00, 0x16, // Length: 22 | |
4549 0x0a, // Type: ALTSVC | |
4550 0x00, // Flags: none | |
4551 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
4552 0x00, 0x00, // Origin-Len: 0 | |
4553 0x74, 0x68, 0x69, 0x73, // thisisnotavalidvalue | |
4554 0x69, 0x73, 0x6e, 0x6f, 0x74, 0x61, 0x76, 0x61, | |
4555 0x6c, 0x69, 0x64, 0x76, 0x61, 0x6c, 0x75, 0x65, | |
4556 }; | |
4557 | |
4558 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4559 TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION); | |
4560 framer.set_visitor(&visitor); | |
4561 framer.ProcessInput(kFrameData, sizeof(kFrameData)); | |
4562 | |
4563 EXPECT_EQ(1, visitor.error_count_); | |
4564 EXPECT_EQ(0, visitor.altsvc_count_); | |
4565 EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); | |
4566 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.spdy_framer_error()) | |
4567 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4568 } | |
4569 | |
4570 // Tests handling of PRIORITY frames. | |
4571 TEST_P(SpdyFramerTest, ReadPriority) { | |
4572 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4573 SpdyPriorityIR priority(3, 1, 256, false); | |
4574 SpdySerializedFrame frame(framer.SerializePriority(priority)); | |
4575 if (use_output_) { | |
4576 output_.Reset(); | |
4577 ASSERT_TRUE(framer.SerializePriority(priority, &output_)); | |
4578 frame = SpdySerializedFrame(output_.Begin(), output_.Size(), false); | |
4579 } | |
4580 testing::StrictMock<test::MockSpdyFramerVisitor> visitor; | |
4581 framer.set_visitor(&visitor); | |
4582 EXPECT_CALL(visitor, OnPriority(3, 1, 256, false)); | |
4583 framer.ProcessInput(frame.data(), frame.size()); | |
4584 | |
4585 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4586 EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.spdy_framer_error()) | |
4587 << SpdyFramer::SpdyFramerErrorToString(framer.spdy_framer_error()); | |
4588 // TODO(mlavan): once we actually maintain a priority tree, | |
4589 // check that state is adjusted correctly. | |
4590 } | |
4591 | |
4592 // Tests handling of PRIORITY frame with incorrect size. | |
4593 TEST_P(SpdyFramerTest, ReadIncorrectlySizedPriority) { | |
4594 // PRIORITY frame of size 4, which isn't correct. | |
4595 const unsigned char kFrameData[] = { | |
4596 0x00, 0x00, 0x04, // Length: 4 | |
4597 0x02, // Type: PRIORITY | |
4598 0x00, // Flags: none | |
4599 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
4600 0x00, 0x00, 0x00, 0x01, // Priority (Truncated) | |
4601 }; | |
4602 | |
4603 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4604 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4605 | |
4606 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
4607 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4608 visitor.framer_.spdy_framer_error()) | |
4609 << SpdyFramer::SpdyFramerErrorToString( | |
4610 visitor.framer_.spdy_framer_error()); | |
4611 } | |
4612 | |
4613 // Tests handling of PING frame with incorrect size. | |
4614 TEST_P(SpdyFramerTest, ReadIncorrectlySizedPing) { | |
4615 // PING frame of size 4, which isn't correct. | |
4616 const unsigned char kFrameData[] = { | |
4617 0x00, 0x00, 0x04, // Length: 4 | |
4618 0x06, // Type: PING | |
4619 0x00, // Flags: none | |
4620 0x00, 0x00, 0x00, 0x00, // Stream: 0 | |
4621 0x00, 0x00, 0x00, 0x01, // Ping (Truncated) | |
4622 }; | |
4623 | |
4624 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4625 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4626 | |
4627 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
4628 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4629 visitor.framer_.spdy_framer_error()) | |
4630 << SpdyFramer::SpdyFramerErrorToString( | |
4631 visitor.framer_.spdy_framer_error()); | |
4632 } | |
4633 | |
4634 // Tests handling of WINDOW_UPDATE frame with incorrect size. | |
4635 TEST_P(SpdyFramerTest, ReadIncorrectlySizedWindowUpdate) { | |
4636 // WINDOW_UPDATE frame of size 3, which isn't correct. | |
4637 const unsigned char kFrameData[] = { | |
4638 0x00, 0x00, 0x03, // Length: 3 | |
4639 0x08, // Type: WINDOW_UPDATE | |
4640 0x00, // Flags: none | |
4641 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
4642 0x00, 0x00, 0x01, // WindowUpdate (Truncated) | |
4643 }; | |
4644 | |
4645 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4646 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4647 | |
4648 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
4649 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4650 visitor.framer_.spdy_framer_error()) | |
4651 << SpdyFramer::SpdyFramerErrorToString( | |
4652 visitor.framer_.spdy_framer_error()); | |
4653 } | |
4654 | |
4655 // Tests handling of RST_STREAM frame with incorrect size. | |
4656 TEST_P(SpdyFramerTest, ReadIncorrectlySizedRstStream) { | |
4657 // RST_STREAM frame of size 3, which isn't correct. | |
4658 const unsigned char kFrameData[] = { | |
4659 0x00, 0x00, 0x03, // Length: 3 | |
4660 0x03, // Type: RST_STREAM | |
4661 0x00, // Flags: none | |
4662 0x00, 0x00, 0x00, 0x03, // Stream: 3 | |
4663 0x00, 0x00, 0x01, // RstStream (Truncated) | |
4664 }; | |
4665 | |
4666 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4667 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4668 | |
4669 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
4670 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4671 visitor.framer_.spdy_framer_error()) | |
4672 << SpdyFramer::SpdyFramerErrorToString( | |
4673 visitor.framer_.spdy_framer_error()); | |
4674 } | |
4675 | |
4676 // Regression test for https://crbug.com/548674: | |
4677 // RST_STREAM with payload must not be accepted. | |
4678 TEST_P(SpdyFramerTest, ReadInvalidRstStreamWithPayload) { | |
4679 const unsigned char kFrameData[] = { | |
4680 0x00, 0x00, 0x07, // Length: 7 | |
4681 0x03, // Type: RST_STREAM | |
4682 0x00, // Flags: none | |
4683 0x00, 0x00, 0x00, 0x01, // Stream: 1 | |
4684 0x00, 0x00, 0x00, 0x00, // Error: NO_ERROR | |
4685 'f', 'o', 'o' // Payload: "foo" | |
4686 }; | |
4687 | |
4688 TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION); | |
4689 visitor.SimulateInFramer(kFrameData, sizeof(kFrameData)); | |
4690 | |
4691 EXPECT_EQ(SpdyFramer::SPDY_ERROR, visitor.framer_.state()); | |
4692 EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_SIZE, | |
4693 visitor.framer_.spdy_framer_error()) | |
4694 << SpdyFramer::SpdyFramerErrorToString( | |
4695 visitor.framer_.spdy_framer_error()); | |
4696 } | |
4697 | |
4698 // Test that SpdyFramer processes, by default, all passed input in one call | |
4699 // to ProcessInput (i.e. will not be calling set_process_single_input_frame()). | |
4700 TEST_P(SpdyFramerTest, ProcessAllInput) { | |
4701 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4702 auto visitor = | |
4703 base::MakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION); | |
4704 framer.set_visitor(visitor.get()); | |
4705 | |
4706 // Create two input frames. | |
4707 SpdyHeadersIR headers(1); | |
4708 headers.SetHeader("alpha", "beta"); | |
4709 headers.SetHeader("gamma", "charlie"); | |
4710 headers.SetHeader("cookie", "key1=value1; key2=value2"); | |
4711 SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( | |
4712 &framer, headers, use_output_ ? &output_ : nullptr)); | |
4713 | |
4714 const char four_score[] = "Four score and seven years ago"; | |
4715 SpdyDataIR four_score_ir(1, four_score); | |
4716 SpdySerializedFrame four_score_frame(framer.SerializeData(four_score_ir)); | |
4717 | |
4718 // Put them in a single buffer (new variables here to make it easy to | |
4719 // change the order and type of frames). | |
4720 SpdySerializedFrame frame1 = std::move(headers_frame); | |
4721 SpdySerializedFrame frame2 = std::move(four_score_frame); | |
4722 | |
4723 const size_t frame1_size = frame1.size(); | |
4724 const size_t frame2_size = frame2.size(); | |
4725 | |
4726 VLOG(1) << "frame1_size = " << frame1_size; | |
4727 VLOG(1) << "frame2_size = " << frame2_size; | |
4728 | |
4729 SpdyString input_buffer; | |
4730 input_buffer.append(frame1.data(), frame1_size); | |
4731 input_buffer.append(frame2.data(), frame2_size); | |
4732 | |
4733 const char* buf = input_buffer.data(); | |
4734 const size_t buf_size = input_buffer.size(); | |
4735 | |
4736 VLOG(1) << "buf_size = " << buf_size; | |
4737 | |
4738 size_t processed = framer.ProcessInput(buf, buf_size); | |
4739 EXPECT_EQ(buf_size, processed); | |
4740 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4741 EXPECT_EQ(1, visitor->headers_frame_count_); | |
4742 EXPECT_EQ(1, visitor->data_frame_count_); | |
4743 EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_)); | |
4744 } | |
4745 | |
4746 // Test that SpdyFramer stops after processing a full frame if | |
4747 // process_single_input_frame is set. Input to ProcessInput has two frames, but | |
4748 // only processes the first when we give it the first frame split at any point, | |
4749 // or give it more than one frame in the input buffer. | |
4750 TEST_P(SpdyFramerTest, ProcessAtMostOneFrame) { | |
4751 SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION); | |
4752 framer.set_process_single_input_frame(true); | |
4753 | |
4754 // Create two input frames. | |
4755 const char four_score[] = "Four score and ..."; | |
4756 SpdyDataIR four_score_ir(1, four_score); | |
4757 SpdySerializedFrame four_score_frame(framer.SerializeData(four_score_ir)); | |
4758 | |
4759 SpdyHeadersIR headers(2); | |
4760 headers.SetHeader("alpha", "beta"); | |
4761 headers.SetHeader("gamma", "charlie"); | |
4762 headers.SetHeader("cookie", "key1=value1; key2=value2"); | |
4763 SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders( | |
4764 &framer, headers, use_output_ ? &output_ : nullptr)); | |
4765 | |
4766 // Put them in a single buffer (new variables here to make it easy to | |
4767 // change the order and type of frames). | |
4768 SpdySerializedFrame frame1 = std::move(four_score_frame); | |
4769 SpdySerializedFrame frame2 = std::move(headers_frame); | |
4770 | |
4771 const size_t frame1_size = frame1.size(); | |
4772 const size_t frame2_size = frame2.size(); | |
4773 | |
4774 VLOG(1) << "frame1_size = " << frame1_size; | |
4775 VLOG(1) << "frame2_size = " << frame2_size; | |
4776 | |
4777 SpdyString input_buffer; | |
4778 input_buffer.append(frame1.data(), frame1_size); | |
4779 input_buffer.append(frame2.data(), frame2_size); | |
4780 | |
4781 const char* buf = input_buffer.data(); | |
4782 const size_t buf_size = input_buffer.size(); | |
4783 | |
4784 VLOG(1) << "buf_size = " << buf_size; | |
4785 | |
4786 for (size_t first_size = 0; first_size <= buf_size; ++first_size) { | |
4787 VLOG(1) << "first_size = " << first_size; | |
4788 auto visitor = | |
4789 base::MakeUnique<TestSpdyVisitor>(SpdyFramer::DISABLE_COMPRESSION); | |
4790 framer.set_visitor(visitor.get()); | |
4791 | |
4792 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4793 | |
4794 size_t processed_first = framer.ProcessInput(buf, first_size); | |
4795 if (first_size < frame1_size) { | |
4796 EXPECT_EQ(first_size, processed_first); | |
4797 | |
4798 if (first_size == 0) { | |
4799 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4800 } else { | |
4801 EXPECT_NE(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4802 } | |
4803 | |
4804 const char* rest = buf + processed_first; | |
4805 const size_t remaining = buf_size - processed_first; | |
4806 VLOG(1) << "remaining = " << remaining; | |
4807 | |
4808 size_t processed_second = framer.ProcessInput(rest, remaining); | |
4809 | |
4810 // Redundant tests just to make it easier to think about. | |
4811 EXPECT_EQ(frame1_size - processed_first, processed_second); | |
4812 size_t processed_total = processed_first + processed_second; | |
4813 EXPECT_EQ(frame1_size, processed_total); | |
4814 } else { | |
4815 EXPECT_EQ(frame1_size, processed_first); | |
4816 } | |
4817 | |
4818 EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); | |
4819 | |
4820 // At this point should have processed the entirety of the first frame, | |
4821 // and none of the second frame. | |
4822 | |
4823 EXPECT_EQ(1, visitor->data_frame_count_); | |
4824 EXPECT_EQ(strlen(four_score), static_cast<unsigned>(visitor->data_bytes_)); | |
4825 EXPECT_EQ(0, visitor->headers_frame_count_); | |
4826 } | |
4827 } | |
4828 | |
4829 } // namespace test | |
4830 | |
4831 } // namespace net | |
OLD | NEW |