blob: 32c55399c02cb168d5705649778068e3be0bfebf [file] [log] [blame]
// 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_