blob: 1fc6ab37afdaba8cfaa9abc2ae121c5153628c86 [file] [log] [blame]
[email protected]999bcaa2013-07-17 13:42:541// 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_channel.h"
6
7#include <algorithm>
8
9#include "base/basictypes.h" // for size_t
10#include "base/bind.h"
[email protected]f485985e2013-10-24 13:47:4411#include "base/compiler_specific.h"
[email protected]cd48ed12014-01-22 14:34:2212#include "base/memory/weak_ptr.h"
13#include "base/message_loop/message_loop.h"
[email protected]cb154062014-01-17 03:32:4014#include "base/numerics/safe_conversions.h"
[email protected]48cc6922014-02-10 14:20:4815#include "base/stl_util.h"
[email protected]ea56b982014-01-27 03:21:0316#include "base/strings/stringprintf.h"
[email protected]3a266762013-10-23 08:15:1017#include "base/time/time.h"
[email protected]999bcaa2013-07-17 13:42:5418#include "net/base/big_endian.h"
19#include "net/base/io_buffer.h"
20#include "net/base/net_log.h"
[email protected]cd48ed12014-01-22 14:34:2221#include "net/http/http_request_headers.h"
22#include "net/http/http_response_headers.h"
[email protected]53deacb2013-11-22 14:02:4323#include "net/http/http_util.h"
[email protected]999bcaa2013-07-17 13:42:5424#include "net/websockets/websocket_errors.h"
25#include "net/websockets/websocket_event_interface.h"
26#include "net/websockets/websocket_frame.h"
[email protected]cd48ed12014-01-22 14:34:2227#include "net/websockets/websocket_handshake_request_info.h"
28#include "net/websockets/websocket_handshake_response_info.h"
[email protected]999bcaa2013-07-17 13:42:5429#include "net/websockets/websocket_mux.h"
30#include "net/websockets/websocket_stream.h"
31
32namespace net {
33
34namespace {
35
[email protected]48cc6922014-02-10 14:20:4836using base::StreamingUtf8Validator;
37
[email protected]999bcaa2013-07-17 13:42:5438const int kDefaultSendQuotaLowWaterMark = 1 << 16;
39const int kDefaultSendQuotaHighWaterMark = 1 << 17;
40const size_t kWebSocketCloseCodeLength = 2;
[email protected]3a266762013-10-23 08:15:1041// This timeout is based on TCPMaximumSegmentLifetime * 2 from
42// MainThreadWebSocketChannel.cpp in Blink.
43const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
[email protected]999bcaa2013-07-17 13:42:5444
[email protected]f485985e2013-10-24 13:47:4445typedef WebSocketEventInterface::ChannelState ChannelState;
46const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
47const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
48
[email protected]3de65092013-10-24 09:39:4449// Maximum close reason length = max control frame payload -
50// status code length
51// = 125 - 2
52const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength;
53
54// Check a close status code for strict compliance with RFC6455. This is only
55// used for close codes received from a renderer that we are intending to send
56// out over the network. See ParseClose() for the restrictions on incoming close
57// codes. The |code| parameter is type int for convenience of implementation;
58// the real type is uint16.
59bool IsStrictlyValidCloseStatusCode(int code) {
60 static const int kInvalidRanges[] = {
61 // [BAD, OK)
62 0, 1000, // 1000 is the first valid code
63 1005, 1007, // 1005 and 1006 MUST NOT be set.
64 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved.
65 5000, 65536, // Codes above 5000 are invalid.
66 };
67 const int* const kInvalidRangesEnd =
68 kInvalidRanges + arraysize(kInvalidRanges);
69
70 DCHECK_GE(code, 0);
71 DCHECK_LT(code, 65536);
72 const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code);
73 DCHECK_NE(kInvalidRangesEnd, upper);
74 DCHECK_GT(upper, kInvalidRanges);
75 DCHECK_GT(*upper, code);
76 DCHECK_LE(*(upper - 1), code);
77 return ((upper - kInvalidRanges) % 2) == 0;
78}
79
[email protected]f485985e2013-10-24 13:47:4480// This function avoids a bunch of boilerplate code.
81void AllowUnused(ChannelState ALLOW_UNUSED unused) {}
82
[email protected]8b3d14e2014-02-13 14:24:2883// Sets |name| to the name of the frame type for the given |opcode|. Note that
84// for all of Text, Binary and Continuation opcode, this method returns
85// "Data frame".
86void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode,
87 std::string* name) {
88 switch (opcode) {
89 case WebSocketFrameHeader::kOpCodeText: // fall-thru
90 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
91 case WebSocketFrameHeader::kOpCodeContinuation:
92 *name = "Data frame";
93 break;
94
95 case WebSocketFrameHeader::kOpCodePing:
96 *name = "Ping";
97 break;
98
99 case WebSocketFrameHeader::kOpCodePong:
100 *name = "Pong";
101 break;
102
103 case WebSocketFrameHeader::kOpCodeClose:
104 *name = "Close";
105 break;
106
107 default:
108 *name = "Unknown frame type";
109 break;
110 }
111
112 return;
113}
114
[email protected]999bcaa2013-07-17 13:42:54115} // namespace
116
117// A class to encapsulate a set of frames and information about the size of
118// those frames.
119class WebSocketChannel::SendBuffer {
120 public:
121 SendBuffer() : total_bytes_(0) {}
122
[email protected]2f5d9f62013-09-26 12:14:28123 // Add a WebSocketFrame to the buffer and increase total_bytes_.
124 void AddFrame(scoped_ptr<WebSocketFrame> chunk);
[email protected]999bcaa2013-07-17 13:42:54125
126 // Return a pointer to the frames_ for write purposes.
[email protected]2f5d9f62013-09-26 12:14:28127 ScopedVector<WebSocketFrame>* frames() { return &frames_; }
[email protected]999bcaa2013-07-17 13:42:54128
129 private:
130 // The frames_ that will be sent in the next call to WriteFrames().
[email protected]2f5d9f62013-09-26 12:14:28131 ScopedVector<WebSocketFrame> frames_;
[email protected]999bcaa2013-07-17 13:42:54132
[email protected]2f5d9f62013-09-26 12:14:28133 // The total size of the payload data in |frames_|. This will be used to
134 // measure the throughput of the link.
[email protected]999bcaa2013-07-17 13:42:54135 // TODO(ricea): Measure the throughput of the link.
136 size_t total_bytes_;
137};
138
[email protected]2f5d9f62013-09-26 12:14:28139void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) {
140 total_bytes_ += frame->header.payload_length;
141 frames_.push_back(frame.release());
[email protected]999bcaa2013-07-17 13:42:54142}
143
144// Implementation of WebSocketStream::ConnectDelegate that simply forwards the
145// calls on to the WebSocketChannel that created it.
146class WebSocketChannel::ConnectDelegate
147 : public WebSocketStream::ConnectDelegate {
148 public:
149 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {}
150
151 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
152 creator_->OnConnectSuccess(stream.Pass());
[email protected]f485985e2013-10-24 13:47:44153 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54154 }
155
[email protected]96868202014-01-09 10:38:04156 virtual void OnFailure(const std::string& message) OVERRIDE {
157 creator_->OnConnectFailure(message);
[email protected]f485985e2013-10-24 13:47:44158 // |this| has been deleted.
[email protected]999bcaa2013-07-17 13:42:54159 }
160
[email protected]cd48ed12014-01-22 14:34:22161 virtual void OnStartOpeningHandshake(
162 scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
163 creator_->OnStartOpeningHandshake(request.Pass());
164 }
165
166 virtual void OnFinishOpeningHandshake(
167 scoped_ptr<WebSocketHandshakeResponseInfo> response)
168 OVERRIDE {
169 creator_->OnFinishOpeningHandshake(response.Pass());
170 }
171
[email protected]999bcaa2013-07-17 13:42:54172 private:
[email protected]caab2cc2013-08-27 10:24:37173 // A pointer to the WebSocketChannel that created this object. There is no
174 // danger of this pointer being stale, because deleting the WebSocketChannel
175 // cancels the connect process, deleting this object and preventing its
176 // callbacks from being called.
[email protected]999bcaa2013-07-17 13:42:54177 WebSocketChannel* const creator_;
178
179 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate);
180};
181
[email protected]cd48ed12014-01-22 14:34:22182class WebSocketChannel::HandshakeNotificationSender
183 : public base::SupportsWeakPtr<HandshakeNotificationSender> {
184 public:
185 explicit HandshakeNotificationSender(WebSocketChannel* channel);
186 ~HandshakeNotificationSender();
187
188 static void Send(base::WeakPtr<HandshakeNotificationSender> sender);
189
190 ChannelState SendImmediately(WebSocketEventInterface* event_interface);
191
192 const WebSocketHandshakeRequestInfo* handshake_request_info() const {
193 return handshake_request_info_.get();
194 }
195
196 void set_handshake_request_info(
197 scoped_ptr<WebSocketHandshakeRequestInfo> request_info) {
198 handshake_request_info_ = request_info.Pass();
199 }
200
201 const WebSocketHandshakeResponseInfo* handshake_response_info() const {
202 return handshake_response_info_.get();
203 }
204
205 void set_handshake_response_info(
206 scoped_ptr<WebSocketHandshakeResponseInfo> response_info) {
207 handshake_response_info_ = response_info.Pass();
208 }
209
210 private:
211 WebSocketChannel* owner_;
212 scoped_ptr<WebSocketHandshakeRequestInfo> handshake_request_info_;
213 scoped_ptr<WebSocketHandshakeResponseInfo> handshake_response_info_;
214};
215
216WebSocketChannel::HandshakeNotificationSender::HandshakeNotificationSender(
217 WebSocketChannel* channel) : owner_(channel) {}
218
219WebSocketChannel::HandshakeNotificationSender::~HandshakeNotificationSender() {}
220
221void WebSocketChannel::HandshakeNotificationSender::Send(
222 base::WeakPtr<HandshakeNotificationSender> sender) {
223 // Do nothing if |sender| is already destructed.
224 if (sender) {
225 WebSocketChannel* channel = sender->owner_;
226 AllowUnused(sender->SendImmediately(channel->event_interface_.get()));
227 }
228}
229
230ChannelState WebSocketChannel::HandshakeNotificationSender::SendImmediately(
231 WebSocketEventInterface* event_interface) {
232
233 if (handshake_request_info_.get()) {
234 if (CHANNEL_DELETED == event_interface->OnStartOpeningHandshake(
235 handshake_request_info_.Pass()))
236 return CHANNEL_DELETED;
237 }
238
239 if (handshake_response_info_.get()) {
240 if (CHANNEL_DELETED == event_interface->OnFinishOpeningHandshake(
241 handshake_response_info_.Pass()))
242 return CHANNEL_DELETED;
243
244 // TODO(yhirano): We can release |this| to save memory because
245 // there will be no more opening handshake notification.
246 }
247
248 return CHANNEL_ALIVE;
249}
250
[email protected]999bcaa2013-07-17 13:42:54251WebSocketChannel::WebSocketChannel(
[email protected]dab33eb2013-10-08 02:27:51252 scoped_ptr<WebSocketEventInterface> event_interface,
253 URLRequestContext* url_request_context)
254 : event_interface_(event_interface.Pass()),
255 url_request_context_(url_request_context),
[email protected]999bcaa2013-07-17 13:42:54256 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark),
257 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
258 current_send_quota_(0),
[email protected]3a266762013-10-23 08:15:10259 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
[email protected]8b3d14e2014-02-13 14:24:28260 received_close_code_(0),
[email protected]cd48ed12014-01-22 14:34:22261 state_(FRESHLY_CONSTRUCTED),
[email protected]48cc6922014-02-10 14:20:48262 notification_sender_(new HandshakeNotificationSender(this)),
263 sending_text_message_(false),
264 receiving_text_message_(false) {}
[email protected]999bcaa2013-07-17 13:42:54265
266WebSocketChannel::~WebSocketChannel() {
[email protected]2f5d9f62013-09-26 12:14:28267 // The stream may hold a pointer to read_frames_, and so it needs to be
[email protected]999bcaa2013-07-17 13:42:54268 // destroyed first.
269 stream_.reset();
[email protected]3a266762013-10-23 08:15:10270 // The timer may have a callback pointing back to us, so stop it just in case
271 // someone decides to run the event loop from their destructor.
272 timer_.Stop();
[email protected]999bcaa2013-07-17 13:42:54273}
274
275void WebSocketChannel::SendAddChannelRequest(
[email protected]dab33eb2013-10-08 02:27:51276 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54277 const std::vector<std::string>& requested_subprotocols,
[email protected]dab33eb2013-10-08 02:27:51278 const GURL& origin) {
[email protected]999bcaa2013-07-17 13:42:54279 // Delegate to the tested version.
[email protected]969dde72013-11-13 15:59:14280 SendAddChannelRequestWithSuppliedCreator(
[email protected]dab33eb2013-10-08 02:27:51281 socket_url,
[email protected]999bcaa2013-07-17 13:42:54282 requested_subprotocols,
283 origin,
[email protected]999bcaa2013-07-17 13:42:54284 base::Bind(&WebSocketStream::CreateAndConnectStream));
285}
286
[email protected]c0d29c22013-07-26 20:40:41287bool WebSocketChannel::InClosingState() const {
[email protected]caab2cc2013-08-27 10:24:37288 // The state RECV_CLOSED is not supported here, because it is only used in one
289 // code path and should not leak into the code in general.
[email protected]c0d29c22013-07-26 20:40:41290 DCHECK_NE(RECV_CLOSED, state_)
291 << "InClosingState called with state_ == RECV_CLOSED";
292 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED;
293}
294
[email protected]999bcaa2013-07-17 13:42:54295void WebSocketChannel::SendFrame(bool fin,
296 WebSocketFrameHeader::OpCode op_code,
297 const std::vector<char>& data) {
298 if (data.size() > INT_MAX) {
299 NOTREACHED() << "Frame size sanity check failed";
300 return;
301 }
302 if (stream_ == NULL) {
303 LOG(DFATAL) << "Got SendFrame without a connection established; "
304 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code
305 << " data.size()=" << data.size();
306 return;
307 }
[email protected]c0d29c22013-07-26 20:40:41308 if (InClosingState()) {
[email protected]999bcaa2013-07-17 13:42:54309 VLOG(1) << "SendFrame called in state " << state_
310 << ". This may be a bug, or a harmless race.";
311 return;
312 }
313 if (state_ != CONNECTED) {
314 NOTREACHED() << "SendFrame() called in state " << state_;
315 return;
316 }
[email protected]cb154062014-01-17 03:32:40317 if (data.size() > base::checked_cast<size_t>(current_send_quota_)) {
[email protected]ea56b982014-01-27 03:21:03318 // TODO(ricea): Kill renderer.
319 AllowUnused(
320 FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""));
[email protected]53deacb2013-11-22 14:02:43321 // |this| has been deleted.
[email protected]999bcaa2013-07-17 13:42:54322 return;
323 }
324 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
325 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code
326 << "; misbehaving renderer? fin=" << fin
327 << " data.size()=" << data.size();
328 return;
329 }
[email protected]48cc6922014-02-10 14:20:48330 if (op_code == WebSocketFrameHeader::kOpCodeText ||
331 (op_code == WebSocketFrameHeader::kOpCodeContinuation &&
332 sending_text_message_)) {
333 StreamingUtf8Validator::State state =
334 outgoing_utf8_validator_.AddBytes(vector_as_array(&data), data.size());
335 if (state == StreamingUtf8Validator::INVALID ||
336 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) {
337 // TODO(ricea): Kill renderer.
338 AllowUnused(
339 FailChannel("Browser sent a text frame containing invalid UTF-8",
340 kWebSocketErrorGoingAway,
341 ""));
342 // |this| has been deleted.
343 return;
344 }
345 sending_text_message_ = !fin;
346 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT);
347 }
[email protected]999bcaa2013-07-17 13:42:54348 current_send_quota_ -= data.size();
349 // TODO(ricea): If current_send_quota_ has dropped below
[email protected]caab2cc2013-08-27 10:24:37350 // send_quota_low_water_mark_, it might be good to increase the "low
351 // water mark" and "high water mark", but only if the link to the WebSocket
352 // server is not saturated.
[email protected]2f5d9f62013-09-26 12:14:28353 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
[email protected]999bcaa2013-07-17 13:42:54354 std::copy(data.begin(), data.end(), buffer->data());
[email protected]f485985e2013-10-24 13:47:44355 AllowUnused(SendIOBuffer(fin, op_code, buffer, data.size()));
356 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54357}
358
359void WebSocketChannel::SendFlowControl(int64 quota) {
[email protected]abda70d2013-12-12 07:53:54360 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED ||
361 state_ == CLOSE_WAIT);
[email protected]999bcaa2013-07-17 13:42:54362 // TODO(ricea): Add interface to WebSocketStream and implement.
363 // stream_->SendFlowControl(quota);
364}
365
366void WebSocketChannel::StartClosingHandshake(uint16 code,
367 const std::string& reason) {
[email protected]c0d29c22013-07-26 20:40:41368 if (InClosingState()) {
[email protected]999bcaa2013-07-17 13:42:54369 VLOG(1) << "StartClosingHandshake called in state " << state_
370 << ". This may be a bug, or a harmless race.";
371 return;
372 }
[email protected]6dfd8b32014-02-05 11:24:49373 if (state_ == CONNECTING) {
374 // Abort the in-progress handshake and drop the connection immediately.
375 stream_request_.reset();
376 state_ = CLOSED;
[email protected]86ec55502014-02-10 13:16:16377 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""));
[email protected]6dfd8b32014-02-05 11:24:49378 return;
379 }
[email protected]999bcaa2013-07-17 13:42:54380 if (state_ != CONNECTED) {
381 NOTREACHED() << "StartClosingHandshake() called in state " << state_;
382 return;
383 }
[email protected]3de65092013-10-24 09:39:44384 // Javascript actually only permits 1000 and 3000-4999, but the implementation
385 // itself may produce different codes. The length of |reason| is also checked
386 // by Javascript.
387 if (!IsStrictlyValidCloseStatusCode(code) ||
388 reason.size() > kMaximumCloseReasonLength) {
389 // "InternalServerError" is actually used for errors from any endpoint, per
390 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
391 // reason it must be malfunctioning in some way, and based on that we
392 // interpret this as an internal error.
[email protected]ea56b982014-01-27 03:21:03393 AllowUnused(SendClose(kWebSocketErrorInternalServerError, ""));
[email protected]f485985e2013-10-24 13:47:44394 // |this| may have been deleted.
[email protected]3de65092013-10-24 09:39:44395 return;
396 }
[email protected]48cc6922014-02-10 14:20:48397 AllowUnused(SendClose(
398 code, StreamingUtf8Validator::Validate(reason) ? reason : std::string()));
[email protected]f485985e2013-10-24 13:47:44399 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54400}
401
402void WebSocketChannel::SendAddChannelRequestForTesting(
[email protected]dab33eb2013-10-08 02:27:51403 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54404 const std::vector<std::string>& requested_subprotocols,
405 const GURL& origin,
[email protected]969dde72013-11-13 15:59:14406 const WebSocketStreamCreator& creator) {
407 SendAddChannelRequestWithSuppliedCreator(
408 socket_url, requested_subprotocols, origin, creator);
[email protected]3a266762013-10-23 08:15:10409}
410
411void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
412 base::TimeDelta delay) {
413 timeout_ = delay;
[email protected]999bcaa2013-07-17 13:42:54414}
415
[email protected]969dde72013-11-13 15:59:14416void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
[email protected]dab33eb2013-10-08 02:27:51417 const GURL& socket_url,
[email protected]999bcaa2013-07-17 13:42:54418 const std::vector<std::string>& requested_subprotocols,
419 const GURL& origin,
[email protected]969dde72013-11-13 15:59:14420 const WebSocketStreamCreator& creator) {
[email protected]999bcaa2013-07-17 13:42:54421 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
[email protected]53deacb2013-11-22 14:02:43422 if (!socket_url.SchemeIsWSOrWSS()) {
423 // TODO(ricea): Kill the renderer (this error should have been caught by
424 // Javascript).
[email protected]6c5d9f62014-01-27 15:05:21425 AllowUnused(event_interface_->OnAddChannelResponse(true, "", ""));
[email protected]53deacb2013-11-22 14:02:43426 // |this| is deleted here.
427 return;
428 }
[email protected]dab33eb2013-10-08 02:27:51429 socket_url_ = socket_url;
[email protected]999bcaa2013-07-17 13:42:54430 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
431 new ConnectDelegate(this));
[email protected]969dde72013-11-13 15:59:14432 stream_request_ = creator.Run(socket_url_,
[email protected]999bcaa2013-07-17 13:42:54433 requested_subprotocols,
434 origin,
[email protected]dab33eb2013-10-08 02:27:51435 url_request_context_,
[email protected]999bcaa2013-07-17 13:42:54436 BoundNetLog(),
437 connect_delegate.Pass());
438 state_ = CONNECTING;
439}
440
441void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) {
442 DCHECK(stream);
443 DCHECK_EQ(CONNECTING, state_);
444 stream_ = stream.Pass();
445 state_ = CONNECTED;
[email protected]f485985e2013-10-24 13:47:44446 if (event_interface_->OnAddChannelResponse(
[email protected]6c5d9f62014-01-27 15:05:21447 false, stream_->GetSubProtocol(), stream_->GetExtensions()) ==
448 CHANNEL_DELETED)
[email protected]f485985e2013-10-24 13:47:44449 return;
[email protected]999bcaa2013-07-17 13:42:54450
451 // TODO(ricea): Get flow control information from the WebSocketStream once we
452 // have a multiplexing WebSocketStream.
453 current_send_quota_ = send_quota_high_water_mark_;
[email protected]f485985e2013-10-24 13:47:44454 if (event_interface_->OnFlowControl(send_quota_high_water_mark_) ==
455 CHANNEL_DELETED)
456 return;
[email protected]999bcaa2013-07-17 13:42:54457
[email protected]caab2cc2013-08-27 10:24:37458 // |stream_request_| is not used once the connection has succeeded.
[email protected]999bcaa2013-07-17 13:42:54459 stream_request_.reset();
[email protected]f485985e2013-10-24 13:47:44460 AllowUnused(ReadFrames());
461 // |this| may have been deleted.
[email protected]999bcaa2013-07-17 13:42:54462}
463
[email protected]96868202014-01-09 10:38:04464void WebSocketChannel::OnConnectFailure(const std::string& message) {
[email protected]999bcaa2013-07-17 13:42:54465 DCHECK_EQ(CONNECTING, state_);
466 state_ = CLOSED;
467 stream_request_.reset();
[email protected]cd48ed12014-01-22 14:34:22468
469 if (CHANNEL_DELETED ==
470 notification_sender_->SendImmediately(event_interface_.get())) {
471 // |this| has been deleted.
472 return;
473 }
[email protected]96868202014-01-09 10:38:04474 AllowUnused(event_interface_->OnFailChannel(message));
[email protected]f485985e2013-10-24 13:47:44475 // |this| has been deleted.
[email protected]999bcaa2013-07-17 13:42:54476}
477
[email protected]cd48ed12014-01-22 14:34:22478void WebSocketChannel::OnStartOpeningHandshake(
479 scoped_ptr<WebSocketHandshakeRequestInfo> request) {
480 DCHECK(!notification_sender_->handshake_request_info());
481
482 // Because it is hard to handle an IPC error synchronously is difficult,
483 // we asynchronously notify the information.
484 notification_sender_->set_handshake_request_info(request.Pass());
485 ScheduleOpeningHandshakeNotification();
486}
487
488void WebSocketChannel::OnFinishOpeningHandshake(
489 scoped_ptr<WebSocketHandshakeResponseInfo> response) {
490 DCHECK(!notification_sender_->handshake_response_info());
491
492 // Because it is hard to handle an IPC error synchronously is difficult,
493 // we asynchronously notify the information.
494 notification_sender_->set_handshake_response_info(response.Pass());
495 ScheduleOpeningHandshakeNotification();
496}
497
498void WebSocketChannel::ScheduleOpeningHandshakeNotification() {
499 base::MessageLoop::current()->PostTask(
500 FROM_HERE,
501 base::Bind(HandshakeNotificationSender::Send,
502 notification_sender_->AsWeakPtr()));
503}
504
[email protected]f485985e2013-10-24 13:47:44505ChannelState WebSocketChannel::WriteFrames() {
[email protected]999bcaa2013-07-17 13:42:54506 int result = OK;
507 do {
[email protected]caab2cc2013-08-27 10:24:37508 // This use of base::Unretained is safe because this object owns the
509 // WebSocketStream and destroying it cancels all callbacks.
[email protected]999bcaa2013-07-17 13:42:54510 result = stream_->WriteFrames(
[email protected]c0d29c22013-07-26 20:40:41511 data_being_sent_->frames(),
[email protected]f485985e2013-10-24 13:47:44512 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
513 base::Unretained(this),
514 false));
[email protected]999bcaa2013-07-17 13:42:54515 if (result != ERR_IO_PENDING) {
[email protected]f485985e2013-10-24 13:47:44516 if (OnWriteDone(true, result) == CHANNEL_DELETED)
517 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54518 }
519 } while (result == OK && data_being_sent_);
[email protected]f485985e2013-10-24 13:47:44520 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54521}
522
[email protected]f485985e2013-10-24 13:47:44523ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
[email protected]999bcaa2013-07-17 13:42:54524 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
525 DCHECK_NE(CONNECTING, state_);
526 DCHECK_NE(ERR_IO_PENDING, result);
527 DCHECK(data_being_sent_);
528 switch (result) {
529 case OK:
530 if (data_to_send_next_) {
531 data_being_sent_ = data_to_send_next_.Pass();
[email protected]f485985e2013-10-24 13:47:44532 if (!synchronous)
533 return WriteFrames();
[email protected]999bcaa2013-07-17 13:42:54534 } else {
535 data_being_sent_.reset();
536 if (current_send_quota_ < send_quota_low_water_mark_) {
537 // TODO(ricea): Increase low_water_mark and high_water_mark if
538 // throughput is high, reduce them if throughput is low. Low water
539 // mark needs to be >= the bandwidth delay product *of the IPC
540 // channel*. Because factors like context-switch time, thread wake-up
541 // time, and bus speed come into play it is complex and probably needs
542 // to be determined empirically.
543 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_);
544 // TODO(ricea): Truncate quota by the quota specified by the remote
545 // server, if the protocol in use supports quota.
546 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_;
547 current_send_quota_ += fresh_quota;
[email protected]f485985e2013-10-24 13:47:44548 return event_interface_->OnFlowControl(fresh_quota);
[email protected]999bcaa2013-07-17 13:42:54549 }
550 }
[email protected]f485985e2013-10-24 13:47:44551 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54552
553 // If a recoverable error condition existed, it would go here.
554
555 default:
556 DCHECK_LT(result, 0)
557 << "WriteFrames() should only return OK or ERR_ codes";
558 stream_->Close();
[email protected]f485985e2013-10-24 13:47:44559 DCHECK_NE(CLOSED, state_);
560 state_ = CLOSED;
[email protected]86ec55502014-02-10 13:16:16561 return DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
[email protected]999bcaa2013-07-17 13:42:54562 }
563}
564
[email protected]f485985e2013-10-24 13:47:44565ChannelState WebSocketChannel::ReadFrames() {
[email protected]999bcaa2013-07-17 13:42:54566 int result = OK;
567 do {
[email protected]caab2cc2013-08-27 10:24:37568 // This use of base::Unretained is safe because this object owns the
569 // WebSocketStream, and any pending reads will be cancelled when it is
570 // destroyed.
[email protected]999bcaa2013-07-17 13:42:54571 result = stream_->ReadFrames(
[email protected]2f5d9f62013-09-26 12:14:28572 &read_frames_,
[email protected]f485985e2013-10-24 13:47:44573 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone),
574 base::Unretained(this),
575 false));
[email protected]999bcaa2013-07-17 13:42:54576 if (result != ERR_IO_PENDING) {
[email protected]f485985e2013-10-24 13:47:44577 if (OnReadDone(true, result) == CHANNEL_DELETED)
578 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54579 }
[email protected]f485985e2013-10-24 13:47:44580 DCHECK_NE(CLOSED, state_);
581 } while (result == OK);
582 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54583}
584
[email protected]f485985e2013-10-24 13:47:44585ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
[email protected]999bcaa2013-07-17 13:42:54586 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
587 DCHECK_NE(CONNECTING, state_);
588 DCHECK_NE(ERR_IO_PENDING, result);
589 switch (result) {
590 case OK:
591 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
592 // with no data read, not an empty response.
[email protected]2f5d9f62013-09-26 12:14:28593 DCHECK(!read_frames_.empty())
[email protected]999bcaa2013-07-17 13:42:54594 << "ReadFrames() returned OK, but nothing was read.";
[email protected]2f5d9f62013-09-26 12:14:28595 for (size_t i = 0; i < read_frames_.size(); ++i) {
596 scoped_ptr<WebSocketFrame> frame(read_frames_[i]);
597 read_frames_[i] = NULL;
[email protected]8b3d14e2014-02-13 14:24:28598 if (HandleFrame(frame.Pass()) == CHANNEL_DELETED)
[email protected]f485985e2013-10-24 13:47:44599 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54600 }
[email protected]2f5d9f62013-09-26 12:14:28601 read_frames_.clear();
[email protected]caab2cc2013-08-27 10:24:37602 // There should always be a call to ReadFrames pending.
[email protected]2f5d9f62013-09-26 12:14:28603 // TODO(ricea): Unless we are out of quota.
[email protected]f485985e2013-10-24 13:47:44604 DCHECK_NE(CLOSED, state_);
605 if (!synchronous)
606 return ReadFrames();
607 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54608
[email protected]2f5d9f62013-09-26 12:14:28609 case ERR_WS_PROTOCOL_ERROR:
[email protected]ea56b982014-01-27 03:21:03610 // This could be kWebSocketErrorProtocolError (specifically, non-minimal
611 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an
612 // extension-specific error.
613 return FailChannel("Invalid frame header",
[email protected]f485985e2013-10-24 13:47:44614 kWebSocketErrorProtocolError,
615 "WebSocket Protocol Error");
[email protected]2f5d9f62013-09-26 12:14:28616
[email protected]c0d29c22013-07-26 20:40:41617 default:
[email protected]999bcaa2013-07-17 13:42:54618 DCHECK_LT(result, 0)
619 << "ReadFrames() should only return OK or ERR_ codes";
620 stream_->Close();
[email protected]f485985e2013-10-24 13:47:44621 DCHECK_NE(CLOSED, state_);
622 state_ = CLOSED;
623 uint16 code = kWebSocketErrorAbnormalClosure;
[email protected]5742ae62014-02-06 11:03:18624 std::string reason = "";
[email protected]86ec55502014-02-10 13:16:16625 bool was_clean = false;
[email protected]8b3d14e2014-02-13 14:24:28626 if (received_close_code_ != 0) {
627 code = received_close_code_;
628 reason = received_close_reason_;
[email protected]86ec55502014-02-10 13:16:16629 was_clean = (result == ERR_CONNECTION_CLOSED);
[email protected]999bcaa2013-07-17 13:42:54630 }
[email protected]86ec55502014-02-10 13:16:16631 return DoDropChannel(was_clean, code, reason);
[email protected]999bcaa2013-07-17 13:42:54632 }
633}
634
[email protected]8b3d14e2014-02-13 14:24:28635ChannelState WebSocketChannel::HandleFrame(
636 scoped_ptr<WebSocketFrame> frame) {
[email protected]2f5d9f62013-09-26 12:14:28637 if (frame->header.masked) {
638 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
639 // masked frame."
[email protected]ea56b982014-01-27 03:21:03640 return FailChannel(
641 "A server must not mask any frames that it sends to the "
642 "client.",
643 kWebSocketErrorProtocolError,
644 "Masked frame from server");
[email protected]999bcaa2013-07-17 13:42:54645 }
[email protected]2f5d9f62013-09-26 12:14:28646 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
647 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) &&
648 !frame->header.final) {
[email protected]ea56b982014-01-27 03:21:03649 return FailChannel(
650 base::StringPrintf("Received fragmented control frame: opcode = %d",
651 opcode),
652 kWebSocketErrorProtocolError,
653 "Control message with FIN bit unset received");
[email protected]999bcaa2013-07-17 13:42:54654 }
655
[email protected]999bcaa2013-07-17 13:42:54656 // Respond to the frame appropriately to its type.
[email protected]8b3d14e2014-02-13 14:24:28657 return HandleFrameByState(
[email protected]2f5d9f62013-09-26 12:14:28658 opcode, frame->header.final, frame->data, frame->header.payload_length);
[email protected]999bcaa2013-07-17 13:42:54659}
660
[email protected]8b3d14e2014-02-13 14:24:28661ChannelState WebSocketChannel::HandleFrameByState(
[email protected]f485985e2013-10-24 13:47:44662 const WebSocketFrameHeader::OpCode opcode,
663 bool final,
664 const scoped_refptr<IOBuffer>& data_buffer,
665 size_t size) {
[email protected]999bcaa2013-07-17 13:42:54666 DCHECK_NE(RECV_CLOSED, state_)
667 << "HandleFrame() does not support being called re-entrantly from within "
668 "SendClose()";
[email protected]f485985e2013-10-24 13:47:44669 DCHECK_NE(CLOSED, state_);
670 if (state_ == CLOSE_WAIT) {
[email protected]999bcaa2013-07-17 13:42:54671 std::string frame_name;
[email protected]8b3d14e2014-02-13 14:24:28672 GetFrameTypeForOpcode(opcode, &frame_name);
[email protected]999bcaa2013-07-17 13:42:54673
[email protected]ea56b982014-01-27 03:21:03674 // FailChannel() won't send another Close frame.
675 return FailChannel(
676 frame_name + " received after close", kWebSocketErrorProtocolError, "");
[email protected]999bcaa2013-07-17 13:42:54677 }
678 switch (opcode) {
679 case WebSocketFrameHeader::kOpCodeText: // fall-thru
680 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
681 case WebSocketFrameHeader::kOpCodeContinuation:
682 if (state_ == CONNECTED) {
[email protected]48cc6922014-02-10 14:20:48683 if (opcode == WebSocketFrameHeader::kOpCodeText ||
684 (opcode == WebSocketFrameHeader::kOpCodeContinuation &&
685 receiving_text_message_)) {
686 // This call is not redundant when size == 0 because it tells us what
687 // the current state is.
688 StreamingUtf8Validator::State state =
689 incoming_utf8_validator_.AddBytes(
690 size ? data_buffer->data() : NULL, size);
691 if (state == StreamingUtf8Validator::INVALID ||
692 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) {
693 return FailChannel("Could not decode a text frame as UTF-8.",
694 kWebSocketErrorProtocolError,
695 "Invalid UTF-8 in text frame");
696 }
697 receiving_text_message_ = !final;
698 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT);
699 }
[email protected]999bcaa2013-07-17 13:42:54700 // TODO(ricea): Can this copy be eliminated?
[email protected]00f4daf2013-11-12 13:56:41701 const char* const data_begin = size ? data_buffer->data() : NULL;
[email protected]2f5d9f62013-09-26 12:14:28702 const char* const data_end = data_begin + size;
[email protected]999bcaa2013-07-17 13:42:54703 const std::vector<char> data(data_begin, data_end);
[email protected]caab2cc2013-08-27 10:24:37704 // TODO(ricea): Handle the case when ReadFrames returns far
705 // more data at once than should be sent in a single IPC. This needs to
706 // be handled carefully, as an overloaded IO thread is one possible
707 // cause of receiving very large chunks.
[email protected]999bcaa2013-07-17 13:42:54708
[email protected]caab2cc2013-08-27 10:24:37709 // Sends the received frame to the renderer process.
[email protected]f485985e2013-10-24 13:47:44710 return event_interface_->OnDataFrame(final, opcode, data);
[email protected]999bcaa2013-07-17 13:42:54711 }
[email protected]f485985e2013-10-24 13:47:44712 VLOG(3) << "Ignored data packet received in state " << state_;
713 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54714
715 case WebSocketFrameHeader::kOpCodePing:
[email protected]2f5d9f62013-09-26 12:14:28716 VLOG(1) << "Got Ping of size " << size;
[email protected]f485985e2013-10-24 13:47:44717 if (state_ == CONNECTED)
718 return SendIOBuffer(
[email protected]2f5d9f62013-09-26 12:14:28719 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size);
[email protected]f485985e2013-10-24 13:47:44720 VLOG(3) << "Ignored ping in state " << state_;
721 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54722
723 case WebSocketFrameHeader::kOpCodePong:
[email protected]2f5d9f62013-09-26 12:14:28724 VLOG(1) << "Got Pong of size " << size;
[email protected]caab2cc2013-08-27 10:24:37725 // There is no need to do anything with pong messages.
[email protected]f485985e2013-10-24 13:47:44726 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54727
728 case WebSocketFrameHeader::kOpCodeClose: {
729 uint16 code = kWebSocketNormalClosure;
730 std::string reason;
[email protected]ea56b982014-01-27 03:21:03731 std::string message;
732 if (!ParseClose(data_buffer, size, &code, &reason, &message)) {
733 return FailChannel(message, code, reason);
734 }
[email protected]999bcaa2013-07-17 13:42:54735 // TODO(ricea): Find a way to safely log the message from the close
736 // message (escape control codes and so on).
737 VLOG(1) << "Got Close with code " << code;
738 switch (state_) {
739 case CONNECTED:
740 state_ = RECV_CLOSED;
[email protected]f485985e2013-10-24 13:47:44741 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT
742 CHANNEL_DELETED)
743 return CHANNEL_DELETED;
744 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
745 return CHANNEL_DELETED;
[email protected]8b3d14e2014-02-13 14:24:28746 received_close_code_ = code;
747 received_close_reason_ = reason;
[email protected]999bcaa2013-07-17 13:42:54748 break;
749
750 case SEND_CLOSED:
[email protected]c0d29c22013-07-26 20:40:41751 state_ = CLOSE_WAIT;
[email protected]999bcaa2013-07-17 13:42:54752 // From RFC6455 section 7.1.5: "Each endpoint
753 // will see the status code sent by the other end as _The WebSocket
754 // Connection Close Code_."
[email protected]8b3d14e2014-02-13 14:24:28755 received_close_code_ = code;
756 received_close_reason_ = reason;
[email protected]999bcaa2013-07-17 13:42:54757 break;
758
759 default:
760 LOG(DFATAL) << "Got Close in unexpected state " << state_;
761 break;
762 }
[email protected]f485985e2013-10-24 13:47:44763 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54764 }
765
766 default:
[email protected]f485985e2013-10-24 13:47:44767 return FailChannel(
[email protected]ea56b982014-01-27 03:21:03768 base::StringPrintf("Unrecognized frame opcode: %d", opcode),
769 kWebSocketErrorProtocolError,
770 "Unknown opcode");
[email protected]999bcaa2013-07-17 13:42:54771 }
772}
773
[email protected]f485985e2013-10-24 13:47:44774ChannelState WebSocketChannel::SendIOBuffer(
775 bool fin,
776 WebSocketFrameHeader::OpCode op_code,
777 const scoped_refptr<IOBuffer>& buffer,
778 size_t size) {
[email protected]999bcaa2013-07-17 13:42:54779 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
780 DCHECK(stream_);
[email protected]2f5d9f62013-09-26 12:14:28781 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code));
782 WebSocketFrameHeader& header = frame->header;
783 header.final = fin;
784 header.masked = true;
785 header.payload_length = size;
786 frame->data = buffer;
[email protected]999bcaa2013-07-17 13:42:54787 if (data_being_sent_) {
[email protected]caab2cc2013-08-27 10:24:37788 // Either the link to the WebSocket server is saturated, or several messages
789 // are being sent in a batch.
790 // TODO(ricea): Keep some statistics to work out the situation and adjust
791 // quota appropriately.
[email protected]999bcaa2013-07-17 13:42:54792 if (!data_to_send_next_)
793 data_to_send_next_.reset(new SendBuffer);
[email protected]2f5d9f62013-09-26 12:14:28794 data_to_send_next_->AddFrame(frame.Pass());
[email protected]f485985e2013-10-24 13:47:44795 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54796 }
[email protected]f485985e2013-10-24 13:47:44797 data_being_sent_.reset(new SendBuffer);
798 data_being_sent_->AddFrame(frame.Pass());
799 return WriteFrames();
[email protected]999bcaa2013-07-17 13:42:54800}
801
[email protected]ea56b982014-01-27 03:21:03802ChannelState WebSocketChannel::FailChannel(const std::string& message,
[email protected]f485985e2013-10-24 13:47:44803 uint16 code,
804 const std::string& reason) {
[email protected]999bcaa2013-07-17 13:42:54805 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
806 DCHECK_NE(CONNECTING, state_);
[email protected]f485985e2013-10-24 13:47:44807 DCHECK_NE(CLOSED, state_);
[email protected]999bcaa2013-07-17 13:42:54808 // TODO(ricea): Logging.
[email protected]999bcaa2013-07-17 13:42:54809 if (state_ == CONNECTED) {
[email protected]ea56b982014-01-27 03:21:03810 if (SendClose(code, reason) == // Sets state_ to SEND_CLOSED
[email protected]f485985e2013-10-24 13:47:44811 CHANNEL_DELETED)
812 return CHANNEL_DELETED;
[email protected]999bcaa2013-07-17 13:42:54813 }
[email protected]caab2cc2013-08-27 10:24:37814 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
815 // should close the connection itself without waiting for the closing
816 // handshake.
[email protected]999bcaa2013-07-17 13:42:54817 stream_->Close();
818 state_ = CLOSED;
819
[email protected]ea56b982014-01-27 03:21:03820 return event_interface_->OnFailChannel(message);
[email protected]999bcaa2013-07-17 13:42:54821}
822
[email protected]f485985e2013-10-24 13:47:44823ChannelState WebSocketChannel::SendClose(uint16 code,
824 const std::string& reason) {
[email protected]999bcaa2013-07-17 13:42:54825 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
[email protected]3de65092013-10-24 09:39:44826 DCHECK_LE(reason.size(), kMaximumCloseReasonLength);
[email protected]2f5d9f62013-09-26 12:14:28827 scoped_refptr<IOBuffer> body;
828 size_t size = 0;
[email protected]c0d29c22013-07-26 20:40:41829 if (code == kWebSocketErrorNoStatusReceived) {
830 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
831 // frame with no payload.
[email protected]2f5d9f62013-09-26 12:14:28832 body = new IOBuffer(0);
[email protected]c0d29c22013-07-26 20:40:41833 } else {
834 const size_t payload_length = kWebSocketCloseCodeLength + reason.length();
[email protected]2f5d9f62013-09-26 12:14:28835 body = new IOBuffer(payload_length);
836 size = payload_length;
[email protected]c0d29c22013-07-26 20:40:41837 WriteBigEndian(body->data(), code);
838 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength,
839 they_should_both_be_two);
840 std::copy(
841 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
842 }
[email protected]3a266762013-10-23 08:15:10843 // This use of base::Unretained() is safe because we stop the timer in the
844 // destructor.
845 timer_.Start(
846 FROM_HERE,
847 timeout_,
848 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
[email protected]f485985e2013-10-24 13:47:44849 if (SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
850 CHANNEL_DELETED)
851 return CHANNEL_DELETED;
852 // SendIOBuffer() checks |state_|, so it is best not to change it until after
853 // SendIOBuffer() returns.
[email protected]c0d29c22013-07-26 20:40:41854 state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT;
[email protected]f485985e2013-10-24 13:47:44855 return CHANNEL_ALIVE;
[email protected]999bcaa2013-07-17 13:42:54856}
857
[email protected]ea56b982014-01-27 03:21:03858bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
[email protected]2f5d9f62013-09-26 12:14:28859 size_t size,
[email protected]999bcaa2013-07-17 13:42:54860 uint16* code,
[email protected]ea56b982014-01-27 03:21:03861 std::string* reason,
862 std::string* message) {
863 bool parsed_ok = true;
[email protected]999bcaa2013-07-17 13:42:54864 reason->clear();
865 if (size < kWebSocketCloseCodeLength) {
866 *code = kWebSocketErrorNoStatusReceived;
867 if (size != 0) {
[email protected]ea56b982014-01-27 03:21:03868 DVLOG(1) << "Close frame with payload size " << size << " received "
869 << "(the first byte is " << std::hex
870 << static_cast<int>(buffer->data()[0]) << ")";
871 parsed_ok = false;
872 *code = kWebSocketErrorProtocolError;
873 *message =
874 "Received a broken close frame containing an invalid size body.";
[email protected]999bcaa2013-07-17 13:42:54875 }
[email protected]ea56b982014-01-27 03:21:03876 return parsed_ok;
[email protected]999bcaa2013-07-17 13:42:54877 }
[email protected]00f4daf2013-11-12 13:56:41878 const char* data = buffer->data();
[email protected]999bcaa2013-07-17 13:42:54879 uint16 unchecked_code = 0;
880 ReadBigEndian(data, &unchecked_code);
881 COMPILE_ASSERT(sizeof(unchecked_code) == kWebSocketCloseCodeLength,
882 they_should_both_be_two_bytes);
[email protected]ea56b982014-01-27 03:21:03883 switch (unchecked_code) {
884 case kWebSocketErrorNoStatusReceived:
885 case kWebSocketErrorAbnormalClosure:
886 case kWebSocketErrorTlsHandshake:
887 *code = kWebSocketErrorProtocolError;
888 *message =
889 "Received a broken close frame containing a reserved status code.";
890 parsed_ok = false;
891 break;
892
893 default:
894 *code = unchecked_code;
895 break;
[email protected]999bcaa2013-07-17 13:42:54896 }
[email protected]ea56b982014-01-27 03:21:03897 if (parsed_ok) {
898 std::string text(data + kWebSocketCloseCodeLength, data + size);
[email protected]48cc6922014-02-10 14:20:48899 if (StreamingUtf8Validator::Validate(text)) {
[email protected]ea56b982014-01-27 03:21:03900 reason->swap(text);
901 } else {
902 *code = kWebSocketErrorProtocolError;
903 *reason = "Invalid UTF-8 in Close frame";
904 *message = "Received a broken close frame containing invalid UTF-8.";
905 parsed_ok = false;
906 }
[email protected]999bcaa2013-07-17 13:42:54907 }
[email protected]ea56b982014-01-27 03:21:03908 return parsed_ok;
[email protected]999bcaa2013-07-17 13:42:54909}
910
[email protected]86ec55502014-02-10 13:16:16911ChannelState WebSocketChannel::DoDropChannel(bool was_clean,
912 uint16 code,
[email protected]cd48ed12014-01-22 14:34:22913 const std::string& reason) {
914 if (CHANNEL_DELETED ==
915 notification_sender_->SendImmediately(event_interface_.get()))
916 return CHANNEL_DELETED;
[email protected]86ec55502014-02-10 13:16:16917 return event_interface_->OnDropChannel(was_clean, code, reason);
[email protected]cd48ed12014-01-22 14:34:22918}
919
[email protected]3a266762013-10-23 08:15:10920void WebSocketChannel::CloseTimeout() {
921 stream_->Close();
[email protected]f485985e2013-10-24 13:47:44922 DCHECK_NE(CLOSED, state_);
923 state_ = CLOSED;
[email protected]86ec55502014-02-10 13:16:16924 AllowUnused(DoDropChannel(false, kWebSocketErrorAbnormalClosure, ""));
[email protected]f485985e2013-10-24 13:47:44925 // |this| has been deleted.
[email protected]3a266762013-10-23 08:15:10926}
927
[email protected]999bcaa2013-07-17 13:42:54928} // namespace net