Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/spdy/buffered_spdy_framer.h"
      6 
      7 #include "net/spdy/spdy_test_util_common.h"
      8 #include "testing/platform_test.h"
      9 
     10 namespace net {
     11 
     12 namespace {
     13 
     14 class TestBufferedSpdyVisitor : public BufferedSpdyFramerVisitorInterface {
     15  public:
     16   explicit TestBufferedSpdyVisitor(SpdyMajorVersion spdy_version)
     17       : buffered_spdy_framer_(spdy_version, true),
     18         error_count_(0),
     19         setting_count_(0),
     20         syn_frame_count_(0),
     21         syn_reply_frame_count_(0),
     22         headers_frame_count_(0),
     23         header_stream_id_(-1) {
     24   }
     25 
     26   virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE {
     27     LOG(INFO) << "SpdyFramer Error: " << error_code;
     28     error_count_++;
     29   }
     30 
     31   virtual void OnStreamError(
     32       SpdyStreamId stream_id,
     33       const std::string& description) OVERRIDE {
     34     LOG(INFO) << "SpdyFramer Error on stream: " << stream_id  << " "
     35               << description;
     36     error_count_++;
     37   }
     38 
     39   virtual void OnSynStream(SpdyStreamId stream_id,
     40                            SpdyStreamId associated_stream_id,
     41                            SpdyPriority priority,
     42                            uint8 credential_slot,
     43                            bool fin,
     44                            bool unidirectional,
     45                            const SpdyHeaderBlock& headers) OVERRIDE {
     46     header_stream_id_ = stream_id;
     47     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
     48     syn_frame_count_++;
     49     headers_ = headers;
     50   }
     51 
     52   virtual void OnSynReply(SpdyStreamId stream_id,
     53                           bool fin,
     54                           const SpdyHeaderBlock& headers) OVERRIDE {
     55     header_stream_id_ = stream_id;
     56     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
     57     syn_reply_frame_count_++;
     58     headers_ = headers;
     59   }
     60 
     61   virtual void OnHeaders(SpdyStreamId stream_id,
     62                          bool fin,
     63                          const SpdyHeaderBlock& headers) OVERRIDE {
     64     header_stream_id_ = stream_id;
     65     EXPECT_NE(header_stream_id_, SpdyFramer::kInvalidStream);
     66     headers_frame_count_++;
     67     headers_ = headers;
     68   }
     69 
     70   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
     71                                  size_t length,
     72                                  bool fin) OVERRIDE {
     73     ADD_FAILURE() << "Unexpected OnDataFrameHeader call.";
     74   }
     75 
     76   virtual void OnStreamFrameData(SpdyStreamId stream_id,
     77                                  const char* data,
     78                                  size_t len,
     79                                  bool fin) OVERRIDE {
     80     LOG(FATAL) << "Unexpected OnStreamFrameData call.";
     81   }
     82 
     83   virtual void OnSettings(bool clear_persisted) OVERRIDE {}
     84 
     85   virtual void OnSetting(SpdySettingsIds id,
     86                          uint8 flags,
     87                          uint32 value) OVERRIDE {
     88     setting_count_++;
     89   }
     90 
     91   virtual void OnPing(uint32 unique_id) OVERRIDE {}
     92 
     93   virtual void OnRstStream(SpdyStreamId stream_id,
     94                            SpdyRstStreamStatus status) OVERRIDE {
     95   }
     96 
     97   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
     98                         SpdyGoAwayStatus status) OVERRIDE {
     99   }
    100 
    101   bool OnCredentialFrameData(const char*, size_t) {
    102     LOG(FATAL) << "Unexpected OnCredentialFrameData call.";
    103     return false;
    104   }
    105 
    106   void OnDataFrameHeader(const SpdyFrame* frame) {
    107     LOG(FATAL) << "Unexpected OnDataFrameHeader call.";
    108   }
    109 
    110   void OnRstStream(const SpdyFrame& frame) {}
    111   void OnGoAway(const SpdyFrame& frame) {}
    112   void OnPing(const SpdyFrame& frame) {}
    113   virtual void OnWindowUpdate(SpdyStreamId stream_id,
    114                               uint32 delta_window_size) OVERRIDE {}
    115   virtual void OnPushPromise(SpdyStreamId stream_id,
    116                              SpdyStreamId promised_stream_id) OVERRIDE {}
    117   void OnCredential(const SpdyFrame& frame) {}
    118 
    119   // Convenience function which runs a framer simulation with particular input.
    120   void SimulateInFramer(const unsigned char* input, size_t size) {
    121     buffered_spdy_framer_.set_visitor(this);
    122     size_t input_remaining = size;
    123     const char* input_ptr = reinterpret_cast<const char*>(input);
    124     while (input_remaining > 0 &&
    125            buffered_spdy_framer_.error_code() == SpdyFramer::SPDY_NO_ERROR) {
    126       // To make the tests more interesting, we feed random (amd small) chunks
    127       // into the framer.  This simulates getting strange-sized reads from
    128       // the socket.
    129       const size_t kMaxReadSize = 32;
    130       size_t bytes_read =
    131           (rand() % std::min(input_remaining, kMaxReadSize)) + 1;
    132       size_t bytes_processed =
    133           buffered_spdy_framer_.ProcessInput(input_ptr, bytes_read);
    134       input_remaining -= bytes_processed;
    135       input_ptr += bytes_processed;
    136     }
    137   }
    138 
    139   BufferedSpdyFramer buffered_spdy_framer_;
    140 
    141   // Counters from the visitor callbacks.
    142   int error_count_;
    143   int setting_count_;
    144   int syn_frame_count_;
    145   int syn_reply_frame_count_;
    146   int headers_frame_count_;
    147 
    148   // Header block streaming state:
    149   SpdyStreamId header_stream_id_;
    150 
    151   // Headers from OnSyn, OnSynReply and OnHeaders for verification.
    152   SpdyHeaderBlock headers_;
    153 };
    154 
    155 }  // namespace
    156 
    157 class BufferedSpdyFramerTest
    158     : public PlatformTest,
    159       public ::testing::WithParamInterface<NextProto> {
    160  protected:
    161   // Returns true if the two header blocks have equivalent content.
    162   bool CompareHeaderBlocks(const SpdyHeaderBlock* expected,
    163                            const SpdyHeaderBlock* actual) {
    164     if (expected->size() != actual->size()) {
    165       LOG(ERROR) << "Expected " << expected->size() << " headers; actually got "
    166                  << actual->size() << ".";
    167       return false;
    168     }
    169     for (SpdyHeaderBlock::const_iterator it = expected->begin();
    170          it != expected->end();
    171          ++it) {
    172       SpdyHeaderBlock::const_iterator it2 = actual->find(it->first);
    173       if (it2 == actual->end()) {
    174         LOG(ERROR) << "Expected header name '" << it->first << "'.";
    175         return false;
    176       }
    177       if (it->second.compare(it2->second) != 0) {
    178         LOG(ERROR) << "Expected header named '" << it->first
    179                    << "' to have a value of '" << it->second
    180                    << "'. The actual value received was '" << it2->second
    181                    << "'.";
    182         return false;
    183       }
    184     }
    185     return true;
    186   }
    187 
    188   SpdyMajorVersion spdy_version() {
    189     return NextProtoToSpdyMajorVersion(GetParam());
    190   }
    191 };
    192 
    193 INSTANTIATE_TEST_CASE_P(
    194     NextProto,
    195     BufferedSpdyFramerTest,
    196     testing::Values(kProtoDeprecatedSPDY2,
    197                     kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
    198                     kProtoHTTP2Draft04));
    199 
    200 TEST_P(BufferedSpdyFramerTest, OnSetting) {
    201   SpdyFramer framer(spdy_version());
    202   SettingsMap settings;
    203   settings[SETTINGS_UPLOAD_BANDWIDTH] =
    204       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 0x00000002);
    205   settings[SETTINGS_DOWNLOAD_BANDWIDTH] =
    206       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, 0x00000003);
    207 
    208   scoped_ptr<SpdyFrame> control_frame(framer.CreateSettings(settings));
    209   TestBufferedSpdyVisitor visitor(spdy_version());
    210 
    211   visitor.SimulateInFramer(
    212       reinterpret_cast<unsigned char*>(control_frame->data()),
    213       control_frame->size());
    214   EXPECT_EQ(0, visitor.error_count_);
    215   EXPECT_EQ(2, visitor.setting_count_);
    216 }
    217 
    218 TEST_P(BufferedSpdyFramerTest, ReadSynStreamHeaderBlock) {
    219   SpdyHeaderBlock headers;
    220   headers["aa"] = "vv";
    221   headers["bb"] = "ww";
    222   BufferedSpdyFramer framer(spdy_version(), true);
    223   scoped_ptr<SpdyFrame> control_frame(
    224       framer.CreateSynStream(1,                        // stream_id
    225                              0,                        // associated_stream_id
    226                              1,                        // priority
    227                              0,                        // credential_slot
    228                              CONTROL_FLAG_NONE,
    229                              &headers));
    230   EXPECT_TRUE(control_frame.get() != NULL);
    231 
    232   TestBufferedSpdyVisitor visitor(spdy_version());
    233   visitor.SimulateInFramer(
    234       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
    235       control_frame.get()->size());
    236   EXPECT_EQ(0, visitor.error_count_);
    237   EXPECT_EQ(1, visitor.syn_frame_count_);
    238   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
    239   EXPECT_EQ(0, visitor.headers_frame_count_);
    240   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
    241 }
    242 
    243 TEST_P(BufferedSpdyFramerTest, ReadSynReplyHeaderBlock) {
    244   SpdyHeaderBlock headers;
    245   headers["alpha"] = "beta";
    246   headers["gamma"] = "delta";
    247   BufferedSpdyFramer framer(spdy_version(), true);
    248   scoped_ptr<SpdyFrame> control_frame(
    249       framer.CreateSynReply(1,                        // stream_id
    250                             CONTROL_FLAG_NONE,
    251                             &headers));
    252   EXPECT_TRUE(control_frame.get() != NULL);
    253 
    254   TestBufferedSpdyVisitor visitor(spdy_version());
    255   visitor.SimulateInFramer(
    256       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
    257       control_frame.get()->size());
    258   EXPECT_EQ(0, visitor.error_count_);
    259   EXPECT_EQ(0, visitor.syn_frame_count_);
    260   EXPECT_EQ(1, visitor.syn_reply_frame_count_);
    261   EXPECT_EQ(0, visitor.headers_frame_count_);
    262   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
    263 }
    264 
    265 TEST_P(BufferedSpdyFramerTest, ReadHeadersHeaderBlock) {
    266   SpdyHeaderBlock headers;
    267   headers["alpha"] = "beta";
    268   headers["gamma"] = "delta";
    269   BufferedSpdyFramer framer(spdy_version(), true);
    270   scoped_ptr<SpdyFrame> control_frame(
    271       framer.CreateHeaders(1,                        // stream_id
    272                            CONTROL_FLAG_NONE,
    273                            &headers));
    274   EXPECT_TRUE(control_frame.get() != NULL);
    275 
    276   TestBufferedSpdyVisitor visitor(spdy_version());
    277   visitor.SimulateInFramer(
    278       reinterpret_cast<unsigned char*>(control_frame.get()->data()),
    279       control_frame.get()->size());
    280   EXPECT_EQ(0, visitor.error_count_);
    281   EXPECT_EQ(0, visitor.syn_frame_count_);
    282   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
    283   EXPECT_EQ(1, visitor.headers_frame_count_);
    284   EXPECT_TRUE(CompareHeaderBlocks(&headers, &visitor.headers_));
    285 }
    286 
    287 }  // namespace net
    288