// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/spdy/spdy_websocket_stream.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/compiler_specific.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/spdy/spdy_framer.h" #include "net/spdy/spdy_protocol.h" #include "net/spdy/spdy_session.h" #include "net/spdy/spdy_stream.h" #include "url/gurl.h" namespace net { SpdyWebSocketStream::SpdyWebSocketStream( const base::WeakPtr& spdy_session, Delegate* delegate) : weak_ptr_factory_(this), spdy_session_(spdy_session), pending_send_data_length_(0), delegate_(delegate) { DCHECK(spdy_session_.get()); DCHECK(delegate_); } SpdyWebSocketStream::~SpdyWebSocketStream() { delegate_ = NULL; Close(); } int SpdyWebSocketStream::InitializeStream(const GURL& url, RequestPriority request_priority, const BoundNetLog& net_log) { if (!spdy_session_) return ERR_SOCKET_NOT_CONNECTED; int rv = stream_request_.StartRequest( SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url, request_priority, net_log, base::Bind(&SpdyWebSocketStream::OnSpdyStreamCreated, weak_ptr_factory_.GetWeakPtr())); if (rv == OK) { stream_ = stream_request_.ReleaseStream(); DCHECK(stream_.get()); stream_->SetDelegate(this); } return rv; } int SpdyWebSocketStream::SendRequest(scoped_ptr headers) { if (!stream_.get()) { NOTREACHED(); return ERR_UNEXPECTED; } int result = stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND); if (result < OK && result != ERR_IO_PENDING) Close(); return result; } int SpdyWebSocketStream::SendData(const char* data, int length) { if (!stream_.get()) { NOTREACHED(); return ERR_UNEXPECTED; } DCHECK_GE(length, 0); pending_send_data_length_ = static_cast(length); scoped_refptr buf(new IOBuffer(length)); memcpy(buf->data(), data, length); stream_->SendData(buf.get(), length, MORE_DATA_TO_SEND); return ERR_IO_PENDING; } void SpdyWebSocketStream::Close() { if (stream_.get()) { stream_->Close(); DCHECK(!stream_.get()); } } void SpdyWebSocketStream::OnRequestHeadersSent() { DCHECK(delegate_); delegate_->OnSentSpdyHeaders(); } SpdyResponseHeadersStatus SpdyWebSocketStream::OnResponseHeadersUpdated( const SpdyHeaderBlock& response_headers) { DCHECK(delegate_); delegate_->OnSpdyResponseHeadersUpdated(response_headers); return RESPONSE_HEADERS_ARE_COMPLETE; } void SpdyWebSocketStream::OnDataReceived(scoped_ptr buffer) { DCHECK(delegate_); delegate_->OnReceivedSpdyData(buffer.Pass()); } void SpdyWebSocketStream::OnDataSent() { DCHECK(delegate_); delegate_->OnSentSpdyData(pending_send_data_length_); pending_send_data_length_ = 0; } void SpdyWebSocketStream::OnClose(int status) { stream_.reset(); // Destruction without Close() call OnClose() with delegate_ being NULL. if (!delegate_) return; Delegate* delegate = delegate_; delegate_ = NULL; delegate->OnCloseSpdyStream(); } void SpdyWebSocketStream::OnSpdyStreamCreated(int result) { DCHECK_NE(ERR_IO_PENDING, result); if (result == OK) { stream_ = stream_request_.ReleaseStream(); DCHECK(stream_.get()); stream_->SetDelegate(this); } DCHECK(delegate_); delegate_->OnCreatedSpdyStream(result); } } // namespace net