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