1*6777b538SAndroid Build Coastguard Worker // Copyright 2014 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/server/web_socket_encoder.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <limits>
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_deflate_parameters.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_extension.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_extension_parser.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/websockets/websocket_frame.h"
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker namespace net {
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker const char WebSocketEncoder::kClientExtensions[] =
24*6777b538SAndroid Build Coastguard Worker "permessage-deflate; client_max_window_bits";
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard Worker namespace {
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker const int kInflaterChunkSize = 16 * 1024;
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker // Constants for hybi-10 frame format.
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker const unsigned char kFinalBit = 0x80;
33*6777b538SAndroid Build Coastguard Worker const unsigned char kReserved1Bit = 0x40;
34*6777b538SAndroid Build Coastguard Worker const unsigned char kReserved2Bit = 0x20;
35*6777b538SAndroid Build Coastguard Worker const unsigned char kReserved3Bit = 0x10;
36*6777b538SAndroid Build Coastguard Worker const unsigned char kOpCodeMask = 0xF;
37*6777b538SAndroid Build Coastguard Worker const unsigned char kMaskBit = 0x80;
38*6777b538SAndroid Build Coastguard Worker const unsigned char kPayloadLengthMask = 0x7F;
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker const size_t kMaxSingleBytePayloadLength = 125;
41*6777b538SAndroid Build Coastguard Worker const size_t kTwoBytePayloadLengthField = 126;
42*6777b538SAndroid Build Coastguard Worker const size_t kEightBytePayloadLengthField = 127;
43*6777b538SAndroid Build Coastguard Worker const size_t kMaskingKeyWidthInBytes = 4;
44*6777b538SAndroid Build Coastguard Worker
DecodeFrameHybi17(std::string_view frame,bool client_frame,int * bytes_consumed,std::string * output,bool * compressed)45*6777b538SAndroid Build Coastguard Worker WebSocket::ParseResult DecodeFrameHybi17(std::string_view frame,
46*6777b538SAndroid Build Coastguard Worker bool client_frame,
47*6777b538SAndroid Build Coastguard Worker int* bytes_consumed,
48*6777b538SAndroid Build Coastguard Worker std::string* output,
49*6777b538SAndroid Build Coastguard Worker bool* compressed) {
50*6777b538SAndroid Build Coastguard Worker size_t data_length = frame.length();
51*6777b538SAndroid Build Coastguard Worker if (data_length < 2)
52*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_INCOMPLETE;
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker const char* buffer_begin = const_cast<char*>(frame.data());
55*6777b538SAndroid Build Coastguard Worker const char* p = buffer_begin;
56*6777b538SAndroid Build Coastguard Worker const char* buffer_end = p + data_length;
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker unsigned char first_byte = *p++;
59*6777b538SAndroid Build Coastguard Worker unsigned char second_byte = *p++;
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker bool final = (first_byte & kFinalBit) != 0;
62*6777b538SAndroid Build Coastguard Worker bool reserved1 = (first_byte & kReserved1Bit) != 0;
63*6777b538SAndroid Build Coastguard Worker bool reserved2 = (first_byte & kReserved2Bit) != 0;
64*6777b538SAndroid Build Coastguard Worker bool reserved3 = (first_byte & kReserved3Bit) != 0;
65*6777b538SAndroid Build Coastguard Worker int op_code = first_byte & kOpCodeMask;
66*6777b538SAndroid Build Coastguard Worker bool masked = (second_byte & kMaskBit) != 0;
67*6777b538SAndroid Build Coastguard Worker *compressed = reserved1;
68*6777b538SAndroid Build Coastguard Worker if (reserved2 || reserved3)
69*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_ERROR; // Only compression extension is supported.
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker bool closed = false;
72*6777b538SAndroid Build Coastguard Worker switch (op_code) {
73*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::kOpCodeClose:
74*6777b538SAndroid Build Coastguard Worker closed = true;
75*6777b538SAndroid Build Coastguard Worker break;
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::kOpCodeText:
78*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::
79*6777b538SAndroid Build Coastguard Worker kOpCodeContinuation: // Treated in the same as kOpCodeText.
80*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::kOpCodePing:
81*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::kOpCodePong:
82*6777b538SAndroid Build Coastguard Worker break;
83*6777b538SAndroid Build Coastguard Worker
84*6777b538SAndroid Build Coastguard Worker case WebSocketFrameHeader::OpCodeEnum::kOpCodeBinary: // We don't support
85*6777b538SAndroid Build Coastguard Worker // binary frames yet.
86*6777b538SAndroid Build Coastguard Worker default:
87*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_ERROR;
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker if (client_frame && !masked) // In Hybi-17 spec client MUST mask its frame.
91*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_ERROR;
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker uint64_t payload_length64 = second_byte & kPayloadLengthMask;
94*6777b538SAndroid Build Coastguard Worker if (payload_length64 > kMaxSingleBytePayloadLength) {
95*6777b538SAndroid Build Coastguard Worker int extended_payload_length_size;
96*6777b538SAndroid Build Coastguard Worker if (payload_length64 == kTwoBytePayloadLengthField) {
97*6777b538SAndroid Build Coastguard Worker extended_payload_length_size = 2;
98*6777b538SAndroid Build Coastguard Worker } else {
99*6777b538SAndroid Build Coastguard Worker DCHECK(payload_length64 == kEightBytePayloadLengthField);
100*6777b538SAndroid Build Coastguard Worker extended_payload_length_size = 8;
101*6777b538SAndroid Build Coastguard Worker }
102*6777b538SAndroid Build Coastguard Worker if (buffer_end - p < extended_payload_length_size)
103*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_INCOMPLETE;
104*6777b538SAndroid Build Coastguard Worker payload_length64 = 0;
105*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < extended_payload_length_size; ++i) {
106*6777b538SAndroid Build Coastguard Worker payload_length64 <<= 8;
107*6777b538SAndroid Build Coastguard Worker payload_length64 |= static_cast<unsigned char>(*p++);
108*6777b538SAndroid Build Coastguard Worker }
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker size_t actual_masking_key_length = masked ? kMaskingKeyWidthInBytes : 0;
112*6777b538SAndroid Build Coastguard Worker static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull;
113*6777b538SAndroid Build Coastguard Worker static size_t max_length = std::numeric_limits<size_t>::max();
114*6777b538SAndroid Build Coastguard Worker if (payload_length64 > max_payload_length ||
115*6777b538SAndroid Build Coastguard Worker payload_length64 + actual_masking_key_length > max_length) {
116*6777b538SAndroid Build Coastguard Worker // WebSocket frame length too large.
117*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_ERROR;
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker size_t payload_length = static_cast<size_t>(payload_length64);
120*6777b538SAndroid Build Coastguard Worker
121*6777b538SAndroid Build Coastguard Worker size_t total_length = actual_masking_key_length + payload_length;
122*6777b538SAndroid Build Coastguard Worker if (static_cast<size_t>(buffer_end - p) < total_length)
123*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_INCOMPLETE;
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker if (masked) {
126*6777b538SAndroid Build Coastguard Worker output->resize(payload_length);
127*6777b538SAndroid Build Coastguard Worker const char* masking_key = p;
128*6777b538SAndroid Build Coastguard Worker char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
129*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < payload_length; ++i) // Unmask the payload.
130*6777b538SAndroid Build Coastguard Worker (*output)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
131*6777b538SAndroid Build Coastguard Worker } else {
132*6777b538SAndroid Build Coastguard Worker output->assign(p, p + payload_length);
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker
135*6777b538SAndroid Build Coastguard Worker size_t pos = p + actual_masking_key_length + payload_length - buffer_begin;
136*6777b538SAndroid Build Coastguard Worker *bytes_consumed = pos;
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker if (op_code == WebSocketFrameHeader::OpCodeEnum::kOpCodePing)
139*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_PING;
140*6777b538SAndroid Build Coastguard Worker
141*6777b538SAndroid Build Coastguard Worker if (op_code == WebSocketFrameHeader::OpCodeEnum::kOpCodePong)
142*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_PONG;
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker if (closed)
145*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_CLOSE;
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker return final ? WebSocket::FRAME_OK_FINAL : WebSocket::FRAME_OK_MIDDLE;
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker
EncodeFrameHybi17(std::string_view message,int masking_key,bool compressed,WebSocketFrameHeader::OpCodeEnum op_code,std::string * output)150*6777b538SAndroid Build Coastguard Worker void EncodeFrameHybi17(std::string_view message,
151*6777b538SAndroid Build Coastguard Worker int masking_key,
152*6777b538SAndroid Build Coastguard Worker bool compressed,
153*6777b538SAndroid Build Coastguard Worker WebSocketFrameHeader::OpCodeEnum op_code,
154*6777b538SAndroid Build Coastguard Worker std::string* output) {
155*6777b538SAndroid Build Coastguard Worker std::vector<char> frame;
156*6777b538SAndroid Build Coastguard Worker size_t data_length = message.length();
157*6777b538SAndroid Build Coastguard Worker
158*6777b538SAndroid Build Coastguard Worker int reserved1 = compressed ? kReserved1Bit : 0;
159*6777b538SAndroid Build Coastguard Worker frame.push_back(kFinalBit | op_code | reserved1);
160*6777b538SAndroid Build Coastguard Worker char mask_key_bit = masking_key != 0 ? kMaskBit : 0;
161*6777b538SAndroid Build Coastguard Worker if (data_length <= kMaxSingleBytePayloadLength) {
162*6777b538SAndroid Build Coastguard Worker frame.push_back(static_cast<char>(data_length) | mask_key_bit);
163*6777b538SAndroid Build Coastguard Worker } else if (data_length <= 0xFFFF) {
164*6777b538SAndroid Build Coastguard Worker frame.push_back(kTwoBytePayloadLengthField | mask_key_bit);
165*6777b538SAndroid Build Coastguard Worker frame.push_back((data_length & 0xFF00) >> 8);
166*6777b538SAndroid Build Coastguard Worker frame.push_back(data_length & 0xFF);
167*6777b538SAndroid Build Coastguard Worker } else {
168*6777b538SAndroid Build Coastguard Worker frame.push_back(kEightBytePayloadLengthField | mask_key_bit);
169*6777b538SAndroid Build Coastguard Worker char extended_payload_length[8];
170*6777b538SAndroid Build Coastguard Worker size_t remaining = data_length;
171*6777b538SAndroid Build Coastguard Worker // Fill the length into extended_payload_length in the network byte order.
172*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 8; ++i) {
173*6777b538SAndroid Build Coastguard Worker extended_payload_length[7 - i] = remaining & 0xFF;
174*6777b538SAndroid Build Coastguard Worker remaining >>= 8;
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker frame.insert(frame.end(), extended_payload_length,
177*6777b538SAndroid Build Coastguard Worker extended_payload_length + 8);
178*6777b538SAndroid Build Coastguard Worker DCHECK(!remaining);
179*6777b538SAndroid Build Coastguard Worker }
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker const char* data = const_cast<char*>(message.data());
182*6777b538SAndroid Build Coastguard Worker if (masking_key != 0) {
183*6777b538SAndroid Build Coastguard Worker const char* mask_bytes = reinterpret_cast<char*>(&masking_key);
184*6777b538SAndroid Build Coastguard Worker frame.insert(frame.end(), mask_bytes, mask_bytes + 4);
185*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < data_length; ++i) // Mask the payload.
186*6777b538SAndroid Build Coastguard Worker frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]);
187*6777b538SAndroid Build Coastguard Worker } else {
188*6777b538SAndroid Build Coastguard Worker frame.insert(frame.end(), data, data + data_length);
189*6777b538SAndroid Build Coastguard Worker }
190*6777b538SAndroid Build Coastguard Worker *output = std::string(frame.data(), frame.size());
191*6777b538SAndroid Build Coastguard Worker }
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker } // anonymous namespace
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Worker // static
CreateServer()196*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer() {
197*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr));
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker
200*6777b538SAndroid Build Coastguard Worker // static
CreateServer(const std::string & extensions,WebSocketDeflateParameters * deflate_parameters)201*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer(
202*6777b538SAndroid Build Coastguard Worker const std::string& extensions,
203*6777b538SAndroid Build Coastguard Worker WebSocketDeflateParameters* deflate_parameters) {
204*6777b538SAndroid Build Coastguard Worker WebSocketExtensionParser parser;
205*6777b538SAndroid Build Coastguard Worker if (!parser.Parse(extensions)) {
206*6777b538SAndroid Build Coastguard Worker // Failed to parse Sec-WebSocket-Extensions header. We MUST fail the
207*6777b538SAndroid Build Coastguard Worker // connection.
208*6777b538SAndroid Build Coastguard Worker return nullptr;
209*6777b538SAndroid Build Coastguard Worker }
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker for (const auto& extension : parser.extensions()) {
212*6777b538SAndroid Build Coastguard Worker std::string failure_message;
213*6777b538SAndroid Build Coastguard Worker WebSocketDeflateParameters offer;
214*6777b538SAndroid Build Coastguard Worker if (!offer.Initialize(extension, &failure_message) ||
215*6777b538SAndroid Build Coastguard Worker !offer.IsValidAsRequest(&failure_message)) {
216*6777b538SAndroid Build Coastguard Worker // We decline unknown / malformed extensions.
217*6777b538SAndroid Build Coastguard Worker continue;
218*6777b538SAndroid Build Coastguard Worker }
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker WebSocketDeflateParameters response = offer;
221*6777b538SAndroid Build Coastguard Worker if (offer.is_client_max_window_bits_specified() &&
222*6777b538SAndroid Build Coastguard Worker !offer.has_client_max_window_bits_value()) {
223*6777b538SAndroid Build Coastguard Worker // We need to choose one value for the response.
224*6777b538SAndroid Build Coastguard Worker response.SetClientMaxWindowBits(15);
225*6777b538SAndroid Build Coastguard Worker }
226*6777b538SAndroid Build Coastguard Worker DCHECK(response.IsValidAsResponse());
227*6777b538SAndroid Build Coastguard Worker DCHECK(offer.IsCompatibleWith(response));
228*6777b538SAndroid Build Coastguard Worker auto deflater = std::make_unique<WebSocketDeflater>(
229*6777b538SAndroid Build Coastguard Worker response.server_context_take_over_mode());
230*6777b538SAndroid Build Coastguard Worker auto inflater = std::make_unique<WebSocketInflater>(kInflaterChunkSize,
231*6777b538SAndroid Build Coastguard Worker kInflaterChunkSize);
232*6777b538SAndroid Build Coastguard Worker if (!deflater->Initialize(response.PermissiveServerMaxWindowBits()) ||
233*6777b538SAndroid Build Coastguard Worker !inflater->Initialize(response.PermissiveClientMaxWindowBits())) {
234*6777b538SAndroid Build Coastguard Worker // For some reason we cannot accept the parameters.
235*6777b538SAndroid Build Coastguard Worker continue;
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker *deflate_parameters = response;
238*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(
239*6777b538SAndroid Build Coastguard Worker FOR_SERVER, std::move(deflater), std::move(inflater)));
240*6777b538SAndroid Build Coastguard Worker }
241*6777b538SAndroid Build Coastguard Worker
242*6777b538SAndroid Build Coastguard Worker // We cannot find an acceptable offer.
243*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr));
244*6777b538SAndroid Build Coastguard Worker }
245*6777b538SAndroid Build Coastguard Worker
246*6777b538SAndroid Build Coastguard Worker // static
CreateClient(const std::string & response_extensions)247*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateClient(
248*6777b538SAndroid Build Coastguard Worker const std::string& response_extensions) {
249*6777b538SAndroid Build Coastguard Worker // TODO(yhirano): Add a way to return an error.
250*6777b538SAndroid Build Coastguard Worker
251*6777b538SAndroid Build Coastguard Worker WebSocketExtensionParser parser;
252*6777b538SAndroid Build Coastguard Worker if (!parser.Parse(response_extensions)) {
253*6777b538SAndroid Build Coastguard Worker // Parse error. Note that there are two cases here.
254*6777b538SAndroid Build Coastguard Worker // 1) There is no Sec-WebSocket-Extensions header.
255*6777b538SAndroid Build Coastguard Worker // 2) There is a malformed Sec-WebSocketExtensions header.
256*6777b538SAndroid Build Coastguard Worker // We should return a deflate-disabled encoder for the former case and
257*6777b538SAndroid Build Coastguard Worker // fail the connection for the latter case.
258*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
259*6777b538SAndroid Build Coastguard Worker }
260*6777b538SAndroid Build Coastguard Worker if (parser.extensions().size() != 1) {
261*6777b538SAndroid Build Coastguard Worker // Only permessage-deflate extension is supported.
262*6777b538SAndroid Build Coastguard Worker // TODO (yhirano): Fail the connection.
263*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
264*6777b538SAndroid Build Coastguard Worker }
265*6777b538SAndroid Build Coastguard Worker const auto& extension = parser.extensions()[0];
266*6777b538SAndroid Build Coastguard Worker WebSocketDeflateParameters params;
267*6777b538SAndroid Build Coastguard Worker std::string failure_message;
268*6777b538SAndroid Build Coastguard Worker if (!params.Initialize(extension, &failure_message) ||
269*6777b538SAndroid Build Coastguard Worker !params.IsValidAsResponse(&failure_message)) {
270*6777b538SAndroid Build Coastguard Worker // TODO (yhirano): Fail the connection.
271*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
272*6777b538SAndroid Build Coastguard Worker }
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard Worker auto deflater = std::make_unique<WebSocketDeflater>(
275*6777b538SAndroid Build Coastguard Worker params.client_context_take_over_mode());
276*6777b538SAndroid Build Coastguard Worker auto inflater = std::make_unique<WebSocketInflater>(kInflaterChunkSize,
277*6777b538SAndroid Build Coastguard Worker kInflaterChunkSize);
278*6777b538SAndroid Build Coastguard Worker if (!deflater->Initialize(params.PermissiveClientMaxWindowBits()) ||
279*6777b538SAndroid Build Coastguard Worker !inflater->Initialize(params.PermissiveServerMaxWindowBits())) {
280*6777b538SAndroid Build Coastguard Worker // TODO (yhirano): Fail the connection.
281*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker
284*6777b538SAndroid Build Coastguard Worker return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, std::move(deflater),
285*6777b538SAndroid Build Coastguard Worker std::move(inflater)));
286*6777b538SAndroid Build Coastguard Worker }
287*6777b538SAndroid Build Coastguard Worker
WebSocketEncoder(Type type,std::unique_ptr<WebSocketDeflater> deflater,std::unique_ptr<WebSocketInflater> inflater)288*6777b538SAndroid Build Coastguard Worker WebSocketEncoder::WebSocketEncoder(Type type,
289*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketDeflater> deflater,
290*6777b538SAndroid Build Coastguard Worker std::unique_ptr<WebSocketInflater> inflater)
291*6777b538SAndroid Build Coastguard Worker : type_(type),
292*6777b538SAndroid Build Coastguard Worker deflater_(std::move(deflater)),
293*6777b538SAndroid Build Coastguard Worker inflater_(std::move(inflater)) {}
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker WebSocketEncoder::~WebSocketEncoder() = default;
296*6777b538SAndroid Build Coastguard Worker
DecodeFrame(std::string_view frame,int * bytes_consumed,std::string * output)297*6777b538SAndroid Build Coastguard Worker WebSocket::ParseResult WebSocketEncoder::DecodeFrame(std::string_view frame,
298*6777b538SAndroid Build Coastguard Worker int* bytes_consumed,
299*6777b538SAndroid Build Coastguard Worker std::string* output) {
300*6777b538SAndroid Build Coastguard Worker bool compressed;
301*6777b538SAndroid Build Coastguard Worker std::string current_output;
302*6777b538SAndroid Build Coastguard Worker WebSocket::ParseResult result = DecodeFrameHybi17(
303*6777b538SAndroid Build Coastguard Worker frame, type_ == FOR_SERVER, bytes_consumed, ¤t_output, &compressed);
304*6777b538SAndroid Build Coastguard Worker switch (result) {
305*6777b538SAndroid Build Coastguard Worker case WebSocket::FRAME_OK_FINAL:
306*6777b538SAndroid Build Coastguard Worker case WebSocket::FRAME_OK_MIDDLE: {
307*6777b538SAndroid Build Coastguard Worker if (continuation_message_frames_.empty())
308*6777b538SAndroid Build Coastguard Worker is_current_message_compressed_ = compressed;
309*6777b538SAndroid Build Coastguard Worker continuation_message_frames_.push_back(current_output);
310*6777b538SAndroid Build Coastguard Worker
311*6777b538SAndroid Build Coastguard Worker if (result == WebSocket::FRAME_OK_FINAL) {
312*6777b538SAndroid Build Coastguard Worker *output = base::StrCat(continuation_message_frames_);
313*6777b538SAndroid Build Coastguard Worker continuation_message_frames_.clear();
314*6777b538SAndroid Build Coastguard Worker if (is_current_message_compressed_ && !Inflate(output)) {
315*6777b538SAndroid Build Coastguard Worker return WebSocket::FRAME_ERROR;
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker }
318*6777b538SAndroid Build Coastguard Worker break;
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard Worker case WebSocket::FRAME_PING:
322*6777b538SAndroid Build Coastguard Worker *output = current_output;
323*6777b538SAndroid Build Coastguard Worker break;
324*6777b538SAndroid Build Coastguard Worker
325*6777b538SAndroid Build Coastguard Worker default:
326*6777b538SAndroid Build Coastguard Worker // This function doesn't need special handling for other parse results.
327*6777b538SAndroid Build Coastguard Worker break;
328*6777b538SAndroid Build Coastguard Worker }
329*6777b538SAndroid Build Coastguard Worker
330*6777b538SAndroid Build Coastguard Worker return result;
331*6777b538SAndroid Build Coastguard Worker }
332*6777b538SAndroid Build Coastguard Worker
EncodeTextFrame(std::string_view frame,int masking_key,std::string * output)333*6777b538SAndroid Build Coastguard Worker void WebSocketEncoder::EncodeTextFrame(std::string_view frame,
334*6777b538SAndroid Build Coastguard Worker int masking_key,
335*6777b538SAndroid Build Coastguard Worker std::string* output) {
336*6777b538SAndroid Build Coastguard Worker std::string compressed;
337*6777b538SAndroid Build Coastguard Worker constexpr auto op_code = WebSocketFrameHeader::OpCodeEnum::kOpCodeText;
338*6777b538SAndroid Build Coastguard Worker if (Deflate(frame, &compressed))
339*6777b538SAndroid Build Coastguard Worker EncodeFrameHybi17(compressed, masking_key, true, op_code, output);
340*6777b538SAndroid Build Coastguard Worker else
341*6777b538SAndroid Build Coastguard Worker EncodeFrameHybi17(frame, masking_key, false, op_code, output);
342*6777b538SAndroid Build Coastguard Worker }
343*6777b538SAndroid Build Coastguard Worker
EncodeCloseFrame(std::string_view frame,int masking_key,std::string * output)344*6777b538SAndroid Build Coastguard Worker void WebSocketEncoder::EncodeCloseFrame(std::string_view frame,
345*6777b538SAndroid Build Coastguard Worker int masking_key,
346*6777b538SAndroid Build Coastguard Worker std::string* output) {
347*6777b538SAndroid Build Coastguard Worker constexpr auto op_code = WebSocketFrameHeader::OpCodeEnum::kOpCodeClose;
348*6777b538SAndroid Build Coastguard Worker EncodeFrameHybi17(frame, masking_key, false, op_code, output);
349*6777b538SAndroid Build Coastguard Worker }
350*6777b538SAndroid Build Coastguard Worker
EncodePongFrame(std::string_view frame,int masking_key,std::string * output)351*6777b538SAndroid Build Coastguard Worker void WebSocketEncoder::EncodePongFrame(std::string_view frame,
352*6777b538SAndroid Build Coastguard Worker int masking_key,
353*6777b538SAndroid Build Coastguard Worker std::string* output) {
354*6777b538SAndroid Build Coastguard Worker constexpr auto op_code = WebSocketFrameHeader::OpCodeEnum::kOpCodePong;
355*6777b538SAndroid Build Coastguard Worker EncodeFrameHybi17(frame, masking_key, false, op_code, output);
356*6777b538SAndroid Build Coastguard Worker }
357*6777b538SAndroid Build Coastguard Worker
Inflate(std::string * message)358*6777b538SAndroid Build Coastguard Worker bool WebSocketEncoder::Inflate(std::string* message) {
359*6777b538SAndroid Build Coastguard Worker if (!inflater_)
360*6777b538SAndroid Build Coastguard Worker return false;
361*6777b538SAndroid Build Coastguard Worker if (!inflater_->AddBytes(message->data(), message->length()))
362*6777b538SAndroid Build Coastguard Worker return false;
363*6777b538SAndroid Build Coastguard Worker if (!inflater_->Finish())
364*6777b538SAndroid Build Coastguard Worker return false;
365*6777b538SAndroid Build Coastguard Worker
366*6777b538SAndroid Build Coastguard Worker std::vector<char> output;
367*6777b538SAndroid Build Coastguard Worker while (inflater_->CurrentOutputSize() > 0) {
368*6777b538SAndroid Build Coastguard Worker scoped_refptr<IOBufferWithSize> chunk =
369*6777b538SAndroid Build Coastguard Worker inflater_->GetOutput(inflater_->CurrentOutputSize());
370*6777b538SAndroid Build Coastguard Worker if (!chunk.get())
371*6777b538SAndroid Build Coastguard Worker return false;
372*6777b538SAndroid Build Coastguard Worker output.insert(output.end(), chunk->data(), chunk->data() + chunk->size());
373*6777b538SAndroid Build Coastguard Worker }
374*6777b538SAndroid Build Coastguard Worker
375*6777b538SAndroid Build Coastguard Worker *message =
376*6777b538SAndroid Build Coastguard Worker output.size() ? std::string(output.data(), output.size()) : std::string();
377*6777b538SAndroid Build Coastguard Worker return true;
378*6777b538SAndroid Build Coastguard Worker }
379*6777b538SAndroid Build Coastguard Worker
Deflate(std::string_view message,std::string * output)380*6777b538SAndroid Build Coastguard Worker bool WebSocketEncoder::Deflate(std::string_view message, std::string* output) {
381*6777b538SAndroid Build Coastguard Worker if (!deflater_)
382*6777b538SAndroid Build Coastguard Worker return false;
383*6777b538SAndroid Build Coastguard Worker if (!deflater_->AddBytes(message.data(), message.length())) {
384*6777b538SAndroid Build Coastguard Worker deflater_->Finish();
385*6777b538SAndroid Build Coastguard Worker return false;
386*6777b538SAndroid Build Coastguard Worker }
387*6777b538SAndroid Build Coastguard Worker if (!deflater_->Finish())
388*6777b538SAndroid Build Coastguard Worker return false;
389*6777b538SAndroid Build Coastguard Worker scoped_refptr<IOBufferWithSize> buffer =
390*6777b538SAndroid Build Coastguard Worker deflater_->GetOutput(deflater_->CurrentOutputSize());
391*6777b538SAndroid Build Coastguard Worker if (!buffer.get())
392*6777b538SAndroid Build Coastguard Worker return false;
393*6777b538SAndroid Build Coastguard Worker *output = std::string(buffer->data(), buffer->size());
394*6777b538SAndroid Build Coastguard Worker return true;
395*6777b538SAndroid Build Coastguard Worker }
396*6777b538SAndroid Build Coastguard Worker
397*6777b538SAndroid Build Coastguard Worker } // namespace net
398