1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/websockets/websocket_channel.h" 6 7 #include <algorithm> 8 9 #include "base/basictypes.h" // for size_t 10 #include "base/bind.h" 11 #include "base/compiler_specific.h" 12 #include "base/safe_numerics.h" 13 #include "base/strings/string_util.h" 14 #include "base/time/time.h" 15 #include "net/base/big_endian.h" 16 #include "net/base/io_buffer.h" 17 #include "net/base/net_log.h" 18 #include "net/http/http_util.h" 19 #include "net/websockets/websocket_errors.h" 20 #include "net/websockets/websocket_event_interface.h" 21 #include "net/websockets/websocket_frame.h" 22 #include "net/websockets/websocket_mux.h" 23 #include "net/websockets/websocket_stream.h" 24 25 namespace net { 26 27 namespace { 28 29 const int kDefaultSendQuotaLowWaterMark = 1 << 16; 30 const int kDefaultSendQuotaHighWaterMark = 1 << 17; 31 const size_t kWebSocketCloseCodeLength = 2; 32 // This timeout is based on TCPMaximumSegmentLifetime * 2 from 33 // MainThreadWebSocketChannel.cpp in Blink. 34 const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60; 35 36 typedef WebSocketEventInterface::ChannelState ChannelState; 37 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE; 38 const ChannelState CHANNEL_DELETED = WebSocketEventInterface::CHANNEL_DELETED; 39 40 // Maximum close reason length = max control frame payload - 41 // status code length 42 // = 125 - 2 43 const size_t kMaximumCloseReasonLength = 125 - kWebSocketCloseCodeLength; 44 45 // Check a close status code for strict compliance with RFC6455. This is only 46 // used for close codes received from a renderer that we are intending to send 47 // out over the network. See ParseClose() for the restrictions on incoming close 48 // codes. The |code| parameter is type int for convenience of implementation; 49 // the real type is uint16. 50 bool IsStrictlyValidCloseStatusCode(int code) { 51 static const int kInvalidRanges[] = { 52 // [BAD, OK) 53 0, 1000, // 1000 is the first valid code 54 1005, 1007, // 1005 and 1006 MUST NOT be set. 55 1014, 3000, // 1014 unassigned; 1015 up to 2999 are reserved. 56 5000, 65536, // Codes above 5000 are invalid. 57 }; 58 const int* const kInvalidRangesEnd = 59 kInvalidRanges + arraysize(kInvalidRanges); 60 61 DCHECK_GE(code, 0); 62 DCHECK_LT(code, 65536); 63 const int* upper = std::upper_bound(kInvalidRanges, kInvalidRangesEnd, code); 64 DCHECK_NE(kInvalidRangesEnd, upper); 65 DCHECK_GT(upper, kInvalidRanges); 66 DCHECK_GT(*upper, code); 67 DCHECK_LE(*(upper - 1), code); 68 return ((upper - kInvalidRanges) % 2) == 0; 69 } 70 71 // This function avoids a bunch of boilerplate code. 72 void AllowUnused(ChannelState ALLOW_UNUSED unused) {} 73 74 } // namespace 75 76 // A class to encapsulate a set of frames and information about the size of 77 // those frames. 78 class WebSocketChannel::SendBuffer { 79 public: 80 SendBuffer() : total_bytes_(0) {} 81 82 // Add a WebSocketFrame to the buffer and increase total_bytes_. 83 void AddFrame(scoped_ptr<WebSocketFrame> chunk); 84 85 // Return a pointer to the frames_ for write purposes. 86 ScopedVector<WebSocketFrame>* frames() { return &frames_; } 87 88 private: 89 // The frames_ that will be sent in the next call to WriteFrames(). 90 ScopedVector<WebSocketFrame> frames_; 91 92 // The total size of the payload data in |frames_|. This will be used to 93 // measure the throughput of the link. 94 // TODO(ricea): Measure the throughput of the link. 95 size_t total_bytes_; 96 }; 97 98 void WebSocketChannel::SendBuffer::AddFrame(scoped_ptr<WebSocketFrame> frame) { 99 total_bytes_ += frame->header.payload_length; 100 frames_.push_back(frame.release()); 101 } 102 103 // Implementation of WebSocketStream::ConnectDelegate that simply forwards the 104 // calls on to the WebSocketChannel that created it. 105 class WebSocketChannel::ConnectDelegate 106 : public WebSocketStream::ConnectDelegate { 107 public: 108 explicit ConnectDelegate(WebSocketChannel* creator) : creator_(creator) {} 109 110 virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { 111 creator_->OnConnectSuccess(stream.Pass()); 112 // |this| may have been deleted. 113 } 114 115 virtual void OnFailure(uint16 websocket_error) OVERRIDE { 116 creator_->OnConnectFailure(websocket_error); 117 // |this| has been deleted. 118 } 119 120 private: 121 // A pointer to the WebSocketChannel that created this object. There is no 122 // danger of this pointer being stale, because deleting the WebSocketChannel 123 // cancels the connect process, deleting this object and preventing its 124 // callbacks from being called. 125 WebSocketChannel* const creator_; 126 127 DISALLOW_COPY_AND_ASSIGN(ConnectDelegate); 128 }; 129 130 WebSocketChannel::WebSocketChannel( 131 scoped_ptr<WebSocketEventInterface> event_interface, 132 URLRequestContext* url_request_context) 133 : event_interface_(event_interface.Pass()), 134 url_request_context_(url_request_context), 135 send_quota_low_water_mark_(kDefaultSendQuotaLowWaterMark), 136 send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark), 137 current_send_quota_(0), 138 timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)), 139 closing_code_(0), 140 state_(FRESHLY_CONSTRUCTED) {} 141 142 WebSocketChannel::~WebSocketChannel() { 143 // The stream may hold a pointer to read_frames_, and so it needs to be 144 // destroyed first. 145 stream_.reset(); 146 // The timer may have a callback pointing back to us, so stop it just in case 147 // someone decides to run the event loop from their destructor. 148 timer_.Stop(); 149 } 150 151 void WebSocketChannel::SendAddChannelRequest( 152 const GURL& socket_url, 153 const std::vector<std::string>& requested_subprotocols, 154 const GURL& origin) { 155 // Delegate to the tested version. 156 SendAddChannelRequestWithSuppliedCreator( 157 socket_url, 158 requested_subprotocols, 159 origin, 160 base::Bind(&WebSocketStream::CreateAndConnectStream)); 161 } 162 163 bool WebSocketChannel::InClosingState() const { 164 // The state RECV_CLOSED is not supported here, because it is only used in one 165 // code path and should not leak into the code in general. 166 DCHECK_NE(RECV_CLOSED, state_) 167 << "InClosingState called with state_ == RECV_CLOSED"; 168 return state_ == SEND_CLOSED || state_ == CLOSE_WAIT || state_ == CLOSED; 169 } 170 171 void WebSocketChannel::SendFrame(bool fin, 172 WebSocketFrameHeader::OpCode op_code, 173 const std::vector<char>& data) { 174 if (data.size() > INT_MAX) { 175 NOTREACHED() << "Frame size sanity check failed"; 176 return; 177 } 178 if (stream_ == NULL) { 179 LOG(DFATAL) << "Got SendFrame without a connection established; " 180 << "misbehaving renderer? fin=" << fin << " op_code=" << op_code 181 << " data.size()=" << data.size(); 182 return; 183 } 184 if (InClosingState()) { 185 VLOG(1) << "SendFrame called in state " << state_ 186 << ". This may be a bug, or a harmless race."; 187 return; 188 } 189 if (state_ != CONNECTED) { 190 NOTREACHED() << "SendFrame() called in state " << state_; 191 return; 192 } 193 if (data.size() > base::checked_numeric_cast<size_t>(current_send_quota_)) { 194 AllowUnused(FailChannel(SEND_GOING_AWAY, 195 kWebSocketMuxErrorSendQuotaViolation, 196 "Send quota exceeded")); 197 // |this| has been deleted. 198 return; 199 } 200 if (!WebSocketFrameHeader::IsKnownDataOpCode(op_code)) { 201 LOG(DFATAL) << "Got SendFrame with bogus op_code " << op_code 202 << "; misbehaving renderer? fin=" << fin 203 << " data.size()=" << data.size(); 204 return; 205 } 206 current_send_quota_ -= data.size(); 207 // TODO(ricea): If current_send_quota_ has dropped below 208 // send_quota_low_water_mark_, it might be good to increase the "low 209 // water mark" and "high water mark", but only if the link to the WebSocket 210 // server is not saturated. 211 // TODO(ricea): For kOpCodeText, do UTF-8 validation? 212 scoped_refptr<IOBuffer> buffer(new IOBuffer(data.size())); 213 std::copy(data.begin(), data.end(), buffer->data()); 214 AllowUnused(SendIOBuffer(fin, op_code, buffer, data.size())); 215 // |this| may have been deleted. 216 } 217 218 void WebSocketChannel::SendFlowControl(int64 quota) { 219 DCHECK(state_ == CONNECTING || state_ == CONNECTED || state_ == SEND_CLOSED || 220 state_ == CLOSE_WAIT); 221 // TODO(ricea): Add interface to WebSocketStream and implement. 222 // stream_->SendFlowControl(quota); 223 } 224 225 void WebSocketChannel::StartClosingHandshake(uint16 code, 226 const std::string& reason) { 227 if (InClosingState()) { 228 VLOG(1) << "StartClosingHandshake called in state " << state_ 229 << ". This may be a bug, or a harmless race."; 230 return; 231 } 232 if (state_ != CONNECTED) { 233 NOTREACHED() << "StartClosingHandshake() called in state " << state_; 234 return; 235 } 236 // Javascript actually only permits 1000 and 3000-4999, but the implementation 237 // itself may produce different codes. The length of |reason| is also checked 238 // by Javascript. 239 if (!IsStrictlyValidCloseStatusCode(code) || 240 reason.size() > kMaximumCloseReasonLength) { 241 // "InternalServerError" is actually used for errors from any endpoint, per 242 // errata 3227 to RFC6455. If the renderer is sending us an invalid code or 243 // reason it must be malfunctioning in some way, and based on that we 244 // interpret this as an internal error. 245 AllowUnused( 246 SendClose(kWebSocketErrorInternalServerError, "Internal Error")); 247 // |this| may have been deleted. 248 return; 249 } 250 AllowUnused(SendClose(code, IsStringUTF8(reason) ? reason : std::string())); 251 // |this| may have been deleted. 252 } 253 254 void WebSocketChannel::SendAddChannelRequestForTesting( 255 const GURL& socket_url, 256 const std::vector<std::string>& requested_subprotocols, 257 const GURL& origin, 258 const WebSocketStreamCreator& creator) { 259 SendAddChannelRequestWithSuppliedCreator( 260 socket_url, requested_subprotocols, origin, creator); 261 } 262 263 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting( 264 base::TimeDelta delay) { 265 timeout_ = delay; 266 } 267 268 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator( 269 const GURL& socket_url, 270 const std::vector<std::string>& requested_subprotocols, 271 const GURL& origin, 272 const WebSocketStreamCreator& creator) { 273 DCHECK_EQ(FRESHLY_CONSTRUCTED, state_); 274 if (!socket_url.SchemeIsWSOrWSS()) { 275 // TODO(ricea): Kill the renderer (this error should have been caught by 276 // Javascript). 277 AllowUnused(event_interface_->OnAddChannelResponse(true, "")); 278 // |this| is deleted here. 279 return; 280 } 281 socket_url_ = socket_url; 282 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( 283 new ConnectDelegate(this)); 284 stream_request_ = creator.Run(socket_url_, 285 requested_subprotocols, 286 origin, 287 url_request_context_, 288 BoundNetLog(), 289 connect_delegate.Pass()); 290 state_ = CONNECTING; 291 } 292 293 void WebSocketChannel::OnConnectSuccess(scoped_ptr<WebSocketStream> stream) { 294 DCHECK(stream); 295 DCHECK_EQ(CONNECTING, state_); 296 stream_ = stream.Pass(); 297 state_ = CONNECTED; 298 if (event_interface_->OnAddChannelResponse( 299 false, stream_->GetSubProtocol()) == CHANNEL_DELETED) 300 return; 301 302 // TODO(ricea): Get flow control information from the WebSocketStream once we 303 // have a multiplexing WebSocketStream. 304 current_send_quota_ = send_quota_high_water_mark_; 305 if (event_interface_->OnFlowControl(send_quota_high_water_mark_) == 306 CHANNEL_DELETED) 307 return; 308 309 // |stream_request_| is not used once the connection has succeeded. 310 stream_request_.reset(); 311 AllowUnused(ReadFrames()); 312 // |this| may have been deleted. 313 } 314 315 void WebSocketChannel::OnConnectFailure(uint16 websocket_error) { 316 DCHECK_EQ(CONNECTING, state_); 317 state_ = CLOSED; 318 stream_request_.reset(); 319 AllowUnused(event_interface_->OnAddChannelResponse(true, "")); 320 // |this| has been deleted. 321 } 322 323 ChannelState WebSocketChannel::WriteFrames() { 324 int result = OK; 325 do { 326 // This use of base::Unretained is safe because this object owns the 327 // WebSocketStream and destroying it cancels all callbacks. 328 result = stream_->WriteFrames( 329 data_being_sent_->frames(), 330 base::Bind(base::IgnoreResult(&WebSocketChannel::OnWriteDone), 331 base::Unretained(this), 332 false)); 333 if (result != ERR_IO_PENDING) { 334 if (OnWriteDone(true, result) == CHANNEL_DELETED) 335 return CHANNEL_DELETED; 336 } 337 } while (result == OK && data_being_sent_); 338 return CHANNEL_ALIVE; 339 } 340 341 ChannelState WebSocketChannel::OnWriteDone(bool synchronous, int result) { 342 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 343 DCHECK_NE(CONNECTING, state_); 344 DCHECK_NE(ERR_IO_PENDING, result); 345 DCHECK(data_being_sent_); 346 switch (result) { 347 case OK: 348 if (data_to_send_next_) { 349 data_being_sent_ = data_to_send_next_.Pass(); 350 if (!synchronous) 351 return WriteFrames(); 352 } else { 353 data_being_sent_.reset(); 354 if (current_send_quota_ < send_quota_low_water_mark_) { 355 // TODO(ricea): Increase low_water_mark and high_water_mark if 356 // throughput is high, reduce them if throughput is low. Low water 357 // mark needs to be >= the bandwidth delay product *of the IPC 358 // channel*. Because factors like context-switch time, thread wake-up 359 // time, and bus speed come into play it is complex and probably needs 360 // to be determined empirically. 361 DCHECK_LE(send_quota_low_water_mark_, send_quota_high_water_mark_); 362 // TODO(ricea): Truncate quota by the quota specified by the remote 363 // server, if the protocol in use supports quota. 364 int fresh_quota = send_quota_high_water_mark_ - current_send_quota_; 365 current_send_quota_ += fresh_quota; 366 return event_interface_->OnFlowControl(fresh_quota); 367 } 368 } 369 return CHANNEL_ALIVE; 370 371 // If a recoverable error condition existed, it would go here. 372 373 default: 374 DCHECK_LT(result, 0) 375 << "WriteFrames() should only return OK or ERR_ codes"; 376 stream_->Close(); 377 DCHECK_NE(CLOSED, state_); 378 state_ = CLOSED; 379 return event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure, 380 "Abnormal Closure"); 381 } 382 } 383 384 ChannelState WebSocketChannel::ReadFrames() { 385 int result = OK; 386 do { 387 // This use of base::Unretained is safe because this object owns the 388 // WebSocketStream, and any pending reads will be cancelled when it is 389 // destroyed. 390 result = stream_->ReadFrames( 391 &read_frames_, 392 base::Bind(base::IgnoreResult(&WebSocketChannel::OnReadDone), 393 base::Unretained(this), 394 false)); 395 if (result != ERR_IO_PENDING) { 396 if (OnReadDone(true, result) == CHANNEL_DELETED) 397 return CHANNEL_DELETED; 398 } 399 DCHECK_NE(CLOSED, state_); 400 } while (result == OK); 401 return CHANNEL_ALIVE; 402 } 403 404 ChannelState WebSocketChannel::OnReadDone(bool synchronous, int result) { 405 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 406 DCHECK_NE(CONNECTING, state_); 407 DCHECK_NE(ERR_IO_PENDING, result); 408 switch (result) { 409 case OK: 410 // ReadFrames() must use ERR_CONNECTION_CLOSED for a closed connection 411 // with no data read, not an empty response. 412 DCHECK(!read_frames_.empty()) 413 << "ReadFrames() returned OK, but nothing was read."; 414 for (size_t i = 0; i < read_frames_.size(); ++i) { 415 scoped_ptr<WebSocketFrame> frame(read_frames_[i]); 416 read_frames_[i] = NULL; 417 if (ProcessFrame(frame.Pass()) == CHANNEL_DELETED) 418 return CHANNEL_DELETED; 419 } 420 read_frames_.clear(); 421 // There should always be a call to ReadFrames pending. 422 // TODO(ricea): Unless we are out of quota. 423 DCHECK_NE(CLOSED, state_); 424 if (!synchronous) 425 return ReadFrames(); 426 return CHANNEL_ALIVE; 427 428 case ERR_WS_PROTOCOL_ERROR: 429 return FailChannel(SEND_REAL_ERROR, 430 kWebSocketErrorProtocolError, 431 "WebSocket Protocol Error"); 432 433 default: 434 DCHECK_LT(result, 0) 435 << "ReadFrames() should only return OK or ERR_ codes"; 436 stream_->Close(); 437 DCHECK_NE(CLOSED, state_); 438 state_ = CLOSED; 439 uint16 code = kWebSocketErrorAbnormalClosure; 440 std::string reason = "Abnormal Closure"; 441 if (closing_code_ != 0) { 442 code = closing_code_; 443 reason = closing_reason_; 444 } 445 return event_interface_->OnDropChannel(code, reason); 446 } 447 } 448 449 ChannelState WebSocketChannel::ProcessFrame(scoped_ptr<WebSocketFrame> frame) { 450 if (frame->header.masked) { 451 // RFC6455 Section 5.1 "A client MUST close a connection if it detects a 452 // masked frame." 453 return FailChannel(SEND_REAL_ERROR, 454 kWebSocketErrorProtocolError, 455 "Masked frame from server"); 456 } 457 const WebSocketFrameHeader::OpCode opcode = frame->header.opcode; 458 if (WebSocketFrameHeader::IsKnownControlOpCode(opcode) && 459 !frame->header.final) { 460 return FailChannel(SEND_REAL_ERROR, 461 kWebSocketErrorProtocolError, 462 "Control message with FIN bit unset received"); 463 } 464 465 // Respond to the frame appropriately to its type. 466 return HandleFrame( 467 opcode, frame->header.final, frame->data, frame->header.payload_length); 468 } 469 470 ChannelState WebSocketChannel::HandleFrame( 471 const WebSocketFrameHeader::OpCode opcode, 472 bool final, 473 const scoped_refptr<IOBuffer>& data_buffer, 474 size_t size) { 475 DCHECK_NE(RECV_CLOSED, state_) 476 << "HandleFrame() does not support being called re-entrantly from within " 477 "SendClose()"; 478 DCHECK_NE(CLOSED, state_); 479 if (state_ == CLOSE_WAIT) { 480 std::string frame_name; 481 switch (opcode) { 482 case WebSocketFrameHeader::kOpCodeText: // fall-thru 483 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru 484 case WebSocketFrameHeader::kOpCodeContinuation: 485 frame_name = "Data frame"; 486 break; 487 488 case WebSocketFrameHeader::kOpCodePing: 489 frame_name = "Ping"; 490 break; 491 492 case WebSocketFrameHeader::kOpCodePong: 493 frame_name = "Pong"; 494 break; 495 496 case WebSocketFrameHeader::kOpCodeClose: 497 frame_name = "Close"; 498 break; 499 500 default: 501 frame_name = "Unknown frame type"; 502 break; 503 } 504 // SEND_REAL_ERROR makes no difference here, as FailChannel() won't send 505 // another Close frame. 506 return FailChannel(SEND_REAL_ERROR, 507 kWebSocketErrorProtocolError, 508 frame_name + " received after close"); 509 } 510 switch (opcode) { 511 case WebSocketFrameHeader::kOpCodeText: // fall-thru 512 case WebSocketFrameHeader::kOpCodeBinary: // fall-thru 513 case WebSocketFrameHeader::kOpCodeContinuation: 514 if (state_ == CONNECTED) { 515 // TODO(ricea): Need to fail the connection if UTF-8 is invalid 516 // post-reassembly. Requires a streaming UTF-8 validator. 517 // TODO(ricea): Can this copy be eliminated? 518 const char* const data_begin = size ? data_buffer->data() : NULL; 519 const char* const data_end = data_begin + size; 520 const std::vector<char> data(data_begin, data_end); 521 // TODO(ricea): Handle the case when ReadFrames returns far 522 // more data at once than should be sent in a single IPC. This needs to 523 // be handled carefully, as an overloaded IO thread is one possible 524 // cause of receiving very large chunks. 525 526 // Sends the received frame to the renderer process. 527 return event_interface_->OnDataFrame(final, opcode, data); 528 } 529 VLOG(3) << "Ignored data packet received in state " << state_; 530 return CHANNEL_ALIVE; 531 532 case WebSocketFrameHeader::kOpCodePing: 533 VLOG(1) << "Got Ping of size " << size; 534 if (state_ == CONNECTED) 535 return SendIOBuffer( 536 true, WebSocketFrameHeader::kOpCodePong, data_buffer, size); 537 VLOG(3) << "Ignored ping in state " << state_; 538 return CHANNEL_ALIVE; 539 540 case WebSocketFrameHeader::kOpCodePong: 541 VLOG(1) << "Got Pong of size " << size; 542 // There is no need to do anything with pong messages. 543 return CHANNEL_ALIVE; 544 545 case WebSocketFrameHeader::kOpCodeClose: { 546 uint16 code = kWebSocketNormalClosure; 547 std::string reason; 548 ParseClose(data_buffer, size, &code, &reason); 549 // TODO(ricea): Find a way to safely log the message from the close 550 // message (escape control codes and so on). 551 VLOG(1) << "Got Close with code " << code; 552 switch (state_) { 553 case CONNECTED: 554 state_ = RECV_CLOSED; 555 if (SendClose(code, reason) == // Sets state_ to CLOSE_WAIT 556 CHANNEL_DELETED) 557 return CHANNEL_DELETED; 558 if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED) 559 return CHANNEL_DELETED; 560 closing_code_ = code; 561 closing_reason_ = reason; 562 break; 563 564 case SEND_CLOSED: 565 state_ = CLOSE_WAIT; 566 // From RFC6455 section 7.1.5: "Each endpoint 567 // will see the status code sent by the other end as _The WebSocket 568 // Connection Close Code_." 569 closing_code_ = code; 570 closing_reason_ = reason; 571 break; 572 573 default: 574 LOG(DFATAL) << "Got Close in unexpected state " << state_; 575 break; 576 } 577 return CHANNEL_ALIVE; 578 } 579 580 default: 581 return FailChannel( 582 SEND_REAL_ERROR, kWebSocketErrorProtocolError, "Unknown opcode"); 583 } 584 } 585 586 ChannelState WebSocketChannel::SendIOBuffer( 587 bool fin, 588 WebSocketFrameHeader::OpCode op_code, 589 const scoped_refptr<IOBuffer>& buffer, 590 size_t size) { 591 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); 592 DCHECK(stream_); 593 scoped_ptr<WebSocketFrame> frame(new WebSocketFrame(op_code)); 594 WebSocketFrameHeader& header = frame->header; 595 header.final = fin; 596 header.masked = true; 597 header.payload_length = size; 598 frame->data = buffer; 599 if (data_being_sent_) { 600 // Either the link to the WebSocket server is saturated, or several messages 601 // are being sent in a batch. 602 // TODO(ricea): Keep some statistics to work out the situation and adjust 603 // quota appropriately. 604 if (!data_to_send_next_) 605 data_to_send_next_.reset(new SendBuffer); 606 data_to_send_next_->AddFrame(frame.Pass()); 607 return CHANNEL_ALIVE; 608 } 609 data_being_sent_.reset(new SendBuffer); 610 data_being_sent_->AddFrame(frame.Pass()); 611 return WriteFrames(); 612 } 613 614 ChannelState WebSocketChannel::FailChannel(ExposeError expose, 615 uint16 code, 616 const std::string& reason) { 617 DCHECK_NE(FRESHLY_CONSTRUCTED, state_); 618 DCHECK_NE(CONNECTING, state_); 619 DCHECK_NE(CLOSED, state_); 620 // TODO(ricea): Logging. 621 if (state_ == CONNECTED) { 622 uint16 send_code = kWebSocketErrorGoingAway; 623 std::string send_reason = "Internal Error"; 624 if (expose == SEND_REAL_ERROR) { 625 send_code = code; 626 send_reason = reason; 627 } 628 if (SendClose(send_code, send_reason) == // Sets state_ to SEND_CLOSED 629 CHANNEL_DELETED) 630 return CHANNEL_DELETED; 631 } 632 // Careful study of RFC6455 section 7.1.7 and 7.1.1 indicates the browser 633 // should close the connection itself without waiting for the closing 634 // handshake. 635 stream_->Close(); 636 state_ = CLOSED; 637 638 return event_interface_->OnDropChannel(code, reason); 639 } 640 641 ChannelState WebSocketChannel::SendClose(uint16 code, 642 const std::string& reason) { 643 DCHECK(state_ == CONNECTED || state_ == RECV_CLOSED); 644 DCHECK_LE(reason.size(), kMaximumCloseReasonLength); 645 scoped_refptr<IOBuffer> body; 646 size_t size = 0; 647 if (code == kWebSocketErrorNoStatusReceived) { 648 // Special case: translate kWebSocketErrorNoStatusReceived into a Close 649 // frame with no payload. 650 body = new IOBuffer(0); 651 } else { 652 const size_t payload_length = kWebSocketCloseCodeLength + reason.length(); 653 body = new IOBuffer(payload_length); 654 size = payload_length; 655 WriteBigEndian(body->data(), code); 656 COMPILE_ASSERT(sizeof(code) == kWebSocketCloseCodeLength, 657 they_should_both_be_two); 658 std::copy( 659 reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength); 660 } 661 // This use of base::Unretained() is safe because we stop the timer in the 662 // destructor. 663 timer_.Start( 664 FROM_HERE, 665 timeout_, 666 base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this))); 667 if (SendIOBuffer(true, WebSocketFrameHeader::kOpCodeClose, body, size) == 668 CHANNEL_DELETED) 669 return CHANNEL_DELETED; 670 // SendIOBuffer() checks |state_|, so it is best not to change it until after 671 // SendIOBuffer() returns. 672 state_ = (state_ == CONNECTED) ? SEND_CLOSED : CLOSE_WAIT; 673 return CHANNEL_ALIVE; 674 } 675 676 void WebSocketChannel::ParseClose(const scoped_refptr<IOBuffer>& buffer, 677 size_t size, 678 uint16* code, 679 std::string* reason) { 680 reason->clear(); 681 if (size < kWebSocketCloseCodeLength) { 682 *code = kWebSocketErrorNoStatusReceived; 683 if (size != 0) { 684 VLOG(1) << "Close frame with payload size " << size << " received " 685 << "(the first byte is " << std::hex 686 << static_cast<int>(buffer->data()[0]) << ")"; 687 } 688 return; 689 } 690 const char* data = buffer->data(); 691 uint16 unchecked_code = 0; 692 ReadBigEndian(data, &unchecked_code); 693 COMPILE_ASSERT(sizeof(unchecked_code) == kWebSocketCloseCodeLength, 694 they_should_both_be_two_bytes); 695 if (unchecked_code >= static_cast<uint16>(kWebSocketNormalClosure) && 696 unchecked_code <= 697 static_cast<uint16>(kWebSocketErrorPrivateReservedMax)) { 698 *code = unchecked_code; 699 } else { 700 VLOG(1) << "Close frame contained code outside of the valid range: " 701 << unchecked_code; 702 *code = kWebSocketErrorAbnormalClosure; 703 } 704 std::string text(data + kWebSocketCloseCodeLength, data + size); 705 // IsStringUTF8() blocks surrogate pairs and non-characters, so it is strictly 706 // stronger than required by RFC3629. 707 if (IsStringUTF8(text)) { 708 reason->swap(text); 709 } 710 } 711 712 void WebSocketChannel::CloseTimeout() { 713 stream_->Close(); 714 DCHECK_NE(CLOSED, state_); 715 state_ = CLOSED; 716 AllowUnused(event_interface_->OnDropChannel(kWebSocketErrorAbnormalClosure, 717 "Abnormal Closure")); 718 // |this| has been deleted. 719 } 720 721 } // namespace net 722