| // Copyright (c) 2009 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. |
| // |
| // WebSocket protocol implementation in chromium. |
| // It is intended to be used for live experiment of WebSocket connectivity |
| // metrics. |
| // Note that it is not used for WebKit's WebSocket communication. |
| // See third_party/WebKit/WebCore/websockets/ instead. |
| |
| #ifndef NET_WEBSOCKETS_WEBSOCKET_H_ |
| #define NET_WEBSOCKETS_WEBSOCKET_H_ |
| |
| #include <deque> |
| #include <string> |
| |
| #include "base/ref_counted.h" |
| #include "googleurl/src/gurl.h" |
| #include "net/base/io_buffer.h" |
| #include "net/socket_stream/socket_stream.h" |
| #include "net/url_request/url_request_context.h" |
| |
| class MessageLoop; |
| |
| namespace net { |
| |
| class ClientSocketFactory; |
| class HostResolver; |
| class HttpResponseHeaders; |
| |
| class WebSocket; |
| |
| // Delegate methods will be called on the same message loop as |
| // WebSocket is constructed. |
| class WebSocketDelegate { |
| public: |
| virtual ~WebSocketDelegate() {} |
| |
| // Called when WebSocket connection has been established. |
| virtual void OnOpen(WebSocket* socket) = 0; |
| |
| // Called when |msg| is received at |socket|. |
| // |msg| should be in UTF-8. |
| virtual void OnMessage(WebSocket* socket, const std::string& msg) = 0; |
| |
| // Called when |socket| is closed. |
| virtual void OnClose(WebSocket* socket) = 0; |
| }; |
| |
| class WebSocket : public base::RefCountedThreadSafe<WebSocket>, |
| public SocketStream::Delegate { |
| public: |
| enum State { |
| INITIALIZED = -1, |
| CONNECTING = 0, |
| OPEN = 1, |
| CLOSED = 2, |
| }; |
| class Request { |
| public: |
| Request(const GURL& url, const std::string protocol, |
| const std::string origin, const std::string location, |
| URLRequestContext* context) |
| : url_(url), |
| protocol_(protocol), |
| origin_(origin), |
| location_(location), |
| context_(context), |
| host_resolver_(NULL), |
| client_socket_factory_(NULL) {} |
| ~Request() {} |
| |
| const GURL& url() const { return url_; } |
| bool is_secure() const; |
| const std::string& protocol() const { return protocol_; } |
| const std::string& origin() const { return origin_; } |
| const std::string& location() const { return location_; } |
| URLRequestContext* context() const { return context_; } |
| |
| // Sets an alternative HostResolver. For testing purposes only. |
| void SetHostResolver(HostResolver* host_resolver) { |
| host_resolver_ = host_resolver; |
| } |
| HostResolver* host_resolver() const { return host_resolver_; } |
| |
| // Sets an alternative ClientSocketFactory. Doesn't take ownership of |
| // |factory|. For testing purposes only. |
| void SetClientSocketFactory(ClientSocketFactory* factory) { |
| client_socket_factory_ = factory; |
| } |
| ClientSocketFactory* client_socket_factory() const { |
| return client_socket_factory_; |
| } |
| |
| private: |
| GURL url_; |
| std::string protocol_; |
| std::string origin_; |
| std::string location_; |
| scoped_refptr<URLRequestContext> context_; |
| |
| scoped_refptr<HostResolver> host_resolver_; |
| ClientSocketFactory* client_socket_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Request); |
| }; |
| |
| // Constructs new WebSocket. |
| // It takes ownership of |req|. |
| // |delegate| must be alive while this object is alive. |
| WebSocket(Request* req, WebSocketDelegate* delegate); |
| |
| WebSocketDelegate* delegate() const { return delegate_; } |
| |
| State ready_state() const { return ready_state_; } |
| |
| // Connects new WebSocket. |
| void Connect(); |
| |
| // Sends |msg| on the WebSocket connection. |
| // |msg| should be in UTF-8. |
| void Send(const std::string& msg); |
| |
| // Closes the WebSocket connection. |
| void Close(); |
| |
| // SocketStream::Delegate methods. |
| // Called on IO thread. |
| virtual void OnConnected(SocketStream* socket_stream, |
| int max_pending_send_allowed); |
| virtual void OnSentData(SocketStream* socket_stream, int amount_sent); |
| virtual void OnReceivedData(SocketStream* socket_stream, |
| const char* data, int len); |
| virtual void OnClose(SocketStream* socket); |
| |
| private: |
| enum Mode { |
| MODE_INCOMPLETE, MODE_NORMAL, MODE_AUTHENTICATE, |
| }; |
| typedef std::deque< scoped_refptr<IOBufferWithSize> > PendingDataQueue; |
| |
| friend class base::RefCountedThreadSafe<WebSocket>; |
| virtual ~WebSocket(); |
| |
| // Creates client handshake mssage based on |request_|. |
| IOBufferWithSize* CreateClientHandshakeMessage() const; |
| |
| // Checks handshake. |
| // Prerequisite: Server handshake message is received in |current_read_buf_|. |
| // Returns number of bytes for server handshake message, |
| // or negative if server handshake message is not received fully yet. |
| int CheckHandshake(); |
| |
| // Processes server handshake message, parsed as |headers|, and updates |
| // |ws_origin_|, |ws_location_| and |ws_protocol_|. |
| // Returns true if it's ok. |
| // Returns false otherwise (e.g. duplicate WebSocket-Origin: header, etc.) |
| bool ProcessHeaders(const HttpResponseHeaders& headers); |
| |
| // Checks |ws_origin_|, |ws_location_| and |ws_protocol_| are valid |
| // against |request_|. |
| // Returns true if it's ok. |
| // Returns false otherwise (e.g. origin mismatch, etc.) |
| bool CheckResponseHeaders() const; |
| |
| // Sends pending data in |current_write_buf_| and/or |pending_write_bufs_|. |
| void SendPending(); |
| |
| // Handles received data. |
| void DoReceivedData(); |
| |
| // Processes frame data in |current_read_buf_|. |
| void ProcessFrameData(); |
| |
| // Skips |len| bytes in |current_read_buf_|. |
| void SkipReadBuffer(int len); |
| |
| // Handles closed connection. |
| void DoClose(); |
| |
| State ready_state_; |
| Mode mode_; |
| scoped_ptr<Request> request_; |
| WebSocketDelegate* delegate_; |
| MessageLoop* origin_loop_; |
| |
| // Handshake messages that server sent. |
| std::string ws_origin_; |
| std::string ws_location_; |
| std::string ws_protocol_; |
| |
| scoped_refptr<SocketStream> socket_stream_; |
| int max_pending_send_allowed_; |
| |
| // [0..offset) is received data from |socket_stream_|. |
| // [0..read_consumed_len_) is already processed. |
| // [read_consumed_len_..offset) is unprocessed data. |
| // [offset..capacity) is free space. |
| scoped_refptr<GrowableIOBuffer> current_read_buf_; |
| int read_consumed_len_; |
| |
| // Drainable IOBuffer on the front of |pending_write_bufs_|. |
| // [0..offset) is already sent to |socket_stream_|. |
| // [offset..size) is being sent to |socket_stream_|, waiting OnSentData. |
| scoped_refptr<DrainableIOBuffer> current_write_buf_; |
| |
| // Deque of IOBuffers in pending. |
| // Front IOBuffer is being sent via |current_write_buf_|. |
| PendingDataQueue pending_write_bufs_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebSocket); |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_WEBSOCKETS_WEBSOCKET_H_ |