1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <algorithm>
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <iostream>
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_framer.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_protocol.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_frame_builder.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "testing/platform_test.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace spdy {
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace test {
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstd::string HexDumpWithMarks(const unsigned char* data, int length,
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             const bool* marks, int mark_length) {
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const char kHexChars[] = "0123456789ABCDEF";
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  static const int kColumns = 4;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string hex;
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (const unsigned char* row = data; length > 0;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       row += kColumns, length -= kColumns) {
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (const unsigned char *p = row; p < row + 4; ++p) {
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (p < row + length) {
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const bool mark =
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            (marks && (p - data) < mark_length && marks[p - data]);
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hex += mark ? '*' : ' ';
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hex += kHexChars[(*p & 0xf0) >> 4];
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hex += kHexChars[*p & 0x0f];
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hex += mark ? '*' : ' ';
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        hex += "    ";
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hex = hex + "  ";
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (const unsigned char *p = row; p < row + 4 && p < row + length; ++p)
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hex += (*p >= 0x20 && *p <= 0x7f) ? (*p) : '.';
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hex = hex + '\n';
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return hex;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid CompareCharArraysWithHexError(
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& description,
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char* actual,
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int actual_len,
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char* expected,
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const int expected_len) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int min_len = actual_len > expected_len ? expected_len : actual_len;
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const int max_len = actual_len > expected_len ? actual_len : expected_len;
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_array<bool> marks(new bool[max_len]);
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool identical = (actual_len == expected_len);
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < min_len; ++i) {
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (actual[i] != expected[i]) {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      marks[i] = true;
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      identical = false;
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      marks[i] = false;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = min_len; i < max_len; ++i) {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    marks[i] = true;
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (identical) return;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ADD_FAILURE()
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "Description:\n"
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << description
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "\n\nExpected:\n"
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << HexDumpWithMarks(expected, expected_len, marks.get(), max_len)
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << "\nActual:\n"
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      << HexDumpWithMarks(actual, actual_len, marks.get(), max_len);
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FramerSetEnableCompressionHelper(SpdyFramer* framer, bool compress) {
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  framer->set_enable_compression(compress);
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass TestSpdyVisitor : public SpdyFramerVisitorInterface  {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestSpdyVisitor()
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : error_count_(0),
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syn_frame_count_(0),
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      syn_reply_frame_count_(0),
89201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      headers_frame_count_(0),
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      data_bytes_(0),
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fin_frame_count_(0),
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fin_flag_count_(0),
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      zero_length_data_frame_count_(0) {
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnError(SpdyFramer* f) {
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    error_count_++;
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnStreamFrameData(SpdyStreamId stream_id,
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         const char* data,
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         size_t len) {
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (len == 0)
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++zero_length_data_frame_count_;
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    data_bytes_ += len;
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::cerr << "OnStreamFrameData(" << stream_id << ", \"";
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (len > 0) {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (size_t i = 0 ; i < len; ++i) {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::cerr << std::hex << (0xFF & (unsigned int)data[i]) << std::dec;
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::cerr << "\", " << len << ")\n";
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnControl(const SpdyControlFrame* frame) {
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool parsed_headers = false;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (frame->type()) {
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SYN_STREAM:
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(parsed_headers);
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        syn_frame_count_++;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case SYN_REPLY:
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(parsed_headers);
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        syn_reply_frame_count_++;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case RST_STREAM:
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        fin_frame_count_++;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
133201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      case HEADERS:
134201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        parsed_headers = framer_.ParseHeaderBlock(frame, &headers);
135201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        DCHECK(parsed_headers);
136201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        headers_frame_count_++;
137201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        break;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(false);  // Error!
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (frame->flags() & CONTROL_FLAG_FIN)
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++fin_flag_count_;
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1452c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  bool OnControlFrameHeaderData(SpdyStreamId stream_id,
1462c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                const char* header_data,
1472c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun                                size_t len) {
1482c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    DCHECK(false);
1492c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    return false;
1502c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1512c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
1522c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  void OnDataFrameHeader(const SpdyDataFrame* frame) {
1532c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun    DCHECK(false);
1542c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun  }
1552c4085b2006233b5e3a3fe507d62642377b5dc2eSelim Gurun
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Convenience function which runs a framer simulation with particular input.
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void SimulateInFramer(const unsigned char* input, size_t size) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    framer_.set_enable_compression(false);
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    framer_.set_visitor(this);
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    size_t input_remaining = size;
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char* input_ptr = reinterpret_cast<const char*>(input);
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    while (input_remaining > 0 &&
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // To make the tests more interesting, we feed random (amd small) chunks
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // into the framer.  This simulates getting strange-sized reads from
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // the socket.
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const size_t kMaxReadSize = 32;
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      size_t bytes_read =
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      size_t bytes_processed = framer_.ProcessInput(input_ptr, bytes_read);
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      input_remaining -= bytes_processed;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      input_ptr += bytes_processed;
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (framer_.state() == SpdyFramer::SPDY_DONE)
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        framer_.Reset();
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer_;
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Counters from the visitor callbacks.
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int error_count_;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int syn_frame_count_;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int syn_reply_frame_count_;
183201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int headers_frame_count_;
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int data_bytes_;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int fin_frame_count_;  // The count of RST_STREAM type frames received.
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int fin_flag_count_;  // The count of frames with the FIN flag set.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int zero_length_data_frame_count_;  // The count of zero-length data frames.
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace test
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace spdy
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyControlFlags;
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyControlFrame;
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyDataFrame;
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyFrame;
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyFrameBuilder;
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyFramer;
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdyHeaderBlock;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SpdySynStreamControlFrame;
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::kControlFlagMask;
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::CONTROL_FLAG_NONE;
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::DATA_FLAG_COMPRESSED;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::DATA_FLAG_FIN;
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::SYN_STREAM;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::test::CompareCharArraysWithHexError;
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::test::FramerSetEnableCompressionHelper;
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing spdy::test::TestSpdyVisitor;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace spdy {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SpdyFramerTest : public PlatformTest {
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void TearDown() {}
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch protected:
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void CompareFrame(const std::string& description,
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    const SpdyFrame& actual_frame,
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    const unsigned char* expected,
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                    const int expected_len) {
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char* actual =
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        reinterpret_cast<const unsigned char*>(actual_frame.data());
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int actual_len = actual_frame.length() + SpdyFrame::size();
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareCharArraysWithHexError(
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        description, actual, actual_len, expected, expected_len);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test that we can encode and decode a SpdyHeaderBlock.
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, HeaderBlock) {
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock headers;
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["alpha"] = "beta";
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["gamma"] = "charlie";
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Encode the header block into a SynStream frame.
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame> frame(
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &headers));
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(frame.get() != NULL);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock new_headers;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(framer.ParseHeaderBlock(frame.get(), &new_headers));
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(headers.size(), new_headers.size());
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(headers["alpha"], new_headers["alpha"]);
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(headers["gamma"], new_headers["gamma"]);
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, OutOfOrderHeaders) {
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(kControlFlagMask | 1);
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(SYN_STREAM);
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // Placeholder for the length.
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(3);  // stream_id
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // associated stream id
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(0);  // Priority.
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(2);  // Number of headers.
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock::iterator it;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("gamma");
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("gamma");
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("alpha");
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("alpha");
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // write the length
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock new_headers;
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> control_frame(frame.take());
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, WrongNumberOfHeaders) {
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame1;
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame2;
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a frame with smaller number of actual headers
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt16(kControlFlagMask | 1);
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt16(SYN_STREAM);
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt32(0);  // Placeholder for the length.
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt32(3);  // stream_id
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt16(0);  // Priority.
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt16(1);  // Wrong number of headers (underflow)
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteString("gamma");
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteString("gamma");
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteString("alpha");
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteString("alpha");
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // write the length
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame1.WriteUInt32ToOffset(4, frame1.length() - SpdyFrame::size());
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // a frame with larger number of actual headers
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt16(kControlFlagMask | 1);
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt16(SYN_STREAM);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt32(0);  // Placeholder for the length.
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt32(3);  // stream_id
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt16(0);  // Priority.
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt16(100);  // Wrong number of headers (overflow)
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteString("gamma");
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteString("gamma");
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteString("alpha");
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteString("alpha");
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // write the length
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame2.WriteUInt32ToOffset(4, frame2.length() - SpdyFrame::size());
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock new_headers;
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> syn_frame1(frame1.take());
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> syn_frame2(frame2.take());
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(syn_frame1.get(), &new_headers));
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(syn_frame2.get(), &new_headers));
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, DuplicateHeader) {
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(kControlFlagMask | 1);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(SYN_STREAM);
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // Placeholder for the length.
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(3);  // stream_id
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // associated stream id
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(0);  // Priority.
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(2);  // Number of headers.
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock::iterator it;
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("name");
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("value1");
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("name");
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("value2");
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // write the length
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock new_headers;
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> control_frame(frame.take());
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This should fail because duplicate headers are verboten by the spec.
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, MultiValueHeader) {
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFrameBuilder frame;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(kControlFlagMask | 1);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(SYN_STREAM);
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // Placeholder for the length.
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(3);  // stream_id
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32(0);  // associated stream id
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(0);  // Priority.
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt16(1);  // Number of headers.
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock::iterator it;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString("name");
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string value("value1\0value2");
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteString(value);
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // write the length
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  frame.WriteUInt32ToOffset(4, frame.length() - SpdyFrame::size());
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock new_headers;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> control_frame(frame.take());
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(framer.ParseHeaderBlock(control_frame.get(), &new_headers));
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(new_headers.find("name") != new_headers.end());
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(value, new_headers.find("name")->second);
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, ZeroLengthHeader) {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock header1;
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock header2;
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock header3;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header1[""] = "value2";
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header2["name3"] = "";
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  header3[""] = "";
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock parsed_headers;
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame> frame1(
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header1));
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(frame1.get() != NULL);
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(frame1.get(), &parsed_headers));
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame> frame2(
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header2));
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(frame2.get() != NULL);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(frame2.get(), &parsed_headers));
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame> frame3(
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true, &header3));
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(frame3.get() != NULL);
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(framer.ParseHeaderBlock(frame3.get(), &parsed_headers));
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, BasicCompression) {
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock headers;
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["server"] = "SpdyServer 1.0";
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["status"] = "200";
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["version"] = "HTTP/1.1";
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["content-type"] = "text/html";
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["content-length"] = "12";
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, true);
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame>
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    &headers));
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame>
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      frame2(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, true,
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    &headers));
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Expect the second frame to be more compact than the first.
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_LE(frame2->length(), frame1->length());
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decompress the first frame
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> frame3(framer.DecompressFrame(*frame1.get()));
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decompress the second frame
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> frame4(framer.DecompressFrame(*frame2.get()));
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Expect frames 3 & 4 to be the same.
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0,
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      memcmp(frame3->data(), frame4->data(),
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SpdyFrame::size() + frame3->length()));
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, DecompressUncompressedFrame) {
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock headers;
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["server"] = "SpdyServer 1.0";
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["date"] = "Mon 12 Jan 2009 12:12:12 PST";
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["status"] = "200";
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["version"] = "HTTP/1.1";
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["content-type"] = "text/html";
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  headers["content-length"] = "12";
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, true);
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdySynStreamControlFrame>
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      frame1(framer.CreateSynStream(1, 0, 1, CONTROL_FLAG_NONE, false,
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                    &headers));
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Decompress the frame
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> frame2(framer.DecompressFrame(*frame1.get()));
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(NULL, frame2.get());
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, Basic) {
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const unsigned char input[] = {
4573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x14,
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'h', 'h',
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'v', 'v',
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
465201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x80, 0x02, 0x00, 0x08,   // HEADERS on Stream #1
466201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x00, 0x00, 0x18,
467201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x00, 0x00, 0x01,
468201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x00, 0x00, 0x02,
469201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x02, 'h', '2',
470201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x02, 'v', '2',
471201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x02, 'h', '3',
472201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x00, 0x02, 'v', '3',
473201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x0c,
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x01,   // SYN Stream #3
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x0c,
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x03,
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x03,   // DATA on Stream #3
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x08,
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x04,
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x03,   // RST_STREAM on Stream #1
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x08,
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x03,   // DATA on Stream #3
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x03,   // RST_STREAM on Stream #3
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x08,
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x03,
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestSpdyVisitor visitor;
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visitor.SimulateInFramer(input, sizeof(input));
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.error_count_);
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(2, visitor.syn_frame_count_);
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.syn_reply_frame_count_);
515201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  EXPECT_EQ(1, visitor.headers_frame_count_);
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(24, visitor.data_bytes_);
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(2, visitor.fin_frame_count_);
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_flag_count_);
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.zero_length_data_frame_count_);
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test that the FIN flag on a data frame signifies EOF.
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, FinOnDataFrame) {
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const unsigned char input[] = {
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x14,
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'h', 'h',
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'v', 'v',
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x02,   // SYN REPLY Stream #1
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x10,
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'a', 'a',
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'b', 'b',
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x0c,
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,   // DATA on Stream #1, with EOF
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x01, 0x00, 0x00, 0x04,
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xde, 0xad, 0xbe, 0xef,
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestSpdyVisitor visitor;
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visitor.SimulateInFramer(input, sizeof(input));
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.error_count_);
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.syn_frame_count_);
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.syn_reply_frame_count_);
557201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  EXPECT_EQ(0, visitor.headers_frame_count_);
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(16, visitor.data_bytes_);
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_frame_count_);
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_flag_count_);
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Test that the FIN flag on a SYN reply frame signifies EOF.
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, FinOnSynReplyFrame) {
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const unsigned char input[] = {
5673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x01,   // SYN Stream #1
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x14,
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x00,
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'h', 'h',
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'v', 'v',
574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    0x80, 0x02, 0x00, 0x02,   // SYN REPLY Stream #1
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x01, 0x00, 0x00, 0x10,
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x00, 0x00, 0x01,
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'a', 'a',
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    0x00, 0x02, 'b', 'b',
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  };
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestSpdyVisitor visitor;
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visitor.SimulateInFramer(input, sizeof(input));
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.error_count_);
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.syn_frame_count_);
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.syn_reply_frame_count_);
589201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  EXPECT_EQ(0, visitor.headers_frame_count_);
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.data_bytes_);
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_frame_count_);
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.fin_flag_count_);
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Basic compression & decompression
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, DataCompression) {
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer send_framer;
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer recv_framer;
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&send_framer, true);
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&recv_framer, true);
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Mix up some SYNs and DATA frames since they use different compressors.
605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kHeader1[] = "header1";
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kHeader2[] = "header2";
607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kHeader3[] = "header3";
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kValue1[] = "value1";
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kValue2[] = "value2";
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kValue3[] = "value3";
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SYN_STREAM #1
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock block;
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block[kHeader1] = kValue1;
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block[kHeader2] = kValue2;
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyControlFlags flags(CONTROL_FLAG_NONE);
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<spdy::SpdyFrame> syn_frame_1(
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(syn_frame_1.get() != NULL);
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DATA #1
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char bytes[] = "this is a test test test test test!";
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> data_frame_1(
624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_framer.CreateDataFrame(1, bytes, arraysize(bytes),
625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  DATA_FLAG_COMPRESSED));
626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(data_frame_1.get() != NULL);
627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // SYN_STREAM #2
629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block[kHeader3] = kValue3;
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> syn_frame_2(
631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_framer.CreateSynStream(3, 0, 0, flags, true, &block));
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(syn_frame_2.get() != NULL);
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // DATA #2
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> data_frame_2(
636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_framer.CreateDataFrame(3, bytes, arraysize(bytes),
637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  DATA_FLAG_COMPRESSED));
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(data_frame_2.get() != NULL);
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Now start decompressing
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> decompressed;
642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyControlFrame* control_frame;
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyDataFrame* data_frame;
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock decompressed_headers;
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed.reset(recv_framer.DuplicateFrame(*syn_frame_1.get()));
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed.get() != NULL);
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed->is_control_frame());
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  control_frame = reinterpret_cast<SpdyControlFrame*>(decompressed.get());
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(SYN_STREAM, control_frame->type());
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(recv_framer.ParseHeaderBlock(
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      control_frame, &decompressed_headers));
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(2u, decompressed_headers.size());
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(SYN_STREAM, control_frame->type());
655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed.reset(recv_framer.DecompressFrame(*data_frame_1.get()));
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed.get() != NULL);
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(decompressed->is_control_frame());
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_frame = reinterpret_cast<SpdyDataFrame*>(decompressed.get());
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(arraysize(bytes), data_frame->length());
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, memcmp(data_frame->payload(), bytes, data_frame->length()));
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
665c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed.reset(recv_framer.DuplicateFrame(*syn_frame_2.get()));
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed.get() != NULL);
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed->is_control_frame());
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  control_frame = reinterpret_cast<SpdyControlFrame*>(decompressed.get());
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(control_frame->type(), SYN_STREAM);
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed_headers.clear();
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(recv_framer.ParseHeaderBlock(
672c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      control_frame, &decompressed_headers));
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(3u, decompressed_headers.size());
674c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(SYN_STREAM, control_frame->type());
675c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(kValue1, decompressed_headers[kHeader1]);
676c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(kValue2, decompressed_headers[kHeader2]);
677c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(kValue3, decompressed_headers[kHeader3]);
678c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
679c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  decompressed.reset(recv_framer.DecompressFrame(*data_frame_2.get()));
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(decompressed.get() != NULL);
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_FALSE(decompressed->is_control_frame());
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data_frame = reinterpret_cast<SpdyDataFrame*>(decompressed.get());
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(arraysize(bytes), data_frame->length());
684c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, memcmp(data_frame->payload(), bytes, data_frame->length()));
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We didn't close these streams, so the compressors should be active.
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(2, send_framer.num_stream_compressors());
688c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, send_framer.num_stream_decompressors());
689c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, recv_framer.num_stream_compressors());
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(2, recv_framer.num_stream_decompressors());
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
692c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Verify we don't leak when we leave streams unclosed
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, UnclosedStreamDataCompressors) {
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer send_framer;
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
697c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&send_framer, false);
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kHeader1[] = "header1";
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kHeader2[] = "header2";
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kValue1[] = "value1";
702c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char kValue2[] = "value2";
703c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
704c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyHeaderBlock block;
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block[kHeader1] = kValue1;
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  block[kHeader2] = kValue2;
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyControlFlags flags(CONTROL_FLAG_NONE);
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<spdy::SpdyFrame> syn_frame(
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_framer.CreateSynStream(1, 0, 0, flags, true, &block));
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(syn_frame.get() != NULL);
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const char bytes[] = "this is a test test test test test!";
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<SpdyFrame> send_frame(
714201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      send_framer.CreateDataFrame(1,
715201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                  bytes,
716201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                  arraysize(bytes),
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                  DATA_FLAG_FIN));
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_TRUE(send_frame.get() != NULL);
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Run the inputs through the framer.
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TestSpdyVisitor visitor;
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const unsigned char* data;
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data = reinterpret_cast<const unsigned char*>(syn_frame->data());
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visitor.SimulateInFramer(data, syn_frame->length() + SpdyFrame::size());
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data = reinterpret_cast<const unsigned char*>(send_frame->data());
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  visitor.SimulateInFramer(data, send_frame->length() + SpdyFrame::size());
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.error_count_);
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.syn_frame_count_);
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.syn_reply_frame_count_);
731201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  EXPECT_EQ(0, visitor.headers_frame_count_);
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_));
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_frame_count_);
734c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.fin_flag_count_);
735c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(1, visitor.zero_length_data_frame_count_);
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We closed the streams, so all compressors should be down.
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.framer_.num_stream_compressors());
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, visitor.framer_.num_stream_decompressors());
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, send_framer.num_stream_compressors());
741c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  EXPECT_EQ(0, send_framer.num_stream_decompressors());
742c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateDataFrame) {
745c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
746c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
748c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "'hello' data frame, no FIN";
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x05,
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'h', 'e', 'l', 'l',
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o'
754c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
755c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, "hello", 5, DATA_FLAG_NONE));
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "Data frame with negative data byte, no FIN";
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
763c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, "\xff", 1, DATA_FLAG_NONE));
769c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "'hello' data frame, with FIN";
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
775c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x05,
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'h', 'e', 'l', 'l',
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o'
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, "hello", 5, DATA_FLAG_FIN));
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "Empty data frame";
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
788c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
789c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, "", 0, DATA_FLAG_NONE));
793c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
794c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
795c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
796c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
797c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "Data frame with max stream ID";
798c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
799c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x05,
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'h', 'e', 'l', 'l',
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o'
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateDataFrame(
805c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0x7fffffff, "hello", 5, DATA_FLAG_FIN));
806c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateSynStreamUncompressed) {
811c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
812c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "SYN_STREAM frame, lowest pri, no FIN";
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
818c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
8223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x01,
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x20,
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xC0, 0x00, 0x00, 0x02,
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r',  0x00, 0x03, 'f',
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o',  'o',  0x00, 0x03,
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x03, 'b',  'a',  'r'
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE,
835c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        false, &headers));
836c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
837c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
838c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
839c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
840c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] =
841c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SYN_STREAM frame with a 0-length header name, highest pri, FIN, "
842c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "max stream ID";
843c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
844c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers[""] = "foo";
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
8493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x01,
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x1D,
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
853c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x03,
855c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
856c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x03, 'f',  'o',  'o',
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r'
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
860c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN,
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        false, &headers));
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] =
868c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SYN_STREAM frame with a 0-length header val, highest pri, FIN, "
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "max stream ID";
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "";
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
8763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x01,
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x1D,
878c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
879c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
881c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
882c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r',  0x00, 0x03, 'f',
883c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o',  'o',  0x00, 0x03,
884c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
885c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00
886c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
887c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
888c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0x7fffffff, 0x7fffffff, SPDY_PRIORITY_HIGHEST, CONTROL_FLAG_FIN,
889c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        false, &headers));
890c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
891c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
892c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
893c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
894c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateSynStreamCompressed) {
895c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
896c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, true);
897c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
898c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
899c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] =
900c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SYN_STREAM frame, lowest pri, no FIN";
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
9073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x01,
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x25,
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xC0, 0x00, 0x38, 0xea,
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xdf, 0xa2, 0x51, 0xb2,
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x62, 0x60, 0x62, 0x60,
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x4e, 0x4a, 0x2c, 0x62,
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x60, 0x4e, 0xcb, 0xcf,
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x87, 0x12, 0x40, 0x2e,
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0xff,
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff
919c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynStream(
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, 0, SPDY_PRIORITY_LOWEST, CONTROL_FLAG_NONE,
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        true, &headers));
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
924c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateSynReplyUncompressed) {
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, false);
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
931c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "SYN_REPLY frame, no FIN";
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
938c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
9393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x02,
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x1C,
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
943c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
944c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r',  0x00, 0x03, 'f',
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o',  'o',  0x00, 0x03,
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x03, 'b',  'a',  'r'
948c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
950c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, CONTROL_FLAG_NONE, false, &headers));
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
953c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
954c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] =
956c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SYN_REPLY frame with a 0-length header name, FIN, max stream ID";
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers[""] = "foo";
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
961c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
9633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x02,
964c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x19,
965c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
966c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
967c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x03,
968c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
969c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x03, 'f',  'o',  'o',
970c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
971c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r'
972c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
973c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
974c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
975c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
976c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
977c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
978c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
979c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] =
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "SYN_REPLY frame with a 0-length header val, FIN, max stream ID";
981c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
982c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
983c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "";
985c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
986c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
9873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x02,
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x19,
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x03, 'b',  'a',
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'r',  0x00, 0x03, 'f',
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'o',  'o',  0x00, 0x03,
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      'f',  'o',  'o',  0x00,
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1001c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1002c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateSynReplyCompressed) {
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FramerSetEnableCompressionHelper(&framer, true);
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1008c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "SYN_REPLY frame, no FIN";
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdyHeaderBlock headers;
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["bar"] = "foo";
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    headers["foo"] = "bar";
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1014c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
10153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x02,
1016c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x21,
1017c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1018c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x38, 0xea,
1019c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xdf, 0xa2, 0x51, 0xb2,
1020c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x62, 0x60, 0x62, 0x60,
1021c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x4e, 0x4a, 0x2c, 0x62,
1022c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x60, 0x4e, 0xcb, 0xcf,
1023c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x87, 0x12, 0x40, 0x2e,
1024c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0xff,
1025c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff
1026c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1027c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSynReply(
1028c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        1, CONTROL_FLAG_NONE, true, &headers));
1029c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateRstStream) {
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1035c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1036c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1037c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "RST_STREAM frame";
1038c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
10393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x03,
1040c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1041c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1042c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1043c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1044c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(1, PROTOCOL_ERROR));
1045c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1046c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1047c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1048c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1049c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "RST_STREAM frame with max stream ID";
1050c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
10513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x03,
1052c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1053c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
1054c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1055c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1056c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
1057c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       PROTOCOL_ERROR));
1058c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1059c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1060c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1061c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1062c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "RST_STREAM frame with max status code";
1063c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
10643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x03,
1065c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1066c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
1067c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x06,
1068c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateRstStream(0x7FFFFFFF,
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       INTERNAL_ERROR));
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1072c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1073c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1074c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1075c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateSettings) {
1076c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1077c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1079c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "Basic SETTINGS frame";
1080c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1081c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdySettings settings;
1082c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x00000000, 0x00000000));
1083c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0xffffffff, 0x00000001));
1084c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0xff000001, 0x00000002));
1085c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1086c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Duplicates allowed
1087c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x01000002, 0x00000003));
1088c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x01000002, 0x00000003));
1089c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1090c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x01000003, 0x000000ff));
1091c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x01000004, 0xff000001));
1092c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    settings.push_back(SpdySetting(0x01000004, 0xffffffff));
1093c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1094c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
10953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x04,
1096c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x44,
1097c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1098c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
1099c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
1100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff, 0xff, 0xff, 0xff,
1101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff, 0x00, 0x00, 0x01,
1103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x02,
1104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x02,
1105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x03,
1106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x02,
1107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x03,
1108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x03,
1109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0xff,
1110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x04,
1111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff, 0x00, 0x00, 0x01,
1112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x01, 0x00, 0x00, 0x04,
1113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0xff, 0xff, 0xff, 0xff,
1114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
1116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "Empty SETTINGS frame";
1121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SpdySettings settings;
1123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
11253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x04,
1126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x04,
1127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
1128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateSettings(settings));
1130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1134c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateNopFrame) {
1135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "NOOP frame";
1139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
11403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x05,
1141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
1142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateNopFrame());
1144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1148c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateGoAway) {
1149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "GOAWAY frame";
1153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
11543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x07,
1155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x04,
1156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x00,
1157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0));
1159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "GOAWAY frame with max stream ID";
1164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
11653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x07,
1166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x04,
1167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
1168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateGoAway(0x7FFFFFFF));
1170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1174201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochTEST_F(SpdyFramerTest, CreateHeadersUncompressed) {
1175201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFramer framer;
1176201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  FramerSetEnableCompressionHelper(&framer, false);
1177201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1178201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  {
1179201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const char kDescription[] = "HEADERS frame, no FIN";
1180201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1181201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1182201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["bar"] = "foo";
1183201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["foo"] = "bar";
1184201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1185201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const unsigned char kFrameData[] = {
1186201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x80, 0x02, 0x00, 0x08,
1187201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x1C,
1188201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x01,
1189201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x02,
1190201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x03, 'b',  'a',
1191201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'r',  0x00, 0x03, 'f',
1192201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'o',  'o',  0x00, 0x03,
1193201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'f',  'o',  'o',  0x00,
1194201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x03, 'b',  'a',  'r'
1195201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    };
1196201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1197201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        1, CONTROL_FLAG_NONE, false, &headers));
1198201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1199201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1200201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  {
1202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const char kDescription[] =
1203201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        "HEADERS frame with a 0-length header name, FIN, max stream ID";
1204201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1205201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1206201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers[""] = "foo";
1207201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["foo"] = "bar";
1208201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1209201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const unsigned char kFrameData[] = {
1210201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x80, 0x02, 0x00, 0x08,
1211201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x01, 0x00, 0x00, 0x19,
1212201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x7f, 0xff, 0xff, 0xff,
1213201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x02,
1214201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x03,
1215201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'f',  'o',  'o',  0x00,
1216201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x03, 'f',  'o',  'o',
1217201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x03, 'b',  'a',
1218201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'r'
1219201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    };
1220201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1221201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
1222201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1223201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1224201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1225201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  {
1226201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const char kDescription[] =
1227201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        "HEADERS frame with a 0-length header val, FIN, max stream ID";
1228201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1229201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1230201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["bar"] = "foo";
1231201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["foo"] = "";
1232201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1233201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const unsigned char kFrameData[] = {
1234201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x80, 0x02, 0x00, 0x08,
1235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x01, 0x00, 0x00, 0x19,
1236201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x7f, 0xff, 0xff, 0xff,
1237201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x02,
1238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x03, 'b',  'a',
1239201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'r',  0x00, 0x03, 'f',
1240201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'o',  'o',  0x00, 0x03,
1241201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      'f',  'o',  'o',  0x00,
1242201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00
1243201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    };
1244201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1245201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        0x7fffffff, CONTROL_FLAG_FIN, false, &headers));
1246201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1247201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1248201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
1249201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1250201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochTEST_F(SpdyFramerTest, CreateHeadersCompressed) {
1251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFramer framer;
1252201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  FramerSetEnableCompressionHelper(&framer, true);
1253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1254201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  {
1255201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const char kDescription[] = "HEADERS frame, no FIN";
1256201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1257201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["bar"] = "foo";
1259201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["foo"] = "bar";
1260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1261201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const unsigned char kFrameData[] = {
1262201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x80, 0x02, 0x00, 0x08,
1263201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x21,
1264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0x01,
1265201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x38, 0xea,
1266201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0xdf, 0xa2, 0x51, 0xb2,
1267201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x62, 0x60, 0x62, 0x60,
1268201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x4e, 0x4a, 0x2c, 0x62,
1269201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x60, 0x4e, 0xcb, 0xcf,
1270201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x87, 0x12, 0x40, 0x2e,
1271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0x00, 0x00, 0x00, 0xff,
1272201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      0xff
1273201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    };
1274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateHeaders(
1275201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        1, CONTROL_FLAG_NONE, true, &headers));
1276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1277201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
1279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1280c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochTEST_F(SpdyFramerTest, CreateWindowUpdate) {
1281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SpdyFramer framer;
1282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "WINDOW_UPDATE frame";
1285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
12863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x09,
1287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 1));
1292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "WINDOW_UPDATE frame with max stream ID";
1297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
12983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x09,
1299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
1301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(0x7FFFFFFF, 1));
1304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
1308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const char kDescription[] = "WINDOW_UPDATE frame with max window delta";
1309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const unsigned char kFrameData[] = {
13103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0x80, 0x02, 0x00, 0x09,
1311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x08,
1312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x00, 0x00, 0x00, 0x01,
1313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      0x7f, 0xff, 0xff, 0xff,
1314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    };
1315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<SpdyFrame> frame(framer.CreateWindowUpdate(1, 0x7FFFFFFF));
1316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
1317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1320201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// This test case reproduces conditions that caused ExpandControlFrameBuffer to
1321201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// fail to expand the buffer control frame buffer when it should have, allowing
1322201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// the framer to overrun the buffer, and smash other heap contents. This test
1323201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// relies on the debug version of the heap manager, which checks for buffer
1324201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// overrun errors during delete processing. Regression test for b/2974814.
1325201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochTEST_F(SpdyFramerTest, ExpandBuffer_HeapSmash) {
1326201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Sweep through the area of problematic values, to make sure we always cover
1327201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // the danger zone, even if it moves around at bit due to SPDY changes.
1328201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (uint16 val2_len = SpdyFramer::kControlFrameBufferInitialSize - 50;
1329201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch       val2_len < SpdyFramer::kControlFrameBufferInitialSize;
1330201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch       val2_len++) {
1331201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    std::string val2 = std::string(val2_len, 'a');
1332201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1333201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["bar"] = "foo";
1334201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["foo"] = "baz";
1335201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    headers["grue"] = val2.c_str();
1336201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyFramer framer;
1337201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdySynStreamControlFrame> template_frame(
1338201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        framer.CreateSynStream(1,                      // stream_id
1339201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               0,                      // associated_stream_id
1340201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               1,                      // priority
1341201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               CONTROL_FLAG_NONE,
1342201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               false,                  // compress
1343201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                               &headers));
1344201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    EXPECT_TRUE(template_frame.get() != NULL);
1345201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    TestSpdyVisitor visitor;
1346201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    visitor.SimulateInFramer(
1347201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        reinterpret_cast<unsigned char*>(template_frame.get()->data()),
1348201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch         template_frame.get()->length() + SpdyControlFrame::size());
1349201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    EXPECT_EQ(1, visitor.syn_frame_count_);
1350201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1351201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
1352201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1353201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstd::string RandomString(int length) {
1354201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string rv;
1355201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (int index = 0; index < length; index++)
1356201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    rv += static_cast<char>('a' + (rand() % 26));
1357201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return rv;
1358201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
1359201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1360201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Stress that we can handle a really large header block compression and
1361201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// decompression.
1362201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochTEST_F(SpdyFramerTest, HugeHeaderBlock) {
1363201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Loop targetting various sizes which will potentially jam up the
1364201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // frame compressor/decompressor.
1365201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFramer compress_framer;
1366201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SpdyFramer decompress_framer;
1367201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (size_t target_size = 1024;
1368201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch       target_size < SpdyFramer::kControlFrameBufferInitialSize;
1369201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch       target_size += 1024) {
1370201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SpdyHeaderBlock headers;
1371201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    for (size_t index = 0; index < target_size; ++index) {
1372201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string name = RandomString(4);
1373201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string value = RandomString(8);
1374201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      headers[name] = value;
1375201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
1376201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1377201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Encode the header block into a SynStream frame.
1378201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scoped_ptr<SpdySynStreamControlFrame> frame(
1379201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        compress_framer.CreateSynStream(1,
1380201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                        0,
1381201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                        1,
1382201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                        CONTROL_FLAG_NONE,
1383201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                        true,
1384201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                        &headers));
1385201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // The point of this test is to exercise the limits.  So, it is ok if the
1386201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // frame was too large to encode, or if the decompress fails.  We just want
1387201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // to make sure we don't crash.
1388201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (frame.get() != NULL) {
1389201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      // Now that same header block should decompress just fine.
1390201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      SpdyHeaderBlock new_headers;
1391201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      decompress_framer.ParseHeaderBlock(frame.get(), &new_headers);
1392201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
1393201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
1394201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
1395201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
1397