blob: 0ef3f17d7e2091a2fa55b232b96ab6096ea6077c [file] [log] [blame]
dgozmana6e70092014-12-12 14:46:211// Copyright 2014 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/server/web_socket_encoder.h"
6
davidben411d3f72016-01-22 01:41:417#include <limits>
dchengc7eeda422015-12-26 03:56:488#include <utility>
yhiranoa10dd4e2015-09-28 09:06:349
Hans Wennborg0924470b2020-04-27 21:08:0510#include "base/check.h"
danakja9850e12016-04-18 22:28:0811#include "base/memory/ptr_util.h"
Shiho Nodabc5f6fe02021-09-13 10:01:3512#include "base/strings/strcat.h"
dgozmana6e70092014-12-12 14:46:2113#include "base/strings/string_number_conversions.h"
dgozmana6e70092014-12-12 14:46:2114#include "net/base/io_buffer.h"
yhiranoa10dd4e2015-09-28 09:06:3415#include "net/websockets/websocket_deflate_parameters.h"
16#include "net/websockets/websocket_extension.h"
dgozmana6e70092014-12-12 14:46:2117#include "net/websockets/websocket_extension_parser.h"
18
19namespace net {
20
21const char WebSocketEncoder::kClientExtensions[] =
Eugene Ostroukhovdea96372017-11-22 23:16:0222 "permessage-deflate; client_max_window_bits";
dgozmana6e70092014-12-12 14:46:2123
24namespace {
25
26const int kInflaterChunkSize = 16 * 1024;
27
28// Constants for hybi-10 frame format.
29
30typedef int OpCode;
31
32const OpCode kOpCodeContinuation = 0x0;
33const OpCode kOpCodeText = 0x1;
34const OpCode kOpCodeBinary = 0x2;
35const OpCode kOpCodeClose = 0x8;
36const OpCode kOpCodePing = 0x9;
37const OpCode kOpCodePong = 0xA;
38
39const unsigned char kFinalBit = 0x80;
40const unsigned char kReserved1Bit = 0x40;
41const unsigned char kReserved2Bit = 0x20;
42const unsigned char kReserved3Bit = 0x10;
43const unsigned char kOpCodeMask = 0xF;
44const unsigned char kMaskBit = 0x80;
45const unsigned char kPayloadLengthMask = 0x7F;
46
47const size_t kMaxSingleBytePayloadLength = 125;
48const size_t kTwoBytePayloadLengthField = 126;
49const size_t kEightBytePayloadLengthField = 127;
50const size_t kMaskingKeyWidthInBytes = 4;
51
52WebSocket::ParseResult DecodeFrameHybi17(const base::StringPiece& frame,
53 bool client_frame,
54 int* bytes_consumed,
55 std::string* output,
56 bool* compressed) {
57 size_t data_length = frame.length();
58 if (data_length < 2)
59 return WebSocket::FRAME_INCOMPLETE;
60
61 const char* buffer_begin = const_cast<char*>(frame.data());
62 const char* p = buffer_begin;
63 const char* buffer_end = p + data_length;
64
65 unsigned char first_byte = *p++;
66 unsigned char second_byte = *p++;
67
68 bool final = (first_byte & kFinalBit) != 0;
69 bool reserved1 = (first_byte & kReserved1Bit) != 0;
70 bool reserved2 = (first_byte & kReserved2Bit) != 0;
71 bool reserved3 = (first_byte & kReserved3Bit) != 0;
72 int op_code = first_byte & kOpCodeMask;
73 bool masked = (second_byte & kMaskBit) != 0;
74 *compressed = reserved1;
Shiho Nodabc5f6fe02021-09-13 10:01:3575 if (reserved2 || reserved3)
dgozmana6e70092014-12-12 14:46:2176 return WebSocket::FRAME_ERROR; // Only compression extension is supported.
77
78 bool closed = false;
79 switch (op_code) {
80 case kOpCodeClose:
81 closed = true;
82 break;
Shiho Nodabc5f6fe02021-09-13 10:01:3583
dgozmana6e70092014-12-12 14:46:2184 case kOpCodeText:
85 break;
Shiho Nodabc5f6fe02021-09-13 10:01:3586
87 case kOpCodeContinuation: // Treated in the same as kOpCodeText.
88 break;
89
dgozmana6e70092014-12-12 14:46:2190 case kOpCodeBinary: // We don't support binary frames yet.
dgozmana6e70092014-12-12 14:46:2191 case kOpCodePing: // We don't support binary frames yet.
92 case kOpCodePong: // We don't support binary frames yet.
93 default:
94 return WebSocket::FRAME_ERROR;
95 }
96
ellyjonesc7a5c502015-06-26 18:55:2097 if (client_frame && !masked) // In Hybi-17 spec client MUST mask its frame.
dgozmana6e70092014-12-12 14:46:2198 return WebSocket::FRAME_ERROR;
99
Avi Drissman13fc8932015-12-20 04:40:46100 uint64_t payload_length64 = second_byte & kPayloadLengthMask;
dgozmana6e70092014-12-12 14:46:21101 if (payload_length64 > kMaxSingleBytePayloadLength) {
102 int extended_payload_length_size;
thestigcf729772016-11-19 04:35:07103 if (payload_length64 == kTwoBytePayloadLengthField) {
dgozmana6e70092014-12-12 14:46:21104 extended_payload_length_size = 2;
thestigcf729772016-11-19 04:35:07105 } else {
dgozmana6e70092014-12-12 14:46:21106 DCHECK(payload_length64 == kEightBytePayloadLengthField);
107 extended_payload_length_size = 8;
108 }
109 if (buffer_end - p < extended_payload_length_size)
110 return WebSocket::FRAME_INCOMPLETE;
111 payload_length64 = 0;
112 for (int i = 0; i < extended_payload_length_size; ++i) {
113 payload_length64 <<= 8;
114 payload_length64 |= static_cast<unsigned char>(*p++);
115 }
116 }
117
118 size_t actual_masking_key_length = masked ? kMaskingKeyWidthInBytes : 0;
Avi Drissman13fc8932015-12-20 04:40:46119 static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull;
dgozmana6e70092014-12-12 14:46:21120 static size_t max_length = std::numeric_limits<size_t>::max();
121 if (payload_length64 > max_payload_length ||
122 payload_length64 + actual_masking_key_length > max_length) {
123 // WebSocket frame length too large.
124 return WebSocket::FRAME_ERROR;
125 }
126 size_t payload_length = static_cast<size_t>(payload_length64);
127
128 size_t total_length = actual_masking_key_length + payload_length;
129 if (static_cast<size_t>(buffer_end - p) < total_length)
130 return WebSocket::FRAME_INCOMPLETE;
131
132 if (masked) {
133 output->resize(payload_length);
134 const char* masking_key = p;
135 char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
136 for (size_t i = 0; i < payload_length; ++i) // Unmask the payload.
137 (*output)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
138 } else {
139 output->assign(p, p + payload_length);
140 }
141
142 size_t pos = p + actual_masking_key_length + payload_length - buffer_begin;
143 *bytes_consumed = pos;
Shiho Nodabc5f6fe02021-09-13 10:01:35144
145 if (closed)
146 return WebSocket::FRAME_CLOSE;
147 return final ? WebSocket::FRAME_OK_FINAL : WebSocket::FRAME_OK_MIDDLE;
dgozmana6e70092014-12-12 14:46:21148}
149
Johannes Henkelda8b9d32019-03-15 16:15:33150void EncodeFrameHybi17(base::StringPiece message,
dgozmana6e70092014-12-12 14:46:21151 int masking_key,
152 bool compressed,
153 std::string* output) {
154 std::vector<char> frame;
155 OpCode op_code = kOpCodeText;
156 size_t data_length = message.length();
157
158 int reserved1 = compressed ? kReserved1Bit : 0;
159 frame.push_back(kFinalBit | op_code | reserved1);
160 char mask_key_bit = masking_key != 0 ? kMaskBit : 0;
brucedawsonef128242015-12-01 04:26:36161 if (data_length <= kMaxSingleBytePayloadLength) {
162 frame.push_back(static_cast<char>(data_length) | mask_key_bit);
163 } else if (data_length <= 0xFFFF) {
dgozmana6e70092014-12-12 14:46:21164 frame.push_back(kTwoBytePayloadLengthField | mask_key_bit);
165 frame.push_back((data_length & 0xFF00) >> 8);
166 frame.push_back(data_length & 0xFF);
167 } else {
168 frame.push_back(kEightBytePayloadLengthField | mask_key_bit);
169 char extended_payload_length[8];
170 size_t remaining = data_length;
171 // Fill the length into extended_payload_length in the network byte order.
172 for (int i = 0; i < 8; ++i) {
173 extended_payload_length[7 - i] = remaining & 0xFF;
174 remaining >>= 8;
175 }
176 frame.insert(frame.end(), extended_payload_length,
177 extended_payload_length + 8);
178 DCHECK(!remaining);
179 }
180
181 const char* data = const_cast<char*>(message.data());
182 if (masking_key != 0) {
183 const char* mask_bytes = reinterpret_cast<char*>(&masking_key);
184 frame.insert(frame.end(), mask_bytes, mask_bytes + 4);
185 for (size_t i = 0; i < data_length; ++i) // Mask the payload.
186 frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]);
187 } else {
188 frame.insert(frame.end(), data, data + data_length);
189 }
David Benjamin739ef112019-11-01 04:21:09190 *output = std::string(frame.data(), frame.size());
dgozmana6e70092014-12-12 14:46:21191}
192
193} // anonymous namespace
194
195// static
danakja9850e12016-04-18 22:28:08196std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer() {
197 return base::WrapUnique(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr));
yhiranoa10dd4e2015-09-28 09:06:34198}
dgozmana6e70092014-12-12 14:46:21199
yhiranoa10dd4e2015-09-28 09:06:34200// static
danakja9850e12016-04-18 22:28:08201std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateServer(
yhiranoa10dd4e2015-09-28 09:06:34202 const std::string& extensions,
203 WebSocketDeflateParameters* deflate_parameters) {
204 WebSocketExtensionParser parser;
205 if (!parser.Parse(extensions)) {
206 // Failed to parse Sec-WebSocket-Extensions header. We MUST fail the
207 // connection.
208 return nullptr;
dgozmana6e70092014-12-12 14:46:21209 }
yhiranoa10dd4e2015-09-28 09:06:34210
211 for (const auto& extension : parser.extensions()) {
212 std::string failure_message;
213 WebSocketDeflateParameters offer;
214 if (!offer.Initialize(extension, &failure_message) ||
215 !offer.IsValidAsRequest(&failure_message)) {
216 // We decline unknown / malformed extensions.
217 continue;
218 }
219
220 WebSocketDeflateParameters response = offer;
221 if (offer.is_client_max_window_bits_specified() &&
222 !offer.has_client_max_window_bits_value()) {
223 // We need to choose one value for the response.
224 response.SetClientMaxWindowBits(15);
225 }
226 DCHECK(response.IsValidAsResponse());
227 DCHECK(offer.IsCompatibleWith(response));
Jeremy Roman0579ed62017-08-29 15:56:19228 auto deflater = std::make_unique<WebSocketDeflater>(
ricea2deef682016-09-09 08:04:07229 response.server_context_take_over_mode());
Jeremy Roman0579ed62017-08-29 15:56:19230 auto inflater = std::make_unique<WebSocketInflater>(kInflaterChunkSize,
ricea2deef682016-09-09 08:04:07231 kInflaterChunkSize);
yhiranoa10dd4e2015-09-28 09:06:34232 if (!deflater->Initialize(response.PermissiveServerMaxWindowBits()) ||
233 !inflater->Initialize(response.PermissiveClientMaxWindowBits())) {
234 // For some reason we cannot accept the parameters.
235 continue;
236 }
237 *deflate_parameters = response;
danakja9850e12016-04-18 22:28:08238 return base::WrapUnique(new WebSocketEncoder(
239 FOR_SERVER, std::move(deflater), std::move(inflater)));
yhiranoa10dd4e2015-09-28 09:06:34240 }
241
242 // We cannot find an acceptable offer.
danakja9850e12016-04-18 22:28:08243 return base::WrapUnique(new WebSocketEncoder(FOR_SERVER, nullptr, nullptr));
dgozmana6e70092014-12-12 14:46:21244}
245
246// static
danakja9850e12016-04-18 22:28:08247std::unique_ptr<WebSocketEncoder> WebSocketEncoder::CreateClient(
dgozmana6e70092014-12-12 14:46:21248 const std::string& response_extensions) {
yhiranoa10dd4e2015-09-28 09:06:34249 // TODO(yhirano): Add a way to return an error.
dgozmana6e70092014-12-12 14:46:21250
dgozmana6e70092014-12-12 14:46:21251 WebSocketExtensionParser parser;
yhiranoa10dd4e2015-09-28 09:06:34252 if (!parser.Parse(response_extensions)) {
253 // Parse error. Note that there are two cases here.
254 // 1) There is no Sec-WebSocket-Extensions header.
255 // 2) There is a malformed Sec-WebSocketExtensions header.
256 // We should return a deflate-disabled encoder for the former case and
257 // fail the connection for the latter case.
danakja9850e12016-04-18 22:28:08258 return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
dgozmana6e70092014-12-12 14:46:21259 }
yhiranoa10dd4e2015-09-28 09:06:34260 if (parser.extensions().size() != 1) {
261 // Only permessage-deflate extension is supported.
262 // TODO (yhirano): Fail the connection.
danakja9850e12016-04-18 22:28:08263 return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
yhiranoa10dd4e2015-09-28 09:06:34264 }
265 const auto& extension = parser.extensions()[0];
266 WebSocketDeflateParameters params;
267 std::string failure_message;
268 if (!params.Initialize(extension, &failure_message) ||
269 !params.IsValidAsResponse(&failure_message)) {
270 // TODO (yhirano): Fail the connection.
danakja9850e12016-04-18 22:28:08271 return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
yhiranoa10dd4e2015-09-28 09:06:34272 }
dgozmana6e70092014-12-12 14:46:21273
Jeremy Roman0579ed62017-08-29 15:56:19274 auto deflater = std::make_unique<WebSocketDeflater>(
ricea2deef682016-09-09 08:04:07275 params.client_context_take_over_mode());
Jeremy Roman0579ed62017-08-29 15:56:19276 auto inflater = std::make_unique<WebSocketInflater>(kInflaterChunkSize,
ricea2deef682016-09-09 08:04:07277 kInflaterChunkSize);
yhiranoa10dd4e2015-09-28 09:06:34278 if (!deflater->Initialize(params.PermissiveClientMaxWindowBits()) ||
279 !inflater->Initialize(params.PermissiveServerMaxWindowBits())) {
280 // TODO (yhirano): Fail the connection.
danakja9850e12016-04-18 22:28:08281 return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, nullptr, nullptr));
dgozmana6e70092014-12-12 14:46:21282 }
yhiranoa10dd4e2015-09-28 09:06:34283
danakja9850e12016-04-18 22:28:08284 return base::WrapUnique(new WebSocketEncoder(FOR_CLIENT, std::move(deflater),
285 std::move(inflater)));
dgozmana6e70092014-12-12 14:46:21286}
287
yhiranoa10dd4e2015-09-28 09:06:34288WebSocketEncoder::WebSocketEncoder(Type type,
danakja9850e12016-04-18 22:28:08289 std::unique_ptr<WebSocketDeflater> deflater,
290 std::unique_ptr<WebSocketInflater> inflater)
dchengc7eeda422015-12-26 03:56:48291 : type_(type),
292 deflater_(std::move(deflater)),
293 inflater_(std::move(inflater)) {}
yhiranoa10dd4e2015-09-28 09:06:34294
Chris Watkins7a41d3552017-12-01 02:13:27295WebSocketEncoder::~WebSocketEncoder() = default;
dgozmana6e70092014-12-12 14:46:21296
297WebSocket::ParseResult WebSocketEncoder::DecodeFrame(
298 const base::StringPiece& frame,
299 int* bytes_consumed,
300 std::string* output) {
301 bool compressed;
Shiho Nodabc5f6fe02021-09-13 10:01:35302 std::string current_output;
yhiranoa10dd4e2015-09-28 09:06:34303 WebSocket::ParseResult result = DecodeFrameHybi17(
Shiho Nodabc5f6fe02021-09-13 10:01:35304 frame, type_ == FOR_SERVER, bytes_consumed, &current_output, &compressed);
305 if (result == WebSocket::FRAME_OK_FINAL ||
306 result == WebSocket::FRAME_OK_MIDDLE) {
307 if (continuation_message_frames_.empty())
308 is_current_message_compressed_ = compressed;
309 continuation_message_frames_.push_back(current_output);
dgozmana6e70092014-12-12 14:46:21310 }
Shiho Nodabc5f6fe02021-09-13 10:01:35311 if (result == WebSocket::FRAME_OK_FINAL) {
312 *output = base::StrCat(continuation_message_frames_);
313 if (is_current_message_compressed_) {
314 if (!Inflate(output))
315 result = WebSocket::FRAME_ERROR;
316 }
317 }
318 if (result != WebSocket::FRAME_OK_MIDDLE)
319 continuation_message_frames_.clear();
dgozmana6e70092014-12-12 14:46:21320 return result;
321}
322
Johannes Henkelda8b9d32019-03-15 16:15:33323void WebSocketEncoder::EncodeFrame(base::StringPiece frame,
dgozmana6e70092014-12-12 14:46:21324 int masking_key,
325 std::string* output) {
326 std::string compressed;
327 if (Deflate(frame, &compressed))
328 EncodeFrameHybi17(compressed, masking_key, true, output);
329 else
330 EncodeFrameHybi17(frame, masking_key, false, output);
331}
332
333bool WebSocketEncoder::Inflate(std::string* message) {
334 if (!inflater_)
335 return false;
336 if (!inflater_->AddBytes(message->data(), message->length()))
337 return false;
338 if (!inflater_->Finish())
339 return false;
340
341 std::vector<char> output;
342 while (inflater_->CurrentOutputSize() > 0) {
343 scoped_refptr<IOBufferWithSize> chunk =
344 inflater_->GetOutput(inflater_->CurrentOutputSize());
345 if (!chunk.get())
346 return false;
347 output.insert(output.end(), chunk->data(), chunk->data() + chunk->size());
348 }
349
350 *message =
David Benjamin739ef112019-11-01 04:21:09351 output.size() ? std::string(output.data(), output.size()) : std::string();
dgozmana6e70092014-12-12 14:46:21352 return true;
353}
354
Johannes Henkelda8b9d32019-03-15 16:15:33355bool WebSocketEncoder::Deflate(base::StringPiece message, std::string* output) {
dgozmana6e70092014-12-12 14:46:21356 if (!deflater_)
357 return false;
358 if (!deflater_->AddBytes(message.data(), message.length())) {
359 deflater_->Finish();
360 return false;
361 }
362 if (!deflater_->Finish())
363 return false;
364 scoped_refptr<IOBufferWithSize> buffer =
365 deflater_->GetOutput(deflater_->CurrentOutputSize());
366 if (!buffer.get())
367 return false;
368 *output = std::string(buffer->data(), buffer->size());
369 return true;
370}
371
372} // namespace net