summaryrefslogtreecommitdiffstats
path: root/net/flip/flip_session.h
blob: 9f21b27550a33ed8c24bf9d2e4a30b846690a2d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// 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/ssl_config_service.h"
#include "net/base/upload_data_stream.h"
#include "net/flip/flip_framer.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 FlipStreamImpl;
class HttpNetworkSession;
class HttpRequestInfo;
class HttpResponseInfo;

// A callback interface for HTTP content retrieved from the Flip stream.
class FlipDelegate {
 public:
  virtual ~FlipDelegate() {}
  virtual const HttpRequestInfo* request() = 0;
  virtual const UploadDataStream* data() = 0;

  virtual void OnRequestSent(int status) = 0;
  virtual void OnResponseReceived(HttpResponseInfo* response) = 0;
  virtual void OnDataReceived(const char* buffer, int bytes) = 0;
  virtual void OnClose(int status) = 0;
  virtual void OnCancel() = 0;
};

class PrioritizedIOBuffer {
 public:
  PrioritizedIOBuffer() : buffer_(0), priority_(0) {}
  PrioritizedIOBuffer(IOBufferWithSize* buffer, int priority)
      : buffer_(buffer),
        priority_(priority),
        position_(++order_) {
  }

  IOBuffer* buffer() const { return buffer_; }

  int size() const { return buffer_->size(); }

  void release() { buffer_ = NULL; }

  int priority() { return priority_; }

  // Supports sorting.
  bool operator<(const PrioritizedIOBuffer& other) const {
    if (priority_ != other.priority_)
      return priority_ > other.priority_;
    return position_ >= other.position_;
  }

 private:
  scoped_refptr<IOBufferWithSize> buffer_;
  int priority_;
  int position_;
  static int order_;  // Maintains a FIFO order for equal priorities.
};

class FlipSession : public base::RefCounted<FlipSession>,
                    public flip::FlipFramerVisitorInterface {
 public:
  // Factory for finding open sessions.
  // TODO(mbelshe): Break this out into a connection pool class?
  static FlipSession* GetFlipSession(const HostResolver::RequestInfo&,
                                     HttpNetworkSession* session);
  virtual ~FlipSession();

  // Get the domain for this FlipSession.
  std::string domain() { 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, int priority);

  // Create a new stream.
  // FlipDelegate must remain valid until the stream is either cancelled by the
  // creator via CancelStream or the FlipDelegate OnClose or OnCancel callbacks
  // have been made.
  // Once the stream is created, the delegate should wait for a callback.
  int CreateStream(FlipDelegate* delegate);

  // Cancel a stream.
  bool CancelStream(int id);

  // Check if a stream is active.
  bool IsStreamActive(int id);

  // The LoadState is used for informing the user of the current network
  // status, such as "resolving host", "connecting", etc.
  LoadState GetLoadState() const;
 protected:
  friend class FlipNetworkTransactionTest;
  friend class FlipSessionPool;

  // 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(std::string host, HttpNetworkSession* session);

  // Closes all open streams.  Used as part of shutdown.
  void CloseAllStreams(net::Error code);

 private:
  // FlipFramerVisitorInterface
  virtual void OnError(flip::FlipFramer*);
  virtual void OnStreamFrameData(flip::FlipStreamId stream_id,
                                 const char* data,
                                 uint32 len);
  virtual void OnControl(const flip::FlipControlFrame* frame);
  virtual void OnLameDuck();

  // 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();

  // Track active streams in the active stream list.
  FlipStreamImpl* ActivateStream(int id, FlipDelegate* delegate);
  void DeactivateStream(int 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.
  FlipStreamImpl* GetPushStream(std::string url);

  // 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.
  ClientSocketHandle connection_;
  bool connection_started_;  // Is the connect process started.
  bool connection_ready_;  // Is the connection ready for use.

  // The read buffer used to read data from the socket.
  enum { kReadBufferSize = (4 * 1024) };
  scoped_refptr<IOBuffer> read_buffer_;
  bool read_pending_;

  int stream_hi_water_mark_;  // The next stream id to use.

  typedef std::map<int, FlipStreamImpl*> ActiveStreamMap;
  typedef std::list<FlipStreamImpl*> ActiveStreamList;
  ActiveStreamMap active_streams_;

  ActiveStreamList pushed_streams_;
  // List of streams declared in X-Associated-Content headers.
  // The key is a string representing the path of the URI being pushed.
  std::map<std::string, FlipDelegate*> pending_streams_;

  // As we gather data to be sent, we put it into the output queue.
  typedef std::priority_queue<PrioritizedIOBuffer> OutputQueue;
  OutputQueue queue_;

  // TODO(mbelshe): this is ugly!!
  // The packet we are currently sending.
  PrioritizedIOBuffer in_flight_write_;
  bool delayed_write_pending_;
  bool write_pending_;

  // Flip Frame state.
  flip::FlipFramer flip_framer_;

  // This is our weak session pool - one session per domain.
  static scoped_ptr<FlipSessionPool> session_pool_;
  static bool disable_compression_;
};

}  // namespace net

#endif  // NET_FLIP_FLIP_SESSION_H_