1 // Copyright 2013 The Chromium Authors
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/websockets/websocket_inflater.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "net/base/io_buffer.h"
11 #include "net/websockets/websocket_deflater.h"
12 #include "net/websockets/websocket_test_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace net {
16
17 namespace {
18
ToString(IOBufferWithSize * buffer)19 std::string ToString(IOBufferWithSize* buffer) {
20 return std::string(buffer->data(), buffer->size());
21 }
22
TEST(WebSocketInflaterTest,Construct)23 TEST(WebSocketInflaterTest, Construct) {
24 WebSocketInflater inflater;
25 ASSERT_TRUE(inflater.Initialize(15));
26
27 EXPECT_EQ(0u, inflater.CurrentOutputSize());
28 }
29
TEST(WebSocketInflaterTest,InflateHelloTakeOverContext)30 TEST(WebSocketInflaterTest, InflateHelloTakeOverContext) {
31 WebSocketInflater inflater;
32 ASSERT_TRUE(inflater.Initialize(15));
33 scoped_refptr<IOBufferWithSize> actual1, actual2;
34
35 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
36 ASSERT_TRUE(inflater.Finish());
37 actual1 = inflater.GetOutput(inflater.CurrentOutputSize());
38 ASSERT_TRUE(actual1.get());
39 EXPECT_EQ("Hello", ToString(actual1.get()));
40 EXPECT_EQ(0u, inflater.CurrentOutputSize());
41
42 ASSERT_TRUE(inflater.AddBytes("\xf2\x00\x11\x00\x00", 5));
43 ASSERT_TRUE(inflater.Finish());
44 actual2 = inflater.GetOutput(inflater.CurrentOutputSize());
45 ASSERT_TRUE(actual2.get());
46 EXPECT_EQ("Hello", ToString(actual2.get()));
47 EXPECT_EQ(0u, inflater.CurrentOutputSize());
48 }
49
TEST(WebSocketInflaterTest,InflateHelloSmallCapacity)50 TEST(WebSocketInflaterTest, InflateHelloSmallCapacity) {
51 WebSocketInflater inflater(1, 1);
52 ASSERT_TRUE(inflater.Initialize(15));
53 std::string actual;
54
55 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
56 ASSERT_TRUE(inflater.Finish());
57 for (size_t i = 0; i < 5; ++i) {
58 ASSERT_EQ(1u, inflater.CurrentOutputSize());
59 scoped_refptr<IOBufferWithSize> buffer = inflater.GetOutput(1);
60 ASSERT_TRUE(buffer.get());
61 ASSERT_EQ(1, buffer->size());
62 actual += ToString(buffer.get());
63 }
64 EXPECT_EQ("Hello", actual);
65 EXPECT_EQ(0u, inflater.CurrentOutputSize());
66 }
67
TEST(WebSocketInflaterTest,InflateHelloSmallCapacityGetTotalOutput)68 TEST(WebSocketInflaterTest, InflateHelloSmallCapacityGetTotalOutput) {
69 WebSocketInflater inflater(1, 1);
70 ASSERT_TRUE(inflater.Initialize(15));
71 scoped_refptr<IOBufferWithSize> actual;
72
73 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
74 ASSERT_TRUE(inflater.Finish());
75 ASSERT_EQ(1u, inflater.CurrentOutputSize());
76 actual = inflater.GetOutput(1024);
77 EXPECT_EQ("Hello", ToString(actual.get()));
78 EXPECT_EQ(0u, inflater.CurrentOutputSize());
79 }
80
TEST(WebSocketInflaterTest,InflateInvalidData)81 TEST(WebSocketInflaterTest, InflateInvalidData) {
82 WebSocketInflater inflater;
83 ASSERT_TRUE(inflater.Initialize(15));
84 EXPECT_FALSE(inflater.AddBytes("\xf2\x48\xcd\xc9INVALID DATA", 16));
85 }
86
TEST(WebSocketInflaterTest,ChokedInvalidData)87 TEST(WebSocketInflaterTest, ChokedInvalidData) {
88 WebSocketInflater inflater(1, 1);
89 ASSERT_TRUE(inflater.Initialize(15));
90
91 EXPECT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9INVALID DATA", 16));
92 EXPECT_TRUE(inflater.Finish());
93 EXPECT_EQ(1u, inflater.CurrentOutputSize());
94 EXPECT_FALSE(inflater.GetOutput(1024).get());
95 }
96
TEST(WebSocketInflaterTest,MultipleAddBytesCalls)97 TEST(WebSocketInflaterTest, MultipleAddBytesCalls) {
98 WebSocketInflater inflater;
99 ASSERT_TRUE(inflater.Initialize(15));
100 std::string input("\xf2\x48\xcd\xc9\xc9\x07\x00", 7);
101 scoped_refptr<IOBufferWithSize> actual;
102
103 for (char& c : input) {
104 ASSERT_TRUE(inflater.AddBytes(&c, 1));
105 }
106 ASSERT_TRUE(inflater.Finish());
107 actual = inflater.GetOutput(5);
108 ASSERT_TRUE(actual.get());
109 EXPECT_EQ("Hello", ToString(actual.get()));
110 }
111
TEST(WebSocketInflaterTest,Reset)112 TEST(WebSocketInflaterTest, Reset) {
113 WebSocketInflater inflater;
114 ASSERT_TRUE(inflater.Initialize(15));
115 scoped_refptr<IOBufferWithSize> actual1, actual2;
116
117 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
118 ASSERT_TRUE(inflater.Finish());
119 actual1 = inflater.GetOutput(inflater.CurrentOutputSize());
120 ASSERT_TRUE(actual1.get());
121 EXPECT_EQ("Hello", ToString(actual1.get()));
122 EXPECT_EQ(0u, inflater.CurrentOutputSize());
123
124 // Reset the stream with a block [BFINAL = 1, BTYPE = 00, LEN = 0]
125 ASSERT_TRUE(inflater.AddBytes("\x01", 1));
126 ASSERT_TRUE(inflater.Finish());
127 ASSERT_EQ(0u, inflater.CurrentOutputSize());
128
129 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
130 ASSERT_TRUE(inflater.Finish());
131 actual2 = inflater.GetOutput(inflater.CurrentOutputSize());
132 ASSERT_TRUE(actual2.get());
133 EXPECT_EQ("Hello", ToString(actual2.get()));
134 EXPECT_EQ(0u, inflater.CurrentOutputSize());
135 }
136
TEST(WebSocketInflaterTest,ResetAndLostContext)137 TEST(WebSocketInflaterTest, ResetAndLostContext) {
138 WebSocketInflater inflater;
139 scoped_refptr<IOBufferWithSize> actual1, actual2;
140 ASSERT_TRUE(inflater.Initialize(15));
141
142 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
143 ASSERT_TRUE(inflater.Finish());
144 actual1 = inflater.GetOutput(inflater.CurrentOutputSize());
145 ASSERT_TRUE(actual1.get());
146 EXPECT_EQ("Hello", ToString(actual1.get()));
147 EXPECT_EQ(0u, inflater.CurrentOutputSize());
148
149 // Reset the stream with a block [BFINAL = 1, BTYPE = 00, LEN = 0]
150 ASSERT_TRUE(inflater.AddBytes("\x01", 1));
151 ASSERT_TRUE(inflater.Finish());
152 ASSERT_EQ(0u, inflater.CurrentOutputSize());
153
154 // The context is already reset.
155 ASSERT_FALSE(inflater.AddBytes("\xf2\x00\x11\x00\x00", 5));
156 }
157
TEST(WebSocketInflaterTest,CallAddBytesAndFinishWithoutGetOutput)158 TEST(WebSocketInflaterTest, CallAddBytesAndFinishWithoutGetOutput) {
159 WebSocketInflater inflater;
160 scoped_refptr<IOBufferWithSize> actual1, actual2;
161 ASSERT_TRUE(inflater.Initialize(15));
162
163 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
164 ASSERT_TRUE(inflater.Finish());
165 EXPECT_EQ(5u, inflater.CurrentOutputSize());
166
167 // This is a test for memory leak detectors.
168 }
169
TEST(WebSocketInflaterTest,CallAddBytesAndFinishWithoutGetOutputChoked)170 TEST(WebSocketInflaterTest, CallAddBytesAndFinishWithoutGetOutputChoked) {
171 WebSocketInflater inflater(1, 1);
172 scoped_refptr<IOBufferWithSize> actual1, actual2;
173 ASSERT_TRUE(inflater.Initialize(15));
174
175 ASSERT_TRUE(inflater.AddBytes("\xf2\x48\xcd\xc9\xc9\x07\x00", 7));
176 ASSERT_TRUE(inflater.Finish());
177 EXPECT_EQ(1u, inflater.CurrentOutputSize());
178
179 // This is a test for memory leak detectors.
180 }
181
TEST(WebSocketInflaterTest,LargeRandomDeflateInflate)182 TEST(WebSocketInflaterTest, LargeRandomDeflateInflate) {
183 const size_t size = 64 * 1024;
184 LinearCongruentialGenerator generator(133);
185 std::vector<char> input;
186 std::vector<char> output;
187 scoped_refptr<IOBufferWithSize> compressed;
188
189 WebSocketDeflater deflater(WebSocketDeflater::TAKE_OVER_CONTEXT);
190 ASSERT_TRUE(deflater.Initialize(8));
191 WebSocketInflater inflater(256, 256);
192 ASSERT_TRUE(inflater.Initialize(8));
193
194 for (size_t i = 0; i < size; ++i)
195 input.push_back(static_cast<char>(generator.Generate()));
196
197 ASSERT_TRUE(deflater.AddBytes(input.data(), input.size()));
198 ASSERT_TRUE(deflater.Finish());
199
200 compressed = deflater.GetOutput(deflater.CurrentOutputSize());
201
202 ASSERT_TRUE(compressed.get());
203 ASSERT_EQ(0u, deflater.CurrentOutputSize());
204
205 ASSERT_TRUE(inflater.AddBytes(compressed->data(), compressed->size()));
206 ASSERT_TRUE(inflater.Finish());
207
208 while (inflater.CurrentOutputSize() > 0) {
209 scoped_refptr<IOBufferWithSize> uncompressed =
210 inflater.GetOutput(inflater.CurrentOutputSize());
211 ASSERT_TRUE(uncompressed.get());
212 output.insert(output.end(),
213 uncompressed->data(),
214 uncompressed->data() + uncompressed->size());
215 }
216
217 EXPECT_EQ(output, input);
218 }
219
220 } // unnamed namespace
221
222 } // namespace net
223