spdy_framer_test.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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 <algorithm>
6#include <iostream>
7#include <limits>
8
9#include "base/compiler_specific.h"
10#include "base/memory/scoped_ptr.h"
11#include "net/spdy/spdy_frame_builder.h"
12#include "net/spdy/spdy_framer.h"
13#include "net/spdy/spdy_protocol.h"
14#include "net/spdy/spdy_test_utils.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/platform_test.h"
17
18using std::string;
19using std::max;
20using std::min;
21using std::numeric_limits;
22using testing::_;
23
24namespace net {
25
26namespace test {
27
28static const size_t kMaxDecompressedSize = 1024;
29
30// TODO(akalin): Make sure expectations on mocks are set before mock
31// functions are called, as interleaving expectations and calls is
32// undefined.
33class MockVisitor : public SpdyFramerVisitorInterface {
34 public:
35  MOCK_METHOD1(OnError, void(SpdyFramer* framer));
36  MOCK_METHOD6(OnSynStream, void(SpdyStreamId stream_id,
37                                 SpdyStreamId associated_stream_id,
38                                 SpdyPriority priority,
39                                 uint8 slot,
40                                 bool fin,
41                                 bool unidirectional));
42  MOCK_METHOD2(OnSynReply, void(SpdyStreamId stream_id, bool fin));
43  MOCK_METHOD2(OnHeaders, void(SpdyStreamId stream_id, bool fin));
44  MOCK_METHOD3(OnControlFrameHeaderData, bool(SpdyStreamId stream_id,
45                                              const char* header_data,
46                                              size_t len));
47  MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
48                                           size_t len));
49  MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId stream_id,
50                                       size_t length,
51                                       bool fin));
52  MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId stream_id,
53                                       const char* data,
54                                       size_t len,
55                                       bool fin));
56  MOCK_METHOD1(OnSettings, void(bool clear_persisted));
57  MOCK_METHOD3(OnSetting, void(SpdySettingsIds id, uint8 flags, uint32 value));
58  MOCK_METHOD1(OnPing, void(uint32 unique_id));
59  MOCK_METHOD2(OnRstStream, void(SpdyStreamId stream_id,
60                                 SpdyRstStreamStatus status));
61  MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
62                              SpdyGoAwayStatus status));
63  MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
64                                    uint32 delta_window_size));
65  MOCK_METHOD2(OnSynStreamCompressed,
66               void(size_t uncompressed_length,
67                    size_t compressed_length));
68  MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
69};
70
71class SpdyFramerTestUtil {
72 public:
73  // Decompress a single frame using the decompression context held by
74  // the SpdyFramer.  The implemention is meant for use only in tests
75  // and will CHECK fail if the input is anything other than a single,
76  // well-formed compressed frame.
77  //
78  // Returns a new decompressed SpdyFrame.
79  template<class SpdyFrameType> static SpdyFrame* DecompressFrame(
80      SpdyFramer* framer, const SpdyFrameType& frame) {
81    DecompressionVisitor visitor(framer->protocol_version());
82    framer->set_visitor(&visitor);
83    CHECK_EQ(frame.size(), framer->ProcessInput(frame.data(), frame.size()));
84    CHECK_EQ(SpdyFramer::SPDY_RESET, framer->state());
85    framer->set_visitor(NULL);
86
87    char* buffer = visitor.ReleaseBuffer();
88    CHECK(buffer != NULL);
89    SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true);
90    if (framer->protocol_version() == 4) {
91      SetFrameLength(decompressed_frame,
92                     visitor.size(),
93                     framer->protocol_version());
94    } else {
95      SetFrameLength(decompressed_frame,
96                     visitor.size() - framer->GetControlFrameHeaderSize(),
97                     framer->protocol_version());
98    }
99    return decompressed_frame;
100  }
101
102  class DecompressionVisitor : public SpdyFramerVisitorInterface {
103   public:
104    explicit DecompressionVisitor(SpdyMajorVersion version)
105        : version_(version), size_(0), finished_(false) {}
106
107    void ResetBuffer() {
108      CHECK(buffer_.get() == NULL);
109      CHECK_EQ(0u, size_);
110      CHECK(!finished_);
111      buffer_.reset(new char[kMaxDecompressedSize]);
112    }
113
114    virtual void OnSynStream(SpdyStreamId stream_id,
115                             SpdyStreamId associated_stream_id,
116                             SpdyPriority priority,
117                             uint8 slot,
118                             bool fin,
119                             bool unidirectional) OVERRIDE {
120      SpdyFramer framer(version_);
121      framer.set_enable_compression(false);
122      const SpdyHeaderBlock null_headers;
123      int flags = CONTROL_FLAG_NONE;
124      if (fin) {
125        flags &= CONTROL_FLAG_FIN;
126      }
127      if (unidirectional) {
128        flags &= CONTROL_FLAG_UNIDIRECTIONAL;
129      }
130      scoped_ptr<SpdyFrame> frame(
131          framer.CreateSynStream(stream_id,
132                                 associated_stream_id,
133                                 priority,
134                                 slot,
135                                 static_cast<SpdyControlFlags>(flags),
136                                 false,
137                                 &null_headers));
138      ResetBuffer();
139      memcpy(buffer_.get(), frame->data(), framer.GetSynStreamMinimumSize());
140      size_ += framer.GetSynStreamMinimumSize();
141    }
142
143    virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
144      SpdyFramer framer(version_);
145      framer.set_enable_compression(false);
146      const SpdyHeaderBlock null_headers;
147      int flags = CONTROL_FLAG_NONE;
148      if (fin) {
149        flags &= CONTROL_FLAG_FIN;
150      }
151      scoped_ptr<SpdyFrame> frame(
152          framer.CreateHeaders(stream_id,
153                               static_cast<SpdyControlFlags>(flags),
154                               false,
155                               &null_headers));
156      ResetBuffer();
157      memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
158      size_ += framer.GetSynStreamMinimumSize();
159    }
160
161    virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {
162      SpdyFramer framer(version_);
163      framer.set_enable_compression(false);
164      const SpdyHeaderBlock null_headers;
165      int flags = CONTROL_FLAG_NONE;
166      if (fin) {
167        flags &= CONTROL_FLAG_FIN;
168      }
169      scoped_ptr<SpdyFrame> frame(
170          framer.CreateHeaders(stream_id,
171                               static_cast<SpdyControlFlags>(flags),
172                               false,
173                               &null_headers));
174      ResetBuffer();
175      memcpy(buffer_.get(), frame->data(), framer.GetHeadersMinimumSize());
176      size_ += framer.GetSynStreamMinimumSize();
177    }
178
179    virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
180                                          const char* header_data,
181                                          size_t len) OVERRIDE {
182      CHECK(buffer_.get() != NULL);
183      CHECK_GE(kMaxDecompressedSize, size_ + len);
184      CHECK(!finished_);
185      if (len != 0) {
186        memcpy(buffer_.get() + size_, header_data, len);
187        size_ += len;
188      } else {
189        // Done.
190        finished_ = true;
191      }
192      return true;
193    }
194
195    virtual bool OnCredentialFrameData(const char* /*credential_data*/,
196                                       size_t /*len*/) OVERRIDE {
197      LOG(FATAL) << "Unexpected CREDENTIAL Frame";
198      return false;
199    }
200
201    virtual void OnError(SpdyFramer* framer) OVERRIDE { LOG(FATAL); }
202    virtual void OnDataFrameHeader(SpdyStreamId stream_id,
203                                   size_t length,
204                                   bool fin) OVERRIDE {
205      LOG(FATAL) << "Unexpected data frame header";
206    }
207    virtual void OnStreamFrameData(SpdyStreamId stream_id,
208                                   const char* data,
209                                   size_t len,
210                                   bool fin) OVERRIDE {
211      LOG(FATAL);
212    }
213    virtual void OnSetting(SpdySettingsIds id,
214                           uint8 flags,
215                           uint32 value) OVERRIDE {
216      LOG(FATAL);
217    }
218    virtual void OnSynStreamCompressed(
219        size_t uncompressed_size,
220        size_t compressed_size) OVERRIDE {
221    }
222    virtual void OnPing(uint32 unique_id) OVERRIDE {
223      LOG(FATAL);
224    }
225    virtual void OnRstStream(SpdyStreamId stream_id,
226                             SpdyRstStreamStatus status) OVERRIDE {
227      LOG(FATAL);
228    }
229    virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
230                          SpdyGoAwayStatus status) OVERRIDE {
231      LOG(FATAL);
232    }
233    virtual void OnWindowUpdate(SpdyStreamId stream_id,
234                                uint32 delta_window_size) OVERRIDE {
235      LOG(FATAL);
236    }
237
238    char* ReleaseBuffer() {
239      CHECK(finished_);
240      return buffer_.release();
241    }
242
243    size_t size() const {
244      CHECK(finished_);
245      return size_;
246    }
247
248   private:
249    SpdyMajorVersion version_;
250    scoped_ptr<char[]> buffer_;
251    size_t size_;
252    bool finished_;
253
254    DISALLOW_COPY_AND_ASSIGN(DecompressionVisitor);
255  };
256
257 private:
258  DISALLOW_COPY_AND_ASSIGN(SpdyFramerTestUtil);
259};
260
261class TestSpdyVisitor : public SpdyFramerVisitorInterface,
262                        public SpdyFramerDebugVisitorInterface {
263 public:
264  static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
265  static const size_t kDefaultCredentialBufferSize = 16 * 1024;
266
267  explicit TestSpdyVisitor(SpdyMajorVersion version)
268    : framer_(version),
269      use_compression_(false),
270      error_count_(0),
271      syn_frame_count_(0),
272      syn_reply_frame_count_(0),
273      headers_frame_count_(0),
274      goaway_count_(0),
275      setting_count_(0),
276      last_window_update_stream_(0),
277      last_window_update_delta_(0),
278      data_bytes_(0),
279      fin_frame_count_(0),
280      fin_flag_count_(0),
281      zero_length_data_frame_count_(0),
282      control_frame_header_data_count_(0),
283      zero_length_control_frame_header_data_count_(0),
284      data_frame_count_(0),
285      last_payload_len_(0),
286      last_frame_len_(0),
287      header_buffer_(new char[kDefaultHeaderBufferSize]),
288      header_buffer_length_(0),
289      header_buffer_size_(kDefaultHeaderBufferSize),
290      header_stream_id_(-1),
291      header_control_type_(DATA),
292      header_buffer_valid_(false),
293      credential_buffer_(new char[kDefaultCredentialBufferSize]),
294      credential_buffer_length_(0),
295      credential_buffer_size_(kDefaultCredentialBufferSize) {
296  }
297
298  virtual void OnError(SpdyFramer* f) OVERRIDE {
299    LOG(INFO) << "SpdyFramer Error: "
300              << SpdyFramer::ErrorCodeToString(f->error_code());
301    error_count_++;
302  }
303
304  virtual void OnDataFrameHeader(SpdyStreamId stream_id,
305                                 size_t length,
306                                 bool fin) OVERRIDE {
307    data_frame_count_++;
308    header_stream_id_ = stream_id;
309  }
310
311  virtual void OnStreamFrameData(SpdyStreamId stream_id,
312                                 const char* data,
313                                 size_t len,
314                                 bool fin) OVERRIDE {
315    EXPECT_EQ(header_stream_id_, stream_id);
316    if (len == 0)
317      ++zero_length_data_frame_count_;
318
319    data_bytes_ += len;
320    std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
321    if (len > 0) {
322      for (size_t i = 0 ; i < len; ++i) {
323        std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
324      }
325    }
326    std::cerr << "\", " << len << ")\n";
327  }
328
329  virtual void OnSynStream(SpdyStreamId stream_id,
330                           SpdyStreamId associated_stream_id,
331                           SpdyPriority priority,
332                           uint8 credential_slot,
333                           bool fin,
334                           bool unidirectional) OVERRIDE {
335    syn_frame_count_++;
336    InitHeaderStreaming(SYN_STREAM, stream_id);
337    if (fin) {
338      fin_flag_count_++;
339    }
340  }
341
342  virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
343    syn_reply_frame_count_++;
344    InitHeaderStreaming(HEADERS, stream_id);
345    if (fin) {
346      fin_flag_count_++;
347    }
348  }
349
350  virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {
351    headers_frame_count_++;
352    InitHeaderStreaming(SYN_REPLY, stream_id);
353    if (fin) {
354      fin_flag_count_++;
355    }
356  }
357
358  virtual void OnSetting(SpdySettingsIds id,
359                         uint8 flags,
360                         uint32 value) OVERRIDE {
361    setting_count_++;
362  }
363
364  virtual void OnSynStreamCompressed(
365      size_t uncompressed_size,
366      size_t compressed_size) OVERRIDE {
367  }
368
369  virtual void OnPing(uint32 unique_id) OVERRIDE {
370    DLOG(FATAL);
371  }
372
373  virtual void OnRstStream(SpdyStreamId stream_id,
374                           SpdyRstStreamStatus status) OVERRIDE {
375    fin_frame_count_++;
376  }
377
378  virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
379                        SpdyGoAwayStatus status) OVERRIDE {
380    goaway_count_++;
381  }
382
383  virtual void OnWindowUpdate(SpdyStreamId stream_id,
384                              uint32 delta_window_size) OVERRIDE {
385    last_window_update_stream_ = stream_id;
386    last_window_update_delta_ = delta_window_size;
387  }
388
389  virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
390                                        const char* header_data,
391                                        size_t len) OVERRIDE {
392    ++control_frame_header_data_count_;
393    CHECK_EQ(header_stream_id_, stream_id);
394    if (len == 0) {
395      ++zero_length_control_frame_header_data_count_;
396      // Indicates end-of-header-block.
397      CHECK(header_buffer_valid_);
398      size_t parsed_length = framer_.ParseHeaderBlockInBuffer(
399          header_buffer_.get(), header_buffer_length_, &headers_);
400      DCHECK_EQ(header_buffer_length_, parsed_length);
401      return true;
402    }
403    const size_t available = header_buffer_size_ - header_buffer_length_;
404    if (len > available) {
405      header_buffer_valid_ = false;
406      return false;
407    }
408    memcpy(header_buffer_.get() + header_buffer_length_, header_data, len);
409    header_buffer_length_ += len;
410    return true;
411  }
412
413  virtual bool OnCredentialFrameData(const char* credential_data,
414                                     size_t len) OVERRIDE {
415    if (len == 0) {
416      if (!framer_.ParseCredentialData(credential_buffer_.get(),
417                                       credential_buffer_length_,
418                                       &credential_)) {
419        ++error_count_;
420      }
421      return true;
422    }
423    const size_t available =
424        credential_buffer_size_ - credential_buffer_length_;
425    if (len > available) {
426      return false;
427    }
428    memcpy(credential_buffer_.get() + credential_buffer_length_,
429           credential_data, len);
430    credential_buffer_length_ += len;
431    return true;
432  }
433
434  virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
435                                     SpdyFrameType type,
436                                     size_t payload_len,
437                                     size_t frame_len) OVERRIDE {
438    last_payload_len_ = payload_len;
439    last_frame_len_ = frame_len;
440  }
441
442  virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id,
443                                        SpdyFrameType type,
444                                        size_t frame_len) OVERRIDE {
445    last_frame_len_ = frame_len;
446  }
447
448  // Convenience function which runs a framer simulation with particular input.
449  void SimulateInFramer(const unsigned char* input, size_t size) {
450    framer_.set_enable_compression(use_compression_);
451    framer_.set_visitor(this);
452    size_t input_remaining = size;
453    const char* input_ptr = reinterpret_cast<const char*>(input);
454    while (input_remaining > 0 &&
455           framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
456      // To make the tests more interesting, we feed random (amd small) chunks
457      // into the framer.  This simulates getting strange-sized reads from
458      // the socket.
459      const size_t kMaxReadSize = 32;
460      size_t bytes_read =
461          (rand() % min(input_remaining, kMaxReadSize)) + 1;
462      size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
463      input_remaining -= bytes_processed;
464      input_ptr += bytes_processed;
465    }
466  }
467
468  void InitHeaderStreaming(SpdyFrameType header_control_type,
469                           SpdyStreamId stream_id) {
470    DCHECK_GE(header_control_type, FIRST_CONTROL_TYPE);
471    DCHECK_LE(header_control_type, LAST_CONTROL_TYPE);
472    memset(header_buffer_.get(), 0, header_buffer_size_);
473    header_buffer_length_ = 0;
474    header_stream_id_ = stream_id;
475    header_control_type_ = header_control_type;
476    header_buffer_valid_ = true;
477    DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
478  }
479
480  // Override the default buffer size (16K). Call before using the framer!
481  void set_header_buffer_size(size_t header_buffer_size) {
482    header_buffer_size_ = header_buffer_size;
483    header_buffer_.reset(new char[header_buffer_size]);
484  }
485
486  static size_t header_data_chunk_max_size() {
487    return SpdyFramer::kHeaderDataChunkMaxSize;
488  }
489
490  SpdyFramer framer_;
491  bool use_compression_;
492
493  // Counters from the visitor callbacks.
494  int error_count_;
495  int syn_frame_count_;
496  int syn_reply_frame_count_;
497  int headers_frame_count_;
498  int goaway_count_;
499  int setting_count_;
500  SpdyStreamId last_window_update_stream_;
501  uint32 last_window_update_delta_;
502  int data_bytes_;
503  int fin_frame_count_;  // The count of RST_STREAM type frames received.
504  int fin_flag_count_;  // The count of frames with the FIN flag set.
505  int zero_length_data_frame_count_;  // The count of zero-length data frames.
506  int control_frame_header_data_count_;  // The count of chunks received.
507  // The count of zero-length control frame header data chunks received.
508  int zero_length_control_frame_header_data_count_;
509  int data_frame_count_;
510  size_t last_payload_len_;
511  size_t last_frame_len_;
512
513  // Header block streaming state:
514  scoped_ptr<char[]> header_buffer_;
515  size_t header_buffer_length_;
516  size_t header_buffer_size_;
517  SpdyStreamId header_stream_id_;
518  SpdyFrameType header_control_type_;
519  bool header_buffer_valid_;
520  SpdyHeaderBlock headers_;
521
522  scoped_ptr<char[]> credential_buffer_;
523  size_t credential_buffer_length_;
524  size_t credential_buffer_size_;
525  SpdyCredential credential_;
526};
527
528// Retrieves serialized headers from SYN_STREAM frame.
529// Does not check that the given frame is a SYN_STREAM.
530base::StringPiece GetSerializedHeaders(const SpdyFrame* frame,
531                                       const SpdyFramer& framer) {
532  return base::StringPiece(frame->data() + framer.GetSynStreamMinimumSize(),
533                           frame->size() - framer.GetSynStreamMinimumSize());
534}
535
536}  // namespace test
537
538}  // namespace net
539
540using net::test::SetFrameLength;
541using net::test::SetFrameFlags;
542using net::test::CompareCharArraysWithHexError;
543using net::test::SpdyFramerTestUtil;
544using net::test::TestSpdyVisitor;
545using net::test::GetSerializedHeaders;
546
547namespace net {
548
549class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> {
550 protected:
551  virtual void SetUp() {
552    spdy_version_ = GetParam();
553    spdy_version_ch_ = static_cast<unsigned char>(spdy_version_);
554  }
555
556  void CompareFrame(const string& description,
557                    const SpdyFrame& actual_frame,
558                    const unsigned char* expected,
559                    const int expected_len) {
560    const unsigned char* actual =
561        reinterpret_cast<const unsigned char*>(actual_frame.data());
562    CompareCharArraysWithHexError(
563        description, actual, actual_frame.size(), expected, expected_len);
564  }
565
566  void CompareFrames(const string& description,
567                     const SpdyFrame& expected_frame,
568                     const SpdyFrame& actual_frame) {
569    CompareCharArraysWithHexError(
570        description,
571        reinterpret_cast<const unsigned char*>(expected_frame.data()),
572        expected_frame.size(),
573        reinterpret_cast<const unsigned char*>(actual_frame.data()),
574        actual_frame.size());
575  }
576
577  // Returns true if the two header blocks have equivalent content.
578  bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
579                           const SpdyHeaderBlock* actual) {
580    if (expected->size() != actual->size()) {
581      LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
582                 << actual->size() << ".";
583      return false;
584    }
585    for (SpdyHeaderBlock::const_iterator it = expected->begin();
586         it != expected->end();
587         ++it) {
588      SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
589      if (it2 == actual->end()) {
590        LOG(ERROR) << "Expected header name '" << it->first << "'.";
591        return false;
592      }
593      if (it->second.compare(it2->second) != 0) {
594        LOG(ERROR) << "Expected header named '" << it->first
595                   << "' to have a value of '" << it->second
596                   << "'. The actual value received was '" << it2->second
597                   << "'.";
598        return false;
599      }
600    }
601    return true;
602  }
603
604  void AddSpdySettingFromWireFormat(SettingsMap* settings,
605                                    uint32 key,
606                                    uint32 value) {
607    SettingsFlagsAndId flags_and_id =
608        SettingsFlagsAndId::FromWireFormat(spdy_version_, key);
609    SpdySettingsIds id = static_cast<SpdySettingsIds>(flags_and_id.id());
610    SpdySettingsFlags flags =
611        static_cast<SpdySettingsFlags>(flags_and_id.flags());
612    CHECK(settings->find(id) == settings->end());
613    settings->insert(std::make_pair(id, SettingsFlagsAndValue(flags, value)));
614  }
615
616  bool IsSpdy2() { return spdy_version_ == SPDY2; }
617  bool IsSpdy3() { return spdy_version_ == SPDY3; }
618  bool IsSpdy4() { return spdy_version_ == SPDY4; }
619
620  // Version of SPDY protocol to be used.
621  SpdyMajorVersion spdy_version_;
622  unsigned char spdy_version_ch_;
623};
624
625// All tests are run with two different SPDY versions: SPDY/2 and SPDY/3.
626INSTANTIATE_TEST_CASE_P(SpdyFramerTests,
627                        SpdyFramerTest,
628                        ::testing::Values(SPDY2, SPDY3, SPDY4));
629
630// Test that we can encode and decode a SpdyHeaderBlock in serialized form.
631TEST_P(SpdyFramerTest, HeaderBlockInBuffer) {
632  SpdyHeaderBlock headers;
633  headers["alpha"] = "beta";
634  headers["gamma"] = "charlie";
635  SpdyFramer framer(spdy_version_);
636  framer.set_enable_compression(false);
637
638  // Encode the header block into a SynStream frame.
639  scoped_ptr<SpdyFrame> frame(
640      framer.CreateSynStream(1,  // stream id
641                             0,  // associated stream id
642                             1,  // priority
643                             0,  // credential slot
644                             CONTROL_FLAG_NONE,
645                             false,  // compress
646                             &headers));
647  EXPECT_TRUE(frame.get() != NULL);
648  base::StringPiece serialized_headers =
649      GetSerializedHeaders(frame.get(), framer);
650  SpdyHeaderBlock new_headers;
651  EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
652                                              serialized_headers.size(),
653                                              &new_headers));
654
655  EXPECT_EQ(headers.size(), new_headers.size());
656  EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
657  EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
658}
659
660// Test that if there's not a full frame, we fail to parse it.
661TEST_P(SpdyFramerTest, UndersizedHeaderBlockInBuffer) {
662  SpdyHeaderBlock headers;
663  headers["alpha"] = "beta";
664  headers["gamma"] = "charlie";
665  SpdyFramer framer(spdy_version_);
666  framer.set_enable_compression(false);
667
668  // Encode the header block into a SynStream frame.
669  scoped_ptr<SpdyFrame> frame(
670      framer.CreateSynStream(1,  // stream id
671                             0,  // associated stream id
672                             1,  // priority
673                             0,  // credential slot
674                             CONTROL_FLAG_NONE,
675                             false,  // compress
676                             &headers));
677  EXPECT_TRUE(frame.get() != NULL);
678
679  base::StringPiece serialized_headers =
680      GetSerializedHeaders(frame.get(), framer);
681  SpdyHeaderBlock new_headers;
682  EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
683                                               serialized_headers.size() - 2,
684                                               &new_headers));
685}
686
687TEST_P(SpdyFramerTest, OutOfOrderHeaders) {
688  SpdyFramer framer(spdy_version_);
689  framer.set_enable_compression(false);
690
691  // Frame builder with plentiful buffer size.
692  SpdyFrameBuilder frame(1024);
693  if (spdy_version_ < 4) {
694    frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
695    frame.WriteUInt32(3);  // stream_id
696  } else {
697    frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
698  }
699
700  frame.WriteUInt32(0);  // Associated stream id
701  frame.WriteUInt16(0);  // Priority.
702
703  if (IsSpdy2()) {
704    frame.WriteUInt16(2);  // Number of headers.
705    frame.WriteString("gamma");
706    frame.WriteString("gamma");
707    frame.WriteString("alpha");
708    frame.WriteString("alpha");
709  } else {
710    frame.WriteUInt32(2);  // Number of headers.
711    frame.WriteStringPiece32("gamma");
712    frame.WriteStringPiece32("gamma");
713    frame.WriteStringPiece32("alpha");
714    frame.WriteStringPiece32("alpha");
715  }
716  // write the length
717  frame.RewriteLength(framer);
718
719  SpdyHeaderBlock new_headers;
720  scoped_ptr<SpdyFrame> control_frame(frame.take());
721  base::StringPiece serialized_headers =
722      GetSerializedHeaders(control_frame.get(), framer);
723  EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
724                                              serialized_headers.size(),
725                                              &new_headers));
726}
727
728TEST_P(SpdyFramerTest, CreateCredential) {
729  SpdyFramer framer(spdy_version_);
730
731  {
732    const char kDescription[] = "CREDENTIAL frame";
733    const unsigned char kV3FrameData[] = {  // Also applies for V2.
734      0x80, spdy_version_ch_, 0x00, 0x0A,
735      0x00, 0x00, 0x00, 0x33,
736      0x00, 0x03, 0x00, 0x00,
737      0x00, 0x05, 'p',  'r',
738      'o',  'o',  'f',  0x00,
739      0x00, 0x00, 0x06, 'a',
740      ' ',  'c',  'e',  'r',
741      't',  0x00, 0x00, 0x00,
742      0x0C, 'a',  'n',  'o',
743      't',  'h',  'e',  'r',
744      ' ',  'c',  'e',  'r',
745      't',  0x00, 0x00, 0x00,
746      0x0A, 'f',  'i',  'n',
747      'a',  'l',  ' ',  'c',
748      'e',  'r',  't',
749    };
750    const unsigned char kV4FrameData[] = {
751      0x00, 0x3b, 0x0A, 0x00,
752      0x00, 0x00, 0x00, 0x00,
753      0x00, 0x03, 0x00, 0x00,
754      0x00, 0x05, 'p',  'r',
755      'o',  'o',  'f',  0x00,
756      0x00, 0x00, 0x06, 'a',
757      ' ',  'c',  'e',  'r',
758      't',  0x00, 0x00, 0x00,
759      0x0C, 'a',  'n',  'o',
760      't',  'h',  'e',  'r',
761      ' ',  'c',  'e',  'r',
762      't',  0x00, 0x00, 0x00,
763      0x0A, 'f',  'i',  'n',
764      'a',  'l',  ' ',  'c',
765      'e',  'r',  't',
766    };
767    SpdyCredential credential;
768    credential.slot = 3;
769    credential.proof = "proof";
770    credential.certs.push_back("a cert");
771    credential.certs.push_back("another cert");
772    credential.certs.push_back("final cert");
773    scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
774    if (IsSpdy4()) {
775      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
776    } else {
777      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
778    }
779  }
780}
781
782TEST_P(SpdyFramerTest, ParseCredentialFrameData) {
783  SpdyFramer framer(spdy_version_);
784
785  {
786    const unsigned char kV3FrameData[] = {  // Also applies for V2.
787      0x80, spdy_version_ch_, 0x00, 0x0A,
788      0x00, 0x00, 0x00, 0x33,
789      0x00, 0x03, 0x00, 0x00,
790      0x00, 0x05, 'p',  'r',
791      'o',  'o',  'f',  0x00,
792      0x00, 0x00, 0x06, 'a',
793      ' ',  'c',  'e',  'r',
794      't',  0x00, 0x00, 0x00,
795      0x0C, 'a',  'n',  'o',
796      't',  'h',  'e',  'r',
797      ' ',  'c',  'e',  'r',
798      't',  0x00,  0x00, 0x00,
799      0x0A, 'f',  'i',  'n',
800      'a',  'l',  ' ',  'c',
801      'e',  'r',  't',
802    };
803    const unsigned char kV4FrameData[] = {
804      0x00, 0x37, 0x0A, 0x00,
805      0x00, 0x00, 0x00, 0x00,
806      0x00, 0x03, 0x00, 0x00,
807      0x00, 0x05, 'p',  'r',
808      'o',  'o',  'f',  0x00,
809      0x00, 0x00, 0x06, 'a',
810      ' ',  'c',  'e',  'r',
811      't',  0x00, 0x00, 0x00,
812      0x0C, 'a',  'n',  'o',
813      't',  'h',  'e',  'r',
814      ' ',  'c',  'e',  'r',
815      't',  0x00,  0x00, 0x00,
816      0x0A, 'f',  'i',  'n',
817      'a',  'l',  ' ',  'c',
818      'e',  'r',  't',
819    };
820
821    SpdyCredential credential;
822    if (IsSpdy4()) {
823      EXPECT_TRUE(SpdyFramer::ParseCredentialData(
824          reinterpret_cast<const char*>(kV4FrameData) +
825              framer.GetControlFrameHeaderSize(),
826          arraysize(kV4FrameData) - framer.GetControlFrameHeaderSize(),
827          &credential));
828    } else {
829      EXPECT_TRUE(SpdyFramer::ParseCredentialData(
830          reinterpret_cast<const char*>(kV3FrameData) +
831              framer.GetControlFrameHeaderSize(),
832          arraysize(kV3FrameData) - framer.GetControlFrameHeaderSize(),
833          &credential));
834    }
835    EXPECT_EQ(3u, credential.slot);
836    EXPECT_EQ("proof", credential.proof);
837    EXPECT_EQ("a cert", credential.certs.front());
838    credential.certs.erase(credential.certs.begin());
839    EXPECT_EQ("another cert", credential.certs.front());
840    credential.certs.erase(credential.certs.begin());
841    EXPECT_EQ("final cert", credential.certs.front());
842    credential.certs.erase(credential.certs.begin());
843    EXPECT_TRUE(credential.certs.empty());
844  }
845}
846
847TEST_P(SpdyFramerTest, DuplicateHeader) {
848  SpdyFramer framer(spdy_version_);
849  // Frame builder with plentiful buffer size.
850  SpdyFrameBuilder frame(1024);
851  if (spdy_version_ < 4) {
852    frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
853    frame.WriteUInt32(3);  // stream_id
854  } else {
855    frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
856  }
857
858  frame.WriteUInt32(0);  // associated stream id
859  frame.WriteUInt16(0);  // Priority.
860
861  if (IsSpdy2()) {
862    frame.WriteUInt16(2);  // Number of headers.
863    frame.WriteString("name");
864    frame.WriteString("value1");
865    frame.WriteString("name");
866    frame.WriteString("value2");
867  } else {
868    frame.WriteUInt32(2);  // Number of headers.
869    frame.WriteStringPiece32("name");
870    frame.WriteStringPiece32("value1");
871    frame.WriteStringPiece32("name");
872    frame.WriteStringPiece32("value2");
873  }
874  // write the length
875  frame.RewriteLength(framer);
876
877  SpdyHeaderBlock new_headers;
878  framer.set_enable_compression(false);
879  scoped_ptr<SpdyFrame> control_frame(frame.take());
880  base::StringPiece serialized_headers =
881      GetSerializedHeaders(control_frame.get(), framer);
882  // This should fail because duplicate headers are verboten by the spec.
883  EXPECT_FALSE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
884                                               serialized_headers.size(),
885                                               &new_headers));
886}
887
888TEST_P(SpdyFramerTest, MultiValueHeader) {
889  SpdyFramer framer(spdy_version_);
890  // Frame builder with plentiful buffer size.
891  SpdyFrameBuilder frame(1024);
892  if (spdy_version_ < 4) {
893    frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
894    frame.WriteUInt32(3);  // stream_id
895  } else {
896    frame.WriteFramePrefix(framer, SYN_STREAM, CONTROL_FLAG_NONE, 3);
897  }
898
899  frame.WriteUInt32(0);  // associated stream id
900  frame.WriteUInt16(0);  // Priority.
901
902  string value("value1\0value2");
903  if (IsSpdy2()) {
904    frame.WriteUInt16(1);  // Number of headers.
905    frame.WriteString("name");
906    frame.WriteString(value);
907  } else {
908    frame.WriteUInt32(1);  // Number of headers.
909    frame.WriteStringPiece32("name");
910    frame.WriteStringPiece32(value);
911  }
912  // write the length
913  frame.RewriteLength(framer);
914
915  SpdyHeaderBlock new_headers;
916  framer.set_enable_compression(false);
917  scoped_ptr<SpdyFrame> control_frame(frame.take());
918  base::StringPiece serialized_headers =
919      GetSerializedHeaders(control_frame.get(), framer);
920  EXPECT_TRUE(framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
921                                              serialized_headers.size(),
922                                              &new_headers));
923  EXPECT_TRUE(new_headers.find("name") != new_headers.end());
924  EXPECT_EQ(value, new_headers.find("name")->second);
925}
926
927TEST_P(SpdyFramerTest, BasicCompression) {
928  SpdyHeaderBlock headers;
929  headers["server"] = "SpdyServer 1.0";
930  headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
931  headers["status"] = "200";
932  headers["version"] = "HTTP/1.1";
933  headers["content-type"] = "text/html";
934  headers["content-length"] = "12";
935
936  scoped_ptr<TestSpdyVisitor> visitor(new TestSpdyVisitor(spdy_version_));
937  SpdyFramer framer(spdy_version_);
938  framer.set_debug_visitor(visitor.get());
939  scoped_ptr<SpdyFrame> frame1(
940      framer.CreateSynStream(1,  // stream id
941                             0,  // associated stream id
942                             1,  // priority
943                             0,  // credential slot
944                             CONTROL_FLAG_NONE,
945                             true,  // compress
946                             &headers));
947  size_t uncompressed_size1 = visitor->last_payload_len_;
948  size_t compressed_size1 =
949      visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
950  if (IsSpdy2()) {
951    EXPECT_EQ(139u, uncompressed_size1);
952#if defined(USE_SYSTEM_ZLIB)
953    EXPECT_EQ(155u, compressed_size1);
954#else  // !defined(USE_SYSTEM_ZLIB)
955    EXPECT_EQ(135u, compressed_size1);
956#endif  // !defined(USE_SYSTEM_ZLIB)
957  } else {
958    EXPECT_EQ(165u, uncompressed_size1);
959#if defined(USE_SYSTEM_ZLIB)
960    EXPECT_EQ(181u, compressed_size1);
961#else  // !defined(USE_SYSTEM_ZLIB)
962    EXPECT_EQ(117u, compressed_size1);
963#endif  // !defined(USE_SYSTEM_ZLIB)
964  }
965  scoped_ptr<SpdyFrame> frame2(
966      framer.CreateSynStream(1,  // stream id
967                             0,  // associated stream id
968                             1,  // priority
969                             0,  // credential slot
970                             CONTROL_FLAG_NONE,
971                             true,  // compress
972                             &headers));
973  size_t uncompressed_size2 = visitor->last_payload_len_;
974  size_t compressed_size2 =
975      visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
976
977  // Expect the second frame to be more compact than the first.
978  EXPECT_LE(frame2->size(), frame1->size());
979
980  // Decompress the first frame
981  scoped_ptr<SpdyFrame> frame3(SpdyFramerTestUtil::DecompressFrame(
982      &framer, *frame1.get()));
983
984  // Decompress the second frame
985  visitor.reset(new TestSpdyVisitor(spdy_version_));
986  framer.set_debug_visitor(visitor.get());
987  scoped_ptr<SpdyFrame> frame4(SpdyFramerTestUtil::DecompressFrame(
988      &framer, *frame2.get()));
989  size_t uncompressed_size4 =
990      frame4->size() - framer.GetSynStreamMinimumSize();
991  size_t compressed_size4 =
992      visitor->last_frame_len_ - framer.GetSynStreamMinimumSize();
993  if (IsSpdy2()) {
994    EXPECT_EQ(139u, uncompressed_size4);
995#if defined(USE_SYSTEM_ZLIB)
996    EXPECT_EQ(149u, compressed_size4);
997#else  // !defined(USE_SYSTEM_ZLIB)
998    EXPECT_EQ(101u, compressed_size4);
999#endif  // !defined(USE_SYSTEM_ZLIB)
1000  } else {
1001    EXPECT_EQ(165u, uncompressed_size4);
1002#if defined(USE_SYSTEM_ZLIB)
1003    EXPECT_EQ(175u, compressed_size4);
1004#else  // !defined(USE_SYSTEM_ZLIB)
1005    EXPECT_EQ(102u, compressed_size4);
1006#endif  // !defined(USE_SYSTEM_ZLIB)
1007  }
1008
1009  EXPECT_EQ(uncompressed_size1, uncompressed_size2);
1010  EXPECT_EQ(uncompressed_size1, uncompressed_size4);
1011  EXPECT_EQ(compressed_size2, compressed_size4);
1012
1013  // Expect frames 3 & 4 to be the same.
1014  CompareFrames("Uncompressed SYN_STREAM", *frame3, *frame4);
1015
1016  // Expect frames 3 to be the same as a uncompressed frame created
1017  // from scratch.
1018  framer.set_enable_compression(false);
1019  scoped_ptr<SpdyFrame> uncompressed_frame(
1020      framer.CreateSynStream(1,  // stream id
1021                             0,  // associated stream id
1022                             1,  // priority
1023                             0,  // credential slot
1024                             CONTROL_FLAG_NONE,
1025                             false,  // compress
1026                             &headers));
1027  CompareFrames("Uncompressed SYN_STREAM", *frame3, *uncompressed_frame);
1028}
1029
1030TEST_P(SpdyFramerTest, CompressEmptyHeaders) {
1031  // See crbug.com/172383
1032  SpdyHeaderBlock headers;
1033  headers["server"] = "SpdyServer 1.0";
1034  headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
1035  headers["status"] = "200";
1036  headers["version"] = "HTTP/1.1";
1037  headers["content-type"] = "text/html";
1038  headers["content-length"] = "12";
1039  headers["x-empty-header"] = "";
1040
1041  SpdyFramer framer(spdy_version_);
1042  framer.set_enable_compression(true);
1043  scoped_ptr<SpdyFrame> frame1(
1044      framer.CreateSynStream(1,  // stream id
1045                             0,  // associated stream id
1046                             1,  // priority
1047                             0,  // credential slot
1048                             CONTROL_FLAG_NONE,
1049                             true,  // compress
1050                             &headers));
1051}
1052
1053TEST_P(SpdyFramerTest, Basic) {
1054  const unsigned char kV2Input[] = {
1055    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1056    0x00, 0x00, 0x00, 0x14,
1057    0x00, 0x00, 0x00, 0x01,
1058    0x00, 0x00, 0x00, 0x00,
1059    0x00, 0x00, 0x00, 0x01,
1060    0x00, 0x02, 'h', 'h',
1061    0x00, 0x02, 'v', 'v',
1062
1063    0x80, spdy_version_ch_, 0x00, 0x08,  // HEADERS on Stream #1
1064    0x00, 0x00, 0x00, 0x18,
1065    0x00, 0x00, 0x00, 0x01,
1066    0x00, 0x00, 0x00, 0x02,
1067    0x00, 0x02, 'h', '2',
1068    0x00, 0x02, 'v', '2',
1069    0x00, 0x02, 'h', '3',
1070    0x00, 0x02, 'v', '3',
1071
1072    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1073    0x00, 0x00, 0x00, 0x0c,
1074    0xde, 0xad, 0xbe, 0xef,
1075    0xde, 0xad, 0xbe, 0xef,
1076    0xde, 0xad, 0xbe, 0xef,
1077
1078    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #3
1079    0x00, 0x00, 0x00, 0x0c,
1080    0x00, 0x00, 0x00, 0x03,
1081    0x00, 0x00, 0x00, 0x00,
1082    0x00, 0x00, 0x00, 0x00,
1083
1084    0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
1085    0x00, 0x00, 0x00, 0x08,
1086    0xde, 0xad, 0xbe, 0xef,
1087    0xde, 0xad, 0xbe, 0xef,
1088
1089    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1090    0x00, 0x00, 0x00, 0x04,
1091    0xde, 0xad, 0xbe, 0xef,
1092
1093    0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #1
1094    0x00, 0x00, 0x00, 0x08,
1095    0x00, 0x00, 0x00, 0x01,
1096    0x00, 0x00, 0x00, 0x00,
1097
1098    0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
1099    0x00, 0x00, 0x00, 0x00,
1100
1101    0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #3
1102    0x00, 0x00, 0x00, 0x08,
1103    0x00, 0x00, 0x00, 0x03,
1104    0x00, 0x00, 0x00, 0x00,
1105  };
1106
1107  const unsigned char kV3Input[] = {
1108    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1109    0x00, 0x00, 0x00, 0x1a,
1110    0x00, 0x00, 0x00, 0x01,
1111    0x00, 0x00, 0x00, 0x00,
1112    0x00, 0x00, 0x00, 0x00,
1113    0x00, 0x01, 0x00, 0x00,
1114    0x00, 0x02, 'h', 'h',
1115    0x00, 0x00, 0x00, 0x02,
1116    'v', 'v',
1117
1118    0x80, spdy_version_ch_, 0x00, 0x08,  // HEADERS on Stream #1
1119    0x00, 0x00, 0x00, 0x20,
1120    0x00, 0x00, 0x00, 0x01,
1121    0x00, 0x00, 0x00, 0x02,
1122    0x00, 0x00, 0x00, 0x02,
1123    'h', '2',
1124    0x00, 0x00, 0x00, 0x02,
1125    'v', '2', 0x00, 0x00,
1126    0x00, 0x02, 'h', '3',
1127    0x00, 0x00, 0x00, 0x02,
1128    'v', '3',
1129
1130    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1131    0x00, 0x00, 0x00, 0x0c,
1132    0xde, 0xad, 0xbe, 0xef,
1133    0xde, 0xad, 0xbe, 0xef,
1134    0xde, 0xad, 0xbe, 0xef,
1135
1136    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #3
1137    0x00, 0x00, 0x00, 0x0e,
1138    0x00, 0x00, 0x00, 0x03,
1139    0x00, 0x00, 0x00, 0x00,
1140    0x00, 0x00, 0x00, 0x00,
1141    0x00, 0x00,
1142
1143    0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
1144    0x00, 0x00, 0x00, 0x08,
1145    0xde, 0xad, 0xbe, 0xef,
1146    0xde, 0xad, 0xbe, 0xef,
1147
1148    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1149    0x00, 0x00, 0x00, 0x04,
1150    0xde, 0xad, 0xbe, 0xef,
1151
1152    0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #1
1153    0x00, 0x00, 0x00, 0x08,
1154    0x00, 0x00, 0x00, 0x01,
1155    0x00, 0x00, 0x00, 0x00,
1156
1157    0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
1158    0x00, 0x00, 0x00, 0x00,
1159
1160    0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #3
1161    0x00, 0x00, 0x00, 0x08,
1162    0x00, 0x00, 0x00, 0x03,
1163    0x00, 0x00, 0x00, 0x00,
1164  };
1165
1166  const unsigned char kV4Input[] = {
1167    0x00, 0x1e, 0x01, 0x00,           // SYN_STREAM #1
1168    0x00, 0x00, 0x00, 0x01,
1169    0x00, 0x00, 0x00, 0x00,
1170    0x00, 0x00, 0x00, 0x00,
1171    0x00, 0x01, 0x00, 0x00,
1172    0x00, 0x02, 'h', 'h',
1173    0x00, 0x00, 0x00, 0x02,
1174    'v', 'v',
1175
1176    0x00, 0x24, 0x08, 0x00,           // HEADERS on Stream #1
1177    0x00, 0x00, 0x00, 0x01,
1178    0x00, 0x00, 0x00, 0x02,
1179    0x00, 0x00, 0x00, 0x02,
1180    'h',  '2',  0x00, 0x00,
1181    0x00, 0x02, 'v',  '2',
1182    0x00, 0x00, 0x00, 0x02,
1183    'h',  '3',  0x00, 0x00,
1184    0x00, 0x02, 'v', '3',
1185
1186    0x00, 0x14, 0x00, 0x00,           // DATA on Stream #1
1187    0x00, 0x00, 0x00, 0x01,
1188    0xde, 0xad, 0xbe, 0xef,
1189    0xde, 0xad, 0xbe, 0xef,
1190    0xde, 0xad, 0xbe, 0xef,
1191
1192    0x00, 0x12, 0x01, 0x00,           // SYN Stream #3
1193    0x00, 0x00, 0x00, 0x03,
1194    0x00, 0x00, 0x00, 0x00,
1195    0x00, 0x00, 0x00, 0x00,
1196    0x00, 0x00,
1197
1198    0x00, 0x10, 0x00, 0x00,           // DATA on Stream #3
1199    0x00, 0x00, 0x00, 0x03,
1200    0xde, 0xad, 0xbe, 0xef,
1201    0xde, 0xad, 0xbe, 0xef,
1202
1203    0x00, 0x0c, 0x00, 0x00,           // DATA on Stream #1
1204    0x00, 0x00, 0x00, 0x01,
1205    0xde, 0xad, 0xbe, 0xef,
1206
1207    0x00, 0x0c, 0x03, 0x00,           // RST_STREAM on Stream #1
1208    0x00, 0x00, 0x00, 0x01,
1209    0x00, 0x00, 0x00, 0x00,
1210
1211    0x00, 0x08, 0x00, 0x00,           // DATA on Stream #3
1212    0x00, 0x00, 0x00, 0x03,
1213
1214    0x00, 0x0c, 0x03, 0x00,           // RST_STREAM on Stream #3
1215    0x00, 0x00, 0x00, 0x03,
1216    0x00, 0x00, 0x00, 0x00,
1217  };
1218
1219  TestSpdyVisitor visitor(spdy_version_);
1220  if (IsSpdy2()) {
1221    visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1222  } else if (IsSpdy3()) {
1223    visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1224  } else {
1225    visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1226  }
1227
1228  EXPECT_EQ(0, visitor.error_count_);
1229  EXPECT_EQ(2, visitor.syn_frame_count_);
1230  EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1231  EXPECT_EQ(1, visitor.headers_frame_count_);
1232  EXPECT_EQ(24, visitor.data_bytes_);
1233  EXPECT_EQ(2, visitor.fin_frame_count_);
1234  EXPECT_EQ(0, visitor.fin_flag_count_);
1235  EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
1236  EXPECT_EQ(4, visitor.data_frame_count_);
1237}
1238
1239// Test that the FIN flag on a data frame signifies EOF.
1240TEST_P(SpdyFramerTest, FinOnDataFrame) {
1241  const unsigned char kV2Input[] = {
1242    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1243    0x00, 0x00, 0x00, 0x14,
1244    0x00, 0x00, 0x00, 0x01,
1245    0x00, 0x00, 0x00, 0x00,
1246    0x00, 0x00, 0x00, 0x01,
1247    0x00, 0x02, 'h', 'h',
1248    0x00, 0x02, 'v', 'v',
1249
1250    0x80, spdy_version_ch_, 0x00, 0x02,  // SYN REPLY Stream #1
1251    0x00, 0x00, 0x00, 0x10,
1252    0x00, 0x00, 0x00, 0x01,
1253    0x00, 0x00, 0x00, 0x01,
1254    0x00, 0x02, 'a', 'a',
1255    0x00, 0x02, 'b', 'b',
1256
1257    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1258    0x00, 0x00, 0x00, 0x0c,
1259    0xde, 0xad, 0xbe, 0xef,
1260    0xde, 0xad, 0xbe, 0xef,
1261    0xde, 0xad, 0xbe, 0xef,
1262
1263    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1, with EOF
1264    0x01, 0x00, 0x00, 0x04,
1265    0xde, 0xad, 0xbe, 0xef,
1266  };
1267  const unsigned char kV3Input[] = {
1268    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1269    0x00, 0x00, 0x00, 0x1a,
1270    0x00, 0x00, 0x00, 0x01,
1271    0x00, 0x00, 0x00, 0x00,
1272    0x00, 0x00, 0x00, 0x00,
1273    0x00, 0x01, 0x00, 0x00,
1274    0x00, 0x02, 'h', 'h',
1275    0x00, 0x00, 0x00, 0x02,
1276    'v',  'v',
1277
1278    0x80, spdy_version_ch_, 0x00, 0x02,  // SYN REPLY Stream #1
1279    0x00, 0x00, 0x00, 0x14,
1280    0x00, 0x00, 0x00, 0x01,
1281    0x00, 0x00, 0x00, 0x01,
1282    0x00, 0x00, 0x00, 0x02,
1283    'a',  'a',  0x00, 0x00,
1284    0x00, 0x02, 'b', 'b',
1285
1286    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1
1287    0x00, 0x00, 0x00, 0x0c,
1288    0xde, 0xad, 0xbe, 0xef,
1289    0xde, 0xad, 0xbe, 0xef,
1290    0xde, 0xad, 0xbe, 0xef,
1291
1292    0x00, 0x00, 0x00, 0x01,           // DATA on Stream #1, with EOF
1293    0x01, 0x00, 0x00, 0x04,
1294    0xde, 0xad, 0xbe, 0xef,
1295  };
1296  const unsigned char kV4Input[] = {
1297    0x00, 0x1e, 0x01, 0x00,           // SYN_STREAM #1
1298    0x00, 0x00, 0x00, 0x01,
1299    0x00, 0x00, 0x00, 0x00,
1300    0x00, 0x00, 0x00, 0x00,
1301    0x00, 0x01, 0x00, 0x00,
1302    0x00, 0x02, 'h', 'h',
1303    0x00, 0x00, 0x00, 0x02,
1304    'v',  'v',
1305
1306    0x00, 0x18, 0x02, 0x00,           // SYN REPLY Stream #1
1307    0x00, 0x00, 0x00, 0x01,
1308    0x00, 0x00, 0x00, 0x01,
1309    0x00, 0x00, 0x00, 0x02,
1310    'a',  'a',  0x00, 0x00,
1311    0x00, 0x02, 'b', 'b',
1312
1313    0x00, 0x14, 0x00, 0x00,           // DATA on Stream #1
1314    0x00, 0x00, 0x00, 0x01,
1315    0xde, 0xad, 0xbe, 0xef,
1316    0xde, 0xad, 0xbe, 0xef,
1317    0xde, 0xad, 0xbe, 0xef,
1318
1319    0x00, 0x0c, 0x00, 0x01,           // DATA on Stream #1, with FIN
1320    0x00, 0x00, 0x00, 0x01,
1321    0xde, 0xad, 0xbe, 0xef,
1322  };
1323
1324  TestSpdyVisitor visitor(spdy_version_);
1325  if (IsSpdy2()) {
1326    visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1327  } else if (IsSpdy3()) {
1328    visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1329  } else {
1330    visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1331  }
1332
1333  EXPECT_EQ(0, visitor.error_count_);
1334  EXPECT_EQ(1, visitor.syn_frame_count_);
1335  EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1336  EXPECT_EQ(0, visitor.headers_frame_count_);
1337  EXPECT_EQ(16, visitor.data_bytes_);
1338  EXPECT_EQ(0, visitor.fin_frame_count_);
1339  EXPECT_EQ(0, visitor.fin_flag_count_);
1340  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1341  EXPECT_EQ(2, visitor.data_frame_count_);
1342}
1343
1344// Test that the FIN flag on a SYN reply frame signifies EOF.
1345TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
1346  const unsigned char kV2Input[] = {
1347    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1348    0x00, 0x00, 0x00, 0x14,
1349    0x00, 0x00, 0x00, 0x01,
1350    0x00, 0x00, 0x00, 0x00,
1351    0x00, 0x00, 0x00, 0x01,
1352    0x00, 0x02, 'h', 'h',
1353    0x00, 0x02, 'v', 'v',
1354
1355    0x80, spdy_version_ch_, 0x00, 0x02,  // SYN REPLY Stream #1
1356    0x01, 0x00, 0x00, 0x10,
1357    0x00, 0x00, 0x00, 0x01,
1358    0x00, 0x00, 0x00, 0x01,
1359    0x00, 0x02, 'a', 'a',
1360    0x00, 0x02, 'b', 'b',
1361  };
1362  const unsigned char kV3Input[] = {
1363    0x80, spdy_version_ch_, 0x00, 0x01,  // SYN Stream #1
1364    0x00, 0x00, 0x00, 0x1a,
1365    0x00, 0x00, 0x00, 0x01,
1366    0x00, 0x00, 0x00, 0x00,
1367    0x00, 0x00, 0x00, 0x00,
1368    0x00, 0x01, 0x00, 0x00,
1369    0x00, 0x02, 'h', 'h',
1370    0x00, 0x00, 0x00, 0x02,
1371    'v', 'v',
1372
1373    0x80, spdy_version_ch_, 0x00, 0x02,  // SYN REPLY Stream #1
1374    0x01, 0x00, 0x00, 0x14,
1375    0x00, 0x00, 0x00, 0x01,
1376    0x00, 0x00, 0x00, 0x01,
1377    0x00, 0x00, 0x00, 0x02,
1378    'a', 'a',   0x00, 0x00,
1379    0x00, 0x02, 'b', 'b',
1380  };
1381  const unsigned char kV4Input[] = {
1382    0x00, 0x1e, 0x01, 0x00,           // SYN_STREAM #1
1383    0x00, 0x00, 0x00, 0x01,
1384    0x00, 0x00, 0x00, 0x00,
1385    0x00, 0x00, 0x00, 0x00,
1386    0x00, 0x01, 0x00, 0x00,
1387    0x00, 0x02, 'h', 'h',
1388    0x00, 0x00, 0x00, 0x02,
1389    'v', 'v',
1390
1391    0x00, 0x18, 0x02, 0x01,           // SYN_REPLY #1, with FIN
1392    0x00, 0x00, 0x00, 0x01,
1393    0x00, 0x00, 0x00, 0x01,
1394    0x00, 0x00, 0x00, 0x02,
1395    'a', 'a',   0x00, 0x00,
1396    0x00, 0x02, 'b', 'b',
1397  };
1398
1399  TestSpdyVisitor visitor(spdy_version_);
1400  if (IsSpdy2()) {
1401    visitor.SimulateInFramer(kV2Input, sizeof(kV2Input));
1402  } else if (IsSpdy3()) {
1403    visitor.SimulateInFramer(kV3Input, sizeof(kV3Input));
1404  } else {
1405    visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
1406  }
1407
1408  EXPECT_EQ(0, visitor.error_count_);
1409  EXPECT_EQ(1, visitor.syn_frame_count_);
1410  EXPECT_EQ(1, visitor.syn_reply_frame_count_);
1411  EXPECT_EQ(0, visitor.headers_frame_count_);
1412  EXPECT_EQ(0, visitor.data_bytes_);
1413  EXPECT_EQ(0, visitor.fin_frame_count_);
1414  EXPECT_EQ(1, visitor.fin_flag_count_);
1415  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1416  EXPECT_EQ(0, visitor.data_frame_count_);
1417}
1418
1419TEST_P(SpdyFramerTest, HeaderCompression) {
1420  SpdyFramer send_framer(spdy_version_);
1421  SpdyFramer recv_framer(spdy_version_);
1422
1423  send_framer.set_enable_compression(true);
1424  recv_framer.set_enable_compression(true);
1425
1426  const char kHeader1[] = "header1";
1427  const char kHeader2[] = "header2";
1428  const char kHeader3[] = "header3";
1429  const char kValue1[] = "value1";
1430  const char kValue2[] = "value2";
1431  const char kValue3[] = "value3";
1432
1433  // SYN_STREAM #1
1434  SpdyHeaderBlock block;
1435  block[kHeader1] = kValue1;
1436  block[kHeader2] = kValue2;
1437  SpdyControlFlags flags(CONTROL_FLAG_NONE);
1438  SpdySynStreamIR syn_ir_1(1);
1439  syn_ir_1.SetHeader(kHeader1, kValue1);
1440  syn_ir_1.SetHeader(kHeader2, kValue2);
1441  scoped_ptr<SpdyFrame> syn_frame_1(send_framer.SerializeFrame(syn_ir_1));
1442  EXPECT_TRUE(syn_frame_1.get() != NULL);
1443
1444  // SYN_STREAM #2
1445  block[kHeader3] = kValue3;
1446  scoped_ptr<SpdyFrame> syn_frame_2(
1447      send_framer.CreateSynStream(3,  // stream id
1448                                  0,  // associated stream id
1449                                  0,  // priority
1450                                  0,  // credential slot
1451                                  flags,
1452                                  true,  // compress
1453                                  &block));
1454  EXPECT_TRUE(syn_frame_2.get() != NULL);
1455
1456  // Now start decompressing
1457  scoped_ptr<SpdyFrame> decompressed;
1458  scoped_ptr<SpdyFrame> uncompressed;
1459  base::StringPiece serialized_headers;
1460  SpdyHeaderBlock decompressed_headers;
1461
1462  // Decompress SYN_STREAM #1
1463  decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1464      &recv_framer, *syn_frame_1.get()));
1465  EXPECT_TRUE(decompressed.get() != NULL);
1466  serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1467  EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1468                                                   serialized_headers.size(),
1469                                                   &decompressed_headers));
1470  EXPECT_EQ(2u, decompressed_headers.size());
1471  EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1472  EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1473
1474  // Decompress SYN_STREAM #2
1475  decompressed.reset(SpdyFramerTestUtil::DecompressFrame(
1476      &recv_framer, *syn_frame_2.get()));
1477  EXPECT_TRUE(decompressed.get() != NULL);
1478  serialized_headers = GetSerializedHeaders(decompressed.get(), send_framer);
1479  decompressed_headers.clear();
1480  EXPECT_TRUE(recv_framer.ParseHeaderBlockInBuffer(serialized_headers.data(),
1481                                                   serialized_headers.size(),
1482                                                   &decompressed_headers));
1483  EXPECT_EQ(3u, decompressed_headers.size());
1484  EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
1485  EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
1486  EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
1487}
1488
1489// Verify we don't leak when we leave streams unclosed
1490TEST_P(SpdyFramerTest, UnclosedStreamDataCompressors) {
1491  SpdyFramer send_framer(spdy_version_);
1492
1493  send_framer.set_enable_compression(true);
1494
1495  const char kHeader1[] = "header1";
1496  const char kHeader2[] = "header2";
1497  const char kValue1[] = "value1";
1498  const char kValue2[] = "value2";
1499
1500  SpdyHeaderBlock block;
1501  block[kHeader1] = kValue1;
1502  block[kHeader2] = kValue2;
1503  SpdyControlFlags flags(CONTROL_FLAG_NONE);
1504  scoped_ptr<SpdyFrame> syn_frame(
1505      send_framer.CreateSynStream(1,  // stream id
1506                                  0,  // associated stream id
1507                                  0,  // priority
1508                                  0,  // credential slot
1509                                  flags,
1510                                  true,  // compress
1511                                  &block));
1512  EXPECT_TRUE(syn_frame.get() != NULL);
1513
1514  const char bytes[] = "this is a test test test test test!";
1515  scoped_ptr<SpdyFrame> send_frame(
1516      send_framer.CreateDataFrame(
1517          1, bytes, arraysize(bytes),
1518          static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1519  EXPECT_TRUE(send_frame.get() != NULL);
1520
1521  // Run the inputs through the framer.
1522  TestSpdyVisitor visitor(spdy_version_);
1523  visitor.use_compression_ = true;
1524  const unsigned char* data;
1525  data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1526  visitor.SimulateInFramer(data, syn_frame->size());
1527  data = reinterpret_cast<const unsigned char*>(send_frame->data());
1528  visitor.SimulateInFramer(data, send_frame->size());
1529
1530  EXPECT_EQ(0, visitor.error_count_);
1531  EXPECT_EQ(1, visitor.syn_frame_count_);
1532  EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1533  EXPECT_EQ(0, visitor.headers_frame_count_);
1534  EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1535  EXPECT_EQ(0, visitor.fin_frame_count_);
1536  EXPECT_EQ(0, visitor.fin_flag_count_);
1537  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1538  EXPECT_EQ(1, visitor.data_frame_count_);
1539}
1540
1541// Verify we can decompress the stream even if handed over to the
1542// framer 1 byte at a time.
1543TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
1544  SpdyFramer send_framer(spdy_version_);
1545
1546  send_framer.set_enable_compression(true);
1547
1548  const char kHeader1[] = "header1";
1549  const char kHeader2[] = "header2";
1550  const char kValue1[] = "value1";
1551  const char kValue2[] = "value2";
1552
1553  SpdyHeaderBlock block;
1554  block[kHeader1] = kValue1;
1555  block[kHeader2] = kValue2;
1556  SpdyControlFlags flags(CONTROL_FLAG_NONE);
1557  scoped_ptr<SpdyFrame> syn_frame(
1558      send_framer.CreateSynStream(1,  // stream id
1559                                  0,  // associated stream id
1560                                  0,  // priority
1561                                  0,  // credential slot
1562                                  flags,
1563                                  true,  // compress
1564                                  &block));
1565  EXPECT_TRUE(syn_frame.get() != NULL);
1566
1567  const char bytes[] = "this is a test test test test test!";
1568  scoped_ptr<SpdyFrame> send_frame(
1569      send_framer.CreateDataFrame(
1570          1, bytes, arraysize(bytes),
1571          static_cast<SpdyDataFlags>(DATA_FLAG_FIN)));
1572  EXPECT_TRUE(send_frame.get() != NULL);
1573
1574  // Run the inputs through the framer.
1575  TestSpdyVisitor visitor(spdy_version_);
1576  visitor.use_compression_ = true;
1577  const unsigned char* data;
1578  data = reinterpret_cast<const unsigned char*>(syn_frame->data());
1579  for (size_t idx = 0; idx < syn_frame->size(); ++idx) {
1580    visitor.SimulateInFramer(data + idx, 1);
1581    ASSERT_EQ(0, visitor.error_count_);
1582  }
1583  data = reinterpret_cast<const unsigned char*>(send_frame->data());
1584  for (size_t idx = 0; idx < send_frame->size(); ++idx) {
1585    visitor.SimulateInFramer(data + idx, 1);
1586    ASSERT_EQ(0, visitor.error_count_);
1587  }
1588
1589  EXPECT_EQ(0, visitor.error_count_);
1590  EXPECT_EQ(1, visitor.syn_frame_count_);
1591  EXPECT_EQ(0, visitor.syn_reply_frame_count_);
1592  EXPECT_EQ(0, visitor.headers_frame_count_);
1593  EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
1594  EXPECT_EQ(0, visitor.fin_frame_count_);
1595  EXPECT_EQ(0, visitor.fin_flag_count_);
1596  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
1597  EXPECT_EQ(1, visitor.data_frame_count_);
1598}
1599
1600TEST_P(SpdyFramerTest, WindowUpdateFrame) {
1601  SpdyFramer framer(spdy_version_);
1602  scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x12345678));
1603
1604  const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
1605  const unsigned char kV3FrameData[] = {  // Also applies for V2.
1606    0x80, spdy_version_ch_, 0x00, 0x09,
1607    0x00, 0x00, 0x00, 0x08,
1608    0x00, 0x00, 0x00, 0x01,
1609    0x12, 0x34, 0x56, 0x78
1610  };
1611  const unsigned char kV4FrameData[] = {
1612    0x00, 0x0c, 0x09, 0x00,
1613    0x00, 0x00, 0x00, 0x01,
1614    0x12, 0x34, 0x56, 0x78
1615  };
1616
1617  if (IsSpdy4()) {
1618     CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1619  } else {
1620     CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1621  }
1622}
1623
1624TEST_P(SpdyFramerTest, CreateDataFrame) {
1625  SpdyFramer framer(spdy_version_);
1626
1627  {
1628    const char kDescription[] = "'hello' data frame, no FIN";
1629    const unsigned char kV3FrameData[] = {  // Also applies for V2.
1630      0x00, 0x00, 0x00, 0x01,
1631      0x00, 0x00, 0x00, 0x05,
1632      'h',  'e',  'l',  'l',
1633      'o'
1634    };
1635    const unsigned char kV4FrameData[] = {
1636      0x00, 0x0d, 0x00, 0x00,
1637      0x00, 0x00, 0x00, 0x01,
1638      'h',  'e',  'l',  'l',
1639      'o'
1640    };
1641    const char bytes[] = "hello";
1642
1643    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1644        1, bytes, strlen(bytes), DATA_FLAG_NONE));
1645    if (IsSpdy4()) {
1646       CompareFrame(
1647           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1648    } else {
1649       CompareFrame(
1650           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1651    }
1652
1653    SpdyDataIR data_ir(1);
1654    data_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes)));
1655    frame.reset(framer.SerializeDataFrameHeader(data_ir));
1656    CompareCharArraysWithHexError(
1657        kDescription,
1658        reinterpret_cast<const unsigned char*>(frame->data()),
1659        framer.GetDataFrameMinimumSize(),
1660        IsSpdy4() ? kV4FrameData : kV3FrameData,
1661        framer.GetDataFrameMinimumSize());
1662  }
1663
1664  {
1665    const char kDescription[] = "Data frame with negative data byte, no FIN";
1666    const unsigned char kV3FrameData[] = {  // Also applies for V2.
1667      0x00, 0x00, 0x00, 0x01,
1668      0x00, 0x00, 0x00, 0x01,
1669      0xff
1670    };
1671    const unsigned char kV4FrameData[] = {
1672      0x00, 0x09, 0x00, 0x00,
1673      0x00, 0x00, 0x00, 0x01,
1674      0xff
1675    };
1676    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1677        1, "\xff", 1, DATA_FLAG_NONE));
1678    if (IsSpdy4()) {
1679       CompareFrame(
1680           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1681    } else {
1682       CompareFrame(
1683           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1684    }
1685  }
1686
1687  {
1688    const char kDescription[] = "'hello' data frame, with FIN";
1689    const unsigned char kV3FrameData[] = {  // Also applies for V2.
1690      0x00, 0x00, 0x00, 0x01,
1691      0x01, 0x00, 0x00, 0x05,
1692      'h', 'e', 'l', 'l',
1693      'o'
1694    };
1695    const unsigned char kV4FrameData[] = {
1696      0x00, 0x0d, 0x00, 0x01,
1697      0x00, 0x00, 0x00, 0x01,
1698      'h',  'e',  'l',  'l',
1699      'o'
1700    };
1701    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1702        1, "hello", 5, DATA_FLAG_FIN));
1703    if (IsSpdy4()) {
1704       CompareFrame(
1705           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1706    } else {
1707       CompareFrame(
1708           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1709    }
1710  }
1711
1712  {
1713    const char kDescription[] = "Empty data frame";
1714    const unsigned char kV3FrameData[] = {  // Also applies for V2.
1715      0x00, 0x00, 0x00, 0x01,
1716      0x00, 0x00, 0x00, 0x00,
1717    };
1718    const unsigned char kV4FrameData[] = {
1719      0x00, 0x08, 0x00, 0x00,
1720      0x00, 0x00, 0x00, 0x01,
1721    };
1722    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1723        1, "", 0, DATA_FLAG_NONE));
1724    if (IsSpdy4()) {
1725       CompareFrame(
1726           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1727    } else {
1728       CompareFrame(
1729           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1730    }
1731  }
1732
1733  {
1734    const char kDescription[] = "Data frame with max stream ID";
1735    const unsigned char kV3FrameData[] = {  // Also applies for V2.
1736      0x7f, 0xff, 0xff, 0xff,
1737      0x01, 0x00, 0x00, 0x05,
1738      'h',  'e',  'l',  'l',
1739      'o'
1740    };
1741    const unsigned char kV4FrameData[] = {
1742      0x00, 0x0d, 0x00, 0x01,
1743      0x7f, 0xff, 0xff, 0xff,
1744      'h',  'e',  'l',  'l',
1745      'o'
1746    };
1747    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1748        0x7fffffff, "hello", 5, DATA_FLAG_FIN));
1749    if (IsSpdy4()) {
1750       CompareFrame(
1751           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1752    } else {
1753       CompareFrame(
1754           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1755    }
1756  }
1757
1758  if (!IsSpdy4()) {
1759    // This test does not apply to SPDY 4 because the max frame size is smaller
1760    // than 4MB.
1761    const char kDescription[] = "Large data frame";
1762    const int kDataSize = 4 * 1024 * 1024;  // 4 MB
1763    const string kData(kDataSize, 'A');
1764    const unsigned char kFrameHeader[] = {
1765      0x00, 0x00, 0x00, 0x01,
1766      0x01, 0x40, 0x00, 0x00,
1767    };
1768
1769    const int kFrameSize = arraysize(kFrameHeader) + kDataSize;
1770    scoped_ptr<unsigned char[]> expected_frame_data(
1771        new unsigned char[kFrameSize]);
1772    memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader));
1773    memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize);
1774
1775    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
1776        1, kData.data(), kData.size(), DATA_FLAG_FIN));
1777    CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize);
1778  }
1779}
1780
1781TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
1782  SpdyFramer framer(spdy_version_);
1783  framer.set_enable_compression(false);
1784
1785  {
1786    const char kDescription[] = "SYN_STREAM frame, lowest pri, slot 2, no FIN";
1787
1788    SpdyHeaderBlock headers;
1789    headers["bar"] = "foo";
1790    headers["foo"] = "bar";
1791
1792    const unsigned char kPri = IsSpdy2() ? 0xC0 : 0xE0;
1793    const unsigned char kCre = IsSpdy2() ? 0 : 2;
1794    const unsigned char kV2FrameData[] = {
1795      0x80, spdy_version_ch_, 0x00, 0x01,
1796      0x00, 0x00, 0x00, 0x20,
1797      0x00, 0x00, 0x00, 0x01,
1798      0x00, 0x00, 0x00, 0x00,
1799      kPri, 0x00, 0x00, 0x02,
1800      0x00, 0x03, 'b',  'a',
1801      'r',  0x00, 0x03, 'f',
1802      'o',  'o',  0x00, 0x03,
1803      'f',  'o',  'o',  0x00,
1804      0x03, 'b',  'a',  'r'
1805    };
1806    const unsigned char kV3FrameData[] = {
1807      0x80, spdy_version_ch_, 0x00, 0x01,
1808      0x00, 0x00, 0x00, 0x2a,
1809      0x00, 0x00, 0x00, 0x01,
1810      0x00, 0x00, 0x00, 0x00,
1811      kPri, kCre, 0x00, 0x00,
1812      0x00, 0x02, 0x00, 0x00,
1813      0x00, 0x03, 'b',  'a',
1814      'r',  0x00, 0x00, 0x00,
1815      0x03, 'f',  'o',  'o',
1816      0x00, 0x00, 0x00, 0x03,
1817      'f',  'o',  'o',  0x00,
1818      0x00, 0x00, 0x03, 'b',
1819      'a',  'r'
1820    };
1821    const unsigned char kV4FrameData[] = {
1822      0x00, 0x2e, 0x01, 0x00,
1823      0x00, 0x00, 0x00, 0x01,
1824      0x00, 0x00, 0x00, 0x00,
1825      kPri, kCre, 0x00, 0x00,
1826      0x00, 0x02, 0x00, 0x00,
1827      0x00, 0x03, 'b',  'a',
1828      'r',  0x00, 0x00, 0x00,
1829      0x03, 'f',  'o',  'o',
1830      0x00, 0x00, 0x00, 0x03,
1831      'f',  'o',  'o',  0x00,
1832      0x00, 0x00, 0x03, 'b',
1833      'a',  'r'
1834    };
1835    scoped_ptr<SpdyFrame> frame(
1836        framer.CreateSynStream(1,  // stream id
1837                               0,  // associated stream id
1838                               framer.GetLowestPriority(),
1839                               kCre,  // credential slot
1840                               CONTROL_FLAG_NONE,
1841                               false,  // compress
1842                               &headers));
1843    if (IsSpdy2()) {
1844      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1845    } else if (IsSpdy3()) {
1846      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1847    } else {
1848      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1849    }
1850  }
1851
1852  {
1853    const char kDescription[] =
1854        "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
1855        "max stream ID";
1856
1857    SpdyHeaderBlock headers;
1858    headers[std::string()] = "foo";
1859    headers["foo"] = "bar";
1860
1861    const unsigned char kV2FrameData[] = {
1862      0x80, spdy_version_ch_, 0x00, 0x01,
1863      0x01, 0x00, 0x00, 0x1D,
1864      0x7f, 0xff, 0xff, 0xff,
1865      0x7f, 0xff, 0xff, 0xff,
1866      0x00, 0x00, 0x00, 0x02,
1867      0x00, 0x00, 0x00, 0x03,
1868      'f',  'o',  'o',  0x00,
1869      0x03, 'f',  'o',  'o',
1870      0x00, 0x03, 'b',  'a',
1871      'r'
1872    };
1873    const unsigned char kV3FrameData[] = {
1874      0x80, spdy_version_ch_, 0x00, 0x01,
1875      0x01, 0x00, 0x00, 0x27,
1876      0x7f, 0xff, 0xff, 0xff,
1877      0x7f, 0xff, 0xff, 0xff,
1878      0x00, 0x00, 0x00, 0x00,
1879      0x00, 0x02, 0x00, 0x00,
1880      0x00, 0x00, 0x00, 0x00,
1881      0x00, 0x03, 'f',  'o',
1882      'o',  0x00, 0x00, 0x00,
1883      0x03, 'f',  'o',  'o',
1884      0x00, 0x00, 0x00, 0x03,
1885      'b',  'a',  'r'
1886    };
1887    const unsigned char kV4FrameData[] = {
1888      0x00, 0x2b, 0x01, 0x01,
1889      0x7f, 0xff, 0xff, 0xff,
1890      0x7f, 0xff, 0xff, 0xff,
1891      0x00, 0x00, 0x00, 0x00,
1892      0x00, 0x02, 0x00, 0x00,
1893      0x00, 0x00, 0x00, 0x00,
1894      0x00, 0x03, 'f',  'o',
1895      'o',  0x00, 0x00, 0x00,
1896      0x03, 'f',  'o',  'o',
1897      0x00, 0x00, 0x00, 0x03,
1898      'b',  'a',  'r'
1899    };
1900    scoped_ptr<SpdyFrame> frame(
1901        framer.CreateSynStream(0x7fffffff,  // stream id
1902                               0x7fffffff,  // associated stream id
1903                               framer.GetHighestPriority(),
1904                               0,  // credential slot
1905                               CONTROL_FLAG_FIN,
1906                               false,  // compress
1907                               &headers));
1908    if (IsSpdy2()) {
1909      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1910    } else if (IsSpdy3()) {
1911      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1912    } else {
1913      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1914    }
1915  }
1916
1917  {
1918    const char kDescription[] =
1919        "SYN_STREAM frame with a 0-length header val, high pri, FIN, "
1920        "max stream ID";
1921
1922    SpdyHeaderBlock headers;
1923    headers["bar"] = "foo";
1924    headers["foo"] = "";
1925
1926    const unsigned char kPri = IsSpdy2() ? 0x40 : 0x20;
1927    const unsigned char kV2FrameData[] = {
1928      0x80, spdy_version_ch_, 0x00, 0x01,
1929      0x01, 0x00, 0x00, 0x1D,
1930      0x7f, 0xff, 0xff, 0xff,
1931      0x7f, 0xff, 0xff, 0xff,
1932      kPri, 0x00, 0x00, 0x02,
1933      0x00, 0x03, 'b',  'a',
1934      'r',  0x00, 0x03, 'f',
1935      'o',  'o',  0x00, 0x03,
1936      'f',  'o',  'o',  0x00,
1937      0x00
1938    };
1939    const unsigned char kV3FrameData[] = {
1940      0x80, spdy_version_ch_, 0x00, 0x01,
1941      0x01, 0x00, 0x00, 0x27,
1942      0x7f, 0xff, 0xff, 0xff,
1943      0x7f, 0xff, 0xff, 0xff,
1944      kPri, 0x00, 0x00, 0x00,
1945      0x00, 0x02, 0x00, 0x00,
1946      0x00, 0x03, 'b',  'a',
1947      'r',  0x00, 0x00, 0x00,
1948      0x03, 'f',  'o',  'o',
1949      0x00, 0x00, 0x00, 0x03,
1950      'f',  'o',  'o',  0x00,
1951      0x00, 0x00, 0x00
1952    };
1953    const unsigned char kV4FrameData[] = {
1954      0x00, 0x2b, 0x01, 0x01,
1955      0x7f, 0xff, 0xff, 0xff,
1956      0x7f, 0xff, 0xff, 0xff,
1957      kPri, 0x00, 0x00, 0x00,
1958      0x00, 0x02, 0x00, 0x00,
1959      0x00, 0x03, 'b',  'a',
1960      'r',  0x00, 0x00, 0x00,
1961      0x03, 'f',  'o',  'o',
1962      0x00, 0x00, 0x00, 0x03,
1963      'f',  'o',  'o',  0x00,
1964      0x00, 0x00, 0x00
1965    };
1966    scoped_ptr<SpdyFrame> frame(
1967        framer.CreateSynStream(0x7fffffff,  // stream id
1968                               0x7fffffff,  // associated stream id
1969                               1,  // priority
1970                               0,  // credential slot
1971                               CONTROL_FLAG_FIN,
1972                               false,  // compress
1973                               &headers));
1974    if (IsSpdy2()) {
1975      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
1976    } else if (IsSpdy3()) {
1977      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
1978    } else {
1979      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
1980    }
1981  }
1982}
1983
1984// TODO(phajdan.jr): Clean up after we no longer need
1985// to workaround http://crbug.com/139744.
1986#if !defined(USE_SYSTEM_ZLIB)
1987TEST_P(SpdyFramerTest, CreateSynStreamCompressed) {
1988  SpdyFramer framer(spdy_version_);
1989  framer.set_enable_compression(true);
1990
1991  {
1992    const char kDescription[] =
1993        "SYN_STREAM frame, low pri, no FIN";
1994
1995    SpdyHeaderBlock headers;
1996    headers["bar"] = "foo";
1997    headers["foo"] = "bar";
1998
1999    const SpdyPriority priority = IsSpdy2() ? 2 : 4;
2000    const unsigned char kV2FrameData[] = {
2001      0x80, spdy_version_ch_, 0x00, 0x01,
2002      0x00, 0x00, 0x00, 0x36,
2003      0x00, 0x00, 0x00, 0x01,
2004      0x00, 0x00, 0x00, 0x00,
2005      0x80, 0x00, 0x38, 0xea,
2006      0xdf, 0xa2, 0x51, 0xb2,
2007      0x62, 0x60, 0x62, 0x60,
2008      0x4e, 0x4a, 0x2c, 0x62,
2009      0x60, 0x06, 0x08, 0xa0,
2010      0xb4, 0xfc, 0x7c, 0x80,
2011      0x00, 0x62, 0x60, 0x4e,
2012      0xcb, 0xcf, 0x67, 0x60,
2013      0x06, 0x08, 0xa0, 0xa4,
2014      0xc4, 0x22, 0x80, 0x00,
2015      0x02, 0x00, 0x00, 0x00,
2016      0xff, 0xff,
2017    };
2018    const unsigned char kV3FrameData[] = {
2019      0x80, spdy_version_ch_, 0x00, 0x01,
2020      0x00, 0x00, 0x00, 0x37,
2021      0x00, 0x00, 0x00, 0x01,
2022      0x00, 0x00, 0x00, 0x00,
2023      0x80, 0x00, 0x38, 0xEA,
2024      0xE3, 0xC6, 0xA7, 0xC2,
2025      0x02, 0xE5, 0x0E, 0x50,
2026      0xC2, 0x4B, 0x4A, 0x04,
2027      0xE5, 0x0B, 0x66, 0x80,
2028      0x00, 0x4A, 0xCB, 0xCF,
2029      0x07, 0x08, 0x20, 0x10,
2030      0x95, 0x96, 0x9F, 0x0F,
2031      0xA2, 0x00, 0x02, 0x28,
2032      0x29, 0xB1, 0x08, 0x20,
2033      0x80, 0x00, 0x00, 0x00,
2034      0x00, 0xFF, 0xFF,
2035    };
2036    const unsigned char kV4FrameData[] = {
2037      0x00, 0x3b, 0x01, 0x00,
2038      0x00, 0x00, 0x00, 0x01,
2039      0x00, 0x00, 0x00, 0x00,
2040      0x80, 0x00, 0x38, 0xea,
2041      0xe3, 0xc6, 0xa7, 0xc2,
2042      0x02, 0xe5, 0x0e, 0x50,
2043      0xc2, 0x4b, 0x4a, 0x04,
2044      0xe5, 0x0b, 0x66, 0x80,
2045      0x00, 0x4a, 0xcb, 0xcf,
2046      0x07, 0x08, 0x20, 0x10,
2047      0x95, 0x96, 0x9f, 0x0f,
2048      0xa2, 0x00, 0x02, 0x28,
2049      0x29, 0xb1, 0x08, 0x20,
2050      0x80, 0x00, 0x00, 0x00,
2051      0x00, 0xff, 0xff,
2052    };
2053    scoped_ptr<SpdyFrame> frame(
2054        framer.CreateSynStream(1,  // stream id
2055                               0,  // associated stream id
2056                               priority,
2057                               0,  // credential slot
2058                               CONTROL_FLAG_NONE,
2059                               true,  // compress
2060                               &headers));
2061    if (IsSpdy2()) {
2062      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2063    } else if (IsSpdy3()) {
2064      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2065    } else {
2066      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2067    }
2068  }
2069}
2070#endif  // !defined(USE_SYSTEM_ZLIB)
2071
2072TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
2073  SpdyFramer framer(spdy_version_);
2074  framer.set_enable_compression(false);
2075
2076  {
2077    const char kDescription[] = "SYN_REPLY frame, no FIN";
2078
2079    SpdyHeaderBlock headers;
2080    headers["bar"] = "foo";
2081    headers["foo"] = "bar";
2082
2083    const unsigned char kV2FrameData[] = {
2084      0x80, spdy_version_ch_, 0x00, 0x02,
2085      0x00, 0x00, 0x00, 0x1C,
2086      0x00, 0x00, 0x00, 0x01,
2087      0x00, 0x00, 0x00, 0x02,
2088      0x00, 0x03, 'b',  'a',
2089      'r',  0x00, 0x03, 'f',
2090      'o',  'o',  0x00, 0x03,
2091      'f',  'o',  'o',  0x00,
2092      0x03, 'b',  'a',  'r'
2093    };
2094    const unsigned char kV3FrameData[] = {
2095      0x80, spdy_version_ch_, 0x00, 0x02,
2096      0x00, 0x00, 0x00, 0x24,
2097      0x00, 0x00, 0x00, 0x01,
2098      0x00, 0x00, 0x00, 0x02,
2099      0x00, 0x00, 0x00, 0x03,
2100      'b',  'a',  'r',  0x00,
2101      0x00, 0x00, 0x03, 'f',
2102      'o',  'o',  0x00, 0x00,
2103      0x00, 0x03, 'f',  'o',
2104      'o',  0x00, 0x00, 0x00,
2105      0x03, 'b',  'a',  'r'
2106    };
2107    const unsigned char kV4FrameData[] = {
2108      0x00, 0x28, 0x02, 0x00,
2109      0x00, 0x00, 0x00, 0x01,
2110      0x00, 0x00, 0x00, 0x02,
2111      0x00, 0x00, 0x00, 0x03,
2112      'b',  'a',  'r',  0x00,
2113      0x00, 0x00, 0x03, 'f',
2114      'o',  'o',  0x00, 0x00,
2115      0x00, 0x03, 'f',  'o',
2116      'o',  0x00, 0x00, 0x00,
2117      0x03, 'b',  'a',  'r'
2118    };
2119    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2120        1, CONTROL_FLAG_NONE, false, &headers));
2121    if (IsSpdy2()) {
2122      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2123    } else if (IsSpdy3()) {
2124      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2125    } else {
2126      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2127    }
2128  }
2129
2130  {
2131    const char kDescription[] =
2132        "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
2133
2134    SpdyHeaderBlock headers;
2135    headers[std::string()] = "foo";
2136    headers["foo"] = "bar";
2137
2138    const unsigned char kV2FrameData[] = {
2139      0x80, spdy_version_ch_, 0x00, 0x02,
2140      0x01, 0x00, 0x00, 0x19,
2141      0x7f, 0xff, 0xff, 0xff,
2142      0x00, 0x00, 0x00, 0x02,
2143      0x00, 0x00, 0x00, 0x03,
2144      'f',  'o',  'o',  0x00,
2145      0x03, 'f',  'o',  'o',
2146      0x00, 0x03, 'b',  'a',
2147      'r'
2148    };
2149    const unsigned char kV3FrameData[] = {
2150      0x80, spdy_version_ch_, 0x00, 0x02,
2151      0x01, 0x00, 0x00, 0x21,
2152      0x7f, 0xff, 0xff, 0xff,
2153      0x00, 0x00, 0x00, 0x02,
2154      0x00, 0x00, 0x00, 0x00,
2155      0x00, 0x00, 0x00, 0x03,
2156      'f',  'o',  'o',  0x00,
2157      0x00, 0x00, 0x03, 'f',
2158      'o',  'o',  0x00, 0x00,
2159      0x00, 0x03, 'b',  'a',
2160      'r'
2161    };
2162    const unsigned char kV4FrameData[] = {
2163      0x00, 0x25, 0x02, 0x01,
2164      0x7f, 0xff, 0xff, 0xff,
2165      0x00, 0x00, 0x00, 0x02,
2166      0x00, 0x00, 0x00, 0x00,
2167      0x00, 0x00, 0x00, 0x03,
2168      'f',  'o',  'o',  0x00,
2169      0x00, 0x00, 0x03, 'f',
2170      'o',  'o',  0x00, 0x00,
2171      0x00, 0x03, 'b',  'a',
2172      'r'
2173    };
2174    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2175        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2176    if (IsSpdy2()) {
2177      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2178    } else if (IsSpdy3()) {
2179      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2180    } else {
2181      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2182    }
2183  }
2184
2185  {
2186    const char kDescription[] =
2187        "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
2188
2189    SpdyHeaderBlock headers;
2190    headers["bar"] = "foo";
2191    headers["foo"] = "";
2192
2193    const unsigned char kV2FrameData[] = {
2194      0x80, spdy_version_ch_, 0x00, 0x02,
2195      0x01, 0x00, 0x00, 0x19,
2196      0x7f, 0xff, 0xff, 0xff,
2197      0x00, 0x00, 0x00, 0x02,
2198      0x00, 0x03, 'b',  'a',
2199      'r',  0x00, 0x03, 'f',
2200      'o',  'o',  0x00, 0x03,
2201      'f',  'o',  'o',  0x00,
2202      0x00
2203    };
2204    const unsigned char kV3FrameData[] = {
2205      0x80, spdy_version_ch_, 0x00, 0x02,
2206      0x01, 0x00, 0x00, 0x21,
2207      0x7f, 0xff, 0xff, 0xff,
2208      0x00, 0x00, 0x00, 0x02,
2209      0x00, 0x00, 0x00, 0x03,
2210      'b',  'a',  'r',  0x00,
2211      0x00, 0x00, 0x03, 'f',
2212      'o',  'o',  0x00, 0x00,
2213      0x00, 0x03, 'f',  'o',
2214      'o',  0x00, 0x00, 0x00,
2215      0x00
2216    };
2217    const unsigned char kV4FrameData[] = {
2218      0x00, 0x25, 0x02, 0x01,
2219      0x7f, 0xff, 0xff, 0xff,
2220      0x00, 0x00, 0x00, 0x02,
2221      0x00, 0x00, 0x00, 0x03,
2222      'b',  'a',  'r',  0x00,
2223      0x00, 0x00, 0x03, 'f',
2224      'o',  'o',  0x00, 0x00,
2225      0x00, 0x03, 'f',  'o',
2226      'o',  0x00, 0x00, 0x00,
2227      0x00
2228    };
2229    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2230        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2231    if (IsSpdy2()) {
2232      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2233    } else if (IsSpdy3()) {
2234      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2235    } else {
2236      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2237    }
2238  }
2239}
2240
2241// TODO(phajdan.jr): Clean up after we no longer need
2242// to workaround http://crbug.com/139744.
2243#if !defined(USE_SYSTEM_ZLIB)
2244TEST_P(SpdyFramerTest, CreateSynReplyCompressed) {
2245  SpdyFramer framer(spdy_version_);
2246  framer.set_enable_compression(true);
2247
2248  {
2249    const char kDescription[] = "SYN_REPLY frame, no FIN";
2250
2251    SpdyHeaderBlock headers;
2252    headers["bar"] = "foo";
2253    headers["foo"] = "bar";
2254
2255    const unsigned char kV2FrameData[] = {
2256      0x80, spdy_version_ch_, 0x00, 0x02,
2257      0x00, 0x00, 0x00, 0x32,
2258      0x00, 0x00, 0x00, 0x01,
2259      0x00, 0x00, 0x38, 0xea,
2260      0xdf, 0xa2, 0x51, 0xb2,
2261      0x62, 0x60, 0x62, 0x60,
2262      0x4e, 0x4a, 0x2c, 0x62,
2263      0x60, 0x06, 0x08, 0xa0,
2264      0xb4, 0xfc, 0x7c, 0x80,
2265      0x00, 0x62, 0x60, 0x4e,
2266      0xcb, 0xcf, 0x67, 0x60,
2267      0x06, 0x08, 0xa0, 0xa4,
2268      0xc4, 0x22, 0x80, 0x00,
2269      0x02, 0x00, 0x00, 0x00,
2270      0xff, 0xff,
2271    };
2272    const unsigned char kV3FrameData[] = {
2273      0x80, spdy_version_ch_, 0x00, 0x02,
2274      0x00, 0x00, 0x00, 0x31,
2275      0x00, 0x00, 0x00, 0x01,
2276      0x38, 0xea, 0xe3, 0xc6,
2277      0xa7, 0xc2, 0x02, 0xe5,
2278      0x0e, 0x50, 0xc2, 0x4b,
2279      0x4a, 0x04, 0xe5, 0x0b,
2280      0x66, 0x80, 0x00, 0x4a,
2281      0xcb, 0xcf, 0x07, 0x08,
2282      0x20, 0x10, 0x95, 0x96,
2283      0x9f, 0x0f, 0xa2, 0x00,
2284      0x02, 0x28, 0x29, 0xb1,
2285      0x08, 0x20, 0x80, 0x00,
2286      0x00, 0x00, 0x00, 0xff,
2287      0xff,
2288    };
2289    const unsigned char kV4FrameData[] = {
2290      0x00, 0x35, 0x02, 0x00,
2291      0x00, 0x00, 0x00, 0x01,
2292      0x38, 0xea, 0xe3, 0xc6,
2293      0xa7, 0xc2, 0x02, 0xe5,
2294      0x0e, 0x50, 0xc2, 0x4b,
2295      0x4a, 0x04, 0xe5, 0x0b,
2296      0x66, 0x80, 0x00, 0x4a,
2297      0xcb, 0xcf, 0x07, 0x08,
2298      0x20, 0x10, 0x95, 0x96,
2299      0x9f, 0x0f, 0xa2, 0x00,
2300      0x02, 0x28, 0x29, 0xb1,
2301      0x08, 0x20, 0x80, 0x00,
2302      0x00, 0x00, 0x00, 0xff,
2303      0xff,
2304    };
2305    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
2306        1, CONTROL_FLAG_NONE, true, &headers));
2307    if (IsSpdy2()) {
2308      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2309    } else if (IsSpdy3()) {
2310      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2311    } else {
2312      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2313    }
2314  }
2315}
2316#endif  // !defined(USE_SYSTEM_ZLIB)
2317
2318TEST_P(SpdyFramerTest, CreateRstStream) {
2319  SpdyFramer framer(spdy_version_);
2320
2321  {
2322    const char kDescription[] = "RST_STREAM frame";
2323    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2324      0x80, spdy_version_ch_, 0x00, 0x03,
2325      0x00, 0x00, 0x00, 0x08,
2326      0x00, 0x00, 0x00, 0x01,
2327      0x00, 0x00, 0x00, 0x01,
2328    };
2329    const unsigned char kV4FrameData[] = {
2330      0x00, 0x0c, 0x03, 0x00,
2331      0x00, 0x00, 0x00, 0x01,
2332      0x00, 0x00, 0x00, 0x01,
2333    };
2334    scoped_ptr<SpdyFrame> frame(
2335        framer.CreateRstStream(1, RST_STREAM_PROTOCOL_ERROR));
2336    if (IsSpdy4()) {
2337      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2338    } else {
2339      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2340    }
2341  }
2342
2343  {
2344    const char kDescription[] = "RST_STREAM frame with max stream ID";
2345    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2346      0x80, spdy_version_ch_, 0x00, 0x03,
2347      0x00, 0x00, 0x00, 0x08,
2348      0x7f, 0xff, 0xff, 0xff,
2349      0x00, 0x00, 0x00, 0x01,
2350    };
2351    const unsigned char kV4FrameData[] = {
2352      0x00, 0x0c, 0x03, 0x00,
2353      0x7f, 0xff, 0xff, 0xff,
2354      0x00, 0x00, 0x00, 0x01,
2355    };
2356    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
2357        0x7FFFFFFF, RST_STREAM_PROTOCOL_ERROR));
2358    if (IsSpdy4()) {
2359      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2360    } else {
2361      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2362    }
2363  }
2364
2365  {
2366    const char kDescription[] = "RST_STREAM frame with max status code";
2367    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2368      0x80, spdy_version_ch_, 0x00, 0x03,
2369      0x00, 0x00, 0x00, 0x08,
2370      0x7f, 0xff, 0xff, 0xff,
2371      0x00, 0x00, 0x00, 0x06,
2372    };
2373    const unsigned char kV4FrameData[] = {
2374      0x00, 0x0c, 0x03, 0x00,
2375      0x7f, 0xff, 0xff, 0xff,
2376      0x00, 0x00, 0x00, 0x06,
2377    };
2378    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(
2379        0x7FFFFFFF, RST_STREAM_INTERNAL_ERROR));
2380    if (IsSpdy4()) {
2381      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2382    } else {
2383      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2384    }
2385  }
2386}
2387
2388TEST_P(SpdyFramerTest, CreateSettings) {
2389  SpdyFramer framer(spdy_version_);
2390
2391  {
2392    const char kDescription[] = "Network byte order SETTINGS frame";
2393
2394    uint32 kValue = 0x0a0b0c0d;
2395    SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01);
2396    SpdySettingsIds kId = static_cast<SpdySettingsIds>(0x020304);
2397
2398    SettingsMap settings;
2399    settings[kId] = SettingsFlagsAndValue(kFlags, kValue);
2400
2401    EXPECT_EQ(kFlags, settings[kId].first);
2402    EXPECT_EQ(kValue, settings[kId].second);
2403
2404    const unsigned char kV2FrameData[] = {
2405      0x80, spdy_version_ch_, 0x00, 0x04,
2406      0x00, 0x00, 0x00, 0x0c,
2407      0x00, 0x00, 0x00, 0x01,
2408      0x04, 0x03, 0x02, 0x01,
2409      0x0a, 0x0b, 0x0c, 0x0d,
2410    };
2411    const unsigned char kV3FrameData[] = {
2412      0x80, spdy_version_ch_, 0x00, 0x04,
2413      0x00, 0x00, 0x00, 0x0c,
2414      0x00, 0x00, 0x00, 0x01,
2415      0x01, 0x02, 0x03, 0x04,
2416      0x0a, 0x0b, 0x0c, 0x0d,
2417    };
2418    const unsigned char kV4FrameData[] = {
2419      0x00, 0x14, 0x04, 0x00,
2420      0x00, 0x00, 0x00, 0x00,
2421      0x00, 0x00, 0x00, 0x01,
2422      0x01, 0x02, 0x03, 0x04,
2423      0x0a, 0x0b, 0x0c, 0x0d,
2424    };
2425
2426    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2427    if (IsSpdy2()) {
2428      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2429    } else if (IsSpdy3()) {
2430      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2431    } else {
2432      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2433    }
2434  }
2435
2436  {
2437    const char kDescription[] = "Basic SETTINGS frame";
2438
2439    SettingsMap settings;
2440    AddSpdySettingFromWireFormat(
2441        &settings, 0x00000000, 0x00000001);  // 1st Setting
2442    AddSpdySettingFromWireFormat(
2443        &settings, 0x01000001, 0x00000002);  // 2nd Setting
2444    AddSpdySettingFromWireFormat(
2445        &settings, 0x02000002, 0x00000003);  // 3rd Setting
2446    AddSpdySettingFromWireFormat(
2447        &settings, 0x03000003, 0xff000004);  // 4th Setting
2448
2449    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2450      0x80, spdy_version_ch_, 0x00, 0x04,
2451      0x00, 0x00, 0x00, 0x24,
2452      0x00, 0x00, 0x00, 0x04,
2453      0x00, 0x00, 0x00, 0x00,  // 1st Setting
2454      0x00, 0x00, 0x00, 0x01,
2455      0x01, 0x00, 0x00, 0x01,  // 2nd Setting
2456      0x00, 0x00, 0x00, 0x02,
2457      0x02, 0x00, 0x00, 0x02,  // 3rd Setting
2458      0x00, 0x00, 0x00, 0x03,
2459      0x03, 0x00, 0x00, 0x03,  // 4th Setting
2460      0xff, 0x00, 0x00, 0x04,
2461    };
2462    const unsigned char kV4FrameData[] = {
2463      0x00, 0x2c, 0x04, 0x00,
2464      0x00, 0x00, 0x00, 0x00,
2465      0x00, 0x00, 0x00, 0x04,
2466      0x00, 0x00, 0x00, 0x00,  // 1st Setting
2467      0x00, 0x00, 0x00, 0x01,
2468      0x01, 0x00, 0x00, 0x01,  // 2nd Setting
2469      0x00, 0x00, 0x00, 0x02,
2470      0x02, 0x00, 0x00, 0x02,  // 3rd Setting
2471      0x00, 0x00, 0x00, 0x03,
2472      0x03, 0x00, 0x00, 0x03,  // 4th Setting
2473      0xff, 0x00, 0x00, 0x04,
2474    };
2475    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2476    if (IsSpdy4()) {
2477      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2478    } else {
2479      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2480    }
2481  }
2482
2483  {
2484    const char kDescription[] = "Empty SETTINGS frame";
2485
2486    SettingsMap settings;
2487
2488    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2489      0x80, spdy_version_ch_, 0x00, 0x04,
2490      0x00, 0x00, 0x00, 0x04,
2491      0x00, 0x00, 0x00, 0x00,
2492    };
2493    const unsigned char kV4FrameData[] = {
2494      0x00, 0x0c, 0x04, 0x00,
2495      0x00, 0x00, 0x00, 0x00,
2496      0x00, 0x00, 0x00, 0x00,
2497    };
2498    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
2499    if (IsSpdy4()) {
2500      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2501    } else {
2502      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2503    }
2504  }
2505}
2506
2507TEST_P(SpdyFramerTest, CreatePingFrame) {
2508  SpdyFramer framer(spdy_version_);
2509
2510  {
2511    const char kDescription[] = "PING frame";
2512    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2513      0x80, spdy_version_ch_, 0x00, 0x06,
2514      0x00, 0x00, 0x00, 0x04,
2515      0x12, 0x34, 0x56, 0x78,
2516    };
2517    const unsigned char kV4FrameData[] = {
2518      0x00, 0x0c, 0x06, 0x00,
2519      0x00, 0x00, 0x00, 0x00,
2520      0x12, 0x34, 0x56, 0x78,
2521    };
2522    scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(0x12345678u));
2523    if (IsSpdy4()) {
2524      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2525    } else {
2526      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2527    }
2528  }
2529}
2530
2531TEST_P(SpdyFramerTest, CreateGoAway) {
2532  SpdyFramer framer(spdy_version_);
2533
2534  {
2535    const char kDescription[] = "GOAWAY frame";
2536    const unsigned char kV2FrameData[] = {
2537      0x80, spdy_version_ch_, 0x00, 0x07,
2538      0x00, 0x00, 0x00, 0x04,
2539      0x00, 0x00, 0x00, 0x00,
2540    };
2541    const unsigned char kV3FrameData[] = {
2542      0x80, spdy_version_ch_, 0x00, 0x07,
2543      0x00, 0x00, 0x00, 0x08,
2544      0x00, 0x00, 0x00, 0x00,
2545      0x00, 0x00, 0x00, 0x00,
2546    };
2547    const unsigned char kV4FrameData[] = {
2548      0x00, 0x10, 0x07, 0x00,
2549      0x00, 0x00, 0x00, 0x00,
2550      0x00, 0x00, 0x00, 0x00,
2551      0x00, 0x00, 0x00, 0x00,
2552    };
2553    scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0, GOAWAY_OK));
2554    if (IsSpdy2()) {
2555      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2556    } else if (IsSpdy3()) {
2557      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2558    } else {
2559      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2560    }
2561  }
2562
2563  {
2564    const char kDescription[] = "GOAWAY frame with max stream ID, status";
2565    const unsigned char kV2FrameData[] = {
2566      0x80, spdy_version_ch_, 0x00, 0x07,
2567      0x00, 0x00, 0x00, 0x04,
2568      0x7f, 0xff, 0xff, 0xff,
2569    };
2570    const unsigned char kV3FrameData[] = {
2571      0x80, spdy_version_ch_, 0x00, 0x07,
2572      0x00, 0x00, 0x00, 0x08,
2573      0x7f, 0xff, 0xff, 0xff,
2574      0x00, 0x00, 0x00, 0x02,
2575    };
2576    const unsigned char kV4FrameData[] = {
2577      0x00, 0x10, 0x07, 0x00,
2578      0x00, 0x00, 0x00, 0x00,
2579      0x7f, 0xff, 0xff, 0xff,
2580      0x00, 0x00, 0x00, 0x02,
2581    };
2582    scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF,
2583                                                    GOAWAY_INTERNAL_ERROR));
2584    if (IsSpdy2()) {
2585      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2586    } else if (IsSpdy3()) {
2587      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2588    } else {
2589      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2590    }
2591  }
2592}
2593
2594TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
2595  SpdyFramer framer(spdy_version_);
2596  framer.set_enable_compression(false);
2597
2598  {
2599    const char kDescription[] = "HEADERS frame, no FIN";
2600
2601    SpdyHeaderBlock headers;
2602    headers["bar"] = "foo";
2603    headers["foo"] = "bar";
2604
2605    const unsigned char kV2FrameData[] = {
2606      0x80, spdy_version_ch_, 0x00, 0x08,
2607      0x00, 0x00, 0x00, 0x1C,
2608      0x00, 0x00, 0x00, 0x01,
2609      0x00, 0x00, 0x00, 0x02,
2610      0x00, 0x03, 'b',  'a',
2611      'r',  0x00, 0x03, 'f',
2612      'o',  'o',  0x00, 0x03,
2613      'f',  'o',  'o',  0x00,
2614      0x03, 'b',  'a',  'r'
2615    };
2616    const unsigned char kV3FrameData[] = {
2617      0x80, spdy_version_ch_, 0x00, 0x08,
2618      0x00, 0x00, 0x00, 0x24,
2619      0x00, 0x00, 0x00, 0x01,
2620      0x00, 0x00, 0x00, 0x02,
2621      0x00, 0x00, 0x00, 0x03,
2622      'b',  'a',  'r',  0x00,
2623      0x00, 0x00, 0x03, 'f',
2624      'o',  'o',  0x00, 0x00,
2625      0x00, 0x03, 'f',  'o',
2626      'o',  0x00, 0x00, 0x00,
2627      0x03, 'b',  'a',  'r'
2628    };
2629    const unsigned char kV4FrameData[] = {
2630      0x00, 0x28, 0x08, 0x00,
2631      0x00, 0x00, 0x00, 0x01,
2632      0x00, 0x00, 0x00, 0x02,
2633      0x00, 0x00, 0x00, 0x03,
2634      'b',  'a',  'r',  0x00,
2635      0x00, 0x00, 0x03, 'f',
2636      'o',  'o',  0x00, 0x00,
2637      0x00, 0x03, 'f',  'o',
2638      'o',  0x00, 0x00, 0x00,
2639      0x03, 'b',  'a',  'r'
2640    };
2641    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2642        1, CONTROL_FLAG_NONE, false, &headers));
2643    if (IsSpdy2()) {
2644      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2645    } else if (IsSpdy3()) {
2646      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2647    } else {
2648      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2649    }
2650  }
2651
2652  {
2653    const char kDescription[] =
2654        "HEADERS frame with a 0-length header name, FIN, max stream ID";
2655
2656    SpdyHeaderBlock headers;
2657    headers[std::string()] = "foo";
2658    headers["foo"] = "bar";
2659
2660    const unsigned char kV2FrameData[] = {
2661      0x80, spdy_version_ch_, 0x00, 0x08,
2662      0x01, 0x00, 0x00, 0x19,
2663      0x7f, 0xff, 0xff, 0xff,
2664      0x00, 0x00, 0x00, 0x02,
2665      0x00, 0x00, 0x00, 0x03,
2666      'f',  'o',  'o',  0x00,
2667      0x03, 'f',  'o',  'o',
2668      0x00, 0x03, 'b',  'a',
2669      'r'
2670    };
2671    const unsigned char kV3FrameData[] = {
2672      0x80, spdy_version_ch_, 0x00, 0x08,
2673      0x01, 0x00, 0x00, 0x21,
2674      0x7f, 0xff, 0xff, 0xff,
2675      0x00, 0x00, 0x00, 0x02,
2676      0x00, 0x00, 0x00, 0x00,
2677      0x00, 0x00, 0x00, 0x03,
2678      'f',  'o',  'o',  0x00,
2679      0x00, 0x00, 0x03, 'f',
2680      'o',  'o',  0x00, 0x00,
2681      0x00, 0x03, 'b',  'a',
2682      'r'
2683    };
2684    const unsigned char kV4FrameData[] = {
2685      0x00, 0x25, 0x08, 0x01,
2686      0x7f, 0xff, 0xff, 0xff,
2687      0x00, 0x00, 0x00, 0x02,
2688      0x00, 0x00, 0x00, 0x00,
2689      0x00, 0x00, 0x00, 0x03,
2690      'f',  'o',  'o',  0x00,
2691      0x00, 0x00, 0x03, 'f',
2692      'o',  'o',  0x00, 0x00,
2693      0x00, 0x03, 'b',  'a',
2694      'r'
2695    };
2696    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2697        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2698    if (IsSpdy2()) {
2699      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2700    } else if (IsSpdy3()) {
2701      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2702    } else {
2703      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2704    }
2705  }
2706
2707  {
2708    const char kDescription[] =
2709        "HEADERS frame with a 0-length header val, FIN, max stream ID";
2710
2711    SpdyHeaderBlock headers;
2712    headers["bar"] = "foo";
2713    headers["foo"] = "";
2714
2715    const unsigned char kV2FrameData[] = {
2716      0x80, spdy_version_ch_, 0x00, 0x08,
2717      0x01, 0x00, 0x00, 0x19,
2718      0x7f, 0xff, 0xff, 0xff,
2719      0x00, 0x00, 0x00, 0x02,
2720      0x00, 0x03, 'b',  'a',
2721      'r',  0x00, 0x03, 'f',
2722      'o',  'o',  0x00, 0x03,
2723      'f',  'o',  'o',  0x00,
2724      0x00
2725    };
2726    const unsigned char kV3FrameData[] = {
2727      0x80, spdy_version_ch_, 0x00, 0x08,
2728      0x01, 0x00, 0x00, 0x21,
2729      0x7f, 0xff, 0xff, 0xff,
2730      0x00, 0x00, 0x00, 0x02,
2731      0x00, 0x00, 0x00, 0x03,
2732      'b',  'a',  'r',  0x00,
2733      0x00, 0x00, 0x03, 'f',
2734      'o',  'o',  0x00, 0x00,
2735      0x00, 0x03, 'f',  'o',
2736      'o',  0x00, 0x00, 0x00,
2737      0x00
2738    };
2739    const unsigned char kV4FrameData[] = {
2740      0x00, 0x25, 0x08, 0x01,
2741      0x7f, 0xff, 0xff, 0xff,
2742      0x00, 0x00, 0x00, 0x02,
2743      0x00, 0x00, 0x00, 0x03,
2744      'b',  'a',  'r',  0x00,
2745      0x00, 0x00, 0x03, 'f',
2746      'o',  'o',  0x00, 0x00,
2747      0x00, 0x03, 'f',  'o',
2748      'o',  0x00, 0x00, 0x00,
2749      0x00
2750    };
2751    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2752        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
2753    if (IsSpdy2()) {
2754      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2755    } else if (IsSpdy3()) {
2756      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2757    } else {
2758      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2759    }
2760  }
2761}
2762
2763// TODO(phajdan.jr): Clean up after we no longer need
2764// to workaround http://crbug.com/139744.
2765#if !defined(USE_SYSTEM_ZLIB)
2766TEST_P(SpdyFramerTest, CreateHeadersCompressed) {
2767  SpdyFramer framer(spdy_version_);
2768  framer.set_enable_compression(true);
2769
2770  {
2771    const char kDescription[] = "HEADERS frame, no FIN";
2772
2773    SpdyHeaderBlock headers;
2774    headers["bar"] = "foo";
2775    headers["foo"] = "bar";
2776
2777    const unsigned char kV2FrameData[] = {
2778      0x80, spdy_version_ch_, 0x00, 0x08,
2779      0x00, 0x00, 0x00, 0x32,
2780      0x00, 0x00, 0x00, 0x01,
2781      0x00, 0x00, 0x38, 0xea,
2782      0xdf, 0xa2, 0x51, 0xb2,
2783      0x62, 0x60, 0x62, 0x60,
2784      0x4e, 0x4a, 0x2c, 0x62,
2785      0x60, 0x06, 0x08, 0xa0,
2786      0xb4, 0xfc, 0x7c, 0x80,
2787      0x00, 0x62, 0x60, 0x4e,
2788      0xcb, 0xcf, 0x67, 0x60,
2789      0x06, 0x08, 0xa0, 0xa4,
2790      0xc4, 0x22, 0x80, 0x00,
2791      0x02, 0x00, 0x00, 0x00,
2792      0xff, 0xff,
2793    };
2794    const unsigned char kV3FrameData[] = {
2795      0x80, spdy_version_ch_, 0x00, 0x08,
2796      0x00, 0x00, 0x00, 0x31,
2797      0x00, 0x00, 0x00, 0x01,
2798      0x38, 0xea, 0xe3, 0xc6,
2799      0xa7, 0xc2, 0x02, 0xe5,
2800      0x0e, 0x50, 0xc2, 0x4b,
2801      0x4a, 0x04, 0xe5, 0x0b,
2802      0x66, 0x80, 0x00, 0x4a,
2803      0xcb, 0xcf, 0x07, 0x08,
2804      0x20, 0x10, 0x95, 0x96,
2805      0x9f, 0x0f, 0xa2, 0x00,
2806      0x02, 0x28, 0x29, 0xb1,
2807      0x08, 0x20, 0x80, 0x00,
2808      0x00, 0x00, 0x00, 0xff,
2809      0xff,
2810    };
2811    const unsigned char kV4FrameData[] = {
2812      0x00, 0x35, 0x08, 0x00,
2813      0x00, 0x00, 0x00, 0x01,
2814      0x38, 0xea, 0xe3, 0xc6,
2815      0xa7, 0xc2, 0x02, 0xe5,
2816      0x0e, 0x50, 0xc2, 0x4b,
2817      0x4a, 0x04, 0xe5, 0x0b,
2818      0x66, 0x80, 0x00, 0x4a,
2819      0xcb, 0xcf, 0x07, 0x08,
2820      0x20, 0x10, 0x95, 0x96,
2821      0x9f, 0x0f, 0xa2, 0x00,
2822      0x02, 0x28, 0x29, 0xb1,
2823      0x08, 0x20, 0x80, 0x00,
2824      0x00, 0x00, 0x00, 0xff,
2825      0xff
2826    };
2827    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
2828        1, CONTROL_FLAG_NONE, true, &headers));
2829    if (IsSpdy2()) {
2830      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
2831    } else if (IsSpdy3()) {
2832      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2833    } else {
2834      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2835    }
2836  }
2837}
2838#endif  // !defined(USE_SYSTEM_ZLIB)
2839
2840TEST_P(SpdyFramerTest, CreateWindowUpdate) {
2841  SpdyFramer framer(spdy_version_);
2842
2843  {
2844    const char kDescription[] = "WINDOW_UPDATE frame";
2845    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2846      0x80, spdy_version_ch_, 0x00, 0x09,
2847      0x00, 0x00, 0x00, 0x08,
2848      0x00, 0x00, 0x00, 0x01,
2849      0x00, 0x00, 0x00, 0x01,
2850    };
2851    const unsigned char kV4FrameData[] = {
2852      0x00, 0x0c, 0x09, 0x00,
2853      0x00, 0x00, 0x00, 0x01,
2854      0x00, 0x00, 0x00, 0x01,
2855    };
2856    scoped_ptr<SpdyFrame> frame(
2857        framer.CreateWindowUpdate(1, 1));
2858    if (IsSpdy4()) {
2859      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2860    } else {
2861      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2862    }
2863  }
2864
2865  {
2866    const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
2867    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2868      0x80, spdy_version_ch_, 0x00, 0x09,
2869      0x00, 0x00, 0x00, 0x08,
2870      0x7f, 0xff, 0xff, 0xff,
2871      0x00, 0x00, 0x00, 0x01,
2872    };
2873    const unsigned char kV4FrameData[] = {
2874      0x00, 0x0c, 0x09, 0x00,
2875      0x7f, 0xff, 0xff, 0xff,
2876      0x00, 0x00, 0x00, 0x01,
2877    };
2878    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
2879    if (IsSpdy4()) {
2880      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2881    } else {
2882      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2883    }
2884  }
2885
2886  {
2887    const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
2888    const unsigned char kV3FrameData[] = {  // Also applies for V2.
2889      0x80, spdy_version_ch_, 0x00, 0x09,
2890      0x00, 0x00, 0x00, 0x08,
2891      0x00, 0x00, 0x00, 0x01,
2892      0x7f, 0xff, 0xff, 0xff,
2893    };
2894    const unsigned char kV4FrameData[] = {
2895      0x00, 0x0c, 0x09, 0x00,
2896      0x00, 0x00, 0x00, 0x01,
2897      0x7f, 0xff, 0xff, 0xff,
2898    };
2899    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
2900    if (IsSpdy4()) {
2901      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
2902    } else {
2903      CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
2904    }
2905  }
2906}
2907
2908TEST_P(SpdyFramerTest, SerializeBlocked) {
2909  if (spdy_version_ < SPDY4) {
2910    return;
2911  }
2912
2913  SpdyFramer framer(spdy_version_);
2914
2915  const char kDescription[] = "BLOCKED frame";
2916  const unsigned char kFrameData[] = {
2917    0x00, 0x08, 0x0b, 0x00,
2918    0x00, 0x00, 0x00, 0x00,
2919  };
2920  SpdyBlockedIR blocked_ir(0);
2921  scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir));
2922  CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
2923
2924}
2925
2926TEST_P(SpdyFramerTest, ReadCompressedSynStreamHeaderBlock) {
2927  SpdyHeaderBlock headers;
2928  headers["aa"] = "vv";
2929  headers["bb"] = "ww";
2930  SpdyFramer framer(spdy_version_);
2931  scoped_ptr<SpdyFrame> control_frame(
2932      framer.CreateSynStream(1,                     // stream_id
2933                             0,                     // associated_stream_id
2934                             1,                     // priority
2935                             0,                     // credential_slot
2936                             CONTROL_FLAG_NONE,
2937                             true,                  // compress
2938                             &headers));
2939  EXPECT_TRUE(control_frame.get() != NULL);
2940  TestSpdyVisitor visitor(spdy_version_);
2941  visitor.use_compression_ = true;
2942  visitor.SimulateInFramer(
2943      reinterpret_cast<unsigned char*>(control_frame->data()),
2944      control_frame->size());
2945  EXPECT_EQ(1, visitor.syn_frame_count_);
2946  EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2947}
2948
2949TEST_P(SpdyFramerTest, ReadCompressedSynReplyHeaderBlock) {
2950  SpdyHeaderBlock headers;
2951  headers["alpha"] = "beta";
2952  headers["gamma"] = "delta";
2953  SpdyFramer framer(spdy_version_);
2954  scoped_ptr<SpdyFrame> control_frame(
2955      framer.CreateSynReply(1,                     // stream_id
2956                            CONTROL_FLAG_NONE,
2957                            true,                  // compress
2958                            &headers));
2959  EXPECT_TRUE(control_frame.get() != NULL);
2960  TestSpdyVisitor visitor(spdy_version_);
2961  visitor.use_compression_ = true;
2962  visitor.SimulateInFramer(
2963      reinterpret_cast<unsigned char*>(control_frame->data()),
2964      control_frame->size());
2965  EXPECT_EQ(1, visitor.syn_reply_frame_count_);
2966  EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2967}
2968
2969TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlock) {
2970  SpdyHeaderBlock headers;
2971  headers["alpha"] = "beta";
2972  headers["gamma"] = "delta";
2973  SpdyFramer framer(spdy_version_);
2974  scoped_ptr<SpdyFrame> control_frame(
2975      framer.CreateHeaders(1,                     // stream_id
2976                           CONTROL_FLAG_NONE,
2977                           true,                  // compress
2978                           &headers));
2979  EXPECT_TRUE(control_frame.get() != NULL);
2980  TestSpdyVisitor visitor(spdy_version_);
2981  visitor.use_compression_ = true;
2982  visitor.SimulateInFramer(
2983      reinterpret_cast<unsigned char*>(control_frame->data()),
2984      control_frame->size());
2985  EXPECT_EQ(1, visitor.headers_frame_count_);
2986  // control_frame_header_data_count_ depends on the random sequence
2987  // produced by rand(), so adding, removing or running single tests
2988  // alters this value.  The best we can do is assert that it happens
2989  // at least twice.
2990  EXPECT_LE(2, visitor.control_frame_header_data_count_);
2991  EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
2992  EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
2993  EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
2994}
2995
2996TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
2997  SpdyHeaderBlock headers;
2998  headers["alpha"] = "beta";
2999  headers["gamma"] = "delta";
3000  SpdyFramer framer(spdy_version_);
3001  scoped_ptr<SpdyFrame> control_frame(
3002      framer.CreateHeaders(1,                     // stream_id
3003                           CONTROL_FLAG_FIN,
3004                           true,                  // compress
3005                           &headers));
3006  EXPECT_TRUE(control_frame.get() != NULL);
3007  TestSpdyVisitor visitor(spdy_version_);
3008  visitor.use_compression_ = true;
3009  visitor.SimulateInFramer(
3010      reinterpret_cast<unsigned char*>(control_frame->data()),
3011      control_frame->size());
3012  EXPECT_EQ(1, visitor.headers_frame_count_);
3013  // control_frame_header_data_count_ depends on the random sequence
3014  // produced by rand(), so adding, removing or running single tests
3015  // alters this value.  The best we can do is assert that it happens
3016  // at least twice.
3017  EXPECT_LE(2, visitor.control_frame_header_data_count_);
3018  EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3019  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
3020  EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
3021}
3022
3023TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
3024  // First find the size of the header value in order to just reach the control
3025  // frame max size.
3026  SpdyFramer framer(spdy_version_);
3027  framer.set_enable_compression(false);
3028  SpdyHeaderBlock headers;
3029  headers["aa"] = "";
3030  scoped_ptr<SpdyFrame> control_frame(
3031      framer.CreateSynStream(1,                     // stream_id
3032                             0,                     // associated_stream_id
3033                             1,                     // priority
3034                             0,                     // credential_slot
3035                             CONTROL_FLAG_NONE,
3036                             false,                 // compress
3037                             &headers));
3038  const size_t kBigValueSize =
3039      framer.GetControlFrameBufferMaxSize() - control_frame->size();
3040
3041  // Create a frame at exatly that size.
3042  string big_value(kBigValueSize, 'x');
3043  headers["aa"] = big_value.c_str();
3044  control_frame.reset(
3045      framer.CreateSynStream(1,                     // stream_id
3046                             0,                     // associated_stream_id
3047                             1,                     // priority
3048                             0,                     // credential_slot
3049                             CONTROL_FLAG_NONE,
3050                             false,                 // compress
3051                             &headers));
3052  EXPECT_TRUE(control_frame.get() != NULL);
3053  EXPECT_EQ(framer.GetControlFrameBufferMaxSize(), control_frame->size());
3054
3055  TestSpdyVisitor visitor(spdy_version_);
3056  visitor.SimulateInFramer(
3057      reinterpret_cast<unsigned char*>(control_frame->data()),
3058      control_frame->size());
3059  EXPECT_TRUE(visitor.header_buffer_valid_);
3060  EXPECT_EQ(0, visitor.error_count_);
3061  EXPECT_EQ(1, visitor.syn_frame_count_);
3062  EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
3063  EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3064  EXPECT_LT(kBigValueSize, visitor.header_buffer_length_);
3065}
3066
3067TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
3068  // First find the size of the header value in order to just reach the control
3069  // frame max size.
3070  SpdyFramer framer(spdy_version_);
3071  framer.set_enable_compression(false);
3072  SpdyHeaderBlock headers;
3073  headers["aa"] = "";
3074  scoped_ptr<SpdyFrame> control_frame(
3075      framer.CreateSynStream(1,                     // stream_id
3076                             0,                     // associated_stream_id
3077                             1,                     // priority
3078                             0,                     // credential_slot
3079                             CONTROL_FLAG_NONE,
3080                             false,                 // compress
3081                             &headers));
3082  const size_t kBigValueSize =
3083      framer.GetControlFrameBufferMaxSize() - control_frame->size() + 1;
3084
3085  // Create a frame at exatly that size.
3086  string big_value(kBigValueSize, 'x');
3087  headers["aa"] = big_value.c_str();
3088  control_frame.reset(
3089      framer.CreateSynStream(1,                     // stream_id
3090                             0,                     // associated_stream_id
3091                             1,                     // priority
3092                             0,                     // credential_slot
3093                             CONTROL_FLAG_NONE,
3094                             false,                 // compress
3095                             &headers));
3096  EXPECT_TRUE(control_frame.get() != NULL);
3097  EXPECT_EQ(framer.GetControlFrameBufferMaxSize() + 1,
3098            control_frame->size());
3099
3100  TestSpdyVisitor visitor(spdy_version_);
3101  visitor.SimulateInFramer(
3102      reinterpret_cast<unsigned char*>(control_frame->data()),
3103      control_frame->size());
3104  EXPECT_FALSE(visitor.header_buffer_valid_);
3105  EXPECT_EQ(1, visitor.error_count_);
3106  EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
3107            visitor.framer_.error_code());
3108  EXPECT_EQ(0, visitor.syn_frame_count_);
3109  EXPECT_EQ(0u, visitor.header_buffer_length_);
3110}
3111
3112// Check that the framer stops delivering header data chunks once the visitor
3113// declares it doesn't want any more. This is important to guard against
3114// "zip bomb" types of attacks.
3115TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
3116  SpdyHeaderBlock headers;
3117  const size_t kHeaderBufferChunks = 4;
3118  const size_t kHeaderBufferSize =
3119      TestSpdyVisitor::header_data_chunk_max_size() * kHeaderBufferChunks;
3120  const size_t kBigValueSize = kHeaderBufferSize * 2;
3121  string big_value(kBigValueSize, 'x');
3122  headers["aa"] = big_value.c_str();
3123  SpdyFramer framer(spdy_version_);
3124  scoped_ptr<SpdyFrame> control_frame(
3125      framer.CreateSynStream(1,                     // stream_id
3126                             0,                     // associated_stream_id
3127                             1,                     // priority
3128                             0,                     // credential_slot
3129                             CONTROL_FLAG_FIN,      // half close
3130                             true,                  // compress
3131                             &headers));
3132  EXPECT_TRUE(control_frame.get() != NULL);
3133  TestSpdyVisitor visitor(spdy_version_);
3134  visitor.set_header_buffer_size(kHeaderBufferSize);
3135  visitor.use_compression_ = true;
3136  visitor.SimulateInFramer(
3137      reinterpret_cast<unsigned char*>(control_frame->data()),
3138      control_frame->size());
3139  EXPECT_FALSE(visitor.header_buffer_valid_);
3140  EXPECT_EQ(1, visitor.error_count_);
3141  EXPECT_EQ(SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE,
3142            visitor.framer_.error_code());
3143
3144  // The framer should have stoped delivering chunks after the visitor
3145  // signaled "stop" by returning false from OnControlFrameHeaderData().
3146  //
3147  // control_frame_header_data_count_ depends on the random sequence
3148  // produced by rand(), so adding, removing or running single tests
3149  // alters this value.  The best we can do is assert that it happens
3150  // at least kHeaderBufferChunks + 1.
3151  EXPECT_LE(kHeaderBufferChunks + 1,
3152            static_cast<unsigned>(visitor.control_frame_header_data_count_));
3153  EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
3154
3155  // The framer should not have sent half-close to the visitor.
3156  EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
3157}
3158
3159TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
3160  SpdyHeaderBlock headers;
3161  headers["aa"] = "alpha beta gamma delta";
3162  SpdyFramer framer(spdy_version_);
3163  framer.set_enable_compression(false);
3164  // Construct a SYN_STREAM control frame without compressing the header block,
3165  // and have the framer try to decompress it. This will cause the framer to
3166  // deal with a decompression error.
3167  scoped_ptr<SpdyFrame> control_frame(
3168      framer.CreateSynStream(1,                     // stream_id
3169                             0,                     // associated_stream_id
3170                             1,                     // priority
3171                             0,                     // credential_slot
3172                             CONTROL_FLAG_NONE,
3173                             false,                 // compress
3174                             &headers));
3175  TestSpdyVisitor visitor(spdy_version_);
3176  visitor.use_compression_ = true;
3177  visitor.SimulateInFramer(
3178      reinterpret_cast<unsigned char*>(control_frame->data()),
3179      control_frame->size());
3180  EXPECT_EQ(1, visitor.error_count_);
3181  EXPECT_EQ(SpdyFramer::SPDY_DECOMPRESS_FAILURE, visitor.framer_.error_code());
3182  EXPECT_EQ(0u, visitor.header_buffer_length_);
3183}
3184
3185TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
3186  // Create a GoAway frame that has a few extra bytes at the end.
3187  // We create enough overhead to overflow the framer's control frame buffer.
3188  ASSERT_GE(250u, SpdyFramer::kControlFrameBufferSize);
3189  const unsigned char length =  1 + SpdyFramer::kControlFrameBufferSize;
3190  const unsigned char kV3FrameData[] = {  // Also applies for V2.
3191    0x80, spdy_version_ch_, 0x00, 0x07,
3192    0x00, 0x00, 0x00, length,
3193    0x00, 0x00, 0x00, 0x00,
3194    0x00, 0x00, 0x00, 0x00,
3195  };
3196  const unsigned char kV4FrameData[] = {
3197    0x00, static_cast<uint8>(length + 4), 0x07, 0x00,
3198    0x00, 0x00, 0x00, 0x00,
3199    0x00, 0x00, 0x00, 0x00,
3200  };
3201  SpdyFramer framer(spdy_version_);
3202  const size_t pad_length =
3203      length + framer.GetControlFrameHeaderSize() -
3204      (IsSpdy4() ? sizeof(kV4FrameData) : sizeof(kV3FrameData));
3205  string pad('A', pad_length);
3206  TestSpdyVisitor visitor(spdy_version_);
3207
3208  if (IsSpdy4()) {
3209    visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3210  } else {
3211    visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3212  }
3213  visitor.SimulateInFramer(
3214      reinterpret_cast<const unsigned char*>(pad.c_str()),
3215      pad.length());
3216
3217  EXPECT_EQ(1, visitor.error_count_);  // This generated an error.
3218  EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME,
3219            visitor.framer_.error_code());
3220  EXPECT_EQ(0, visitor.goaway_count_);  // Frame not parsed.
3221}
3222
3223TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
3224  SpdyFramer framer(spdy_version_);
3225  SettingsMap settings;
3226  scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3227  SetFrameLength(control_frame.get(), 0, spdy_version_);
3228  TestSpdyVisitor visitor(spdy_version_);
3229  visitor.use_compression_ = false;
3230  visitor.SimulateInFramer(
3231      reinterpret_cast<unsigned char*>(control_frame->data()),
3232      framer.GetControlFrameHeaderSize());
3233  // Should generate an error, since zero-len settings frames are unsupported.
3234  EXPECT_EQ(1, visitor.error_count_);
3235}
3236
3237// Tests handling of SETTINGS frames with invalid length.
3238TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
3239  SpdyFramer framer(spdy_version_);
3240  SettingsMap settings;
3241  // Add a setting to pad the frame so that we don't get a buffer overflow when
3242  // calling SimulateInFramer() below.
3243  settings[SETTINGS_UPLOAD_BANDWIDTH] =
3244      SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, 0x00000002);
3245  scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3246  const size_t kNewLength = 5;
3247  SetFrameLength(control_frame.get(), kNewLength, spdy_version_);
3248  TestSpdyVisitor visitor(spdy_version_);
3249  visitor.use_compression_ = false;
3250  visitor.SimulateInFramer(
3251      reinterpret_cast<unsigned char*>(control_frame->data()),
3252      framer.GetControlFrameHeaderSize() + kNewLength);
3253  // Should generate an error, since zero-len settings frames are unsupported.
3254  EXPECT_EQ(1, visitor.error_count_);
3255}
3256
3257// Tests handling of SETTINGS frames larger than the frame buffer size.
3258TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
3259  SpdyFramer framer(spdy_version_);
3260  SettingsMap settings;
3261  SpdySettingsFlags flags = SETTINGS_FLAG_PLEASE_PERSIST;
3262  settings[SETTINGS_UPLOAD_BANDWIDTH] =
3263      SettingsFlagsAndValue(flags, 0x00000002);
3264  settings[SETTINGS_DOWNLOAD_BANDWIDTH] =
3265      SettingsFlagsAndValue(flags, 0x00000003);
3266  settings[SETTINGS_ROUND_TRIP_TIME] = SettingsFlagsAndValue(flags, 0x00000004);
3267  scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
3268  EXPECT_LT(SpdyFramer::kControlFrameBufferSize,
3269            control_frame->size());
3270  TestSpdyVisitor visitor(spdy_version_);
3271  visitor.use_compression_ = false;
3272
3273  // Read all at once.
3274  visitor.SimulateInFramer(
3275      reinterpret_cast<unsigned char*>(control_frame->data()),
3276      control_frame->size());
3277  EXPECT_EQ(0, visitor.error_count_);
3278  EXPECT_EQ(settings.size(), static_cast<unsigned>(visitor.setting_count_));
3279
3280  // Read data in small chunks.
3281  size_t framed_data = 0;
3282  size_t unframed_data = control_frame->size();
3283  size_t kReadChunkSize = 5;  // Read five bytes at a time.
3284  while (unframed_data > 0) {
3285    size_t to_read = min(kReadChunkSize, unframed_data);
3286    visitor.SimulateInFramer(
3287        reinterpret_cast<unsigned char*>(control_frame->data() + framed_data),
3288        to_read);
3289    unframed_data -= to_read;
3290    framed_data += to_read;
3291  }
3292  EXPECT_EQ(0, visitor.error_count_);
3293  EXPECT_EQ(settings.size() * 2, static_cast<unsigned>(visitor.setting_count_));
3294}
3295
3296// Tests handling of SETTINGS frame with duplicate entries.
3297TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
3298  SpdyFramer framer(spdy_version_);
3299
3300  const unsigned char kV2FrameData[] = {
3301    0x80, spdy_version_ch_, 0x00, 0x04,
3302    0x00, 0x00, 0x00, 0x1C,
3303    0x00, 0x00, 0x00, 0x03,
3304    0x01, 0x00, 0x00, 0x00,  // 1st Setting
3305    0x00, 0x00, 0x00, 0x02,
3306    0x01, 0x00, 0x00, 0x00,  // 2nd (duplicate) Setting
3307    0x00, 0x00, 0x00, 0x03,
3308    0x03, 0x00, 0x00, 0x00,  // 3rd (unprocessed) Setting
3309    0x00, 0x00, 0x00, 0x03,
3310  };
3311  const unsigned char kV3FrameData[] = {
3312    0x80, spdy_version_ch_, 0x00, 0x04,
3313    0x00, 0x00, 0x00, 0x1C,
3314    0x00, 0x00, 0x00, 0x03,
3315    0x00, 0x00, 0x00, 0x01,  // 1st Setting
3316    0x00, 0x00, 0x00, 0x02,
3317    0x00, 0x00, 0x00, 0x01,  // 2nd (duplicate) Setting
3318    0x00, 0x00, 0x00, 0x03,
3319    0x00, 0x00, 0x00, 0x03,  // 3rd (unprocessed) Setting
3320    0x00, 0x00, 0x00, 0x03,
3321  };
3322  const unsigned char kV4FrameData[] = {
3323    0x00, 0x24, 0x04, 0x00,
3324    0x00, 0x00, 0x00, 0x00,
3325    0x00, 0x00, 0x00, 0x03,
3326    0x00, 0x00, 0x00, 0x01,  // 1st Setting
3327    0x00, 0x00, 0x00, 0x02,
3328    0x00, 0x00, 0x00, 0x01,  // 2nd (duplicate) Setting
3329    0x00, 0x00, 0x00, 0x03,
3330    0x00, 0x00, 0x00, 0x03,  // 3rd (unprocessed) Setting
3331    0x00, 0x00, 0x00, 0x03,
3332  };
3333
3334  TestSpdyVisitor visitor(spdy_version_);
3335  visitor.use_compression_ = false;
3336  if (IsSpdy2()) {
3337    visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
3338  } else if (IsSpdy3()) {
3339    visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3340  } else {
3341    visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3342  }
3343  EXPECT_EQ(1, visitor.error_count_);
3344  EXPECT_EQ(1, visitor.setting_count_);
3345}
3346
3347// Tests handling of SETTINGS frame with entries out of order.
3348TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
3349  SpdyFramer framer(spdy_version_);
3350
3351  const unsigned char kV2FrameData[] = {
3352    0x80, spdy_version_ch_, 0x00, 0x04,
3353    0x00, 0x00, 0x00, 0x1C,
3354    0x00, 0x00, 0x00, 0x03,
3355    0x02, 0x00, 0x00, 0x00,  // 1st Setting
3356    0x00, 0x00, 0x00, 0x02,
3357    0x01, 0x00, 0x00, 0x00,  // 2nd (out of order) Setting
3358    0x00, 0x00, 0x00, 0x03,
3359    0x03, 0x00, 0x00, 0x00,  // 3rd (unprocessed) Setting
3360    0x00, 0x00, 0x00, 0x03,
3361  };
3362  const unsigned char kV3FrameData[] = {
3363    0x80, spdy_version_ch_, 0x00, 0x04,
3364    0x00, 0x00, 0x00, 0x1C,
3365    0x00, 0x00, 0x00, 0x03,
3366    0x00, 0x00, 0x00, 0x02,  // 1st Setting
3367    0x00, 0x00, 0x00, 0x02,
3368    0x00, 0x00, 0x00, 0x01,  // 2nd (out of order) Setting
3369    0x00, 0x00, 0x00, 0x03,
3370    0x00, 0x00, 0x01, 0x03,  // 3rd (unprocessed) Setting
3371    0x00, 0x00, 0x00, 0x03,
3372  };
3373  const unsigned char kV4FrameData[] = {
3374    0x00, 0x24, 0x04, 0x00,
3375    0x00, 0x00, 0x00, 0x00,
3376    0x00, 0x00, 0x00, 0x03,
3377    0x00, 0x00, 0x00, 0x02,  // 1st Setting
3378    0x00, 0x00, 0x00, 0x02,
3379    0x00, 0x00, 0x00, 0x01,  // 2nd (out of order) Setting
3380    0x00, 0x00, 0x00, 0x03,
3381    0x00, 0x00, 0x01, 0x03,  // 3rd (unprocessed) Setting
3382    0x00, 0x00, 0x00, 0x03,
3383  };
3384
3385  TestSpdyVisitor visitor(spdy_version_);
3386  visitor.use_compression_ = false;
3387  if (IsSpdy2()) {
3388    visitor.SimulateInFramer(kV2FrameData, sizeof(kV2FrameData));
3389  } else if (IsSpdy3()) {
3390    visitor.SimulateInFramer(kV3FrameData, sizeof(kV3FrameData));
3391  } else {
3392    visitor.SimulateInFramer(kV4FrameData, sizeof(kV4FrameData));
3393  }
3394  EXPECT_EQ(1, visitor.error_count_);
3395  EXPECT_EQ(1, visitor.setting_count_);
3396}
3397
3398TEST_P(SpdyFramerTest, ReadWindowUpdate) {
3399  SpdyFramer framer(spdy_version_);
3400  scoped_ptr<SpdyFrame> control_frame(
3401      framer.CreateWindowUpdate(1, 2));
3402  TestSpdyVisitor visitor(spdy_version_);
3403  visitor.SimulateInFramer(
3404      reinterpret_cast<unsigned char*>(control_frame->data()),
3405      control_frame->size());
3406  EXPECT_EQ(1u, visitor.last_window_update_stream_);
3407  EXPECT_EQ(2u, visitor.last_window_update_delta_);
3408}
3409
3410TEST_P(SpdyFramerTest, ReadCredentialFrame) {
3411  SpdyCredential credential;
3412  credential.slot = 3;
3413  credential.proof = "proof";
3414  credential.certs.push_back("a cert");
3415  credential.certs.push_back("another cert");
3416  credential.certs.push_back("final cert");
3417  SpdyFramer framer(spdy_version_);
3418  scoped_ptr<SpdyFrame> control_frame(
3419      framer.CreateCredentialFrame(credential));
3420  EXPECT_TRUE(control_frame.get() != NULL);
3421  TestSpdyVisitor visitor(spdy_version_);
3422  visitor.use_compression_ = false;
3423  visitor.SimulateInFramer(
3424      reinterpret_cast<unsigned char*>(control_frame->data()),
3425      control_frame->size());
3426  EXPECT_EQ(0, visitor.error_count_);
3427  EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(),
3428            visitor.credential_buffer_length_);
3429  EXPECT_EQ(credential.slot, visitor.credential_.slot);
3430  EXPECT_EQ(credential.proof, visitor.credential_.proof);
3431  EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
3432  for (size_t i = 0; i < credential.certs.size(); i++) {
3433    EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
3434  }
3435}
3436
3437TEST_P(SpdyFramerTest, ReadCredentialFrameOneByteAtATime) {
3438  SpdyCredential credential;
3439  credential.slot = 3;
3440  credential.proof = "proof";
3441  credential.certs.push_back("a cert");
3442  credential.certs.push_back("another cert");
3443  credential.certs.push_back("final cert");
3444  SpdyFramer framer(spdy_version_);
3445  scoped_ptr<SpdyFrame> control_frame(
3446      framer.CreateCredentialFrame(credential));
3447  EXPECT_TRUE(control_frame.get() != NULL);
3448  TestSpdyVisitor visitor(spdy_version_);
3449  visitor.use_compression_ = false;
3450  // Read one byte at a time to make sure we handle edge cases
3451  unsigned char* data =
3452      reinterpret_cast<unsigned char*>(control_frame->data());
3453  for (size_t idx = 0; idx < control_frame->size(); ++idx) {
3454    visitor.SimulateInFramer(data + idx, 1);
3455    ASSERT_EQ(0, visitor.error_count_);
3456  }
3457  EXPECT_EQ(0, visitor.error_count_);
3458  EXPECT_EQ(control_frame->size() - framer.GetControlFrameHeaderSize(),
3459            visitor.credential_buffer_length_);
3460  EXPECT_EQ(credential.slot, visitor.credential_.slot);
3461  EXPECT_EQ(credential.proof, visitor.credential_.proof);
3462  EXPECT_EQ(credential.certs.size(), visitor.credential_.certs.size());
3463  for (size_t i = 0; i < credential.certs.size(); i++) {
3464    EXPECT_EQ(credential.certs[i], visitor.credential_.certs[i]);
3465  }
3466}
3467
3468TEST_P(SpdyFramerTest, ReadCredentialFrameWithNoPayload) {
3469  SpdyCredential credential;
3470  credential.slot = 3;
3471  credential.proof = "proof";
3472  credential.certs.push_back("a cert");
3473  credential.certs.push_back("another cert");
3474  credential.certs.push_back("final cert");
3475  SpdyFramer framer(spdy_version_);
3476  scoped_ptr<SpdyFrame> control_frame(
3477      framer.CreateCredentialFrame(credential));
3478  EXPECT_TRUE(control_frame.get() != NULL);
3479  TestSpdyVisitor visitor(spdy_version_);
3480  visitor.use_compression_ = false;
3481  SetFrameLength(control_frame.get(), 0, spdy_version_);
3482  unsigned char* data =
3483      reinterpret_cast<unsigned char*>(control_frame->data());
3484  visitor.SimulateInFramer(data, framer.GetControlFrameHeaderSize());
3485  EXPECT_EQ(1, visitor.error_count_);
3486}
3487
3488TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptProof) {
3489  SpdyCredential credential;
3490  credential.slot = 3;
3491  credential.proof = "proof";
3492  credential.certs.push_back("a cert");
3493  credential.certs.push_back("another cert");
3494  credential.certs.push_back("final cert");
3495  SpdyFramer framer(spdy_version_);
3496  scoped_ptr<SpdyFrame> control_frame(
3497      framer.CreateCredentialFrame(credential));
3498  EXPECT_TRUE(control_frame.get() != NULL);
3499  TestSpdyVisitor visitor(spdy_version_);
3500  visitor.use_compression_ = false;
3501  unsigned char* data =
3502      reinterpret_cast<unsigned char*>(control_frame->data());
3503  size_t offset = framer.GetControlFrameHeaderSize() + 4;
3504  data[offset] = 0xFF;  // Proof length is past the end of the frame
3505  visitor.SimulateInFramer(
3506      data, control_frame->size());
3507  EXPECT_EQ(1, visitor.error_count_);
3508}
3509
3510TEST_P(SpdyFramerTest, ReadCredentialFrameWithCorruptCertificate) {
3511  SpdyCredential credential;
3512  credential.slot = 3;
3513  credential.proof = "proof";
3514  credential.certs.push_back("a cert");
3515  credential.certs.push_back("another cert");
3516  credential.certs.push_back("final cert");
3517  SpdyFramer framer(spdy_version_);
3518  scoped_ptr<SpdyFrame> control_frame(
3519      framer.CreateCredentialFrame(credential));
3520  EXPECT_TRUE(control_frame.get() != NULL);
3521  TestSpdyVisitor visitor(spdy_version_);
3522  visitor.use_compression_ = false;
3523  unsigned char* data =
3524      reinterpret_cast<unsigned char*>(control_frame->data());
3525  size_t offset = framer.GetCredentialMinimumSize() + 1;
3526  data[offset] = 0xFF;  // Proof length is past the end of the frame
3527  visitor.SimulateInFramer(
3528      data, control_frame->size());
3529  EXPECT_EQ(1, visitor.error_count_);
3530}
3531
3532TEST_P(SpdyFramerTest, ReadGarbage) {
3533  SpdyFramer framer(spdy_version_);
3534  unsigned char garbage_frame[256];
3535  memset(garbage_frame, ~0, sizeof(garbage_frame));
3536  TestSpdyVisitor visitor(spdy_version_);
3537  visitor.use_compression_ = false;
3538  visitor.SimulateInFramer(garbage_frame, sizeof(garbage_frame));
3539  EXPECT_EQ(1, visitor.error_count_);
3540}
3541
3542TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
3543  if (IsSpdy4()) {
3544    // Not valid for SPDY 4 since there is no version field.
3545    return;
3546  }
3547  SpdyFramer framer(spdy_version_);
3548  const unsigned char kFrameData[] = {
3549    0x80, spdy_version_ch_, 0xff, 0xff,
3550    0xff, 0xff, 0xff, 0xff,
3551  };
3552  TestSpdyVisitor visitor(spdy_version_);
3553  visitor.use_compression_ = false;
3554  visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
3555  EXPECT_EQ(1, visitor.error_count_);
3556}
3557
3558TEST_P(SpdyFramerTest, SizesTest) {
3559  SpdyFramer framer(spdy_version_);
3560  EXPECT_EQ(8u, framer.GetDataFrameMinimumSize());
3561  if (IsSpdy4()) {
3562    EXPECT_EQ(8u, framer.GetSynReplyMinimumSize());
3563    EXPECT_EQ(12u, framer.GetRstStreamSize());
3564    EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
3565    EXPECT_EQ(12u, framer.GetPingSize());
3566    EXPECT_EQ(16u, framer.GetGoAwaySize());
3567    EXPECT_EQ(8u, framer.GetHeadersMinimumSize());
3568    EXPECT_EQ(12u, framer.GetWindowUpdateSize());
3569    EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
3570    EXPECT_EQ(8u, framer.GetBlockedSize());
3571    EXPECT_EQ(8u, framer.GetFrameMinimumSize());
3572    EXPECT_EQ(65535u, framer.GetFrameMaximumSize());
3573    EXPECT_EQ(65527u, framer.GetDataFrameMaximumPayload());
3574  } else {
3575    EXPECT_EQ(8u, framer.GetControlFrameHeaderSize());
3576    EXPECT_EQ(18u, framer.GetSynStreamMinimumSize());
3577    EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetSynReplyMinimumSize());
3578    EXPECT_EQ(16u, framer.GetRstStreamSize());
3579    EXPECT_EQ(12u, framer.GetSettingsMinimumSize());
3580    EXPECT_EQ(12u, framer.GetPingSize());
3581    EXPECT_EQ(IsSpdy2() ? 12u : 16u, framer.GetGoAwaySize());
3582    EXPECT_EQ(IsSpdy2() ? 14u : 12u, framer.GetHeadersMinimumSize());
3583    EXPECT_EQ(16u, framer.GetWindowUpdateSize());
3584    EXPECT_EQ(10u, framer.GetCredentialMinimumSize());
3585    EXPECT_EQ(8u, framer.GetFrameMinimumSize());
3586    EXPECT_EQ(16777215u, framer.GetFrameMaximumSize());
3587    EXPECT_EQ(16777207u, framer.GetDataFrameMaximumPayload());
3588  }
3589}
3590
3591TEST_P(SpdyFramerTest, StateToStringTest) {
3592  EXPECT_STREQ("ERROR",
3593               SpdyFramer::StateToString(SpdyFramer::SPDY_ERROR));
3594  EXPECT_STREQ("AUTO_RESET",
3595               SpdyFramer::StateToString(SpdyFramer::SPDY_AUTO_RESET));
3596  EXPECT_STREQ("RESET",
3597               SpdyFramer::StateToString(SpdyFramer::SPDY_RESET));
3598  EXPECT_STREQ("READING_COMMON_HEADER",
3599               SpdyFramer::StateToString(
3600                   SpdyFramer::SPDY_READING_COMMON_HEADER));
3601  EXPECT_STREQ("CONTROL_FRAME_PAYLOAD",
3602               SpdyFramer::StateToString(
3603                   SpdyFramer::SPDY_CONTROL_FRAME_PAYLOAD));
3604  EXPECT_STREQ("IGNORE_REMAINING_PAYLOAD",
3605               SpdyFramer::StateToString(
3606                   SpdyFramer::SPDY_IGNORE_REMAINING_PAYLOAD));
3607  EXPECT_STREQ("FORWARD_STREAM_FRAME",
3608               SpdyFramer::StateToString(
3609                   SpdyFramer::SPDY_FORWARD_STREAM_FRAME));
3610  EXPECT_STREQ("SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK",
3611               SpdyFramer::StateToString(
3612                   SpdyFramer::SPDY_CONTROL_FRAME_BEFORE_HEADER_BLOCK));
3613  EXPECT_STREQ("SPDY_CONTROL_FRAME_HEADER_BLOCK",
3614               SpdyFramer::StateToString(
3615                   SpdyFramer::SPDY_CONTROL_FRAME_HEADER_BLOCK));
3616  EXPECT_STREQ("SPDY_CREDENTIAL_FRAME_PAYLOAD",
3617               SpdyFramer::StateToString(
3618                   SpdyFramer::SPDY_CREDENTIAL_FRAME_PAYLOAD));
3619  EXPECT_STREQ("SPDY_SETTINGS_FRAME_PAYLOAD",
3620               SpdyFramer::StateToString(
3621                   SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD));
3622  EXPECT_STREQ("UNKNOWN_STATE",
3623               SpdyFramer::StateToString(
3624                   SpdyFramer::SPDY_SETTINGS_FRAME_PAYLOAD + 1));
3625}
3626
3627TEST_P(SpdyFramerTest, ErrorCodeToStringTest) {
3628  EXPECT_STREQ("NO_ERROR",
3629               SpdyFramer::ErrorCodeToString(SpdyFramer::SPDY_NO_ERROR));
3630  EXPECT_STREQ("INVALID_CONTROL_FRAME",
3631               SpdyFramer::ErrorCodeToString(
3632                   SpdyFramer::SPDY_INVALID_CONTROL_FRAME));
3633  EXPECT_STREQ("CONTROL_PAYLOAD_TOO_LARGE",
3634               SpdyFramer::ErrorCodeToString(
3635                   SpdyFramer::SPDY_CONTROL_PAYLOAD_TOO_LARGE));
3636  EXPECT_STREQ("ZLIB_INIT_FAILURE",
3637               SpdyFramer::ErrorCodeToString(
3638                   SpdyFramer::SPDY_ZLIB_INIT_FAILURE));
3639  EXPECT_STREQ("UNSUPPORTED_VERSION",
3640               SpdyFramer::ErrorCodeToString(
3641                   SpdyFramer::SPDY_UNSUPPORTED_VERSION));
3642  EXPECT_STREQ("DECOMPRESS_FAILURE",
3643               SpdyFramer::ErrorCodeToString(
3644                   SpdyFramer::SPDY_DECOMPRESS_FAILURE));
3645  EXPECT_STREQ("COMPRESS_FAILURE",
3646               SpdyFramer::ErrorCodeToString(
3647                   SpdyFramer::SPDY_COMPRESS_FAILURE));
3648  EXPECT_STREQ("SPDY_INVALID_DATA_FRAME_FLAGS",
3649               SpdyFramer::ErrorCodeToString(
3650                   SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS));
3651  EXPECT_STREQ("SPDY_INVALID_CONTROL_FRAME_FLAGS",
3652               SpdyFramer::ErrorCodeToString(
3653                   SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS));
3654  EXPECT_STREQ("UNKNOWN_ERROR",
3655               SpdyFramer::ErrorCodeToString(SpdyFramer::LAST_ERROR));
3656}
3657
3658TEST_P(SpdyFramerTest, StatusCodeToStringTest) {
3659  EXPECT_STREQ("INVALID",
3660               SpdyFramer::StatusCodeToString(RST_STREAM_INVALID));
3661  EXPECT_STREQ("PROTOCOL_ERROR",
3662               SpdyFramer::StatusCodeToString(RST_STREAM_PROTOCOL_ERROR));
3663  EXPECT_STREQ("INVALID_STREAM",
3664               SpdyFramer::StatusCodeToString(RST_STREAM_INVALID_STREAM));
3665  EXPECT_STREQ("REFUSED_STREAM",
3666               SpdyFramer::StatusCodeToString(RST_STREAM_REFUSED_STREAM));
3667  EXPECT_STREQ("UNSUPPORTED_VERSION",
3668               SpdyFramer::StatusCodeToString(RST_STREAM_UNSUPPORTED_VERSION));
3669  EXPECT_STREQ("CANCEL",
3670               SpdyFramer::StatusCodeToString(RST_STREAM_CANCEL));
3671  EXPECT_STREQ("INTERNAL_ERROR",
3672               SpdyFramer::StatusCodeToString(RST_STREAM_INTERNAL_ERROR));
3673  EXPECT_STREQ("FLOW_CONTROL_ERROR",
3674               SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR));
3675  EXPECT_STREQ("UNKNOWN_STATUS",
3676               SpdyFramer::StatusCodeToString(RST_STREAM_NUM_STATUS_CODES));
3677}
3678
3679TEST_P(SpdyFramerTest, FrameTypeToStringTest) {
3680  EXPECT_STREQ("DATA",
3681               SpdyFramer::FrameTypeToString(DATA));
3682  EXPECT_STREQ("SYN_STREAM",
3683               SpdyFramer::FrameTypeToString(SYN_STREAM));
3684  EXPECT_STREQ("SYN_REPLY",
3685               SpdyFramer::FrameTypeToString(SYN_REPLY));
3686  EXPECT_STREQ("RST_STREAM",
3687               SpdyFramer::FrameTypeToString(RST_STREAM));
3688  EXPECT_STREQ("SETTINGS",
3689               SpdyFramer::FrameTypeToString(SETTINGS));
3690  EXPECT_STREQ("NOOP",
3691               SpdyFramer::FrameTypeToString(NOOP));
3692  EXPECT_STREQ("PING",
3693               SpdyFramer::FrameTypeToString(PING));
3694  EXPECT_STREQ("GOAWAY",
3695               SpdyFramer::FrameTypeToString(GOAWAY));
3696  EXPECT_STREQ("HEADERS",
3697               SpdyFramer::FrameTypeToString(HEADERS));
3698  EXPECT_STREQ("WINDOW_UPDATE",
3699               SpdyFramer::FrameTypeToString(WINDOW_UPDATE));
3700  EXPECT_STREQ("CREDENTIAL",
3701               SpdyFramer::FrameTypeToString(CREDENTIAL));
3702}
3703
3704TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
3705  if (IsSpdy4()) {
3706    // TODO(hkhalil): catch probable HTTP response in SPDY 4?
3707    return;
3708  }
3709  {
3710    testing::StrictMock<test::MockVisitor> visitor;
3711    SpdyFramer framer(spdy_version_);
3712    framer.set_visitor(&visitor);
3713
3714    EXPECT_CALL(visitor, OnError(_));
3715    framer.ProcessInput("HTTP/1.1", 8);
3716    EXPECT_TRUE(framer.probable_http_response());
3717    EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3718    EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code());
3719  }
3720  {
3721    testing::StrictMock<test::MockVisitor> visitor;
3722    SpdyFramer framer(spdy_version_);
3723    framer.set_visitor(&visitor);
3724
3725    EXPECT_CALL(visitor, OnError(_));
3726    framer.ProcessInput("HTTP/1.0", 8);
3727    EXPECT_TRUE(framer.probable_http_response());
3728    EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3729    EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code());
3730  }
3731}
3732
3733TEST_P(SpdyFramerTest, DataFrameFlags) {
3734  for (int flags = 0; flags < 256; ++flags) {
3735    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3736
3737    testing::StrictMock<test::MockVisitor> visitor;
3738    SpdyFramer framer(spdy_version_);
3739    framer.set_visitor(&visitor);
3740
3741    scoped_ptr<SpdyFrame> frame(
3742        framer.CreateDataFrame(1, "hello", 5, DATA_FLAG_NONE));
3743    SetFrameFlags(frame.get(), flags, spdy_version_);
3744
3745    if (flags & ~DATA_FLAG_FIN) {
3746      EXPECT_CALL(visitor, OnError(_));
3747    } else {
3748      EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
3749      EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
3750      if (flags & DATA_FLAG_FIN) {
3751        EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3752      }
3753    }
3754
3755    framer.ProcessInput(frame->data(), frame->size());
3756    if (flags & ~DATA_FLAG_FIN) {
3757      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3758      EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS,
3759                framer.error_code());
3760    } else {
3761      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3762      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3763    }
3764  }
3765}
3766
3767TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
3768  for (int flags = 0; flags < 256; ++flags) {
3769    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3770
3771    testing::StrictMock<test::MockVisitor> visitor;
3772    SpdyFramer framer(spdy_version_);
3773    framer.set_visitor(&visitor);
3774
3775    EXPECT_CALL(visitor, OnSynStreamCompressed(_, _));
3776
3777    SpdyHeaderBlock headers;
3778    headers["foo"] = "bar";
3779    scoped_ptr<SpdyFrame> frame(
3780        framer.CreateSynStream(8, 3, 1, 0, CONTROL_FLAG_NONE, true, &headers));
3781    SetFrameFlags(frame.get(), flags, spdy_version_);
3782
3783    if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
3784      EXPECT_CALL(visitor, OnError(_));
3785    } else {
3786      EXPECT_CALL(visitor, OnSynStream(8, 3, 1, 0, flags & CONTROL_FLAG_FIN,
3787                                       flags & CONTROL_FLAG_UNIDIRECTIONAL));
3788      EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _))
3789          .WillRepeatedly(testing::Return(true));
3790      if (flags & DATA_FLAG_FIN) {
3791        EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3792      }
3793    }
3794
3795    framer.ProcessInput(frame->data(), frame->size());
3796    if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) {
3797      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3798      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3799                framer.error_code());
3800    } else {
3801      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3802      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3803    }
3804  }
3805}
3806
3807TEST_P(SpdyFramerTest, SynReplyFrameFlags) {
3808  for (int flags = 0; flags < 256; ++flags) {
3809    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3810
3811    testing::StrictMock<test::MockVisitor> visitor;
3812    SpdyFramer framer(spdy_version_);
3813    framer.set_visitor(&visitor);
3814
3815    SpdyHeaderBlock headers;
3816    headers["foo"] = "bar";
3817    scoped_ptr<SpdyFrame> frame(
3818        framer.CreateSynReply(37, CONTROL_FLAG_NONE, true, &headers));
3819    SetFrameFlags(frame.get(), flags, spdy_version_);
3820
3821    if (flags & ~CONTROL_FLAG_FIN) {
3822      EXPECT_CALL(visitor, OnError(_));
3823    } else {
3824      EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN));
3825      EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _))
3826          .WillRepeatedly(testing::Return(true));
3827      if (flags & DATA_FLAG_FIN) {
3828        EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3829      }
3830    }
3831
3832    framer.ProcessInput(frame->data(), frame->size());
3833    if (flags & ~CONTROL_FLAG_FIN) {
3834      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3835      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3836                framer.error_code());
3837    } else {
3838      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3839      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3840    }
3841  }
3842}
3843
3844TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
3845  for (int flags = 0; flags < 256; ++flags) {
3846    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3847
3848    testing::StrictMock<test::MockVisitor> visitor;
3849    SpdyFramer framer(spdy_version_);
3850    framer.set_visitor(&visitor);
3851
3852    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(13, RST_STREAM_CANCEL));
3853    SetFrameFlags(frame.get(), flags, spdy_version_);
3854
3855    if (flags != 0) {
3856      EXPECT_CALL(visitor, OnError(_));
3857    } else {
3858      EXPECT_CALL(visitor, OnRstStream(13, RST_STREAM_CANCEL));
3859    }
3860
3861    framer.ProcessInput(frame->data(), frame->size());
3862    if (flags != 0) {
3863      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3864      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3865                framer.error_code());
3866    } else {
3867      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3868      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3869    }
3870  }
3871}
3872
3873TEST_P(SpdyFramerTest, SettingsFrameFlags) {
3874  for (int flags = 0; flags < 256; ++flags) {
3875    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3876
3877    testing::StrictMock<test::MockVisitor> visitor;
3878    SpdyFramer framer(spdy_version_);
3879    framer.set_visitor(&visitor);
3880
3881    SettingsMap settings;
3882    settings[SETTINGS_UPLOAD_BANDWIDTH] =
3883        std::make_pair(SETTINGS_FLAG_NONE, 54321);
3884    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
3885    SetFrameFlags(frame.get(), flags, spdy_version_);
3886
3887    if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
3888      EXPECT_CALL(visitor, OnError(_));
3889    } else {
3890      EXPECT_CALL(visitor, OnSettings(
3891          flags & SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS));
3892      EXPECT_CALL(visitor, OnSetting(SETTINGS_UPLOAD_BANDWIDTH,
3893                                     SETTINGS_FLAG_NONE, 54321));
3894    }
3895
3896    framer.ProcessInput(frame->data(), frame->size());
3897    if (flags & ~SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) {
3898      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3899      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3900                framer.error_code());
3901    } else {
3902      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3903      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3904    }
3905  }
3906}
3907
3908TEST_P(SpdyFramerTest, GoawayFrameFlags) {
3909  for (int flags = 0; flags < 256; ++flags) {
3910    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3911
3912    testing::StrictMock<test::MockVisitor> visitor;
3913    SpdyFramer framer(spdy_version_);
3914    framer.set_visitor(&visitor);
3915
3916    scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(97, GOAWAY_OK));
3917    SetFrameFlags(frame.get(), flags, spdy_version_);
3918
3919    if (flags != 0) {
3920      EXPECT_CALL(visitor, OnError(_));
3921    } else {
3922      EXPECT_CALL(visitor, OnGoAway(97, GOAWAY_OK));
3923    }
3924
3925    framer.ProcessInput(frame->data(), frame->size());
3926    if (flags != 0) {
3927      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3928      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3929                framer.error_code());
3930    } else {
3931      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3932      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3933    }
3934  }
3935}
3936
3937TEST_P(SpdyFramerTest, HeadersFrameFlags) {
3938  for (int flags = 0; flags < 256; ++flags) {
3939    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3940
3941    testing::StrictMock<test::MockVisitor> visitor;
3942    SpdyFramer framer(spdy_version_);
3943    framer.set_visitor(&visitor);
3944
3945    SpdyHeaderBlock headers;
3946    headers["foo"] = "bar";
3947    scoped_ptr<SpdyFrame> frame(
3948        framer.CreateHeaders(57, CONTROL_FLAG_NONE, true, &headers));
3949    SetFrameFlags(frame.get(), flags, spdy_version_);
3950
3951    if (flags & ~CONTROL_FLAG_FIN) {
3952      EXPECT_CALL(visitor, OnError(_));
3953    } else {
3954      EXPECT_CALL(visitor, OnHeaders(57, flags & CONTROL_FLAG_FIN));
3955      EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _))
3956          .WillRepeatedly(testing::Return(true));
3957      if (flags & DATA_FLAG_FIN) {
3958        EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
3959      }
3960    }
3961
3962    framer.ProcessInput(frame->data(), frame->size());
3963    if (flags & ~CONTROL_FLAG_FIN) {
3964      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3965      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3966                framer.error_code());
3967    } else {
3968      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3969      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3970    }
3971  }
3972}
3973
3974TEST_P(SpdyFramerTest, PingFrameFlags) {
3975  for (int flags = 0; flags < 256; ++flags) {
3976    SCOPED_TRACE(testing::Message() << "Flags " << flags);
3977
3978    testing::StrictMock<test::MockVisitor> visitor;
3979    SpdyFramer framer(spdy_version_);
3980    framer.set_visitor(&visitor);
3981
3982    scoped_ptr<SpdyFrame> frame(framer.CreatePingFrame(42));
3983    SetFrameFlags(frame.get(), flags, spdy_version_);
3984
3985    if (flags != 0) {
3986      EXPECT_CALL(visitor, OnError(_));
3987    } else {
3988      EXPECT_CALL(visitor, OnPing(42));
3989    }
3990
3991    framer.ProcessInput(frame->data(), frame->size());
3992    if (flags != 0) {
3993      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
3994      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
3995                framer.error_code());
3996    } else {
3997      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
3998      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
3999    }
4000  }
4001}
4002
4003TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
4004  for (int flags = 0; flags < 256; ++flags) {
4005    SCOPED_TRACE(testing::Message() << "Flags " << flags);
4006
4007    testing::StrictMock<test::MockVisitor> visitor;
4008    SpdyFramer framer(spdy_version_);
4009    framer.set_visitor(&visitor);
4010
4011    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(4, 1024));
4012    SetFrameFlags(frame.get(), flags, spdy_version_);
4013
4014    if (flags != 0) {
4015      EXPECT_CALL(visitor, OnError(_));
4016    } else {
4017      EXPECT_CALL(visitor, OnWindowUpdate(4, 1024));
4018    }
4019
4020    framer.ProcessInput(frame->data(), frame->size());
4021    if (flags != 0) {
4022      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4023      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
4024                framer.error_code());
4025    } else {
4026      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4027      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4028    }
4029  }
4030}
4031
4032TEST_P(SpdyFramerTest, CredentialFrameFlags) {
4033  for (int flags = 0; flags < 256; ++flags) {
4034    SCOPED_TRACE(testing::Message() << "Flags " << flags);
4035
4036    testing::StrictMock<test::MockVisitor> visitor;
4037    SpdyFramer framer(spdy_version_);
4038    framer.set_visitor(&visitor);
4039
4040    SpdyCredential credential;
4041    scoped_ptr<SpdyFrame> frame(framer.CreateCredentialFrame(credential));
4042    SetFrameFlags(frame.get(), flags, spdy_version_);
4043
4044    if (flags != 0) {
4045      EXPECT_CALL(visitor, OnError(_));
4046    } else {
4047      EXPECT_CALL(visitor, OnCredentialFrameData(_, _))
4048          .WillRepeatedly(testing::Return(true));
4049    }
4050
4051    framer.ProcessInput(frame->data(), frame->size());
4052    if (flags != 0) {
4053      EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
4054      EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS,
4055                framer.error_code());
4056    } else {
4057      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4058      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4059    }
4060  }
4061}
4062
4063TEST_P(SpdyFramerTest, EmptySynStream) {
4064  SpdyHeaderBlock headers;
4065
4066  testing::StrictMock<test::MockVisitor> visitor;
4067  SpdyFramer framer(spdy_version_);
4068  framer.set_visitor(&visitor);
4069
4070  EXPECT_CALL(visitor, OnSynStreamCompressed(_, _));
4071  scoped_ptr<SpdyFrame>
4072      frame(framer.CreateSynStream(1, 0, 1, 0, CONTROL_FLAG_NONE, true,
4073                                   &headers));
4074  // Adjust size to remove the name/value block.
4075  if (IsSpdy4()) {
4076    SetFrameLength(
4077        frame.get(),
4078        framer.GetSynStreamMinimumSize(),
4079        spdy_version_);
4080  } else {
4081    SetFrameLength(
4082        frame.get(),
4083        framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
4084        spdy_version_);
4085  }
4086
4087  EXPECT_CALL(visitor, OnSynStream(1, 0, 1, 0, false, false));
4088  EXPECT_CALL(visitor, OnControlFrameHeaderData(1, NULL, 0));
4089
4090  framer.ProcessInput(frame->data(), framer.GetSynStreamMinimumSize());
4091  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4092  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4093}
4094
4095TEST_P(SpdyFramerTest, SettingsFlagsAndId) {
4096  const uint32 kId = 0x020304;
4097  const uint32 kFlags = 0x01;
4098  const uint32 kWireFormat = htonl(IsSpdy2() ? 0x04030201 : 0x01020304);
4099
4100  SettingsFlagsAndId id_and_flags =
4101      SettingsFlagsAndId::FromWireFormat(spdy_version_, kWireFormat);
4102  EXPECT_EQ(kId, id_and_flags.id());
4103  EXPECT_EQ(kFlags, id_and_flags.flags());
4104  EXPECT_EQ(kWireFormat, id_and_flags.GetWireFormat(spdy_version_));
4105}
4106
4107// Test handling of a RST_STREAM with out-of-bounds status codes.
4108TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
4109  DCHECK_GE(0xff, RST_STREAM_NUM_STATUS_CODES);
4110
4111  const unsigned char kV3RstStreamInvalid[] = {
4112    0x80, spdy_version_ch_, 0x00, 0x03,
4113    0x00, 0x00, 0x00, 0x08,
4114    0x00, 0x00, 0x00, 0x01,
4115    0x00, 0x00, 0x00, RST_STREAM_INVALID
4116  };
4117  const unsigned char kV4RstStreamInvalid[] = {
4118    0x00, 0x0c, 0x03, 0x00,
4119    0x00, 0x00, 0x00, 0x01,
4120    0x00, 0x00, 0x00, RST_STREAM_INVALID
4121  };
4122
4123  const unsigned char kV3RstStreamNumStatusCodes[] = {
4124    0x80, spdy_version_ch_, 0x00, 0x03,
4125    0x00, 0x00, 0x00, 0x08,
4126    0x00, 0x00, 0x00, 0x01,
4127    0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
4128  };
4129  const unsigned char kV4RstStreamNumStatusCodes[] = {
4130    0x00, 0x0c, 0x03, 0x00,
4131    0x00, 0x00, 0x00, 0x01,
4132    0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
4133  };
4134
4135  testing::StrictMock<test::MockVisitor> visitor;
4136  SpdyFramer framer(spdy_version_);
4137  framer.set_visitor(&visitor);
4138
4139  EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
4140  if (IsSpdy4()) {
4141    framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid),
4142                        arraysize(kV4RstStreamInvalid));
4143  } else {
4144    framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid),
4145                        arraysize(kV3RstStreamInvalid));
4146  }
4147  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4148  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4149
4150  EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
4151  if (IsSpdy4()) {
4152    framer.ProcessInput(
4153        reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes),
4154        arraysize(kV4RstStreamNumStatusCodes));
4155  } else {
4156    framer.ProcessInput(
4157        reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes),
4158        arraysize(kV3RstStreamNumStatusCodes));
4159  }
4160  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4161  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4162}
4163
4164// Tests handling of a GOAWAY frame with out-of-bounds stream ID.
4165TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
4166  const unsigned char kV2FrameData[] = {
4167    0x80, spdy_version_ch_, 0x00, 0x07,
4168    0x00, 0x00, 0x00, 0x04,
4169    0xff, 0xff, 0xff, 0xff,
4170  };
4171  const unsigned char kV3FrameData[] = {
4172    0x80, spdy_version_ch_, 0x00, 0x07,
4173    0x00, 0x00, 0x00, 0x08,
4174    0xff, 0xff, 0xff, 0xff,
4175    0x00, 0x00, 0x00, 0x00,
4176  };
4177  const unsigned char kV4FrameData[] = {
4178    0x00, 0x10, 0x07, 0x00,
4179    0x00, 0x00, 0x00, 0x00,
4180    0xff, 0xff, 0xff, 0xff,
4181    0x00, 0x00, 0x00, 0x00,
4182  };
4183
4184  testing::StrictMock<test::MockVisitor> visitor;
4185  SpdyFramer framer(spdy_version_);
4186  framer.set_visitor(&visitor);
4187
4188  EXPECT_CALL(visitor, OnGoAway(0x7fffffff, GOAWAY_OK));
4189  if (IsSpdy2()) {
4190    framer.ProcessInput(reinterpret_cast<const char*>(kV2FrameData),
4191                        arraysize(kV2FrameData));
4192  } else if (IsSpdy3()) {
4193    framer.ProcessInput(reinterpret_cast<const char*>(kV3FrameData),
4194                        arraysize(kV3FrameData));
4195  } else {
4196    framer.ProcessInput(reinterpret_cast<const char*>(kV4FrameData),
4197                        arraysize(kV4FrameData));
4198  }
4199  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4200  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4201}
4202
4203TEST_P(SpdyFramerTest, OnBlocked) {
4204  if (spdy_version_ < SPDY4) {
4205    return;
4206  }
4207
4208  const SpdyStreamId kStreamId = 0;
4209
4210  testing::StrictMock<test::MockVisitor> visitor;
4211  SpdyFramer framer(spdy_version_);
4212  framer.set_visitor(&visitor);
4213
4214  EXPECT_CALL(visitor, OnBlocked(kStreamId));
4215
4216  SpdyBlockedIR blocked_ir(0);
4217  scoped_ptr<SpdySerializedFrame> frame(framer.SerializeFrame(blocked_ir));
4218  framer.ProcessInput(frame->data(), framer.GetBlockedSize());
4219
4220  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
4221  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code());
4222}
4223
4224}  // namespace net
4225