| // 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/scoped_ptr.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/time.h" | 
 | #include "base/timer.h" | 
 | #include "net/base/address_list.h" | 
 | #include "net/base/completion_callback.h" | 
 | #include "net/socket_stream/socket_stream_job.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: | 
 |   // This is state of WebSocket, not SocketStream. | 
 |   enum State { | 
 |     INITIALIZED = -1, | 
 |     CONNECTING = 0, | 
 |     OPEN = 1, | 
 |     SEND_CLOSED = 2,  // A Close frame has been sent but not received. | 
 |     RECV_CLOSED = 3,  // Used briefly between receiving a Close frame and | 
 |                       // sending the response. Once the response is sent, the | 
 |                       // state changes to CLOSED. | 
 |     CLOSE_WAIT = 4,   // The Closing Handshake has completed, but the remote | 
 |                       // server has not yet closed the connection. | 
 |     CLOSED = 5,       // The Closing Handshake has completed and the connection | 
 |                       // has been closed; or the connection is failed. | 
 |   }; | 
 |  | 
 |   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; | 
 |  | 
 |   WebSocketHandshakeResponseHandler* GetHandshakeResponse() { | 
 |     return handshake_response_.get(); | 
 |   } | 
 |  | 
 |   void SetState(const State new_state) { | 
 |     DCHECK_GE(new_state, state_);  // states should only move forward. | 
 |     state_ = new_state; | 
 |   } | 
 |  | 
 |  private: | 
 |   friend class WebSocketThrottle; | 
 |   virtual ~WebSocketJob(); | 
 |  | 
 |   bool SendHandshakeRequest(const char* data, int len); | 
 |   void AddCookieHeaderAndSend(); | 
 |   void LoadCookieCallback(const std::string& cookie); | 
 |  | 
 |   void OnSentHandshakeRequest(SocketStream* socket, int amount_sent); | 
 |   void OnReceivedHandshakeResponse( | 
 |       SocketStream* socket, const char* data, int len); | 
 |   void SaveCookiesAndNotifyHeaderComplete(); | 
 |   void SaveNextCookie(); | 
 |   void SaveCookieCallback(bool cookie_status); | 
 |   void DoSendData(); | 
 |  | 
 |   GURL GetURLForCookies() const; | 
 |  | 
 |   const AddressList& address_list() const; | 
 |   void SetWaiting(); | 
 |   bool IsWaiting() const; | 
 |   void Wakeup(); | 
 |   void RetryPendingIO(); | 
 |   void CompleteIO(int result); | 
 |  | 
 |   bool SendDataInternal(const char* data, int length); | 
 |   void CloseInternal(); | 
 |   void SendPending(); | 
 |   void CloseTimeout(); | 
 |   void StopTimer(base::WaitableEvent* timer_stop_event); | 
 |  | 
 |   void WaitForSocketClose(); | 
 |   void DelayedClose(); | 
 |  | 
 |   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_; | 
 |  | 
 |   std::string challenge_; | 
 |  | 
 |   base::TimeDelta closing_handshake_timeout_; | 
 |   scoped_ptr<base::OneShotTimer<WebSocketJob> > close_timer_; | 
 |  | 
 |   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_ |