1 // Copyright (c) 2012 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/spdy/spdy_websocket_stream.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/compiler_specific.h" 10 #include "net/base/io_buffer.h" 11 #include "net/base/net_errors.h" 12 #include "net/spdy/spdy_framer.h" 13 #include "net/spdy/spdy_protocol.h" 14 #include "net/spdy/spdy_session.h" 15 #include "net/spdy/spdy_stream.h" 16 #include "url/gurl.h" 17 18 namespace net { 19 20 SpdyWebSocketStream::SpdyWebSocketStream( 21 const base::WeakPtr<SpdySession>& spdy_session, Delegate* delegate) 22 : spdy_session_(spdy_session), 23 pending_send_data_length_(0), 24 delegate_(delegate), 25 weak_ptr_factory_(this) { 26 DCHECK(spdy_session_.get()); 27 DCHECK(delegate_); 28 } 29 30 SpdyWebSocketStream::~SpdyWebSocketStream() { 31 delegate_ = NULL; 32 Close(); 33 } 34 35 int SpdyWebSocketStream::InitializeStream(const GURL& url, 36 RequestPriority request_priority, 37 const BoundNetLog& net_log) { 38 if (!spdy_session_) 39 return ERR_SOCKET_NOT_CONNECTED; 40 41 int rv = stream_request_.StartRequest( 42 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url, request_priority, net_log, 43 base::Bind(&SpdyWebSocketStream::OnSpdyStreamCreated, 44 weak_ptr_factory_.GetWeakPtr())); 45 46 if (rv == OK) { 47 stream_ = stream_request_.ReleaseStream(); 48 DCHECK(stream_.get()); 49 stream_->SetDelegate(this); 50 } 51 return rv; 52 } 53 54 int SpdyWebSocketStream::SendRequest(scoped_ptr<SpdyHeaderBlock> headers) { 55 if (!stream_.get()) { 56 NOTREACHED(); 57 return ERR_UNEXPECTED; 58 } 59 int result = stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND); 60 if (result < OK && result != ERR_IO_PENDING) 61 Close(); 62 return result; 63 } 64 65 int SpdyWebSocketStream::SendData(const char* data, int length) { 66 if (!stream_.get()) { 67 NOTREACHED(); 68 return ERR_UNEXPECTED; 69 } 70 DCHECK_GE(length, 0); 71 pending_send_data_length_ = static_cast<size_t>(length); 72 scoped_refptr<IOBuffer> buf(new IOBuffer(length)); 73 memcpy(buf->data(), data, length); 74 stream_->SendData(buf.get(), length, MORE_DATA_TO_SEND); 75 return ERR_IO_PENDING; 76 } 77 78 void SpdyWebSocketStream::Close() { 79 if (stream_.get()) { 80 stream_->Close(); 81 DCHECK(!stream_.get()); 82 } 83 } 84 85 void SpdyWebSocketStream::OnRequestHeadersSent() { 86 DCHECK(delegate_); 87 delegate_->OnSentSpdyHeaders(); 88 } 89 90 SpdyResponseHeadersStatus SpdyWebSocketStream::OnResponseHeadersUpdated( 91 const SpdyHeaderBlock& response_headers) { 92 DCHECK(delegate_); 93 delegate_->OnSpdyResponseHeadersUpdated(response_headers); 94 return RESPONSE_HEADERS_ARE_COMPLETE; 95 } 96 97 void SpdyWebSocketStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) { 98 DCHECK(delegate_); 99 delegate_->OnReceivedSpdyData(buffer.Pass()); 100 } 101 102 void SpdyWebSocketStream::OnDataSent() { 103 DCHECK(delegate_); 104 delegate_->OnSentSpdyData(pending_send_data_length_); 105 pending_send_data_length_ = 0; 106 } 107 108 void SpdyWebSocketStream::OnClose(int status) { 109 stream_.reset(); 110 111 // Destruction without Close() call OnClose() with delegate_ being NULL. 112 if (!delegate_) 113 return; 114 Delegate* delegate = delegate_; 115 delegate_ = NULL; 116 delegate->OnCloseSpdyStream(); 117 } 118 119 void SpdyWebSocketStream::OnSpdyStreamCreated(int result) { 120 DCHECK_NE(ERR_IO_PENDING, result); 121 if (result == OK) { 122 stream_ = stream_request_.ReleaseStream(); 123 DCHECK(stream_.get()); 124 stream_->SetDelegate(this); 125 } 126 DCHECK(delegate_); 127 delegate_->OnCreatedSpdyStream(result); 128 } 129 130 } // namespace net 131