Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_framer_test.cc
index 30db38d..8542835 100644 (file)
@@ -11,6 +11,7 @@
 #include "net/spdy/hpack_output_stream.h"
 #include "net/spdy/mock_spdy_framer_visitor.h"
 #include "net/spdy/spdy_frame_builder.h"
+#include "net/spdy/spdy_frame_reader.h"
 #include "net/spdy/spdy_framer.h"
 #include "net/spdy/spdy_protocol.h"
 #include "net/spdy/spdy_test_utils.h"
@@ -63,15 +64,9 @@ class SpdyFramerTestUtil {
     char* buffer = visitor.ReleaseBuffer();
     CHECK(buffer != NULL);
     SpdyFrame* decompressed_frame = new SpdyFrame(buffer, visitor.size(), true);
-    if (framer->protocol_version() == 4) {
-      SetFrameLength(decompressed_frame,
-                     visitor.size(),
-                     framer->protocol_version());
-    } else {
-      SetFrameLength(decompressed_frame,
-                     visitor.size() - framer->GetControlFrameHeaderSize(),
-                     framer->protocol_version());
-    }
+    SetFrameLength(decompressed_frame,
+                   visitor.size() - framer->GetControlFrameHeaderSize(),
+                   framer->protocol_version());
     return decompressed_frame;
   }
 
@@ -227,6 +222,8 @@ class SpdyFramerTestUtil {
 class TestSpdyVisitor : public SpdyFramerVisitorInterface,
                         public SpdyFramerDebugVisitorInterface {
  public:
+  // This is larger than our max frame size because header blocks that
+  // are too long can spill over into CONTINUATION frames.
   static const size_t kDefaultHeaderBufferSize = 16 * 1024 * 1024;
 
   explicit TestSpdyVisitor(SpdyMajorVersion version)
@@ -236,6 +233,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
       syn_frame_count_(0),
       syn_reply_frame_count_(0),
       headers_frame_count_(0),
+      push_promise_frame_count_(0),
       goaway_count_(0),
       setting_count_(0),
       settings_ack_sent_(0),
@@ -266,13 +264,13 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
   virtual void OnError(SpdyFramer* f) OVERRIDE {
     LOG(INFO) << "SpdyFramer Error: "
               << SpdyFramer::ErrorCodeToString(f->error_code());
-    error_count_++;
+    ++error_count_;
   }
 
   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
                                  size_t length,
                                  bool fin) OVERRIDE {
-    data_frame_count_++;
+    ++data_frame_count_;
     header_stream_id_ = stream_id;
   }
 
@@ -306,7 +304,9 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
       CHECK(header_buffer_valid_);
       size_t parsed_length = framer_.ParseHeaderBlockInBuffer(
           header_buffer_.get(), header_buffer_length_, &headers_);
-      DCHECK_EQ(header_buffer_length_, parsed_length);
+      LOG_IF(DFATAL, header_buffer_length_ != parsed_length)
+          << "Check failed: header_buffer_length_ == parsed_length "
+          << "(" << header_buffer_length_ << " vs. " << parsed_length << ")";
       return true;
     }
     const size_t available = header_buffer_size_ - header_buffer_length_;
@@ -324,24 +324,24 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
                            SpdyPriority priority,
                            bool fin,
                            bool unidirectional) OVERRIDE {
-    syn_frame_count_++;
+    ++syn_frame_count_;
     InitHeaderStreaming(SYN_STREAM, stream_id);
     if (fin) {
-      fin_flag_count_++;
+      ++fin_flag_count_;
     }
   }
 
   virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
-    syn_reply_frame_count_++;
+    ++syn_reply_frame_count_;
     InitHeaderStreaming(SYN_REPLY, stream_id);
     if (fin) {
-      fin_flag_count_++;
+      ++fin_flag_count_;
     }
   }
 
   virtual void OnRstStream(SpdyStreamId stream_id,
                            SpdyRstStreamStatus status) OVERRIDE {
-    fin_frame_count_++;
+    ++fin_frame_count_;
   }
 
   virtual bool OnRstStreamFrameData(const char* rst_stream_data,
@@ -355,17 +355,17 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
   virtual void OnSetting(SpdySettingsIds id,
                          uint8 flags,
                          uint32 value) OVERRIDE {
-    setting_count_++;
+    ++setting_count_;
   }
 
   virtual void OnSettingsAck() OVERRIDE {
-    DCHECK_GE(4, framer_.protocol_version());
-    settings_ack_received_++;
+    DCHECK_LT(SPDY3, framer_.protocol_version());
+    ++settings_ack_received_;
   }
 
   virtual void OnSettingsEnd() OVERRIDE {
-    if (framer_.protocol_version() < 4) { return; }
-    settings_ack_sent_++;
+    if (framer_.protocol_version() <= SPDY3) { return; }
+    ++settings_ack_sent_;
   }
 
   virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {
@@ -374,14 +374,14 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
 
   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
                         SpdyGoAwayStatus status) OVERRIDE {
-    goaway_count_++;
+    ++goaway_count_;
   }
 
   virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) OVERRIDE {
-    headers_frame_count_++;
+    ++headers_frame_count_;
     InitHeaderStreaming(HEADERS, stream_id);
     if (fin) {
-      fin_flag_count_++;
+      ++fin_flag_count_;
     }
   }
 
@@ -394,13 +394,14 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
   virtual void OnPushPromise(SpdyStreamId stream_id,
                              SpdyStreamId promised_stream_id,
                              bool end) OVERRIDE {
+    ++push_promise_frame_count_;
     InitHeaderStreaming(PUSH_PROMISE, stream_id);
     last_push_promise_stream_ = stream_id;
     last_push_promise_promised_stream_ = promised_stream_id;
   }
 
   virtual void OnContinuation(SpdyStreamId stream_id, bool end) OVERRIDE {
-    continuation_count_++;
+    ++continuation_count_;
   }
 
   virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
@@ -467,6 +468,7 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
   int syn_frame_count_;
   int syn_reply_frame_count_;
   int headers_frame_count_;
+  int push_promise_frame_count_;
   int goaway_count_;
   int setting_count_;
   int settings_ack_sent_;
@@ -498,12 +500,39 @@ class TestSpdyVisitor : public SpdyFramerVisitorInterface,
   SpdyHeaderBlock headers_;
 };
 
-// Retrieves serialized headers from SYN_STREAM frame.
-// Does not check that the given frame is a SYN_STREAM.
+// Retrieves serialized headers from a HEADERS or SYN_STREAM frame.
 base::StringPiece GetSerializedHeaders(const SpdyFrame* frame,
                                        const SpdyFramer& framer) {
-  return base::StringPiece(frame->data() + framer.GetSynStreamMinimumSize(),
-                           frame->size() - framer.GetSynStreamMinimumSize());
+  SpdyFrameReader reader(frame->data(), frame->size());
+  reader.Seek(2);  // Seek past the frame length.
+  SpdyFrameType frame_type;
+  if (framer.protocol_version() > SPDY3) {
+    uint8 serialized_type;
+    reader.ReadUInt8(&serialized_type);
+    frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(),
+                                               serialized_type);
+    DCHECK_EQ(HEADERS, frame_type);
+    uint8 flags;
+    reader.ReadUInt8(&flags);
+    if (flags & HEADERS_FLAG_PRIORITY) {
+      frame_type = SYN_STREAM;
+    }
+  } else {
+    uint16 serialized_type;
+    reader.ReadUInt16(&serialized_type);
+    frame_type = SpdyConstants::ParseFrameType(framer.protocol_version(),
+                                               serialized_type);
+    DCHECK(frame_type == HEADERS ||
+           frame_type == SYN_STREAM) << frame_type;
+  }
+
+  if (frame_type == SYN_STREAM) {
+    return StringPiece(frame->data() + framer.GetSynStreamMinimumSize(),
+                       frame->size() - framer.GetSynStreamMinimumSize());
+  } else {
+    return StringPiece(frame->data() + framer.GetHeadersMinimumSize(),
+                       frame->size() - framer.GetHeadersMinimumSize());
+  }
 }
 
 }  // namespace test
@@ -523,7 +552,8 @@ class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> {
  protected:
   virtual void SetUp() {
     spdy_version_ = GetParam();
-    spdy_version_ch_ = static_cast<unsigned char>(spdy_version_);
+    spdy_version_ch_ = static_cast<unsigned char>(
+        SpdyConstants::SerializeMajorVersion(spdy_version_));
   }
 
   void CompareFrame(const string& description,
@@ -574,18 +604,6 @@ class SpdyFramerTest : public ::testing::TestWithParam<SpdyMajorVersion> {
     return true;
   }
 
-  void AddSpdySettingFromWireFormat(SettingsMap* settings,
-                                    uint32 key,
-                                    uint32 value) {
-    SettingsFlagsAndId flags_and_id =
-        SettingsFlagsAndId::FromWireFormat(spdy_version_, key);
-    SpdySettingsIds id = static_cast<SpdySettingsIds>(flags_and_id.id());
-    SpdySettingsFlags flags =
-        static_cast<SpdySettingsFlags>(flags_and_id.flags());
-    CHECK(settings->find(id) == settings->end());
-    settings->insert(std::make_pair(id, SettingsFlagsAndValue(flags, value)));
-  }
-
   bool IsSpdy2() { return spdy_version_ == SPDY2; }
   bool IsSpdy3() { return spdy_version_ == SPDY3; }
   bool IsSpdy4() { return spdy_version_ == SPDY4; }
@@ -691,7 +709,7 @@ TEST_P(SpdyFramerTest, HeadersWithStreamIdZero) {
 // Test that if we receive a PUSH_PROMISE with stream ID zero, we signal an
 // error (but don't crash).
 TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) {
-  if (spdy_version_ < SPDY4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
@@ -716,7 +734,7 @@ TEST_P(SpdyFramerTest, PushPromiseWithStreamIdZero) {
 // Test that if we receive a PUSH_PROMISE with promised stream ID zero, we
 // signal an error (but don't crash).
 TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {
-  if (spdy_version_ < SPDY4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
@@ -739,7 +757,7 @@ TEST_P(SpdyFramerTest, PushPromiseWithPromisedStreamIdZero) {
 }
 
 TEST_P(SpdyFramerTest, DuplicateHeader) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // TODO(jgraettinger): Punting on this because we haven't determined
     // whether duplicate HPACK headers other than Cookie are an error.
     // If they are, this will need to be updated to use HpackOutputStream.
@@ -747,14 +765,14 @@ TEST_P(SpdyFramerTest, DuplicateHeader) {
   }
   SpdyFramer framer(spdy_version_);
   // Frame builder with plentiful buffer size.
-  SpdyFrameBuilder frame(1024);
-  if (spdy_version_ < 4) {
+  SpdyFrameBuilder frame(1024, spdy_version_);
+  if (spdy_version_ <= SPDY3) {
     frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
     frame.WriteUInt32(3);  // stream_id
     frame.WriteUInt32(0);  // associated stream id
     frame.WriteUInt16(0);  // Priority.
   } else {
-    frame.WriteFramePrefix(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3);
+    frame.BeginNewFrame(framer, HEADERS, HEADERS_FLAG_PRIORITY, 3);
     frame.WriteUInt32(framer.GetHighestPriority());
   }
 
@@ -788,17 +806,17 @@ TEST_P(SpdyFramerTest, DuplicateHeader) {
 TEST_P(SpdyFramerTest, MultiValueHeader) {
   SpdyFramer framer(spdy_version_);
   // Frame builder with plentiful buffer size.
-  SpdyFrameBuilder frame(1024);
-  if (spdy_version_ < 4) {
+  SpdyFrameBuilder frame(1024, spdy_version_);
+  if (spdy_version_ <= SPDY3) {
     frame.WriteControlFrameHeader(framer, SYN_STREAM, CONTROL_FLAG_NONE);
     frame.WriteUInt32(3);  // stream_id
     frame.WriteUInt32(0);  // associated stream id
     frame.WriteUInt16(0);  // Priority.
   } else {
-    frame.WriteFramePrefix(framer,
-                           HEADERS,
-                           HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS,
-                           3);
+    frame.BeginNewFrame(framer,
+                        HEADERS,
+                        HEADERS_FLAG_PRIORITY | HEADERS_FLAG_END_HEADERS,
+                        3);
     frame.WriteUInt32(framer.GetHighestPriority());
   }
 
@@ -807,11 +825,13 @@ TEST_P(SpdyFramerTest, MultiValueHeader) {
     frame.WriteUInt16(1);  // Number of headers.
     frame.WriteString("name");
     frame.WriteString(value);
-  } else if (spdy_version_ >= 4) {
-    HpackOutputStream output_stream(1024);
-    output_stream.AppendLiteralHeaderNoIndexingWithName("name", value);
+  } else if (spdy_version_ > SPDY3) {
+    // TODO(jgraettinger): If this pattern appears again, move to test class.
+    std::map<string, string> header_set;
+    header_set["name"] = value;
     string buffer;
-    output_stream.TakeString(&buffer);
+    HpackEncoder encoder(ObtainHpackHuffmanTable());
+    encoder.EncodeHeaderSetWithoutCompression(header_set, &buffer);
     frame.WriteBytes(&buffer[0], buffer.size());
   } else {
     frame.WriteUInt32(1);  // Number of headers.
@@ -835,7 +855,7 @@ TEST_P(SpdyFramerTest, MultiValueHeader) {
 }
 
 TEST_P(SpdyFramerTest, BasicCompression) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // Deflate compression doesn't apply to HPACK.
     return;
   }
@@ -980,7 +1000,7 @@ TEST_P(SpdyFramerTest, Basic) {
     0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #1
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x05,           // RST_STREAM_CANCEL
 
     0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
     0x00, 0x00, 0x00, 0x00,
@@ -988,7 +1008,7 @@ TEST_P(SpdyFramerTest, Basic) {
     0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #3
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x03,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x05,           // RST_STREAM_CANCEL
   };
 
   const unsigned char kV3Input[] = {
@@ -1039,7 +1059,7 @@ TEST_P(SpdyFramerTest, Basic) {
     0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #1
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x05,           // RST_STREAM_CANCEL
 
     0x00, 0x00, 0x00, 0x03,           // DATA on Stream #3
     0x00, 0x00, 0x00, 0x00,
@@ -1047,51 +1067,51 @@ TEST_P(SpdyFramerTest, Basic) {
     0x80, spdy_version_ch_, 0x00, 0x03,  // RST_STREAM on Stream #3
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x03,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x05,           // RST_STREAM_CANCEL
   };
 
   // SYN_STREAM doesn't exist in SPDY4, so instead we send
   // HEADERS frames with PRIORITY and END_HEADERS set.
   const unsigned char kV4Input[] = {
-    0x00, 0x0d, 0x08, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
+    0x00, 0x05, 0x01, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x00, 0x00, 0x00, 0x00,           // Priority 0
     0x82,                             // :method: GET
 
-    0x00, 0x09, 0x08, 0x04,           // HEADERS: END_HEADERS
+    0x00, 0x01, 0x01, 0x04,           // HEADERS: END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x8c,                             // :status: 200
 
-    0x00, 0x14, 0x00, 0x00,           // DATA on Stream #1
+    0x00, 0x0c, 0x00, 0x00,           // DATA on Stream #1
     0x00, 0x00, 0x00, 0x01,
     0xde, 0xad, 0xbe, 0xef,
     0xde, 0xad, 0xbe, 0xef,
     0xde, 0xad, 0xbe, 0xef,
 
-    0x00, 0x0d, 0x08, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
+    0x00, 0x05, 0x01, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
     0x00, 0x00, 0x00, 0x03,           // Stream 3
     0x00, 0x00, 0x00, 0x00,           // Priority 0
     0x82,                             // :method: GET
 
-    0x00, 0x10, 0x00, 0x00,           // DATA on Stream #3
+    0x00, 0x08, 0x00, 0x00,           // DATA on Stream #3
     0x00, 0x00, 0x00, 0x03,
     0xde, 0xad, 0xbe, 0xef,
     0xde, 0xad, 0xbe, 0xef,
 
-    0x00, 0x0c, 0x00, 0x00,           // DATA on Stream #1
+    0x00, 0x04, 0x00, 0x00,           // DATA on Stream #1
     0x00, 0x00, 0x00, 0x01,
     0xde, 0xad, 0xbe, 0xef,
 
-    0x00, 0x0c, 0x03, 0x00,           // RST_STREAM on Stream #1
+    0x00, 0x04, 0x03, 0x00,           // RST_STREAM on Stream #1
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x08,           // RST_STREAM_CANCEL
 
-    0x00, 0x08, 0x00, 0x00,           // DATA on Stream #3
+    0x00, 0x00, 0x00, 0x00,           // DATA on Stream #3
     0x00, 0x00, 0x00, 0x03,
 
-    0x00, 0x17, 0x03, 0x00,           // RST_STREAM on Stream #3
+    0x00, 0x0f, 0x03, 0x00,           // RST_STREAM on Stream #3
     0x00, 0x00, 0x00, 0x03,
-    0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x08,           // RST_STREAM_CANCEL
     0x52, 0x45, 0x53, 0x45,           // opaque data
     0x54, 0x53, 0x54, 0x52,
     0x45, 0x41, 0x4d,
@@ -1188,22 +1208,22 @@ TEST_P(SpdyFramerTest, FinOnDataFrame) {
   // SYN_STREAM and SYN_REPLY don't exist in SPDY4, so instead we send
   // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set.
   const unsigned char kV4Input[] = {
-    0x00, 0x0d, 0x08, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
+    0x00, 0x05, 0x01, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x00, 0x00, 0x00, 0x00,           // Priority 0
     0x82,                             // :method: GET
 
-    0x00, 0x09, 0x08, 0x04,           // HEADERS: END_HEADERS
+    0x00, 0x01, 0x01, 0x04,           // HEADERS: END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x8c,                             // :status: 200
 
-    0x00, 0x14, 0x00, 0x00,           // DATA on Stream #1
+    0x00, 0x0c, 0x00, 0x00,           // DATA on Stream #1
     0x00, 0x00, 0x00, 0x01,
     0xde, 0xad, 0xbe, 0xef,
     0xde, 0xad, 0xbe, 0xef,
     0xde, 0xad, 0xbe, 0xef,
 
-    0x00, 0x0c, 0x00, 0x01,           // DATA on Stream #1, with FIN
+    0x00, 0x04, 0x00, 0x01,           // DATA on Stream #1, with FIN
     0x00, 0x00, 0x00, 0x01,
     0xde, 0xad, 0xbe, 0xef,
   };
@@ -1274,12 +1294,12 @@ TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
   // SYN_STREAM and SYN_REPLY don't exist in SPDY4, so instead we send
   // HEADERS frames with PRIORITY(SYN_STREAM only) and END_HEADERS set.
   const unsigned char kV4Input[] = {
-    0x00, 0x0d, 0x08, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
+    0x00, 0x05, 0x01, 0x0c,           // HEADERS: PRIORITY | END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x00, 0x00, 0x00, 0x00,           // Priority 0
     0x82,                             // :method: GET
 
-    0x00, 0x09, 0x08, 0x05,           // HEADERS: FIN | END_HEADERS
+    0x00, 0x01, 0x01, 0x05,           // HEADERS: FIN | END_HEADERS
     0x00, 0x00, 0x00, 0x01,           // Stream 1
     0x8c,                             // :status: 200
   };
@@ -1310,7 +1330,7 @@ TEST_P(SpdyFramerTest, FinOnSynReplyFrame) {
 }
 
 TEST_P(SpdyFramerTest, HeaderCompression) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // Deflate compression doesn't apply to HPACK.
     return;
   }
@@ -1394,7 +1414,7 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressors) {
   EXPECT_TRUE(syn_frame.get() != NULL);
 
   StringPiece bytes = "this is a test test test test test!";
-  net::SpdyDataIR data_ir(1, bytes);
+  SpdyDataIR data_ir(1, bytes);
   data_ir.set_fin(true);
   scoped_ptr<SpdyFrame> send_frame(send_framer.SerializeData(data_ir));
   EXPECT_TRUE(send_frame.get() != NULL);
@@ -1438,7 +1458,7 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
   EXPECT_TRUE(syn_frame.get() != NULL);
 
   const char bytes[] = "this is a test test test test test!";
-  net::SpdyDataIR data_ir(1, StringPiece(bytes, arraysize(bytes)));
+  SpdyDataIR data_ir(1, StringPiece(bytes, arraysize(bytes)));
   data_ir.set_fin(true);
   scoped_ptr<SpdyFrame> send_frame(send_framer.SerializeData(data_ir));
   EXPECT_TRUE(send_frame.get() != NULL);
@@ -1472,7 +1492,7 @@ TEST_P(SpdyFramerTest, UnclosedStreamDataCompressorsOneByteAtATime) {
 TEST_P(SpdyFramerTest, WindowUpdateFrame) {
   SpdyFramer framer(spdy_version_);
   scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
-      net::SpdyWindowUpdateIR(1, 0x12345678)));
+      SpdyWindowUpdateIR(1, 0x12345678)));
 
   const char kDescription[] = "WINDOW_UPDATE frame, stream 1, delta 0x12345678";
   const unsigned char kV3FrameData[] = {  // Also applies for V2.
@@ -1482,15 +1502,15 @@ TEST_P(SpdyFramerTest, WindowUpdateFrame) {
     0x12, 0x34, 0x56, 0x78
   };
   const unsigned char kV4FrameData[] = {
-    0x00, 0x0c, 0x09, 0x00,
+    0x00, 0x04, 0x08, 0x00,
     0x00, 0x00, 0x00, 0x01,
     0x12, 0x34, 0x56, 0x78
   };
 
   if (IsSpdy4()) {
-     CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+    CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
   } else {
-     CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+    CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
   }
 }
 
@@ -1506,7 +1526,7 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
       'o'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0d, 0x00, 0x00,
+      0x00, 0x05, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x01,
       'h',  'e',  'l',  'l',
       'o'
@@ -1525,7 +1545,143 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
 
     SpdyDataIR data_header_ir(1);
     data_header_ir.SetDataShallow(base::StringPiece(bytes, strlen(bytes)));
-    frame.reset(framer.SerializeDataFrameHeader(data_header_ir));
+    frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(
+        data_header_ir));
+    CompareCharArraysWithHexError(
+        kDescription,
+        reinterpret_cast<const unsigned char*>(frame->data()),
+        framer.GetDataFrameMinimumSize(),
+        IsSpdy4() ? kV4FrameData : kV3FrameData,
+        framer.GetDataFrameMinimumSize());
+  }
+
+  {
+    const char kDescription[] = "'hello' data frame with more padding, no FIN";
+    const unsigned char kV3FrameData[] = {  // Also applies for V2.
+      0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x05,
+      'h',  'e',  'l',  'l',
+      'o'
+    };
+
+    const unsigned char kV4FrameData[] = {
+      0x01, 0x0b, 0x00, 0x30,      // Length = 267.  PAD_HIGH and PAD_LOW set.
+      0x00, 0x00, 0x00, 0x01,
+      0x01, 0x04,                  // Pad Low and Pad High fields.
+      'h',  'e',  'l',  'l',       // Data
+      'o',
+      // Padding of 260 zeros (so both PAD_HIGH and PAD_LOW fields are used).
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+      '0',  '0',  '0',  '0',  '0',  '0',  '0',  '0', '0',  '0',  '0',  '0', '0',
+    };
+    const char bytes[] = "hello";
+
+    SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes)));
+    // 260 zeros and the pad low/high fields make the overall padding to be 262
+    // bytes.
+    data_ir.set_padding_len(262);
+    scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+    if (IsSpdy4()) {
+       CompareFrame(
+           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+    } else {
+       CompareFrame(
+           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+    }
+
+    frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
+    CompareCharArraysWithHexError(
+        kDescription,
+        reinterpret_cast<const unsigned char*>(frame->data()),
+        framer.GetDataFrameMinimumSize(),
+        IsSpdy4() ? kV4FrameData : kV3FrameData,
+        framer.GetDataFrameMinimumSize());
+  }
+
+  {
+    const char kDescription[] = "'hello' data frame with few padding, no FIN";
+    const unsigned char kV3FrameData[] = {  // Also applies for V2.
+      0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x05,
+      'h',  'e',  'l',  'l',
+      'o'
+    };
+
+    const unsigned char kV4FrameData[] = {
+      0x00, 0x0d, 0x00, 0x10,      // Length = 13.  PAD_LOW set.
+      0x00, 0x00, 0x00, 0x01,
+      0x07,                        // Pad Low field.
+      'h',  'e',  'l',  'l',       // Data
+      'o',
+      '0',  '0',  '0',  '0',       // Padding
+      '0',  '0',  '0'
+    };
+    const char bytes[] = "hello";
+
+    SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes)));
+    // 7 zeros and the pad low field make the overall padding to be 8 bytes.
+    data_ir.set_padding_len(8);
+    scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+    if (IsSpdy4()) {
+       CompareFrame(
+           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+    } else {
+       CompareFrame(
+           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+    }
+  }
+
+  {
+    const char kDescription[] =
+        "'hello' data frame with 1 byte padding, no FIN";
+    const unsigned char kV3FrameData[] = {  // Also applies for V2.
+      0x00, 0x00, 0x00, 0x01,
+      0x00, 0x00, 0x00, 0x05,
+      'h',  'e',  'l',  'l',
+      'o'
+    };
+
+    const unsigned char kV4FrameData[] = {
+      0x00, 0x06, 0x00, 0x10,      // Length = 6.  PAD_LOW set.
+      0x00, 0x00, 0x00, 0x01,
+      0x00,                        // Pad Low field.
+      'h',  'e',  'l',  'l',       // Data
+      'o',
+    };
+    const char bytes[] = "hello";
+
+    SpdyDataIR data_ir(1, StringPiece(bytes, strlen(bytes)));
+    // The pad low field itself is used for the 1-byte padding and no padding
+    // payload is needed.
+    data_ir.set_padding_len(1);
+    scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+    if (IsSpdy4()) {
+       CompareFrame(
+           kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+    } else {
+       CompareFrame(
+           kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+    }
+
+    frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
     CompareCharArraysWithHexError(
         kDescription,
         reinterpret_cast<const unsigned char*>(frame->data()),
@@ -1542,11 +1698,11 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
       0xff
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x09, 0x00, 0x00,
+      0x00, 0x01, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x01,
       0xff
     };
-    net::SpdyDataIR data_ir(1, StringPiece("\xff", 1));
+    SpdyDataIR data_ir(1, StringPiece("\xff", 1));
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     if (IsSpdy4()) {
        CompareFrame(
@@ -1566,12 +1722,12 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
       'o'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0d, 0x00, 0x01,
+      0x00, 0x05, 0x00, 0x01,
       0x00, 0x00, 0x00, 0x01,
       'h',  'e',  'l',  'l',
       'o'
     };
-    net::SpdyDataIR data_ir(1, StringPiece("hello", 5));
+    SpdyDataIR data_ir(1, StringPiece("hello", 5));
     data_ir.set_fin(true);
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     if (IsSpdy4()) {
@@ -1590,10 +1746,10 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
       0x00, 0x00, 0x00, 0x00,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x08, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x01,
     };
-    net::SpdyDataIR data_ir(1, StringPiece());
+    SpdyDataIR data_ir(1, StringPiece());
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     if (IsSpdy4()) {
        CompareFrame(
@@ -1602,6 +1758,14 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
        CompareFrame(
            kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
     }
+
+    frame.reset(framer.SerializeDataFrameHeaderWithPaddingLengthField(data_ir));
+    CompareCharArraysWithHexError(
+        kDescription,
+        reinterpret_cast<const unsigned char*>(frame->data()),
+        framer.GetDataFrameMinimumSize(),
+        IsSpdy4() ? kV4FrameData : kV3FrameData,
+        framer.GetDataFrameMinimumSize());
   }
 
   {
@@ -1613,12 +1777,12 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
       'o'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0d, 0x00, 0x01,
+      0x00, 0x05, 0x00, 0x01,
       0x7f, 0xff, 0xff, 0xff,
       'h',  'e',  'l',  'l',
       'o'
     };
-    net::SpdyDataIR data_ir(0x7fffffff, "hello");
+    SpdyDataIR data_ir(0x7fffffff, "hello");
     data_ir.set_fin(true);
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     if (IsSpdy4()) {
@@ -1647,7 +1811,7 @@ TEST_P(SpdyFramerTest, CreateDataFrame) {
     memcpy(expected_frame_data.get(), kFrameHeader, arraysize(kFrameHeader));
     memset(expected_frame_data.get() + arraysize(kFrameHeader), 'A', kDataSize);
 
-    net::SpdyDataIR data_ir(1, StringPiece(kData.data(), kData.size()));
+    SpdyDataIR data_ir(1, StringPiece(kData.data(), kData.size()));
     data_ir.set_fin(true);
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     CompareFrame(kDescription, *frame, expected_frame_data.get(), kFrameSize);
@@ -1690,7 +1854,7 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
       'a',  'r'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x1e, 0x08, 0x0c,  // HEADERS: PRIORITY | END_HEADERS
+      0x00, 0x16, 0x01, 0x0c,  // HEADERS: PRIORITY | END_HEADERS
       0x00, 0x00, 0x00, 0x01,  // Stream 1
       0x00, 0x00, 0x00, 0x07,  // Priority 7
       0x40, 0x03, 0x62, 0x61,  // @.ba
@@ -1745,7 +1909,7 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
       'b',  'a',  'r'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x1b, 0x08, 0x0d,  // HEADERS: PRIORITY | FIN | END_HEADERS
+      0x00, 0x13, 0x01, 0x0d,  // HEADERS: PRIORITY | FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x00, 0x00, 0x00, 0x00,  // Priority 0
       0x40, 0x00, 0x03, 0x66,  // @..f
@@ -1802,7 +1966,7 @@ TEST_P(SpdyFramerTest, CreateSynStreamUncompressed) {
       0x00, 0x00, 0x00
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x1b, 0x08, 0x0d,  // HEADERS: PRIORITY | FIN | END_HEADERS
+      0x00, 0x13, 0x01, 0x0d,  // HEADERS: PRIORITY | FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x00, 0x00, 0x00, 0x01,  // Priority 1
       0x40, 0x03, 0x62, 0x61,  // @.ba
@@ -1923,7 +2087,7 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
       0x03, 'b',  'a',  'r'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x1a, 0x08, 0x04,  // HEADER: END_HEADERS
+      0x00, 0x12, 0x01, 0x04,  // HEADER: END_HEADERS
       0x00, 0x00, 0x00, 0x01,  // Stream 1
       0x40, 0x03, 0x62, 0x61,  // @.ba
       0x72, 0x03, 0x66, 0x6f,  // r.fo
@@ -1973,7 +2137,7 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
       'r'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x17, 0x08, 0x05,  // HEADER: FIN | END_HEADERS
+      0x00, 0x0f, 0x01, 0x05,  // HEADER: FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x40, 0x00, 0x03, 0x66,  // @..f
       0x6f, 0x6f, 0x40, 0x03,  // oo@.
@@ -2023,7 +2187,7 @@ TEST_P(SpdyFramerTest, CreateSynReplyUncompressed) {
       0x00
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x17, 0x08, 0x05,  // HEADER: FIN | END_HEADERS
+      0x00, 0x0f, 0x01, 0x05,  // HEADER: FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x40, 0x03, 0x62, 0x61,  // @.ba
       0x72, 0x03, 0x66, 0x6f,  // r.fo
@@ -2116,12 +2280,12 @@ TEST_P(SpdyFramerTest, CreateRstStream) {
       0x00, 0x00, 0x00, 0x01,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0f, 0x03, 0x00,
+      0x00, 0x07, 0x03, 0x00,
       0x00, 0x00, 0x00, 0x01,
       0x00, 0x00, 0x00, 0x01,
       0x52, 0x53, 0x54
     };
-    net::SpdyRstStreamIR rst_stream(1, RST_STREAM_PROTOCOL_ERROR, "RST");
+    SpdyRstStreamIR rst_stream(1, RST_STREAM_PROTOCOL_ERROR, "RST");
     scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
@@ -2139,13 +2303,13 @@ TEST_P(SpdyFramerTest, CreateRstStream) {
       0x00, 0x00, 0x00, 0x01,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0c, 0x03, 0x00,
+      0x00, 0x04, 0x03, 0x00,
       0x7f, 0xff, 0xff, 0xff,
       0x00, 0x00, 0x00, 0x01,
     };
-    net::SpdyRstStreamIR rst_stream(0x7FFFFFFF,
-                                    RST_STREAM_PROTOCOL_ERROR,
-                                    "");
+    SpdyRstStreamIR rst_stream(0x7FFFFFFF,
+                               RST_STREAM_PROTOCOL_ERROR,
+                               "");
     scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
@@ -2163,13 +2327,13 @@ TEST_P(SpdyFramerTest, CreateRstStream) {
       0x00, 0x00, 0x00, 0x06,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0c, 0x03, 0x00,
+      0x00, 0x04, 0x03, 0x00,
       0x7f, 0xff, 0xff, 0xff,
       0x00, 0x00, 0x00, 0x06,
     };
-    net::SpdyRstStreamIR rst_stream(0x7FFFFFFF,
-                                    RST_STREAM_INTERNAL_ERROR,
-                                    "");
+    SpdyRstStreamIR rst_stream(0x7FFFFFFF,
+                               RST_STREAM_INTERNAL_ERROR,
+                               "");
     scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
@@ -2189,20 +2353,20 @@ TEST_P(SpdyFramerTest, CreateSettings) {
       0x80, spdy_version_ch_, 0x00, 0x04,
       0x00, 0x00, 0x00, 0x0c,
       0x00, 0x00, 0x00, 0x01,
-      0x04, 0x03, 0x02, 0x01,
+      0x07, 0x00, 0x00, 0x01,
       0x0a, 0x0b, 0x0c, 0x0d,
     };
     const unsigned char kV3FrameData[] = {
       0x80, spdy_version_ch_, 0x00, 0x04,
       0x00, 0x00, 0x00, 0x0c,
       0x00, 0x00, 0x00, 0x01,
-      0x01, 0x02, 0x03, 0x04,
+      0x01, 0x00, 0x00, 0x07,
       0x0a, 0x0b, 0x0c, 0x0d,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0d, 0x04, 0x00,
+      0x00, 0x05, 0x04, 0x00,
       0x00, 0x00, 0x00, 0x00,
-      0x01, 0x0a, 0x0b, 0x0c,
+      0x04, 0x0a, 0x0b, 0x0c,
       0x0d,
     };
 
@@ -2210,10 +2374,7 @@ TEST_P(SpdyFramerTest, CreateSettings) {
     SpdySettingsIR settings_ir;
 
     SpdySettingsFlags kFlags = static_cast<SpdySettingsFlags>(0x01);
-    SpdySettingsIds kId = static_cast<SpdySettingsIds>(0x020304);
-    if (IsSpdy4()) {
-      kId = static_cast<SpdySettingsIds>(0x01);
-    }
+    SpdySettingsIds kId = SETTINGS_INITIAL_WINDOW_SIZE;
     SettingsMap settings;
     settings[kId] = SettingsFlagsAndValue(kFlags, kValue);
     EXPECT_EQ(kFlags, settings[kId].first);
@@ -2236,66 +2397,73 @@ TEST_P(SpdyFramerTest, CreateSettings) {
   {
     const char kDescription[] = "Basic SETTINGS frame";
 
-    SettingsMap settings;
-    AddSpdySettingFromWireFormat(
-        &settings, 0x00000000, 0x00000001);  // 1st Setting
-    AddSpdySettingFromWireFormat(
-        &settings, 0x01000001, 0x00000002);  // 2nd Setting
-    AddSpdySettingFromWireFormat(
-        &settings, 0x02000002, 0x00000003);  // 3rd Setting
-    AddSpdySettingFromWireFormat(
-        &settings, 0x03000003, 0xff000004);  // 4th Setting
-
-    const unsigned char kV3FrameData[] = {  // Also applies for V2.
+    const unsigned char kV2FrameData[] = {
       0x80, spdy_version_ch_, 0x00, 0x04,
       0x00, 0x00, 0x00, 0x24,
       0x00, 0x00, 0x00, 0x04,
-      0x00, 0x00, 0x00, 0x00,  // 1st Setting
-      0x00, 0x00, 0x00, 0x01,
-      0x01, 0x00, 0x00, 0x01,  // 2nd Setting
-      0x00, 0x00, 0x00, 0x02,
-      0x02, 0x00, 0x00, 0x02,  // 3rd Setting
-      0x00, 0x00, 0x00, 0x03,
-      0x03, 0x00, 0x00, 0x03,  // 4th Setting
-      0xff, 0x00, 0x00, 0x04,
+      0x01, 0x00, 0x00, 0x00,  // 1st Setting
+      0x00, 0x00, 0x00, 0x05,
+      0x02, 0x00, 0x00, 0x00,  // 2nd Setting
+      0x00, 0x00, 0x00, 0x06,
+      0x03, 0x00, 0x00, 0x00,  // 3rd Setting
+      0x00, 0x00, 0x00, 0x07,
+      0x04, 0x00, 0x00, 0x00,  // 4th Setting
+      0x00, 0x00, 0x00, 0x08,
+    };
+    const unsigned char kV3FrameData[] = {
+      0x80, spdy_version_ch_, 0x00, 0x04,
+      0x00, 0x00, 0x00, 0x24,
+      0x00, 0x00, 0x00, 0x04,
+      0x00, 0x00, 0x00, 0x01,  // 1st Setting
+      0x00, 0x00, 0x00, 0x05,
+      0x00, 0x00, 0x00, 0x02,  // 2nd Setting
+      0x00, 0x00, 0x00, 0x06,
+      0x00, 0x00, 0x00, 0x03,  // 3rd Setting
+      0x00, 0x00, 0x00, 0x07,
+      0x00, 0x00, 0x00, 0x04,  // 4th Setting
+      0x00, 0x00, 0x00, 0x08,
     };
+    // These end up seemingly out of order because of the way that our internal
+    // ordering for settings_ir works. HTTP2 has no requirement on ordering on
+    // the wire.
     const unsigned char kV4FrameData[] = {
-      0x00, 0x1c, 0x04, 0x00,
+      0x00, 0x14, 0x04, 0x00,
       0x00, 0x00, 0x00, 0x00,
-      0x01,                    // 1st Setting
-      0x00, 0x00, 0x00, 0x01,
-      0x02,                    // 2nd Setting
-      0x00, 0x00, 0x00, 0x02,
       0x03,                    // 3rd Setting
-      0x00, 0x00, 0x00, 0x03,
+      0x00, 0x00, 0x00, 0x07,
       0x04,                    // 4th Setting
-      0xff, 0x00, 0x00, 0x04,
+      0x00, 0x00, 0x00, 0x08,
+      0x01,                    // 1st Setting
+      0x00, 0x00, 0x00, 0x05,
+      0x02,                    // 2nd Setting
+      0x00, 0x00, 0x00, 0x06,
     };
+
     SpdySettingsIR settings_ir;
-    if (!IsSpdy4()) {
-      for (SettingsMap::const_iterator it = settings.begin();
-           it != settings.end();
-           ++it) {
-        settings_ir.AddSetting(it->first,
-                               it->second.first & SETTINGS_FLAG_PLEASE_PERSIST,
-                               it->second.first & SETTINGS_FLAG_PERSISTED,
-                               it->second.second);
-      }
-    } else {
-      SpdySettingsIds kId = static_cast<SpdySettingsIds>(0x01);
-      settings_ir.AddSetting(kId, 0, 0, 0x00000001);
-      kId = static_cast<SpdySettingsIds>(0x02);
-      settings_ir.AddSetting(kId, 0, 0, 0x00000002);
-      kId = static_cast<SpdySettingsIds>(0x03);
-      settings_ir.AddSetting(kId, 0, 0, 0x00000003);
-      kId = static_cast<SpdySettingsIds>(0x04);
-      settings_ir.AddSetting(kId, 0, 0, 0xff000004);
-    }
+    settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1),
+                           false,  // persist
+                           false,  // persisted
+                           5);
+    settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2),
+                           false,  // persist
+                           false,  // persisted
+                           6);
+    settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3),
+                           false,  // persist
+                           false,  // persisted
+                           7);
+    settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 4),
+                           false,  // persist
+                           false,  // persisted
+                           8);
     scoped_ptr<SpdyFrame> frame(framer.SerializeSettings(settings_ir));
-    if (IsSpdy4()) {
-      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
-    } else {
+
+    if (IsSpdy2()) {
+      CompareFrame(kDescription, *frame, kV2FrameData, arraysize(kV2FrameData));
+    } else if (IsSpdy3()) {
       CompareFrame(kDescription, *frame, kV3FrameData, arraysize(kV3FrameData));
+    } else {
+      CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
     }
   }
 
@@ -2308,7 +2476,7 @@ TEST_P(SpdyFramerTest, CreateSettings) {
       0x00, 0x00, 0x00, 0x00,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x08, 0x04, 0x00,
+      0x00, 0x00, 0x04, 0x00,
       0x00, 0x00, 0x00, 0x00,
     };
     SpdySettingsIR settings_ir;
@@ -2332,13 +2500,13 @@ TEST_P(SpdyFramerTest, CreatePingFrame) {
       0x12, 0x34, 0x56, 0x78,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x10, 0x06, 0x00,
+      0x00, 0x08, 0x06, 0x00,
       0x00, 0x00, 0x00, 0x00,
       0x12, 0x34, 0x56, 0x78,
       0x9a, 0xbc, 0xde, 0xff,
     };
     const unsigned char kV4FrameDataWithAck[] = {
-      0x00, 0x10, 0x06, 0x01,
+      0x00, 0x08, 0x06, 0x01,
       0x00, 0x00, 0x00, 0x00,
       0x12, 0x34, 0x56, 0x78,
       0x9a, 0xbc, 0xde, 0xff,
@@ -2382,7 +2550,7 @@ TEST_P(SpdyFramerTest, CreateGoAway) {
       0x00, 0x00, 0x00, 0x00,  // Status
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x12, 0x07, 0x00,
+      0x00, 0x0a, 0x07, 0x00,
       0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00,  // Stream id
       0x00, 0x00, 0x00, 0x00,  // Status
@@ -2413,7 +2581,7 @@ TEST_P(SpdyFramerTest, CreateGoAway) {
       0x00, 0x00, 0x00, 0x02,  // Status
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x12, 0x07, 0x00,
+      0x00, 0x0a, 0x07, 0x00,
       0x00, 0x00, 0x00, 0x00,
       0x7f, 0xff, 0xff, 0xff,  // Stream Id
       0x00, 0x00, 0x00, 0x02,  // Status
@@ -2463,7 +2631,7 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
       0x03, 'b',  'a',  'r'
     };
     const unsigned char kV4FrameData[] = {
-       0x00, 0x1a, 0x08, 0x04,  // Headers: END_HEADERS
+       0x00, 0x12, 0x01, 0x04,  // Headers: END_HEADERS
        0x00, 0x00, 0x00, 0x01,  // Stream 1
        0x40, 0x03, 0x62, 0x61,  // @.ba
        0x72, 0x03, 0x66, 0x6f,  // r.fo
@@ -2513,7 +2681,7 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
       'r'
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x17, 0x08, 0x05,  // HEADER: FIN | END_HEADERS
+      0x00, 0x0f, 0x01, 0x05,  // HEADER: FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x40, 0x00, 0x03, 0x66,  // @..f
       0x6f, 0x6f, 0x40, 0x03,  // oo@.
@@ -2563,7 +2731,7 @@ TEST_P(SpdyFramerTest, CreateHeadersUncompressed) {
       0x00
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x17, 0x08, 0x05,  // HEADER: FIN | END_HEADERS
+      0x00, 0x0f, 0x01, 0x05,  // HEADER: FIN | END_HEADERS
       0x7f, 0xff, 0xff, 0xff,  // Stream 0x7fffffff
       0x40, 0x03, 0x62, 0x61,  // @.ba
       0x72, 0x03, 0x66, 0x6f,  // r.fo
@@ -2656,12 +2824,12 @@ TEST_P(SpdyFramerTest, CreateWindowUpdate) {
       0x00, 0x00, 0x00, 0x01,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0c, 0x09, 0x00,
+      0x00, 0x04, 0x08, 0x00,
       0x00, 0x00, 0x00, 0x01,
       0x00, 0x00, 0x00, 0x01,
     };
     scoped_ptr<SpdyFrame> frame(
-        framer.SerializeWindowUpdate(net::SpdyWindowUpdateIR(1, 1)));
+        framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 1)));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
     } else {
@@ -2678,12 +2846,12 @@ TEST_P(SpdyFramerTest, CreateWindowUpdate) {
       0x00, 0x00, 0x00, 0x01,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0c, 0x09, 0x00,
+      0x00, 0x04, 0x08, 0x00,
       0x7f, 0xff, 0xff, 0xff,
       0x00, 0x00, 0x00, 0x01,
     };
     scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
-        net::SpdyWindowUpdateIR(0x7FFFFFFF, 1)));
+        SpdyWindowUpdateIR(0x7FFFFFFF, 1)));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
     } else {
@@ -2700,12 +2868,12 @@ TEST_P(SpdyFramerTest, CreateWindowUpdate) {
       0x7f, 0xff, 0xff, 0xff,
     };
     const unsigned char kV4FrameData[] = {
-      0x00, 0x0c, 0x09, 0x00,
+      0x00, 0x04, 0x08, 0x00,
       0x00, 0x00, 0x00, 0x01,
       0x7f, 0xff, 0xff, 0xff,
     };
     scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
-        net::SpdyWindowUpdateIR(1, 0x7FFFFFFF)));
+        SpdyWindowUpdateIR(1, 0x7FFFFFFF)));
     if (IsSpdy4()) {
       CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
     } else {
@@ -2723,7 +2891,7 @@ TEST_P(SpdyFramerTest, SerializeBlocked) {
 
   const char kDescription[] = "BLOCKED frame";
   const unsigned char kFrameData[] = {
-    0x00, 0x08, 0x0b, 0x00,
+    0x00, 0x00, 0x0a, 0x00,
     0x00, 0x00, 0x00, 0x00,
   };
   SpdyBlockedIR blocked_ir(0);
@@ -2750,17 +2918,17 @@ TEST_P(SpdyFramerTest, CreateBlocked) {
   CompareFrames(kDescription, *frame_serialized, *frame_created);
 }
 
-TEST_P(SpdyFramerTest, CreatePushPromise) {
+TEST_P(SpdyFramerTest, CreatePushPromiseUncompressed) {
   if (spdy_version_ < SPDY4) {
     return;
   }
 
   SpdyFramer framer(spdy_version_);
-
+  framer.set_enable_compression(false);
   const char kDescription[] = "PUSH_PROMISE frame";
 
   const unsigned char kFrameData[] = {
-    0x00, 0x1e, 0x0c, 0x04,  // PUSH_PROMISE: END_HEADERS
+    0x00, 0x16, 0x05, 0x04,  // PUSH_PROMISE: END_HEADERS
     0x00, 0x00, 0x00, 0x2a,  // Stream 42
     0x00, 0x00, 0x00, 0x39,  // Promised stream 57
     0x40, 0x03, 0x62, 0x61,  // @.ba
@@ -2869,7 +3037,7 @@ TEST_P(SpdyFramerTest, ReadCompressedHeadersHeaderBlockWithHalfClose) {
 }
 
 TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // TODO(jgraettinger): This test setup doesn't work with HPACK.
     return;
   }
@@ -2904,7 +3072,7 @@ TEST_P(SpdyFramerTest, ControlFrameAtMaxSizeLimit) {
 }
 
 TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // TODO(jgraettinger): This test setup doesn't work with HPACK.
     return;
   }
@@ -2944,6 +3112,63 @@ TEST_P(SpdyFramerTest, ControlFrameTooLarge) {
   EXPECT_EQ(0u, visitor.header_buffer_length_);
 }
 
+TEST_P(SpdyFramerTest, TooLargeHeadersFrameUsesContinuation) {
+  if (spdy_version_ < SPDY4) {
+    return;
+  }
+  SpdyFramer framer(spdy_version_);
+  framer.set_enable_compression(false);
+  SpdyHeadersIR headers(1);
+
+  // Exact payload length will change with HPACK, but this should be long
+  // enough to cause an overflow.
+  const size_t kBigValueSize = framer.GetControlFrameBufferMaxSize();
+  string big_value(kBigValueSize, 'x');
+  headers.SetHeader("aa", big_value.c_str());
+  scoped_ptr<SpdyFrame> control_frame(framer.SerializeHeaders(headers));
+  EXPECT_TRUE(control_frame.get() != NULL);
+  EXPECT_GT(control_frame->size(), framer.GetControlFrameBufferMaxSize());
+
+  TestSpdyVisitor visitor(spdy_version_);
+  visitor.SimulateInFramer(
+      reinterpret_cast<unsigned char*>(control_frame->data()),
+      control_frame->size());
+  EXPECT_TRUE(visitor.header_buffer_valid_);
+  EXPECT_EQ(0, visitor.error_count_);
+  EXPECT_EQ(1, visitor.headers_frame_count_);
+  EXPECT_EQ(1, visitor.continuation_count_);
+  EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
+}
+
+TEST_P(SpdyFramerTest, TooLargePushPromiseFrameUsesContinuation) {
+  if (spdy_version_ < SPDY4) {
+    return;
+  }
+  SpdyFramer framer(spdy_version_);
+  framer.set_enable_compression(false);
+  SpdyPushPromiseIR push_promise(1, 2);
+
+  // Exact payload length will change with HPACK, but this should be long
+  // enough to cause an overflow.
+  const size_t kBigValueSize = framer.GetControlFrameBufferMaxSize();
+  string big_value(kBigValueSize, 'x');
+  push_promise.SetHeader("aa", big_value.c_str());
+  scoped_ptr<SpdyFrame> control_frame(
+      framer.SerializePushPromise(push_promise));
+  EXPECT_TRUE(control_frame.get() != NULL);
+  EXPECT_GT(control_frame->size(), framer.GetControlFrameBufferMaxSize());
+
+  TestSpdyVisitor visitor(spdy_version_);
+  visitor.SimulateInFramer(
+      reinterpret_cast<unsigned char*>(control_frame->data()),
+      control_frame->size());
+  EXPECT_TRUE(visitor.header_buffer_valid_);
+  EXPECT_EQ(0, visitor.error_count_);
+  EXPECT_EQ(1, visitor.push_promise_frame_count_);
+  EXPECT_EQ(1, visitor.continuation_count_);
+  EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_);
+}
+
 // Check that the framer stops delivering header data chunks once the visitor
 // declares it doesn't want any more. This is important to guard against
 // "zip bomb" types of attacks.
@@ -2988,7 +3213,7 @@ TEST_P(SpdyFramerTest, ControlFrameMuchTooLarge) {
 }
 
 TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) {
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     // Deflate compression doesn't apply to HPACK.
     return;
   }
@@ -3027,7 +3252,8 @@ TEST_P(SpdyFramerTest, ControlFrameSizesAreValidated) {
 
   // SPDY version 4 and up GOAWAY frames are only bound to a minimal length,
   // since it may carry opaque data. Verify that minimal length is tested.
-  const unsigned char less_than_min_length =  framer.GetGoAwayMinimumSize() - 1;
+  const unsigned char less_than_min_length =
+      framer.GetGoAwayMinimumSize() - framer.GetControlFrameHeaderSize() - 1;
   const unsigned char kV4FrameData[] = {
     0x00, static_cast<uint8>(less_than_min_length), 0x07, 0x00,
     0x00, 0x00, 0x00, 0x00,
@@ -3066,8 +3292,13 @@ TEST_P(SpdyFramerTest, ReadZeroLenSettingsFrame) {
   visitor.SimulateInFramer(
       reinterpret_cast<unsigned char*>(control_frame->data()),
       framer.GetControlFrameHeaderSize());
-  // Should generate an error, since zero-len settings frames are unsupported.
-  EXPECT_EQ(1, visitor.error_count_);
+  if (spdy_version_ <= SPDY3) {
+    // Should generate an error, since zero-len settings frames are unsupported.
+    EXPECT_EQ(1, visitor.error_count_);
+  } else {
+    // Zero-len settings frames are permitted as of SPDY 4.
+    EXPECT_EQ(0, visitor.error_count_);
+  }
 }
 
 // Tests handling of SETTINGS frames with invalid length.
@@ -3077,11 +3308,8 @@ TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
 
   // Add a setting to pad the frame so that we don't get a buffer overflow when
   // calling SimulateInFramer() below.
-  SettingsMap settings;
-  settings[SETTINGS_UPLOAD_BANDWIDTH] =
-      SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, 0x00000002);
-  settings_ir.AddSetting(SETTINGS_UPLOAD_BANDWIDTH,
-                         true,  // please persist
+  settings_ir.AddSetting(SETTINGS_INITIAL_WINDOW_SIZE,
+                         false,
                          false,
                          0x00000002);
   scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
@@ -3101,22 +3329,18 @@ TEST_P(SpdyFramerTest, ReadBogusLenSettingsFrame) {
 TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
   SpdyFramer framer(spdy_version_);
   SpdySettingsIR settings_ir;
-  SettingsMap settings;
-
-  SpdySettingsFlags flags = SETTINGS_FLAG_PLEASE_PERSIST;
-  settings[SETTINGS_UPLOAD_BANDWIDTH] =
-    SettingsFlagsAndValue(flags, 0x00000002);
-  settings[SETTINGS_DOWNLOAD_BANDWIDTH] =
-    SettingsFlagsAndValue(flags, 0x00000003);
-  settings[SETTINGS_ROUND_TRIP_TIME] = SettingsFlagsAndValue(flags, 0x00000004);
-  for (SettingsMap::const_iterator it = settings.begin();
-       it != settings.end();
-       ++it) {
-    settings_ir.AddSetting(it->first,
-                           it->second.first & SETTINGS_FLAG_PLEASE_PERSIST,
-                           it->second.first & SETTINGS_FLAG_PERSISTED,
-                           it->second.second);
-  }
+  settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 1),
+                         false,  // persist
+                         false,  // persisted
+                         5);
+  settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 2),
+                         false,  // persist
+                         false,  // persisted
+                         6);
+  settings_ir.AddSetting(SpdyConstants::ParseSettingId(spdy_version_, 3),
+                         false,  // persist
+                         false,  // persisted
+                         7);
 
   scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
   EXPECT_LT(SpdyFramer::kControlFrameBufferSize,
@@ -3130,7 +3354,7 @@ TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
       control_frame->size());
   EXPECT_EQ(0, visitor.error_count_);
   EXPECT_EQ(3, visitor.setting_count_);
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     EXPECT_EQ(1, visitor.settings_ack_sent_);
   }
 
@@ -3148,7 +3372,7 @@ TEST_P(SpdyFramerTest, ReadLargeSettingsFrame) {
   }
   EXPECT_EQ(0, visitor.error_count_);
   EXPECT_EQ(3 * 2, visitor.setting_count_);
-  if (spdy_version_ >= 4) {
+  if (spdy_version_ > SPDY3) {
     EXPECT_EQ(2, visitor.settings_ack_sent_);
   }
 }
@@ -3180,7 +3404,7 @@ TEST_P(SpdyFramerTest, ReadDuplicateSettings) {
     0x00, 0x00, 0x00, 0x03,
   };
   const unsigned char kV4FrameData[] = {
-    0x00, 0x17, 0x04, 0x00,
+    0x00, 0x0f, 0x04, 0x00,
     0x00, 0x00, 0x00, 0x00,
     0x01,  // 1st Setting
     0x00, 0x00, 0x00, 0x02,
@@ -3239,7 +3463,7 @@ TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
     0x00, 0x00, 0x00, 0x03,
   };
   const unsigned char kV4FrameData[] = {
-    0x00, 0x17, 0x04, 0x00,
+    0x00, 0x0f, 0x04, 0x00,
     0x00, 0x00, 0x00, 0x00,
     0x02,  // 1st Setting
     0x00, 0x00, 0x00, 0x02,
@@ -3271,13 +3495,13 @@ TEST_P(SpdyFramerTest, ReadOutOfOrderSettings) {
 }
 
 TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
   SpdyFramer framer(spdy_version_);
 
   const unsigned char kFrameData[] = {
-    0x00, 0x08, 0x04, 0x01,
+    0x00, 0x00, 0x04, 0x01,
     0x00, 0x00, 0x00, 0x00,
   };
 
@@ -3290,10 +3514,79 @@ TEST_P(SpdyFramerTest, ProcessSettingsAckFrame) {
   EXPECT_EQ(1, visitor.settings_ack_received_);
 }
 
+
+TEST_P(SpdyFramerTest, ProcessDataFrameWithPadding) {
+  if (spdy_version_ <= SPDY3) {
+    return;
+  }
+
+  const int kPaddingLen = 512;  // So we get two bytes for padding length field.
+  const char data_payload[] = "hello";
+
+  testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+  SpdyFramer framer(spdy_version_);
+  framer.set_visitor(&visitor);
+
+  SpdyDataIR data_ir(1, StringPiece(data_payload, strlen(data_payload)));
+  data_ir.set_padding_len(kPaddingLen);
+  scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+  ASSERT_TRUE(frame.get() != NULL);
+
+  int bytes_consumed = 0;
+
+  // Send the frame header.
+  EXPECT_CALL(visitor, OnDataFrameHeader(1,
+                                         kPaddingLen + strlen(data_payload),
+                                         false));
+  CHECK_EQ(8u, framer.ProcessInput(frame->data(), 8));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_PADDING_LENGTH);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 8;
+
+  // Send the first byte of the padding length field.
+  CHECK_EQ(1u, framer.ProcessInput(frame->data() + bytes_consumed, 1));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_PADDING_LENGTH);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 1;
+
+  // Send the second byte of the padding length field.
+  CHECK_EQ(1u, framer.ProcessInput(frame->data() + bytes_consumed, 1));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 1;
+
+  // Send the first two bytes of the data payload.
+  EXPECT_CALL(visitor, OnStreamFrameData(1, _, 2, false));
+  CHECK_EQ(2u, framer.ProcessInput(frame->data() + bytes_consumed, 2));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_FORWARD_STREAM_FRAME);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 2;
+
+  // Send the rest three bytes of the data payload.
+  EXPECT_CALL(visitor, OnStreamFrameData(1, _, 3, false));
+  CHECK_EQ(3u, framer.ProcessInput(frame->data() + bytes_consumed, 3));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 3;
+
+  // Send the first 100 bytes of the padding payload.
+  EXPECT_CALL(visitor, OnStreamFrameData(1, NULL, 100, false));
+  CHECK_EQ(100u, framer.ProcessInput(frame->data() + bytes_consumed, 100));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_CONSUME_PADDING);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+  bytes_consumed += 100;
+
+  // Send rest of the padding payload.
+  EXPECT_CALL(visitor, OnStreamFrameData(1, NULL, 410, false));
+  CHECK_EQ(410u, framer.ProcessInput(frame->data() + bytes_consumed, 410));
+  CHECK_EQ(framer.state(), SpdyFramer::SPDY_RESET);
+  CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
+}
+
 TEST_P(SpdyFramerTest, ReadWindowUpdate) {
   SpdyFramer framer(spdy_version_);
   scoped_ptr<SpdyFrame> control_frame(
-      framer.SerializeWindowUpdate(net::SpdyWindowUpdateIR(1, 2)));
+      framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2)));
   TestSpdyVisitor visitor(spdy_version_);
   visitor.SimulateInFramer(
       reinterpret_cast<unsigned char*>(control_frame->data()),
@@ -3357,7 +3650,7 @@ TEST_P(SpdyFramerTest, ReadCredentialFrameFollowedByAnotherFrame) {
   string multiple_frame_data(reinterpret_cast<const char*>(kV3FrameData),
                              arraysize(kV3FrameData));
   scoped_ptr<SpdyFrame> control_frame(
-      framer.SerializeWindowUpdate(net::SpdyWindowUpdateIR(1, 2)));
+      framer.SerializeWindowUpdate(SpdyWindowUpdateIR(1, 2)));
   multiple_frame_data.append(string(control_frame->data(),
                                     control_frame->size()));
   visitor.SimulateInFramer(
@@ -3368,17 +3661,17 @@ TEST_P(SpdyFramerTest, ReadCredentialFrameFollowedByAnotherFrame) {
   EXPECT_EQ(2u, visitor.last_window_update_delta_);
 }
 
-TEST_P(SpdyFramerTest, CreateContinuation) {
+TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
   if (spdy_version_ < SPDY4) {
     return;
   }
 
   SpdyFramer framer(spdy_version_);
-
+  framer.set_enable_compression(false);
   const char kDescription[] = "CONTINUATION frame";
 
   const unsigned char kFrameData[] = {
-     0x00, 0x1a, 0x0d, 0x00,  // CONTINUATION
+     0x00, 0x12, 0x09, 0x00,  // CONTINUATION
      0x00, 0x00, 0x00, 0x2a,  // Stream 42
      0x40, 0x03, 0x62, 0x61,  // @.ba
      0x72, 0x03, 0x66, 0x6f,  // r.fo
@@ -3396,7 +3689,7 @@ TEST_P(SpdyFramerTest, CreateContinuation) {
 }
 
 TEST_P(SpdyFramerTest, ReadCompressedPushPromise) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
@@ -3419,19 +3712,19 @@ TEST_P(SpdyFramerTest, ReadCompressedPushPromise) {
 }
 
 TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x08, 0x00,  // HEADERS
+    0x00, 0x10, 0x01, 0x00,  // HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
     0x07, 0x66, 0x6f, 0x6f,
     0x3d, 0x62, 0x61, 0x72,
 
-    0x00, 0x1c, 0x0D, 0x00,  // CONTINUATION
+    0x00, 0x14, 0x09, 0x00,  // CONTINUATION
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3439,7 +3732,7 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
     0x3d, 0x62, 0x69, 0x6e,
     0x67, 0x40, 0x06, 0x43,
 
-    0x00, 0x1a, 0x0D, 0x04,  // CONTINUATION: END_HEADERS
+    0x00, 0x12, 0x09, 0x04,  // CONTINUATION: END_HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x6f, 0x6f, 0x6b, 0x69,
     0x65, 0x00, 0x40, 0x04,
@@ -3464,19 +3757,19 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuation) {
 }
 
 TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x08, 0x01,  // HEADERS: FIN
+    0x00, 0x10, 0x01, 0x01,  // HEADERS: FIN
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
     0x07, 0x66, 0x6f, 0x6f,
     0x3d, 0x62, 0x61, 0x72,
 
-    0x00, 0x1c, 0x0D, 0x00,  // CONTINUATION
+    0x00, 0x14, 0x09, 0x00,  // CONTINUATION
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3484,7 +3777,7 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
     0x3d, 0x62, 0x69, 0x6e,
     0x67, 0x40, 0x06, 0x43,
 
-    0x00, 0x1a, 0x0D, 0x04,  // CONTINUATION: END_HEADERS
+    0x00, 0x12, 0x09, 0x04,  // CONTINUATION: END_HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x6f, 0x6f, 0x6b, 0x69,
     0x65, 0x00, 0x40, 0x04,
@@ -3510,12 +3803,12 @@ TEST_P(SpdyFramerTest, ReadHeadersWithContinuationAndFin) {
 }
 
 TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x1c, 0x0C, 0x00,  // PUSH_PROMISE
+    0x00, 0x14, 0x05, 0x00,  // PUSH_PROMISE
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x00, 0x00, 0x00, 0x2A,  // Promised stream 42
     0x40, 0x06, 0x43, 0x6f,
@@ -3523,7 +3816,7 @@ TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
     0x07, 0x66, 0x6f, 0x6f,
     0x3d, 0x62, 0x61, 0x72,
 
-    0x00, 0x1c, 0x0D, 0x00,  // CONTINUATION
+    0x00, 0x14, 0x09, 0x00,  // CONTINUATION
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3531,7 +3824,7 @@ TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
     0x3d, 0x62, 0x69, 0x6e,
     0x67, 0x40, 0x06, 0x43,
 
-    0x00, 0x1a, 0x0D, 0x04,  // CONTINUATION: END_HEADERS
+    0x00, 0x12, 0x09, 0x04,  // CONTINUATION: END_HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x6f, 0x6f, 0x6b, 0x69,
     0x65, 0x00, 0x40, 0x04,
@@ -3557,19 +3850,19 @@ TEST_P(SpdyFramerTest, ReadPushPromiseWithContinuation) {
 }
 
 TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x08, 0x00,  // HEADERS
+    0x00, 0x10, 0x01, 0x00,  // HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
     0x07, 0x66, 0x6f, 0x6f,
     0x3d, 0x62, 0x61, 0x72,
 
-    0x00, 0x1c, 0x0D, 0x00,  // CONTINUATION
+    0x00, 0x14, 0x09, 0x00,  // CONTINUATION
     0x00, 0x00, 0x00, 0x02,  // Stream 2
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3593,12 +3886,12 @@ TEST_P(SpdyFramerTest, ReadContinuationWithWrongStreamId) {
 }
 
 TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x0D, 0x00,  // CONTINUATION
+    0x00, 0x10, 0x09, 0x00,  // CONTINUATION
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3620,12 +3913,12 @@ TEST_P(SpdyFramerTest, ReadContinuationOutOfOrder) {
 }
 
 TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x08, 0x00,  // HEADERS
+    0x00, 0x10, 0x01, 0x00,  // HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
@@ -3653,19 +3946,19 @@ TEST_P(SpdyFramerTest, ExpectContinuationReceiveData) {
 }
 
 TEST_P(SpdyFramerTest, ExpectContinuationReceiveControlFrame) {
-  if (spdy_version_ < 4) {
+  if (spdy_version_ <= SPDY3) {
     return;
   }
 
   const unsigned char kInput[] = {
-    0x00, 0x18, 0x08, 0x00,  // HEADERS
+    0x00, 0x10, 0x01, 0x00,  // HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,
     0x6f, 0x6b, 0x69, 0x65,
     0x07, 0x66, 0x6f, 0x6f,
     0x3d, 0x62, 0x61, 0x72,
 
-    0x00, 0x1c, 0x08, 0x00,  // HEADERS
+    0x00, 0x14, 0x08, 0x00,  // HEADERS
     0x00, 0x00, 0x00, 0x01,  // Stream 1
     0x40, 0x06, 0x43, 0x6f,  // (Note this is a valid continued encoding).
     0x6f, 0x6b, 0x69, 0x65,
@@ -3699,6 +3992,23 @@ TEST_P(SpdyFramerTest, ReadGarbage) {
   EXPECT_EQ(1, visitor.error_count_);
 }
 
+TEST_P(SpdyFramerTest, ReadGarbageWithValidLength) {
+  if (!IsSpdy4()) {
+    return;
+  }
+  SpdyFramer framer(spdy_version_);
+  const unsigned char kFrameData[] = {
+    0x00, 0x10, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff,
+  };
+  TestSpdyVisitor visitor(spdy_version_);
+  visitor.use_compression_ = false;
+  visitor.SimulateInFramer(kFrameData, arraysize(kFrameData));
+  EXPECT_EQ(1, visitor.error_count_);
+}
+
 TEST_P(SpdyFramerTest, ReadGarbageWithValidVersion) {
   if (IsSpdy4()) {
     // Not valid for SPDY 4 since there is no version field.
@@ -3829,7 +4139,7 @@ TEST_P(SpdyFramerTest, StatusCodeToStringTest) {
   EXPECT_STREQ("FLOW_CONTROL_ERROR",
                SpdyFramer::StatusCodeToString(RST_STREAM_FLOW_CONTROL_ERROR));
   EXPECT_STREQ("UNKNOWN_STATUS",
-               SpdyFramer::StatusCodeToString(RST_STREAM_NUM_STATUS_CODES));
+               SpdyFramer::StatusCodeToString(-1));
 }
 
 TEST_P(SpdyFramerTest, FrameTypeToStringTest) {
@@ -3892,7 +4202,11 @@ TEST_P(SpdyFramerTest, CatchProbableHttpResponse) {
   }
 }
 
-TEST_P(SpdyFramerTest, DataFrameFlags) {
+TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) {
+  if (spdy_version_ > SPDY3) {
+    return;
+  }
+
   for (int flags = 0; flags < 256; ++flags) {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
@@ -3900,7 +4214,7 @@ TEST_P(SpdyFramerTest, DataFrameFlags) {
     SpdyFramer framer(spdy_version_);
     framer.set_visitor(&visitor);
 
-    net::SpdyDataIR data_ir(1, StringPiece("hello", 5));
+    SpdyDataIR data_ir(1, StringPiece("hello", 5));
     scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
     SetFrameFlags(frame.get(), flags, spdy_version_);
 
@@ -3928,6 +4242,55 @@ TEST_P(SpdyFramerTest, DataFrameFlags) {
   }
 }
 
+TEST_P(SpdyFramerTest, DataFrameFlagsV4) {
+  if (spdy_version_ <= SPDY3) {
+    return;
+  }
+
+  uint8 valid_data_flags = DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT |
+      DATA_FLAG_PAD_LOW | DATA_FLAG_PAD_HIGH;
+
+  for (int flags = 0; flags < 256; ++flags) {
+    SCOPED_TRACE(testing::Message() << "Flags " << flags);
+
+    testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
+    SpdyFramer framer(spdy_version_);
+    framer.set_visitor(&visitor);
+
+    SpdyDataIR data_ir(1, StringPiece("hello", 5));
+    scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir));
+    SetFrameFlags(frame.get(), flags, spdy_version_);
+
+    if (flags & ~valid_data_flags) {
+      EXPECT_CALL(visitor, OnError(_));
+    } else {
+      EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN));
+      if ((flags & DATA_FLAG_PAD_LOW) || (flags & DATA_FLAG_PAD_HIGH)) {
+        // Expect Error since we don't set pad_high and pad_low in payload.
+        EXPECT_CALL(visitor, OnError(_));
+      } else {
+        EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false));
+        if (flags & DATA_FLAG_FIN) {
+          EXPECT_CALL(visitor, OnStreamFrameData(_, _, 0, true));
+        }
+      }
+    }
+
+    framer.ProcessInput(frame->data(), frame->size());
+    if ((flags & ~valid_data_flags) || (flags & DATA_FLAG_PAD_LOW) ||
+        (flags & DATA_FLAG_PAD_HIGH)) {
+        EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+        EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS,
+                  framer.error_code())
+            << SpdyFramer::ErrorCodeToString(framer.error_code());
+    } else {
+      EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
+      EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+          << SpdyFramer::ErrorCodeToString(framer.error_code());
+    }
+  }
+}
+
 TEST_P(SpdyFramerTest, SynStreamFrameFlags) {
   for (int flags = 0; flags < 256; ++flags) {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
@@ -4053,7 +4416,7 @@ TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
     SpdyFramer framer(spdy_version_);
     framer.set_visitor(&visitor);
 
-    net::SpdyRstStreamIR rst_stream(13, RST_STREAM_CANCEL, "");
+    SpdyRstStreamIR rst_stream(13, RST_STREAM_CANCEL, "");
     scoped_ptr<SpdyFrame> frame(framer.SerializeRstStream(rst_stream));
     SetFrameFlags(frame.get(), flags, spdy_version_);
 
@@ -4078,7 +4441,7 @@ TEST_P(SpdyFramerTest, RstStreamFrameFlags) {
 }
 
 TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) {
-  if (spdy_version_ >= 4) { return; }
+  if (spdy_version_ > SPDY3) { return; }
   for (int flags = 0; flags < 256; ++flags) {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
@@ -4119,7 +4482,7 @@ TEST_P(SpdyFramerTest, SettingsFrameFlagsOldFormat) {
 }
 
 TEST_P(SpdyFramerTest, SettingsFrameFlags) {
-  if (spdy_version_ < 4) { return; }
+  if (spdy_version_ <= SPDY3) { return; }
   for (int flags = 0; flags < 256; ++flags) {
     SCOPED_TRACE(testing::Message() << "Flags " << flags);
 
@@ -4265,7 +4628,7 @@ TEST_P(SpdyFramerTest, PingFrameFlags) {
     scoped_ptr<SpdyFrame> frame(framer.SerializePing(SpdyPingIR(42)));
     SetFrameFlags(frame.get(), flags, spdy_version_);
 
-    if (spdy_version_ >= SPDY4 &&
+    if (spdy_version_ > SPDY3 &&
         flags == PING_FLAG_ACK) {
       EXPECT_CALL(visitor, OnPing(42, true));
     } else if (flags == 0) {
@@ -4275,7 +4638,7 @@ TEST_P(SpdyFramerTest, PingFrameFlags) {
     }
 
     framer.ProcessInput(frame->data(), frame->size());
-    if ((spdy_version_ >= SPDY4 && flags == PING_FLAG_ACK) ||
+    if ((spdy_version_ > SPDY3 && flags == PING_FLAG_ACK) ||
         flags == 0) {
       EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
       EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
@@ -4298,7 +4661,7 @@ TEST_P(SpdyFramerTest, WindowUpdateFrameFlags) {
     framer.set_visitor(&visitor);
 
     scoped_ptr<SpdyFrame> frame(framer.SerializeWindowUpdate(
-        net::SpdyWindowUpdateIR(4, 1024)));
+        SpdyWindowUpdateIR(4, 1024)));
     SetFrameFlags(frame.get(), flags, spdy_version_);
 
     if (flags != 0) {
@@ -4437,17 +4800,10 @@ TEST_P(SpdyFramerTest, EmptySynStream) {
   syn_stream.set_priority(1);
   scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream));
   // Adjust size to remove the name/value block.
-  if (IsSpdy4()) {
-    SetFrameLength(
-        frame.get(),
-        framer.GetSynStreamMinimumSize(),
-        spdy_version_);
-  } else {
-    SetFrameLength(
-        frame.get(),
-        framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
-        spdy_version_);
-  }
+  SetFrameLength(
+      frame.get(),
+      framer.GetSynStreamMinimumSize() - framer.GetControlFrameHeaderSize(),
+      spdy_version_);
 
   EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(1, SYN_STREAM, _));
   EXPECT_CALL(visitor, OnSynStream(1, 0, 1, false, false));
@@ -4473,61 +4829,72 @@ TEST_P(SpdyFramerTest, SettingsFlagsAndId) {
 
 // Test handling of a RST_STREAM with out-of-bounds status codes.
 TEST_P(SpdyFramerTest, RstStreamStatusBounds) {
-  DCHECK_GE(0xff, RST_STREAM_NUM_STATUS_CODES);
-
+  const unsigned char kRstStreamStatusTooLow = 0x00;
+  const unsigned char kRstStreamStatusTooHigh = 0xff;
   const unsigned char kV3RstStreamInvalid[] = {
     0x80, spdy_version_ch_, 0x00, 0x03,
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, RST_STREAM_INVALID
+    0x00, 0x00, 0x00, kRstStreamStatusTooLow
   };
   const unsigned char kV4RstStreamInvalid[] = {
-    0x00, 0x0c, 0x03, 0x00,
+    0x00, 0x04, 0x03, 0x00,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, RST_STREAM_INVALID
+    0x00, 0x00, 0x00, kRstStreamStatusTooLow
   };
 
   const unsigned char kV3RstStreamNumStatusCodes[] = {
     0x80, spdy_version_ch_, 0x00, 0x03,
     0x00, 0x00, 0x00, 0x08,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
+    0x00, 0x00, 0x00, kRstStreamStatusTooHigh
   };
   const unsigned char kV4RstStreamNumStatusCodes[] = {
-    0x00, 0x0c, 0x03, 0x00,
+    0x00, 0x04, 0x03, 0x00,
     0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x00, RST_STREAM_NUM_STATUS_CODES
+    0x00, 0x00, 0x00, kRstStreamStatusTooHigh
   };
 
   testing::StrictMock<test::MockSpdyFramerVisitor> visitor;
   SpdyFramer framer(spdy_version_);
   framer.set_visitor(&visitor);
 
-  EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
   if (IsSpdy4()) {
+    EXPECT_CALL(visitor, OnError(_));
     framer.ProcessInput(reinterpret_cast<const char*>(kV4RstStreamInvalid),
                         arraysize(kV4RstStreamInvalid));
+    EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+    EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
+      << SpdyFramer::ErrorCodeToString(framer.error_code());
   } else {
+    EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
     framer.ProcessInput(reinterpret_cast<const char*>(kV3RstStreamInvalid),
                         arraysize(kV3RstStreamInvalid));
-  }
-  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
-  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+    EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
+    EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
       << SpdyFramer::ErrorCodeToString(framer.error_code());
+  }
+
+
+  framer.Reset();
 
-  EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
   if (IsSpdy4()) {
+    EXPECT_CALL(visitor, OnError(_));
     framer.ProcessInput(
         reinterpret_cast<const char*>(kV4RstStreamNumStatusCodes),
         arraysize(kV4RstStreamNumStatusCodes));
+    EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state());
+    EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME, framer.error_code())
+      << SpdyFramer::ErrorCodeToString(framer.error_code());
   } else {
+    EXPECT_CALL(visitor, OnRstStream(1, RST_STREAM_INVALID));
     framer.ProcessInput(
         reinterpret_cast<const char*>(kV3RstStreamNumStatusCodes),
         arraysize(kV3RstStreamNumStatusCodes));
-  }
-  EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
-  EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
+    EXPECT_EQ(SpdyFramer::SPDY_RESET, framer.state());
+    EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code())
       << SpdyFramer::ErrorCodeToString(framer.error_code());
+  }
 }
 
 // Tests handling of a GOAWAY frame with out-of-bounds stream ID.
@@ -4544,7 +4911,7 @@ TEST_P(SpdyFramerTest, GoAwayStreamIdBounds) {
     0x00, 0x00, 0x00, 0x00,
   };
   const unsigned char kV4FrameData[] = {
-    0x00, 0x10, 0x07, 0x00,
+    0x00, 0x08, 0x07, 0x00,
     0x00, 0x00, 0x00, 0x00,
     0xff, 0xff, 0xff, 0xff,
     0x00, 0x00, 0x00, 0x00,