Home | History | Annotate | Download | only in websockets
      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