Home | History | Annotate | Download | only in websockets
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "modules/websockets/WebSocketExtensionDispatcher.h"
     28 
     29 #include "modules/websockets/WebSocketExtensionParser.h"
     30 #include "modules/websockets/WebSocketExtensionProcessor.h"
     31 #include "wtf/text/CString.h"
     32 #include "wtf/text/StringHash.h"
     33 #include <gtest/gtest.h>
     34 
     35 using namespace WebCore;
     36 
     37 namespace {
     38 
     39 class WebSocketExtensionDispatcherTest;
     40 
     41 class MockWebSocketExtensionProcessor : public WebSocketExtensionProcessor {
     42 public:
     43     MockWebSocketExtensionProcessor(const String& name, WebSocketExtensionDispatcherTest* test)
     44         : WebSocketExtensionProcessor(name)
     45         , m_test(test)
     46     {
     47     }
     48     virtual String handshakeString() OVERRIDE { return extensionToken(); }
     49     virtual bool processResponse(const HashMap<String, String>&) OVERRIDE;
     50 
     51 private:
     52     WebSocketExtensionDispatcherTest* m_test;
     53 };
     54 
     55 class WebSocketExtensionDispatcherTest : public testing::Test {
     56 public:
     57     WebSocketExtensionDispatcherTest() { }
     58 
     59     void SetUp() { }
     60 
     61     void TearDown() { }
     62 
     63     void addMockProcessor(const String& extensionToken)
     64     {
     65         m_extensions.addProcessor(adoptPtr(new MockWebSocketExtensionProcessor(extensionToken, this)));
     66 
     67     }
     68 
     69     void appendResult(const String& extensionToken, const HashMap<String, String>& parameters)
     70     {
     71         m_parsedExtensionTokens.append(extensionToken);
     72         m_parsedParameters.append(parameters);
     73     }
     74 
     75 protected:
     76     WebSocketExtensionDispatcher m_extensions;
     77     Vector<String> m_parsedExtensionTokens;
     78     Vector<HashMap<String, String> > m_parsedParameters;
     79 };
     80 
     81 bool MockWebSocketExtensionProcessor::processResponse(const HashMap<String, String>& parameters)
     82 {
     83     m_test->appendResult(extensionToken(), parameters);
     84     return true;
     85 }
     86 
     87 TEST_F(WebSocketExtensionDispatcherTest, TestSingle)
     88 {
     89     addMockProcessor("deflate-frame");
     90     EXPECT_TRUE(m_extensions.processHeaderValue("deflate-frame"));
     91     EXPECT_EQ(1UL, m_parsedExtensionTokens.size());
     92     EXPECT_EQ("deflate-frame", m_parsedExtensionTokens[0]);
     93     EXPECT_EQ("deflate-frame", m_extensions.acceptedExtensions());
     94     EXPECT_EQ(0, m_parsedParameters[0].size());
     95 }
     96 
     97 TEST_F(WebSocketExtensionDispatcherTest, TestParameters)
     98 {
     99     addMockProcessor("mux");
    100     EXPECT_TRUE(m_extensions.processHeaderValue("mux; max-channels=4; flow-control  "));
    101     EXPECT_EQ(1UL, m_parsedExtensionTokens.size());
    102     EXPECT_EQ("mux", m_parsedExtensionTokens[0]);
    103     EXPECT_EQ(2, m_parsedParameters[0].size());
    104     HashMap<String, String>::iterator parameter = m_parsedParameters[0].find("max-channels");
    105     EXPECT_TRUE(parameter != m_parsedParameters[0].end());
    106     EXPECT_EQ("4", parameter->value);
    107     parameter = m_parsedParameters[0].find("flow-control");
    108     EXPECT_TRUE(parameter != m_parsedParameters[0].end());
    109     EXPECT_TRUE(parameter->value.isNull());
    110 }
    111 
    112 TEST_F(WebSocketExtensionDispatcherTest, TestMultiple)
    113 {
    114     struct {
    115         String token;
    116         HashMap<String, String> parameters;
    117     } expected[2];
    118     expected[0].token = "mux";
    119     expected[0].parameters.add("max-channels", "4");
    120     expected[0].parameters.add("flow-control", String());
    121     expected[1].token = "deflate-frame";
    122 
    123     addMockProcessor("mux");
    124     addMockProcessor("deflate-frame");
    125     EXPECT_TRUE(m_extensions.processHeaderValue("mux ;  max-channels =4;flow-control, deflate-frame  "));
    126     EXPECT_TRUE(m_extensions.acceptedExtensions().find("mux") != notFound);
    127     EXPECT_TRUE(m_extensions.acceptedExtensions().find("deflate-frame") != notFound);
    128     for (size_t i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) {
    129         EXPECT_EQ(expected[i].token, m_parsedExtensionTokens[i]);
    130         const HashMap<String, String>& expectedParameters = expected[i].parameters;
    131         const HashMap<String, String>& parsedParameters = m_parsedParameters[i];
    132         EXPECT_EQ(expected[i].parameters.size(), m_parsedParameters[i].size());
    133         for (HashMap<String, String>::const_iterator iterator = expectedParameters.begin(); iterator != expectedParameters.end(); ++iterator) {
    134             HashMap<String, String>::const_iterator parsed = parsedParameters.find(iterator->key);
    135             EXPECT_TRUE(parsed != parsedParameters.end());
    136             if (iterator->value.isNull())
    137                 EXPECT_TRUE(parsed->value.isNull());
    138             else
    139                 EXPECT_EQ(iterator->value, parsed->value);
    140         }
    141     }
    142 }
    143 
    144 TEST_F(WebSocketExtensionDispatcherTest, TestQuotedString)
    145 {
    146     addMockProcessor("x-foo");
    147     ASSERT_TRUE(m_extensions.processHeaderValue("x-foo; param1=\"quoted-string\"; param2=\"quoted\\.string\""));
    148     EXPECT_EQ(2, m_parsedParameters[0].size());
    149     EXPECT_EQ("quoted-string", m_parsedParameters[0].get("param1"));
    150     EXPECT_EQ("quoted.string", m_parsedParameters[0].get("param2"));
    151 }
    152 
    153 TEST_F(WebSocketExtensionDispatcherTest, TestInvalid)
    154 {
    155     const char* inputs[] = {
    156         "\"x-foo\"",
    157         "x-baz",
    158         "x-foo\\",
    159         "x-(foo)",
    160         "x-foo; ",
    161         "x-foo; bar=",
    162         "x-foo; bar=x y",
    163         "x-foo; bar=\"mismatch quote",
    164         "x-foo; bar=\"\\\"",
    165         "x-foo; \"bar\"=baz",
    166         "x-foo; bar=\"\"",
    167         "x-foo; bar=\" \"",
    168         "x-foo; bar=\"bar baz\"",
    169         "x-foo; bar=\"bar,baz\"",
    170         "x-foo; bar=\"ba\xffr,baz\"",
    171         "x-foo x-bar",
    172         "x-foo, x-baz"
    173         "x-foo, ",
    174     };
    175     for (size_t i = 0; i < sizeof(inputs) / sizeof(inputs[0]); ++i) {
    176         m_extensions.reset();
    177         addMockProcessor("x-foo");
    178         addMockProcessor("x-bar");
    179         EXPECT_FALSE(m_extensions.processHeaderValue(inputs[i]));
    180         EXPECT_TRUE(m_extensions.acceptedExtensions().isNull());
    181     }
    182 }
    183 
    184 }
    185