bookmarks: Move bookmark_test_helpers.h into 'bookmarks' namespace.
[chromium-blink-merge.git] / net / websockets / websocket_channel.cc
bloba6eeb1c39100147239879c32f8ee2d18366be2b2
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/websockets/websocket_channel.h"
7 #include <limits.h> // for INT_MAX
9 #include <algorithm>
10 #include <deque>
12 #include "base/basictypes.h" // for size_t
13 #include "base/big_endian.h"
14 #include "base/bind.h"
15 #include "base/compiler_specific.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/histogram.h"
20 #include "base/numerics/safe_conversions.h"
21 #include "base/stl_util.h"
22 #include "base/strings/stringprintf.h"
23 #include "base/time/time.h"
24 #include "net/base/io_buffer.h"
25 #include "net/base/net_log.h"
26 #include "net/http/http_request_headers.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_util.h"
29 #include "net/websockets/websocket_errors.h"
30 #include "net/websockets/websocket_event_interface.h"
31 #include "net/websockets/websocket_frame.h"
32 #include "net/websockets/websocket_handshake_request_info.h"
33 #include "net/websockets/websocket_handshake_response_info.h"
34 #include "net/websockets/websocket_mux.h"
35 #include "net/websockets/websocket_stream.h"
36 #include "url/origin.h"
38 namespace net {
40 namespace {
42 using base::StreamingUtf8Validator;
44 const int kDefaultSendQuotaLowWaterMark = 1 << 16;
45 const int kDefaultSendQuotaHighWaterMark = 1 << 17;
46 const size_t kWebSocketCloseCodeLength = 2;
47 // This timeout is based on TCPMaximumSegmentLifetime * 2 from
48 // MainThreadWebSocketChannel.cpp in Blink.
49 const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
51 typedef WebSocketEventInterface::ChannelState ChannelState;
52 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
53 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED;
55 // Maximum close reason length = max control frame payload -
56 // status code length
57 // = 125 - 2
58 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength;
60 // Check a close status code for strict compliance with RFC6455. This is only
61 // used for close codes received from a renderer that we are intending to send
62 // out over the network. See ParseClose() for the restrictions on incoming close
63 // codes. The |code| parameter is type int for convenience of implementation;
64 // the real type is uint16. Code 1005 is treated specially; it cannot be set
65 // explicitly by Javascript but the renderer uses it to indicate we should send
66 // a Close frame with no payload.
67 bool IsStrictlyValidCloseStatusCode(int code) {
68 static const int kInvalidRanges[] = {
69 // [BAD, OK)
70 0, 1000, // 1000 is the first valid code
71 1006, 1007, // 1006 MUST NOT be set.
72 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved.
73 5000, 65536, // Codes above 5000 are invalid.
75 const int* const kInvalidRangesEnd =
76 kInvalidRanges + arraysize(kInvalidRanges);
78 DCHECK_GE(code, 0);
79 DCHECK_LT(code, 65536);
80 const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code);
81 DCHECK_NE(kInvalidRangesEnd, upper);
82 DCHECK_GT(upper, kInvalidRanges);
83 DCHECK_GT(*upper, code);
84 DCHECK_LE(*(upper - 1), code);
85 return ((upper - kInvalidRanges) % 2) == 0;
88 // Sets |name| to the name of the frame type for the given |opcode|. Note that
89 // for all of Text, Binary and Continuation opcode, this method returns
90 // "Data frame".
91 void GetFrameTypeForOpcode(WebSocketFrameHeader::OpCode opcode,
92 std::string* name) {
93 switch (opcode) {
94 case WebSocketFrameHeader::kOpCodeText: // fall-thru
95 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru
96 case WebSocketFrameHeader::kOpCodeContinuation:
97 *name = "Data frame";
98 break;
100 case WebSocketFrameHeader::kOpCodePing:
101 *name = "Ping";
102 break;
104 case WebSocketFrameHeader::kOpCodePong:
105 *name = "Pong";
106 break;
108 case WebSocketFrameHeader::kOpCodeClose:
109 *name = "Close";
110 break;
112 default:
113 *name = "Unknown frame type";
114 break;
117 return;
120 } // namespace
122 // A class to encapsulate a set of frames and information about the size of
123 // those frames.
124 class WebSocketChannel::SendBuffer {
125 public:
126 SendBuffer() : total_bytes_(0) {}
128 // Add a WebSocketFrame to the buffer and increase total_bytes_.
129 void AddFrame(scoped_ptr<WebSocketFrame> chunk);
131 // Return a pointer to the frames_ for write purposes.
132 ScopedVector<WebSocketFrame>* frames() { return &frames_; }
134 private:
135 // The frames_ that will be sent in the next call to WriteFrames().
136 ScopedVector<WebSocketFrame> frames_;
138 // The total size of the payload data in |frames_|. This will be used to
139 // measure the throughput of the link.
140 // TODO(ricea): Measure the throughput of the link.
141 uint64 total_bytes_;
144 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) {
145 total_bytes_ += frame->header.payload_length;
146 frames_.push_back(frame.release());
149 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the
150 // calls on to the WebSocketChannel that created it.
151 class WebSocketChannel::ConnectDelegate
152 : public WebSocketStream::ConnectDelegate {
153 public:
154 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {}
156 void OnSuccess(scoped_ptr<WebSocketStream> stream) override {
157 creator_->OnConnectSuccess(stream.Pass());
158 // |this| may have been deleted.
161 void OnFailure(const std::string& message) override {
162 creator_->OnConnectFailure(message);
163 // |this| has been deleted.
166 void OnStartOpeningHandshake(
167 scoped_ptr<WebSocketHandshakeRequestInfo> request) override {
168 creator_->OnStartOpeningHandshake(request.Pass());
171 void OnFinishOpeningHandshake(
172 scoped_ptr<WebSocketHandshakeResponseInfo> response) override {
173 creator_->OnFinishOpeningHandshake(response.Pass());
176 void OnSSLCertificateError(
177 scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks>
178 ssl_error_callbacks,
179 const SSLInfo& ssl_info,
180 bool fatal) override {
181 creator_->OnSSLCertificateError(
182 ssl_error_callbacks.Pass(), ssl_info, fatal);
185 private:
186 // A pointer to the WebSocketChannel that created this object. There is no
187 // danger of this pointer being stale, because deleting the WebSocketChannel
188 // cancels the connect process, deleting this object and preventing its
189 // callbacks from being called.
190 WebSocketChannel* const creator_;
192 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate);
195 class WebSocketChannel::HandshakeNotificationSender
196 : public base::SupportsWeakPtr<HandshakeNotificationSender> {
197 public:
198 explicit HandshakeNotificationSender(WebSocketChannel* channel);
199 ~HandshakeNotificationSender();
201 static void Send(base::WeakPtr<HandshakeNotificationSender> sender);
203 ChannelState SendImmediately(WebSocketEventInterface* event_interface);
205 const WebSocketHandshakeRequestInfo* handshake_request_info() const {
206 return handshake_request_info_.get();
209 void set_handshake_request_info(
210 scoped_ptr<WebSocketHandshakeRequestInfo> request_info) {
211 handshake_request_info_ = request_info.Pass();
214 const WebSocketHandshakeResponseInfo* handshake_response_info() const {
215 return handshake_response_info_.get();
218 void set_handshake_response_info(
219 scoped_ptr<WebSocketHandshakeResponseInfo> response_info) {
220 handshake_response_info_ = response_info.Pass();
223 private:
224 WebSocketChannel* owner_;
225 scoped_ptr<WebSocketHandshakeRequestInfo> handshake_request_info_;
226 scoped_ptr<WebSocketHandshakeResponseInfo> handshake_response_info_;
229 WebSocketChannel::HandshakeNotificationSender::HandshakeNotificationSender(
230 WebSocketChannel* channel)
231 : owner_(channel) {}
233 WebSocketChannel::HandshakeNotificationSender::~HandshakeNotificationSender() {}
235 void WebSocketChannel::HandshakeNotificationSender::Send(
236 base::WeakPtr<HandshakeNotificationSender> sender) {
237 // Do nothing if |sender| is already destructed.
238 if (sender) {
239 WebSocketChannel* channel = sender->owner_;
240 sender->SendImmediately(channel->event_interface_.get());
244 ChannelState WebSocketChannel::HandshakeNotificationSender::SendImmediately(
245 WebSocketEventInterface* event_interface) {
247 if (handshake_request_info_.get()) {
248 if (CHANNEL_DELETED == event_interface->OnStartOpeningHandshake(
249 handshake_request_info_.Pass()))
250 return CHANNEL_DELETED;
253 if (handshake_response_info_.get()) {
254 if (CHANNEL_DELETED == event_interface->OnFinishOpeningHandshake(
255 handshake_response_info_.Pass()))
256 return CHANNEL_DELETED;
258 // TODO(yhirano): We can release |this| to save memory because
259 // there will be no more opening handshake notification.
262 return CHANNEL_ALIVE;
265 WebSocketChannel::PendingReceivedFrame::PendingReceivedFrame(
266 bool final,
267 WebSocketFrameHeader::OpCode opcode,
268 const scoped_refptr<IOBuffer>& data,
269 uint64 offset,
270 uint64 size)
271 : final_(final),
272 opcode_(opcode),
273 data_(data),
274 offset_(offset),
275 size_(size) {}
277 WebSocketChannel::PendingReceivedFrame::~PendingReceivedFrame() {}
279 void WebSocketChannel::PendingReceivedFrame::ResetOpcode() {
280 DCHECK(WebSocketFrameHeader::IsKnownDataOpCode(opcode_));
281 opcode_ = WebSocketFrameHeader::kOpCodeContinuation;
284 void WebSocketChannel::PendingReceivedFrame::DidConsume(uint64 bytes) {
285 DCHECK_LE(offset_, size_);
286 DCHECK_LE(bytes, size_ - offset_);
287 offset_ += bytes;
290 WebSocketChannel::WebSocketChannel(
291 scoped_ptr<WebSocketEventInterface> event_interface,
292 URLRequestContext* url_request_context)
293 : event_interface_(event_interface.Pass()),
294 url_request_context_(url_request_context),
295 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark),
296 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
297 current_send_quota_(0),
298 current_receive_quota_(0),
299 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
300 received_close_code_(0),
301 state_(FRESHLY_CONSTRUCTED),
302 notification_sender_(new HandshakeNotificationSender(this)),
303 sending_text_message_(false),
304 receiving_text_message_(false),
305 expecting_to_handle_continuation_(false),
306 initial_frame_forwarded_(false) {}
308 WebSocketChannel::~WebSocketChannel() {
309 // The stream may hold a pointer to read_frames_, and so it needs to be
310 // destroyed first.
311 stream_.reset();
312 // The timer may have a callback pointing back to us, so stop it just in case
313 // someone decides to run the event loop from their destructor.
314 timer_.Stop();
317 void WebSocketChannel::SendAddChannelRequest(
318 const GURL& socket_url,
319 const std::vector<std::string>& requested_subprotocols,
320 const url::Origin& origin) {
321 // Delegate to the tested version.
322 SendAddChannelRequestWithSuppliedCreator(
323 socket_url,
324 requested_subprotocols,
325 origin,
326 base::Bind(&WebSocketStream::CreateAndConnectStream));
329 void WebSocketChannel::SetState(State new_state) {
330 DCHECK_NE(state_, new_state);
332 if (new_state == CONNECTED)
333 established_on_ = base::TimeTicks::Now();
334 if (state_ == CONNECTED && !established_on_.is_null()) {
335 UMA_HISTOGRAM_LONG_TIMES(
336 "Net.WebSocket.Duration", base::TimeTicks::Now() - established_on_);
339 state_ = new_state;
342 bool WebSocketChannel::InClosingState() const {
343 // The state RECV_CLOSED is not supported here, because it is only used in one
344 // code path and should not leak into the code in general.
345 DCHECK_NE(RECV_CLOSED, state_)
346 << "InClosingState called with state_ == RECV_CLOSED";
347 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED;
350 void WebSocketChannel::SendFrame(bool fin,
351 WebSocketFrameHeader::OpCode op_code,
352 const std::vector<char>& data) {
353 if (data.size() > INT_MAX) {
354 NOTREACHED() << "Frame size sanity check failed";
355 return;
357 if (stream_ == NULL) {
358 LOG(DFATAL) << "Got SendFrame without a connection established; "
359 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code
360 << " data.size()=" << data.size();
361 return;
363 if (InClosingState()) {
364 DVLOG(1) << "SendFrame called in state " << state_
365 << ". This may be a bug, or a harmless race.";
366 return;
368 if (state_ != CONNECTED) {
369 NOTREACHED() << "SendFrame() called in state " << state_;
370 return;
372 if (data.size() > base::checked_cast<size_t>(current_send_quota_)) {
373 // TODO(ricea): Kill renderer.
374 ignore_result(
375 FailChannel("Send quota exceeded", kWebSocketErrorGoingAway, ""));
376 // |this| has been deleted.
377 return;
379 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) {
380 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code
381 << "; misbehaving renderer? fin=" << fin
382 << " data.size()=" << data.size();
383 return;
385 if (op_code == WebSocketFrameHeader::kOpCodeText ||
386 (op_code == WebSocketFrameHeader::kOpCodeContinuation &&
387 sending_text_message_)) {
388 StreamingUtf8Validator::State state =
389 outgoing_utf8_validator_.AddBytes(vector_as_array(&data), data.size());
390 if (state == StreamingUtf8Validator::INVALID ||
391 (state == StreamingUtf8Validator::VALID_MIDPOINT && fin)) {
392 // TODO(ricea): Kill renderer.
393 ignore_result(
394 FailChannel("Browser sent a text frame containing invalid UTF-8",
395 kWebSocketErrorGoingAway,
396 ""));
397 // |this| has been deleted.
398 return;
400 sending_text_message_ = !fin;
401 DCHECK(!fin || state == StreamingUtf8Validator::VALID_ENDPOINT);
403 current_send_quota_ -= data.size();
404 // TODO(ricea): If current_send_quota_ has dropped below
405 // send_quota_low_water_mark_, it might be good to increase the "low
406 // water mark" and "high water mark", but only if the link to the WebSocket
407 // server is not saturated.
408 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size()));
409 std::copy(data.begin(), data.end(), buffer->data());
410 ignore_result(SendFrameFromIOBuffer(fin, op_code, buffer, data.size()));
411 // |this| may have been deleted.
414 void WebSocketChannel::SendFlowControl(int64 quota) {
415 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED ||
416 state_ == CLOSE_WAIT);
417 // TODO(ricea): Kill the renderer if it tries to send us a negative quota
418 // value or > INT_MAX.
419 DCHECK_GE(quota, 0);
420 DCHECK_LE(quota, INT_MAX);
421 if (!pending_received_frames_.empty()) {
422 DCHECK_EQ(0u, current_receive_quota_);
424 while (!pending_received_frames_.empty() && quota > 0) {
425 PendingReceivedFrame& front = pending_received_frames_.front();
426 const uint64 data_size = front.size() - front.offset();
427 const uint64 bytes_to_send =
428 std::min(base::checked_cast<uint64>(quota), data_size);
429 const bool final = front.final() && data_size == bytes_to_send;
430 const char* data =
431 front.data().get() ? front.data()->data() + front.offset() : NULL;
432 DCHECK(!bytes_to_send || data) << "Non empty data should not be null.";
433 const std::vector<char> data_vector(data, data + bytes_to_send);
434 DVLOG(3) << "Sending frame previously split due to quota to the "
435 << "renderer: quota=" << quota << " data_size=" << data_size
436 << " bytes_to_send=" << bytes_to_send;
437 if (event_interface_->OnDataFrame(final, front.opcode(), data_vector) ==
438 CHANNEL_DELETED)
439 return;
440 if (bytes_to_send < data_size) {
441 front.DidConsume(bytes_to_send);
442 front.ResetOpcode();
443 return;
445 quota -= bytes_to_send;
447 pending_received_frames_.pop();
449 // If current_receive_quota_ == 0 then there is no pending ReadFrames()
450 // operation.
451 const bool start_read =
452 current_receive_quota_ == 0 && quota > 0 &&
453 (state_ == CONNECTED || state_ == SEND_CLOSED || state_ == CLOSE_WAIT);
454 current_receive_quota_ += quota;
455 if (start_read)
456 ignore_result(ReadFrames());
457 // |this| may have been deleted.
460 void WebSocketChannel::StartClosingHandshake(uint16 code,
461 const std::string& reason) {
462 if (InClosingState()) {
463 // When the associated renderer process is killed while the channel is in
464 // CLOSING state we reach here.
465 DVLOG(1) << "StartClosingHandshake called in state " << state_
466 << ". This may be a bug, or a harmless race.";
467 return;
469 if (state_ == CONNECTING) {
470 // Abort the in-progress handshake and drop the connection immediately.
471 stream_request_.reset();
472 SetState(CLOSED);
473 DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
474 return;
476 if (state_ != CONNECTED) {
477 NOTREACHED() << "StartClosingHandshake() called in state " << state_;
478 return;
480 // Javascript actually only permits 1000 and 3000-4999, but the implementation
481 // itself may produce different codes. The length of |reason| is also checked
482 // by Javascript.
483 if (!IsStrictlyValidCloseStatusCode(code) ||
484 reason.size() > kMaximumCloseReasonLength) {
485 // "InternalServerError" is actually used for errors from any endpoint, per
486 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or
487 // reason it must be malfunctioning in some way, and based on that we
488 // interpret this as an internal error.
489 if (SendClose(kWebSocketErrorInternalServerError, "") != CHANNEL_DELETED) {
490 DCHECK_EQ(CONNECTED, state_);
491 SetState(SEND_CLOSED);
493 return;
495 if (SendClose(
496 code,
497 StreamingUtf8Validator::Validate(reason) ? reason : std::string()) ==
498 CHANNEL_DELETED)
499 return;
500 DCHECK_EQ(CONNECTED, state_);
501 SetState(SEND_CLOSED);
504 void WebSocketChannel::SendAddChannelRequestForTesting(
505 const GURL& socket_url,
506 const std::vector<std::string>& requested_subprotocols,
507 const url::Origin& origin,
508 const WebSocketStreamCreator& creator) {
509 SendAddChannelRequestWithSuppliedCreator(
510 socket_url, requested_subprotocols, origin, creator);
513 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
514 base::TimeDelta delay) {
515 timeout_ = delay;
518 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
519 const GURL& socket_url,
520 const std::vector<std::string>& requested_subprotocols,
521 const url::Origin& origin,
522 const WebSocketStreamCreator& creator) {
523 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_);
524 if (!socket_url.SchemeIsWSOrWSS()) {
525 // TODO(ricea): Kill the renderer (this error should have been caught by
526 // Javascript).
527 ignore_result(event_interface_->OnAddChannelResponse(true, "", ""));
528 // |this| is deleted here.
529 return;
531 socket_url_ = socket_url;
532 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
533 new ConnectDelegate(this));
534 stream_request_ = creator.Run(socket_url_,
535 requested_subprotocols,
536 origin,
537 url_request_context_,
538 BoundNetLog(),
539 connect_delegate.Pass());
540 SetState(CONNECTING);
543 void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) {
544 DCHECK(stream);
545 DCHECK_EQ(CONNECTING, state_);
547 stream_ = stream.Pass();
549 SetState(CONNECTED);
551 if (event_interface_->OnAddChannelResponse(
552 false, stream_->GetSubProtocol(), stream_->GetExtensions()) ==
553 CHANNEL_DELETED)
554 return;
556 // TODO(ricea): Get flow control information from the WebSocketStream once we
557 // have a multiplexing WebSocketStream.
558 current_send_quota_ = send_quota_high_water_mark_;
559 if (event_interface_->OnFlowControl(send_quota_high_water_mark_) ==
560 CHANNEL_DELETED)
561 return;
563 // |stream_request_| is not used once the connection has succeeded.
564 stream_request_.reset();
566 ignore_result(ReadFrames());
567 // |this| may have been deleted.
570 void WebSocketChannel::OnConnectFailure(const std::string& message) {
571 DCHECK_EQ(CONNECTING, state_);
573 // Copy the message before we delete its owner.
574 std::string message_copy = message;
576 SetState(CLOSED);
577 stream_request_.reset();
579 if (CHANNEL_DELETED ==
580 notification_sender_->SendImmediately(event_interface_.get())) {
581 // |this| has been deleted.
582 return;
584 ignore_result(event_interface_->OnFailChannel(message_copy));
585 // |this| has been deleted.
588 void WebSocketChannel::OnSSLCertificateError(
589 scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> ssl_error_callbacks,
590 const SSLInfo& ssl_info,
591 bool fatal) {
592 ignore_result(event_interface_->OnSSLCertificateError(
593 ssl_error_callbacks.Pass(), socket_url_, ssl_info, fatal));
596 void WebSocketChannel::OnStartOpeningHandshake(
597 scoped_ptr<WebSocketHandshakeRequestInfo> request) {
598 DCHECK(!notification_sender_->handshake_request_info());
600 // Because it is hard to handle an IPC error synchronously is difficult,
601 // we asynchronously notify the information.
602 notification_sender_->set_handshake_request_info(request.Pass());
603 ScheduleOpeningHandshakeNotification();
606 void WebSocketChannel::OnFinishOpeningHandshake(
607 scoped_ptr<WebSocketHandshakeResponseInfo> response) {
608 DCHECK(!notification_sender_->handshake_response_info());
610 // Because it is hard to handle an IPC error synchronously is difficult,
611 // we asynchronously notify the information.
612 notification_sender_->set_handshake_response_info(response.Pass());
613 ScheduleOpeningHandshakeNotification();
616 void WebSocketChannel::ScheduleOpeningHandshakeNotification() {
617 base::MessageLoop::current()->PostTask(
618 FROM_HERE,
619 base::Bind(HandshakeNotificationSender::Send,
620 notification_sender_->AsWeakPtr()));
623 ChannelState WebSocketChannel::WriteFrames() {
624 int result = OK;
625 do {
626 // This use of base::Unretained is safe because this object owns the
627 // WebSocketStream and destroying it cancels all callbacks.
628 result = stream_->WriteFrames(
629 data_being_sent_->frames(),
630 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone),
631 base::Unretained(this),
632 false));
633 if (result != ERR_IO_PENDING) {
634 if (OnWriteDone(true, result) == CHANNEL_DELETED)
635 return CHANNEL_DELETED;
636 // OnWriteDone() returns CHANNEL_DELETED on error. Here |state_| is
637 // guaranteed to be the same as before OnWriteDone() call.
639 } while (result == OK && data_being_sent_);
640 return CHANNEL_ALIVE;
643 ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) {
644 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
645 DCHECK_NE(CONNECTING, state_);
646 DCHECK_NE(ERR_IO_PENDING, result);
647 DCHECK(data_being_sent_);
648 switch (result) {
649 case OK:
650 if (data_to_send_next_) {
651 data_being_sent_ = data_to_send_next_.Pass();
652 if (!synchronous)
653 return WriteFrames();
654 } else {
655 data_being_sent_.reset();
656 if (current_send_quota_ < send_quota_low_water_mark_) {
657 // TODO(ricea): Increase low_water_mark and high_water_mark if
658 // throughput is high, reduce them if throughput is low. Low water
659 // mark needs to be >= the bandwidth delay product *of the IPC
660 // channel*. Because factors like context-switch time, thread wake-up
661 // time, and bus speed come into play it is complex and probably needs
662 // to be determined empirically.
663 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_);
664 // TODO(ricea): Truncate quota by the quota specified by the remote
665 // server, if the protocol in use supports quota.
666 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_;
667 current_send_quota_ += fresh_quota;
668 return event_interface_->OnFlowControl(fresh_quota);
671 return CHANNEL_ALIVE;
673 // If a recoverable error condition existed, it would go here.
675 default:
676 DCHECK_LT(result, 0)
677 << "WriteFrames() should only return OK or ERR_ codes";
679 stream_->Close();
680 SetState(CLOSED);
681 return DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
685 ChannelState WebSocketChannel::ReadFrames() {
686 int result = OK;
687 while (result == OK && current_receive_quota_ > 0) {
688 // This use of base::Unretained is safe because this object owns the
689 // WebSocketStream, and any pending reads will be cancelled when it is
690 // destroyed.
691 result = stream_->ReadFrames(
692 &read_frames_,
693 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone),
694 base::Unretained(this),
695 false));
696 if (result != ERR_IO_PENDING) {
697 if (OnReadDone(true, result) == CHANNEL_DELETED)
698 return CHANNEL_DELETED;
700 DCHECK_NE(CLOSED, state_);
702 return CHANNEL_ALIVE;
705 ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) {
706 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
707 DCHECK_NE(CONNECTING, state_);
708 DCHECK_NE(ERR_IO_PENDING, result);
709 switch (result) {
710 case OK:
711 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection
712 // with no data read, not an empty response.
713 DCHECK(!read_frames_.empty())
714 << "ReadFrames() returned OK, but nothing was read.";
715 for (size_t i = 0; i < read_frames_.size(); ++i) {
716 scoped_ptr<WebSocketFrame> frame(read_frames_[i]);
717 read_frames_[i] = NULL;
718 if (HandleFrame(frame.Pass()) == CHANNEL_DELETED)
719 return CHANNEL_DELETED;
721 read_frames_.clear();
722 // There should always be a call to ReadFrames pending.
723 // TODO(ricea): Unless we are out of quota.
724 DCHECK_NE(CLOSED, state_);
725 if (!synchronous)
726 return ReadFrames();
727 return CHANNEL_ALIVE;
729 case ERR_WS_PROTOCOL_ERROR:
730 // This could be kWebSocketErrorProtocolError (specifically, non-minimal
731 // encoding of payload length) or kWebSocketErrorMessageTooBig, or an
732 // extension-specific error.
733 return FailChannel("Invalid frame header",
734 kWebSocketErrorProtocolError,
735 "WebSocket Protocol Error");
737 default:
738 DCHECK_LT(result, 0)
739 << "ReadFrames() should only return OK or ERR_ codes";
741 stream_->Close();
742 SetState(CLOSED);
744 uint16 code = kWebSocketErrorAbnormalClosure;
745 std::string reason = "";
746 bool was_clean = false;
747 if (received_close_code_ != 0) {
748 code = received_close_code_;
749 reason = received_close_reason_;
750 was_clean = (result == ERR_CONNECTION_CLOSED);
753 return DoDropChannel(was_clean, code, reason);
757 ChannelState WebSocketChannel::HandleFrame(scoped_ptr<WebSocketFrame> frame) {
758 if (frame->header.masked) {
759 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a
760 // masked frame."
761 return FailChannel(
762 "A server must not mask any frames that it sends to the "
763 "client.",
764 kWebSocketErrorProtocolError,
765 "Masked frame from server");
767 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode;
768 DCHECK(!WebSocketFrameHeader::IsKnownControlOpCode(opcode) ||
769 frame->header.final);
770 if (frame->header.reserved1 || frame->header.reserved2 ||
771 frame->header.reserved3) {
772 return FailChannel(base::StringPrintf(
773 "One or more reserved bits are on: reserved1 = %d, "
774 "reserved2 = %d, reserved3 = %d",
775 static_cast<int>(frame->header.reserved1),
776 static_cast<int>(frame->header.reserved2),
777 static_cast<int>(frame->header.reserved3)),
778 kWebSocketErrorProtocolError,
779 "Invalid reserved bit");
782 // Respond to the frame appropriately to its type.
783 return HandleFrameByState(
784 opcode, frame->header.final, frame->data, frame->header.payload_length);
787 ChannelState WebSocketChannel::HandleFrameByState(
788 const WebSocketFrameHeader::OpCode opcode,
789 bool final,
790 const scoped_refptr<IOBuffer>& data_buffer,
791 uint64 size) {
792 DCHECK_NE(RECV_CLOSED, state_)
793 << "HandleFrame() does not support being called re-entrantly from within "
794 "SendClose()";
795 DCHECK_NE(CLOSED, state_);
796 if (state_ == CLOSE_WAIT) {
797 std::string frame_name;
798 GetFrameTypeForOpcode(opcode, &frame_name);
800 // FailChannel() won't send another Close frame.
801 return FailChannel(
802 frame_name + " received after close", kWebSocketErrorProtocolError, "");
804 switch (opcode) {
805 case WebSocketFrameHeader::kOpCodeText: // fall-thru
806 case WebSocketFrameHeader::kOpCodeBinary:
807 case WebSocketFrameHeader::kOpCodeContinuation:
808 return HandleDataFrame(opcode, final, data_buffer, size);
810 case WebSocketFrameHeader::kOpCodePing:
811 DVLOG(1) << "Got Ping of size " << size;
812 if (state_ == CONNECTED)
813 return SendFrameFromIOBuffer(
814 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size);
815 DVLOG(3) << "Ignored ping in state " << state_;
816 return CHANNEL_ALIVE;
818 case WebSocketFrameHeader::kOpCodePong:
819 DVLOG(1) << "Got Pong of size " << size;
820 // There is no need to do anything with pong messages.
821 return CHANNEL_ALIVE;
823 case WebSocketFrameHeader::kOpCodeClose: {
824 // TODO(ricea): If there is a message which is queued for transmission to
825 // the renderer, then the renderer should not receive an
826 // OnClosingHandshake or OnDropChannel IPC until the queued message has
827 // been completedly transmitted.
828 uint16 code = kWebSocketNormalClosure;
829 std::string reason;
830 std::string message;
831 if (!ParseClose(data_buffer, size, &code, &reason, &message)) {
832 return FailChannel(message, code, reason);
834 // TODO(ricea): Find a way to safely log the message from the close
835 // message (escape control codes and so on).
836 DVLOG(1) << "Got Close with code " << code;
837 switch (state_) {
838 case CONNECTED:
839 SetState(RECV_CLOSED);
840 if (SendClose(code, reason) == CHANNEL_DELETED)
841 return CHANNEL_DELETED;
842 DCHECK_EQ(RECV_CLOSED, state_);
843 SetState(CLOSE_WAIT);
845 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
846 return CHANNEL_DELETED;
847 received_close_code_ = code;
848 received_close_reason_ = reason;
849 break;
851 case SEND_CLOSED:
852 SetState(CLOSE_WAIT);
853 // From RFC6455 section 7.1.5: "Each endpoint
854 // will see the status code sent by the other end as _The WebSocket
855 // Connection Close Code_."
856 received_close_code_ = code;
857 received_close_reason_ = reason;
858 break;
860 default:
861 LOG(DFATAL) << "Got Close in unexpected state " << state_;
862 break;
864 return CHANNEL_ALIVE;
867 default:
868 return FailChannel(
869 base::StringPrintf("Unrecognized frame opcode: %d", opcode),
870 kWebSocketErrorProtocolError,
871 "Unknown opcode");
875 ChannelState WebSocketChannel::HandleDataFrame(
876 WebSocketFrameHeader::OpCode opcode,
877 bool final,
878 const scoped_refptr<IOBuffer>& data_buffer,
879 uint64 size) {
880 if (state_ != CONNECTED) {
881 DVLOG(3) << "Ignored data packet received in state " << state_;
882 return CHANNEL_ALIVE;
884 DCHECK(opcode == WebSocketFrameHeader::kOpCodeContinuation ||
885 opcode == WebSocketFrameHeader::kOpCodeText ||
886 opcode == WebSocketFrameHeader::kOpCodeBinary);
887 const bool got_continuation =
888 (opcode == WebSocketFrameHeader::kOpCodeContinuation);
889 if (got_continuation != expecting_to_handle_continuation_) {
890 const std::string console_log = got_continuation
891 ? "Received unexpected continuation frame."
892 : "Received start of new message but previous message is unfinished.";
893 const std::string reason = got_continuation
894 ? "Unexpected continuation"
895 : "Previous data frame unfinished";
896 return FailChannel(console_log, kWebSocketErrorProtocolError, reason);
898 expecting_to_handle_continuation_ = !final;
899 WebSocketFrameHeader::OpCode opcode_to_send = opcode;
900 if (!initial_frame_forwarded_ &&
901 opcode == WebSocketFrameHeader::kOpCodeContinuation) {
902 opcode_to_send = receiving_text_message_
903 ? WebSocketFrameHeader::kOpCodeText
904 : WebSocketFrameHeader::kOpCodeBinary;
906 if (opcode == WebSocketFrameHeader::kOpCodeText ||
907 (opcode == WebSocketFrameHeader::kOpCodeContinuation &&
908 receiving_text_message_)) {
909 // This call is not redundant when size == 0 because it tells us what
910 // the current state is.
911 StreamingUtf8Validator::State state = incoming_utf8_validator_.AddBytes(
912 size ? data_buffer->data() : NULL, static_cast<size_t>(size));
913 if (state == StreamingUtf8Validator::INVALID ||
914 (state == StreamingUtf8Validator::VALID_MIDPOINT && final)) {
915 return FailChannel("Could not decode a text frame as UTF-8.",
916 kWebSocketErrorProtocolError,
917 "Invalid UTF-8 in text frame");
919 receiving_text_message_ = !final;
920 DCHECK(!final || state == StreamingUtf8Validator::VALID_ENDPOINT);
922 if (size == 0U && !final)
923 return CHANNEL_ALIVE;
925 initial_frame_forwarded_ = !final;
926 if (size > current_receive_quota_ || !pending_received_frames_.empty()) {
927 const bool no_quota = (current_receive_quota_ == 0);
928 DCHECK(no_quota || pending_received_frames_.empty());
929 DVLOG(3) << "Queueing frame to renderer due to quota. quota="
930 << current_receive_quota_ << " size=" << size;
931 WebSocketFrameHeader::OpCode opcode_to_queue =
932 no_quota ? opcode_to_send : WebSocketFrameHeader::kOpCodeContinuation;
933 pending_received_frames_.push(PendingReceivedFrame(
934 final, opcode_to_queue, data_buffer, current_receive_quota_, size));
935 if (no_quota)
936 return CHANNEL_ALIVE;
937 size = current_receive_quota_;
938 final = false;
941 // TODO(ricea): Can this copy be eliminated?
942 const char* const data_begin = size ? data_buffer->data() : NULL;
943 const char* const data_end = data_begin + size;
944 const std::vector<char> data(data_begin, data_end);
945 current_receive_quota_ -= size;
947 // Sends the received frame to the renderer process.
948 return event_interface_->OnDataFrame(final, opcode_to_send, data);
951 ChannelState WebSocketChannel::SendFrameFromIOBuffer(
952 bool fin,
953 WebSocketFrameHeader::OpCode op_code,
954 const scoped_refptr<IOBuffer>& buffer,
955 uint64 size) {
956 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
957 DCHECK(stream_);
959 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code));
960 WebSocketFrameHeader& header = frame->header;
961 header.final = fin;
962 header.masked = true;
963 header.payload_length = size;
964 frame->data = buffer;
966 if (data_being_sent_) {
967 // Either the link to the WebSocket server is saturated, or several messages
968 // are being sent in a batch.
969 // TODO(ricea): Keep some statistics to work out the situation and adjust
970 // quota appropriately.
971 if (!data_to_send_next_)
972 data_to_send_next_.reset(new SendBuffer);
973 data_to_send_next_->AddFrame(frame.Pass());
974 return CHANNEL_ALIVE;
977 data_being_sent_.reset(new SendBuffer);
978 data_being_sent_->AddFrame(frame.Pass());
979 return WriteFrames();
982 ChannelState WebSocketChannel::FailChannel(const std::string& message,
983 uint16 code,
984 const std::string& reason) {
985 DCHECK_NE(FRESHLY_CONSTRUCTED, state_);
986 DCHECK_NE(CONNECTING, state_);
987 DCHECK_NE(CLOSED, state_);
989 // TODO(ricea): Logging.
990 if (state_ == CONNECTED) {
991 if (SendClose(code, reason) == CHANNEL_DELETED)
992 return CHANNEL_DELETED;
995 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser
996 // should close the connection itself without waiting for the closing
997 // handshake.
998 stream_->Close();
999 SetState(CLOSED);
1000 return event_interface_->OnFailChannel(message);
1003 ChannelState WebSocketChannel::SendClose(uint16 code,
1004 const std::string& reason) {
1005 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED);
1006 DCHECK_LE(reason.size(), kMaximumCloseReasonLength);
1007 scoped_refptr<IOBuffer> body;
1008 uint64 size = 0;
1009 if (code == kWebSocketErrorNoStatusReceived) {
1010 // Special case: translate kWebSocketErrorNoStatusReceived into a Close
1011 // frame with no payload.
1012 DCHECK(reason.empty());
1013 body = new IOBuffer(0);
1014 } else {
1015 const size_t payload_length = kWebSocketCloseCodeLength + reason.length();
1016 body = new IOBuffer(payload_length);
1017 size = payload_length;
1018 base::WriteBigEndian(body->data(), code);
1019 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength,
1020 they_should_both_be_two);
1021 std::copy(
1022 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
1024 // This use of base::Unretained() is safe because we stop the timer in the
1025 // destructor.
1026 timer_.Start(
1027 FROM_HERE,
1028 timeout_,
1029 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
1030 if (SendFrameFromIOBuffer(
1031 true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
1032 CHANNEL_DELETED)
1033 return CHANNEL_DELETED;
1034 return CHANNEL_ALIVE;
1037 bool WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer,
1038 uint64 size,
1039 uint16* code,
1040 std::string* reason,
1041 std::string* message) {
1042 reason->clear();
1043 if (size < kWebSocketCloseCodeLength) {
1044 if (size == 0U) {
1045 *code = kWebSocketErrorNoStatusReceived;
1046 return true;
1049 DVLOG(1) << "Close frame with payload size " << size << " received "
1050 << "(the first byte is " << std::hex
1051 << static_cast<int>(buffer->data()[0]) << ")";
1052 *code = kWebSocketErrorProtocolError;
1053 *message =
1054 "Received a broken close frame containing an invalid size body.";
1055 return false;
1058 const char* data = buffer->data();
1059 uint16 unchecked_code = 0;
1060 base::ReadBigEndian(data, &unchecked_code);
1061 COMPILE_ASSERT(sizeof(unchecked_code) == kWebSocketCloseCodeLength,
1062 they_should_both_be_two_bytes);
1064 switch (unchecked_code) {
1065 case kWebSocketErrorNoStatusReceived:
1066 case kWebSocketErrorAbnormalClosure:
1067 case kWebSocketErrorTlsHandshake:
1068 *code = kWebSocketErrorProtocolError;
1069 *message =
1070 "Received a broken close frame containing a reserved status code.";
1071 return false;
1073 default:
1074 *code = unchecked_code;
1075 break;
1078 std::string text(data + kWebSocketCloseCodeLength, data + size);
1079 if (StreamingUtf8Validator::Validate(text)) {
1080 reason->swap(text);
1081 return true;
1084 *code = kWebSocketErrorProtocolError;
1085 *reason = "Invalid UTF-8 in Close frame";
1086 *message = "Received a broken close frame containing invalid UTF-8.";
1087 return false;
1090 ChannelState WebSocketChannel::DoDropChannel(bool was_clean,
1091 uint16 code,
1092 const std::string& reason) {
1093 if (CHANNEL_DELETED ==
1094 notification_sender_->SendImmediately(event_interface_.get()))
1095 return CHANNEL_DELETED;
1096 ChannelState result =
1097 event_interface_->OnDropChannel(was_clean, code, reason);
1098 DCHECK_EQ(CHANNEL_DELETED, result);
1099 return result;
1102 void WebSocketChannel::CloseTimeout() {
1103 stream_->Close();
1104 SetState(CLOSED);
1105 DoDropChannel(false, kWebSocketErrorAbnormalClosure, "");
1106 // |this| has been deleted.
1109 } // namespace net