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