// 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.
#ifndef NET_FLIP_FLIP_SESSION_H_
#define NET_FLIP_FLIP_SESSION_H_
#include <deque>
#include <list>
#include <map>
#include <queue>
#include <string>
#include "base/ref_counted.h"
#include "net/base/io_buffer.h"
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/request_priority.h"
#include "net/base/ssl_config_service.h"
#include "net/base/upload_data_stream.h"
#include "net/flip/flip_framer.h"
#include "net/flip/flip_io_buffer.h"
#include "net/flip/flip_protocol.h"
#include "net/flip/flip_session_pool.h"
#include "net/socket/client_socket.h"
#include "net/socket/client_socket_handle.h"
#include "testing/platform_test.h"
namespace net {
class FlipStream;
class HttpNetworkSession;
class HttpRequestInfo;
class HttpResponseInfo;
class LoadLog;
class SSLInfo;
class FlipSession : public base::RefCounted<FlipSession>,
public flip::FlipFramerVisitorInterface {
public:
// Get the domain for this FlipSession.
const std::string& domain() const { return domain_; }
// Connect the FLIP Socket.
// Returns net::Error::OK on success.
// Note that this call does not wait for the connect to complete. Callers can
// immediately start using the FlipSession while it connects.
net::Error Connect(const std::string& group_name,
const HostResolver::RequestInfo& host,
RequestPriority priority,
LoadLog* load_log);
// Get a stream for a given |request|. In the typical case, this will involve
// the creation of a new stream (and will send the SYN frame). If the server
// initiates a stream, it might already exist for a given path. The server
// might also not have initiated the stream yet, but indicated it will via
// X-Associated-Content.
// Returns the new or existing stream. Never returns NULL.
scoped_refptr<FlipStream> GetOrCreateStream(const HttpRequestInfo& request,
const UploadDataStream* upload_data, LoadLog* log);
// Write a data frame to the stream.
// Used to create and queue a data frame for the given stream.
int WriteStreamData(flip::FlipStreamId stream_id, net::IOBuffer* data,
int len);
// Cancel a stream.
bool CancelStream(flip::FlipStreamId stream_id);
// Check if a stream is active.
bool IsStreamActive(flip::FlipStreamId stream_id) const;
// The LoadState is used for informing the user of the current network
// status, such as "resolving host", "connecting", etc.
LoadState GetLoadState() const;
// Enable or disable SSL.
static void SetSSLMode(bool enable) { use_ssl_ = enable; }
static bool SSLMode() { return use_ssl_; }
protected:
friend class FlipSessionPool;
enum State {
IDLE,
CONNECTING,
CONNECTED,
CLOSED
};
// Provide access to the framer for testing.
flip::FlipFramer* GetFramer() { return &flip_framer_; }
// Create a new FlipSession.
// |host| is the hostname that this session connects to.
FlipSession(const std::string& host, HttpNetworkSession* session);
// Closes all open streams. Used as part of shutdown.
void CloseAllStreams(net::Error code);
private:
friend class base::RefCounted<FlipSession>;
typedef std::map<int, scoped_refptr<FlipStream> > ActiveStreamMap;
typedef std::list<scoped_refptr<FlipStream> > ActiveStreamList;
typedef std::map<std::string, scoped_refptr<FlipStream> > PendingStreamMap;
typedef std::priority_queue<FlipIOBuffer> OutputQueue;
virtual ~FlipSession();
// Used by FlipSessionPool to initialize with a pre-existing socket.
void InitializeWithSocket(ClientSocketHandle* connection);
// FlipFramerVisitorInterface
virtual void OnError(flip::FlipFramer*);
virtual void OnStreamFrameData(flip::FlipStreamId stream_id,
const char* data,
size_t len);
virtual void OnControl(const flip::FlipControlFrame* frame);
// Control frame handlers.
void OnSyn(const flip::FlipSynStreamControlFrame* frame,
const flip::FlipHeaderBlock* headers);
void OnSynReply(const flip::FlipSynReplyControlFrame* frame,
const flip::FlipHeaderBlock* headers);
void OnFin(const flip::FlipFinStreamControlFrame* frame);
// IO Callbacks
void OnTCPConnect(int result);
void OnSSLConnect(int result);
void OnReadComplete(int result);
void OnWriteComplete(int result);
// Start reading from the socket.
void ReadSocket();
// Write current data to the socket.
void WriteSocketLater();
void WriteSocket();
// Get a new stream id.
int GetNewStreamId();
// Closes this session. This will close all active streams and mark
// the session as permanently closed.
// |err| should not be OK; this function is intended to be called on
// error.
void CloseSessionOnError(net::Error err);
// Track active streams in the active stream list.
void ActivateStream(FlipStream* stream);
void DeactivateStream(flip::FlipStreamId id);
// Check if we have a pending pushed-stream for this url
// Returns the stream if found (and returns it from the pending
// list), returns NULL otherwise.
scoped_refptr<FlipStream> GetPushStream(const std::string& url);
void GetSSLInfo(SSLInfo* ssl_info);
// Callbacks for the Flip session.
CompletionCallbackImpl<FlipSession> connect_callback_;
CompletionCallbackImpl<FlipSession> ssl_connect_callback_;
CompletionCallbackImpl<FlipSession> read_callback_;
CompletionCallbackImpl<FlipSession> write_callback_;
// The domain this session is connected to.
std::string domain_;
SSLConfig ssl_config_;
scoped_refptr<HttpNetworkSession> session_;
// The socket handle for this session.
scoped_ptr<ClientSocketHandle> connection_;
// The read buffer used to read data from the socket.
scoped_refptr<IOBuffer> read_buffer_;
bool read_pending_;
int stream_hi_water_mark_; // The next stream id to use.
// TODO(mbelshe): We need to track these stream lists better.
// I suspect it is possible to remove a stream from
// one list, but not the other.
// Map from stream id to all active streams. Streams are active in the sense
// that they have a consumer (typically FlipNetworkTransaction and regardless
// of whether or not there is currently any ongoing IO [might be waiting for
// the server to start pushing the stream]) or there are still network events
// incoming even though the consumer has already gone away (cancellation).
// TODO(willchan): Perhaps we should separate out cancelled streams and move
// them into a separate ActiveStreamMap, and not deliver network events to
// them?
ActiveStreamMap active_streams_;
// List of all the streams that have already started to be pushed by the
// server, but do not have consumers yet.
ActiveStreamList pushed_streams_;
// List of streams declared in X-Associated-Content headers, but do not have
// consumers yet.
// The key is a string representing the path of the URI being pushed.
PendingStreamMap pending_streams_;
// As we gather data to be sent, we put it into the output queue.
OutputQueue queue_;
// The packet we are currently sending.
bool write_pending_; // Will be true when a write is in progress.
FlipIOBuffer in_flight_write_; // This is the write buffer in progress.
// Flag if we have a pending message scheduled for WriteSocket.
bool delayed_write_pending_;
// Flag if we're using an SSL connection for this FlipSession.
bool is_secure_;
// Flip Frame state.
flip::FlipFramer flip_framer_;
// If an error has occurred on the session, the session is effectively
// dead. Record this error here. When no error has occurred, |error_| will
// be OK.
net::Error error_;
State state_;
// Some statistics counters for the session.
int streams_initiated_count_;
int streams_pushed_count_;
int streams_pushed_and_claimed_count_;
int streams_abandoned_count_;
static bool use_ssl_;
};
} // namespace net
#endif // NET_FLIP_FLIP_SESSION_H_