// 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. #ifndef NET_WEBSOCKETS_WEBSOCKET_JOB_H_ #define NET_WEBSOCKETS_WEBSOCKET_JOB_H_ #include <deque> #include <string> #include <vector> #include "base/memory/weak_ptr.h" #include "net/base/address_list.h" #include "net/base/completion_callback.h" #include "net/socket_stream/socket_stream_job.h" #include "net/spdy/spdy_header_block.h" #include "net/spdy/spdy_websocket_stream.h" class GURL; namespace net { class DrainableIOBuffer; class SSLInfo; class WebSocketHandshakeRequestHandler; class WebSocketHandshakeResponseHandler; // WebSocket protocol specific job on SocketStream. // It captures WebSocket handshake message and handles cookie operations. // Chrome security policy doesn't allow renderer process (except dev tools) // see HttpOnly cookies, so it injects cookie header in handshake request and // strips set-cookie headers in handshake response. // TODO(ukai): refactor websocket.cc to use this. class NET_EXPORT WebSocketJob : public SocketStreamJob, public SocketStream::Delegate, public SpdyWebSocketStream::Delegate { public: // This is state of WebSocket, not SocketStream. enum State { INITIALIZED = -1, CONNECTING = 0, OPEN = 1, CLOSING = 2, CLOSED = 3, }; explicit WebSocketJob(SocketStream::Delegate* delegate); static void EnsureInit(); State state() const { return state_; } virtual void Connect() OVERRIDE; virtual bool SendData(const char* data, int len) OVERRIDE; virtual void Close() OVERRIDE; virtual void RestartWithAuth(const AuthCredentials& credentials) OVERRIDE; virtual void DetachDelegate() OVERRIDE; // SocketStream::Delegate methods. virtual int OnStartOpenConnection( SocketStream* socket, const CompletionCallback& callback) OVERRIDE; virtual void OnConnected(SocketStream* socket, int max_pending_send_allowed) OVERRIDE; virtual void OnSentData(SocketStream* socket, int amount_sent) OVERRIDE; virtual void OnReceivedData(SocketStream* socket, const char* data, int len) OVERRIDE; virtual void OnClose(SocketStream* socket) OVERRIDE; virtual void OnAuthRequired( SocketStream* socket, AuthChallengeInfo* auth_info) OVERRIDE; virtual void OnSSLCertificateError(SocketStream* socket, const SSLInfo& ssl_info, bool fatal) OVERRIDE; virtual void OnError(const SocketStream* socket, int error) OVERRIDE; // SpdyWebSocketStream::Delegate methods. virtual void OnCreatedSpdyStream(int status) OVERRIDE; virtual void OnSentSpdyHeaders() OVERRIDE; virtual void OnSpdyResponseHeadersUpdated( const SpdyHeaderBlock& response_headers) OVERRIDE; virtual void OnSentSpdyData(size_t bytes_sent) OVERRIDE; virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) OVERRIDE; virtual void OnCloseSpdyStream() OVERRIDE; private: friend class WebSocketThrottle; friend class WebSocketJobTest; virtual ~WebSocketJob(); bool SendHandshakeRequest(const char* data, int len); void AddCookieHeaderAndSend(); void LoadCookieCallback(const std::string& cookie); void OnSentHandshakeRequest(SocketStream* socket, int amount_sent); // Parses received data into handshake_response_. When finished receiving the // response, calls SaveCookiesAndNotifyHeadersComplete(). void OnReceivedHandshakeResponse( SocketStream* socket, const char* data, int len); // Saves received cookies to the cookie store, and then notifies the // delegate_ of completion of handshake. void SaveCookiesAndNotifyHeadersComplete(); void SaveNextCookie(); void OnCookieSaved(bool cookie_status); // Clears variables for handling cookies, rebuilds handshake string excluding // cookies, and then pass the handshake string to delegate_. void NotifyHeadersComplete(); void DoSendData(); GURL GetURLForCookies() const; const AddressList& address_list() const; int TrySpdyStream(); void SetWaiting(); bool IsWaiting() const; void Wakeup(); void RetryPendingIO(); void CompleteIO(int result); bool SendDataInternal(const char* data, int length); void CloseInternal(); void SendPending(); SocketStream::Delegate* delegate_; State state_; bool waiting_; AddressList addresses_; CompletionCallback callback_; // for throttling. scoped_ptr<WebSocketHandshakeRequestHandler> handshake_request_; scoped_ptr<WebSocketHandshakeResponseHandler> handshake_response_; bool started_to_send_handshake_request_; size_t handshake_request_sent_; std::vector<std::string> response_cookies_; size_t response_cookies_save_index_; std::deque<scoped_refptr<IOBufferWithSize> > send_buffer_queue_; scoped_refptr<DrainableIOBuffer> current_send_buffer_; std::vector<char> received_data_after_handshake_; int spdy_protocol_version_; scoped_ptr<SpdyWebSocketStream> spdy_websocket_stream_; std::string challenge_; bool save_next_cookie_running_; bool callback_pending_; base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_; base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_for_send_pending_; DISALLOW_COPY_AND_ASSIGN(WebSocketJob); }; } // namespace #endif // NET_WEBSOCKETS_WEBSOCKET_JOB_H_