summaryrefslogtreecommitdiffstats
path: root/chromium/net/spdy/spdy_session.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/spdy/spdy_session.h')
-rw-r--r--chromium/net/spdy/spdy_session.h274
1 files changed, 147 insertions, 127 deletions
diff --git a/chromium/net/spdy/spdy_session.h b/chromium/net/spdy/spdy_session.h
index fde42024be8..b74b1ee8b0a 100644
--- a/chromium/net/spdy/spdy_session.h
+++ b/chromium/net/spdy/spdy_session.h
@@ -61,59 +61,83 @@ const int kMaxReadBytesWithoutYielding = 32 * 1024;
// The initial receive window size for both streams and sessions.
const int32 kDefaultInitialRecvWindowSize = 10 * 1024 * 1024; // 10MB
+// First and last valid stream IDs. As we always act as the client,
+// start at 1 for the first stream id.
+const SpdyStreamId kFirstStreamId = 1;
+const SpdyStreamId kLastStreamId = 0x7fffffff;
+
class BoundNetLog;
struct LoadTimingInfo;
class SpdyStream;
class SSLInfo;
// NOTE: There's an enum of the same name (also with numeric suffixes)
-// in histograms.xml.
-//
-// WARNING: DO NOT INSERT ENUMS INTO THIS LIST! Add only to the end.
+// in histograms.xml. Be sure to add new values there also.
enum SpdyProtocolErrorDetails {
- // SpdyFramer::SpdyErrors
- SPDY_ERROR_NO_ERROR,
- SPDY_ERROR_INVALID_CONTROL_FRAME,
- SPDY_ERROR_CONTROL_PAYLOAD_TOO_LARGE,
- SPDY_ERROR_ZLIB_INIT_FAILURE,
- SPDY_ERROR_UNSUPPORTED_VERSION,
- SPDY_ERROR_DECOMPRESS_FAILURE,
- SPDY_ERROR_COMPRESS_FAILURE,
- SPDY_ERROR_CREDENTIAL_FRAME_CORRUPT,
- SPDY_ERROR_INVALID_DATA_FRAME_FLAGS,
- SPDY_ERROR_INVALID_CONTROL_FRAME_FLAGS,
- // SpdyRstStreamStatus
- STATUS_CODE_INVALID,
- STATUS_CODE_PROTOCOL_ERROR,
- STATUS_CODE_INVALID_STREAM,
- STATUS_CODE_REFUSED_STREAM,
- STATUS_CODE_UNSUPPORTED_VERSION,
- STATUS_CODE_CANCEL,
- STATUS_CODE_INTERNAL_ERROR,
- STATUS_CODE_FLOW_CONTROL_ERROR,
- STATUS_CODE_STREAM_IN_USE,
- STATUS_CODE_STREAM_ALREADY_CLOSED,
- STATUS_CODE_INVALID_CREDENTIALS,
- STATUS_CODE_FRAME_TOO_LARGE,
+ // SpdyFramer::SpdyError mappings.
+ SPDY_ERROR_NO_ERROR = 0,
+ SPDY_ERROR_INVALID_CONTROL_FRAME = 1,
+ SPDY_ERROR_CONTROL_PAYLOAD_TOO_LARGE = 2,
+ SPDY_ERROR_ZLIB_INIT_FAILURE = 3,
+ SPDY_ERROR_UNSUPPORTED_VERSION = 4,
+ SPDY_ERROR_DECOMPRESS_FAILURE = 5,
+ SPDY_ERROR_COMPRESS_FAILURE = 6,
+ // SPDY_ERROR_CREDENTIAL_FRAME_CORRUPT = 7, (removed).
+ SPDY_ERROR_GOAWAY_FRAME_CORRUPT = 29,
+ SPDY_ERROR_RST_STREAM_FRAME_CORRUPT = 30,
+ SPDY_ERROR_INVALID_DATA_FRAME_FLAGS = 8,
+ SPDY_ERROR_INVALID_CONTROL_FRAME_FLAGS = 9,
+ SPDY_ERROR_UNEXPECTED_FRAME = 31,
+ // SpdyRstStreamStatus mappings.
+ // RST_STREAM_INVALID not mapped.
+ STATUS_CODE_PROTOCOL_ERROR = 11,
+ STATUS_CODE_INVALID_STREAM = 12,
+ STATUS_CODE_REFUSED_STREAM = 13,
+ STATUS_CODE_UNSUPPORTED_VERSION = 14,
+ STATUS_CODE_CANCEL = 15,
+ STATUS_CODE_INTERNAL_ERROR = 16,
+ STATUS_CODE_FLOW_CONTROL_ERROR = 17,
+ STATUS_CODE_STREAM_IN_USE = 18,
+ STATUS_CODE_STREAM_ALREADY_CLOSED = 19,
+ STATUS_CODE_INVALID_CREDENTIALS = 20,
+ STATUS_CODE_FRAME_SIZE_ERROR = 21,
+ STATUS_CODE_SETTINGS_TIMEOUT = 32,
+ STATUS_CODE_CONNECT_ERROR = 33,
+ STATUS_CODE_ENHANCE_YOUR_CALM = 34,
+
// SpdySession errors
- PROTOCOL_ERROR_UNEXPECTED_PING,
- PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM,
- PROTOCOL_ERROR_SPDY_COMPRESSION_FAILURE,
- PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION,
- PROTOCOL_ERROR_SYN_REPLY_NOT_RECEIVED,
- PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE,
- PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION,
- NUM_SPDY_PROTOCOL_ERROR_DETAILS
+ PROTOCOL_ERROR_UNEXPECTED_PING = 22,
+ PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM = 23,
+ PROTOCOL_ERROR_SPDY_COMPRESSION_FAILURE = 24,
+ PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION = 25,
+ PROTOCOL_ERROR_SYN_REPLY_NOT_RECEIVED = 26,
+ PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE = 27,
+ PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION = 28,
+
+ // Next free value.
+ NUM_SPDY_PROTOCOL_ERROR_DETAILS = 35,
};
-
-COMPILE_ASSERT(STATUS_CODE_INVALID ==
- static_cast<SpdyProtocolErrorDetails>(SpdyFramer::LAST_ERROR),
+SpdyProtocolErrorDetails NET_EXPORT_PRIVATE
+ MapFramerErrorToProtocolError(SpdyFramer::SpdyError error);
+Error NET_EXPORT_PRIVATE MapFramerErrorToNetError(SpdyFramer::SpdyError error);
+SpdyProtocolErrorDetails NET_EXPORT_PRIVATE
+ MapRstStreamStatusToProtocolError(SpdyRstStreamStatus status);
+SpdyGoAwayStatus NET_EXPORT_PRIVATE MapNetErrorToGoAwayStatus(Error err);
+
+// If these compile asserts fail then SpdyProtocolErrorDetails needs
+// to be updated with new values, as do the mapping functions above.
+COMPILE_ASSERT(12 == SpdyFramer::LAST_ERROR,
SpdyProtocolErrorDetails_SpdyErrors_mismatch);
+COMPILE_ASSERT(15 == RST_STREAM_NUM_STATUS_CODES,
+ SpdyProtocolErrorDetails_RstStreamStatus_mismatch);
-COMPILE_ASSERT(PROTOCOL_ERROR_UNEXPECTED_PING ==
- static_cast<SpdyProtocolErrorDetails>(
- RST_STREAM_NUM_STATUS_CODES + STATUS_CODE_INVALID),
- SpdyProtocolErrorDetails_SpdyErrors_mismatch);
+// Splits pushed |headers| into request and response parts. Request headers are
+// the headers specifying resource URL.
+void NET_EXPORT_PRIVATE
+ SplitPushedHeadersToRequestAndResponse(const SpdyHeaderBlock& headers,
+ SpdyMajorVersion protocol_version,
+ SpdyHeaderBlock* request_headers,
+ SpdyHeaderBlock* response_headers);
// A helper class used to manage a request to create a stream.
class NET_EXPORT_PRIVATE SpdyStreamRequest {
@@ -171,7 +195,6 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest {
void Reset();
- base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_;
SpdyStreamType type_;
base::WeakPtr<SpdySession> session_;
base::WeakPtr<SpdyStream> stream_;
@@ -180,6 +203,8 @@ class NET_EXPORT_PRIVATE SpdyStreamRequest {
BoundNetLog net_log_;
CompletionCallback callback_;
+ base::WeakPtrFactory<SpdyStreamRequest> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(SpdyStreamRequest);
};
@@ -251,13 +276,13 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// |certificate_error_code| must either be OK or less than
// ERR_IO_PENDING.
//
- // Returns OK on success, or an error on failure. Never returns
- // ERR_IO_PENDING. If an error is returned, the session must be
- // destroyed immediately.
- Error InitializeWithSocket(scoped_ptr<ClientSocketHandle> connection,
- SpdySessionPool* pool,
- bool is_secure,
- int certificate_error_code);
+ // The session begins reading from |connection| on a subsequent event loop
+ // iteration, so the SpdySession may close immediately afterwards if the first
+ // read of |connection| fails.
+ void InitializeWithSocket(scoped_ptr<ClientSocketHandle> connection,
+ SpdySessionPool* pool,
+ bool is_secure,
+ int certificate_error_code);
// Returns the protocol used by this session. Always between
// kProtoSPDYMinimumVersion and kProtoSPDYMaximumVersion.
@@ -286,7 +311,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
scoped_ptr<SpdyFrame> CreateSynStream(
SpdyStreamId stream_id,
RequestPriority priority,
- uint8 credential_slot,
SpdyControlFlags flags,
const SpdyHeaderBlock& headers);
@@ -335,12 +359,10 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
void SendStreamWindowUpdate(SpdyStreamId stream_id,
uint32 delta_window_size);
- // Whether the stream is closed, i.e. it has stopped processing data
- // and is about to be destroyed.
- //
- // TODO(akalin): This is only used in tests. Remove this function
- // and have tests test the WeakPtr instead.
- bool IsClosed() const { return availability_state_ == STATE_CLOSED; }
+ // Accessors for the session's availability state.
+ bool IsAvailable() const { return availability_state_ == STATE_AVAILABLE; }
+ bool IsGoingAway() const { return availability_state_ == STATE_GOING_AWAY; }
+ bool IsDraining() const { return availability_state_ == STATE_DRAINING; }
// Closes this session. This will close all active streams and mark
// the session as permanently closed. Callers must assume that the
@@ -353,12 +375,30 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// |description| indicates the reason for the error.
void CloseSessionOnError(Error err, const std::string& description);
+ // Mark this session as unavailable, meaning that it will not be used to
+ // service new streams. Unlike when a GOAWAY frame is received, this function
+ // will not close any streams.
+ void MakeUnavailable();
+
+ // Closes all active streams with stream id's greater than
+ // |last_good_stream_id|, as well as any created or pending
+ // streams. Must be called only when |availability_state_| >=
+ // STATE_GOING_AWAY. After this function, DcheckGoingAway() will
+ // pass. May be called multiple times.
+ void StartGoingAway(SpdyStreamId last_good_stream_id, Error status);
+
+ // Must be called only when going away (i.e., DcheckGoingAway()
+ // passes). If there are no more active streams and the session
+ // isn't closed yet, close it.
+ void MaybeFinishGoingAway();
+
// Retrieves information on the current state of the SPDY session as a
// Value. Caller takes possession of the returned value.
base::Value* GetInfoAsValue() const;
// Indicates whether the session is being reused after having successfully
- // used to send/receive data in the past.
+ // used to send/receive data in the past or if the underlying socket was idle
+ // before being used for a SPDY session.
bool IsReused() const;
// Returns true if the underlying transport socket ever had any reads or
@@ -455,6 +495,10 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
return buffered_spdy_framer_->GetDataFrameMaximumPayload();
}
+ // https://http2.github.io/http2-spec/#TLSUsage mandates minimum security
+ // standards for TLS.
+ bool HasAcceptableTransportSecurity() const;
+
// Must be used only by |pool_|.
base::WeakPtr<SpdySession> GetWeakPtr();
@@ -479,6 +523,9 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoReceiveLeaks);
FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoSendLeaks);
FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlEndToEnd);
+ FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, StreamIdSpaceExhausted);
+ FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, UnstallRacesWithStreamCreation);
+ FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, GoAwayOnSessionFlowControlError);
typedef std::deque<base::WeakPtr<SpdyStreamRequest> >
PendingStreamRequestQueue;
@@ -512,9 +559,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// The session can process data on existing streams but will
// refuse to create new ones.
STATE_GOING_AWAY,
- // The session has been closed, is waiting to be deleted, and will
- // refuse to process any more data.
- STATE_CLOSED
+ // The session is draining its write queue in preparation of closing.
+ // Further writes will not be queued, and further reads will not be issued
+ // (though the remainder of a current read may be processed). The session
+ // will be destroyed by its write loop once the write queue is drained.
+ STATE_DRAINING,
};
enum ReadState {
@@ -529,18 +578,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
WRITE_STATE_DO_WRITE_COMPLETE,
};
- // The return value of DoCloseSession() describing what was done.
- enum CloseSessionResult {
- // The session was already closed so nothing was done.
- SESSION_ALREADY_CLOSED,
- // The session was moved into the closed state but was not removed
- // from |pool_| (because we're in an IO loop).
- SESSION_CLOSED_BUT_NOT_REMOVED,
- // The session was moved into the closed state and removed from
- // |pool_|.
- SESSION_CLOSED_AND_REMOVED,
- };
-
// Checks whether a stream for the given |url| can be created or
// retrieved from the set of unclaimed push streams. Returns OK if
// so. Otherwise, the session is closed and an error <
@@ -574,6 +611,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// possible.
void ProcessPendingStreamRequests();
+ bool TryCreatePushStream(SpdyStreamId stream_id,
+ SpdyStreamId associated_stream_id,
+ SpdyPriority priority,
+ const SpdyHeaderBlock& headers);
+
// Close the stream pointed to by the given iterator. Note that that
// stream may hold the last reference to the session.
void CloseActiveStreamIterator(ActiveStreamMap::iterator it, int status);
@@ -598,30 +640,31 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
SpdyRstStreamStatus status,
const std::string& description);
- // Calls DoReadLoop and then if |availability_state_| is
- // STATE_CLOSED, calls RemoveFromPool().
- //
- // Use this function instead of DoReadLoop when posting a task to
- // pump the read loop.
+ // Calls DoReadLoop. Use this function instead of DoReadLoop when
+ // posting a task to pump the read loop.
void PumpReadLoop(ReadState expected_read_state, int result);
// Advance the ReadState state machine. |expected_read_state| is the
// expected starting read state.
//
- // This function must always be called via PumpReadLoop() except for
- // from InitializeWithSocket().
+ // This function must always be called via PumpReadLoop().
int DoReadLoop(ReadState expected_read_state, int result);
// The implementations of the states of the ReadState state machine.
int DoRead();
int DoReadComplete(int result);
- // Calls DoWriteLoop and then if |availability_state_| is
- // STATE_CLOSED, calls RemoveFromPool().
+ // Calls DoWriteLoop. If |availability_state_| is STATE_DRAINING and no
+ // writes remain, the session is removed from the session pool and
+ // destroyed.
//
// Use this function instead of DoWriteLoop when posting a task to
// pump the write loop.
void PumpWriteLoop(WriteState expected_write_state, int result);
+ // Iff the write loop is not currently active, posts a callback into
+ // PumpWriteLoop().
+ void MaybePostWriteLoop();
+
// Advance the WriteState state machine. |expected_write_state| is
// the expected starting write state.
//
@@ -660,7 +703,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
RequestPriority priority);
// Send the PING frame.
- void WritePingFrame(uint32 unique_id);
+ void WritePingFrame(uint32 unique_id, bool is_ack);
// Post a CheckPingStatus call after delay. Don't post if there is already
// CheckPingStatus running.
@@ -671,7 +714,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
void CheckPingStatus(base::TimeTicks last_check_time);
// Get a new stream id.
- int GetNewStreamId();
+ SpdyStreamId GetNewStreamId();
// Pushes the given frame with the given priority into the write
// queue for the session.
@@ -724,36 +767,13 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
void DcheckGoingAway() const;
// Calls DcheckGoingAway(), then DCHECKs that |availability_state_|
- // == STATE_CLOSED, |error_on_close_| has a valid value, that there
- // are no active streams or unclaimed pushed streams, and that the
- // write queue is empty.
- void DcheckClosed() const;
-
- // Closes all active streams with stream id's greater than
- // |last_good_stream_id|, as well as any created or pending
- // streams. Must be called only when |availability_state_| >=
- // STATE_GOING_AWAY. After this function, DcheckGoingAway() will
- // pass. May be called multiple times.
- void StartGoingAway(SpdyStreamId last_good_stream_id, Error status);
+ // == STATE_DRAINING, |error_on_close_| has a valid value, and that there
+ // are no active streams or unclaimed pushed streams.
+ void DcheckDraining() const;
- // Must be called only when going away (i.e., DcheckGoingAway()
- // passes). If there are no more active streams and the session
- // isn't closed yet, close it.
- void MaybeFinishGoingAway();
-
- // If the stream is already closed, does nothing. Otherwise, moves
- // the session to a closed state. Then, if we're in an IO loop,
- // returns (as the IO loop will do the pool removal itself when its
- // done). Otherwise, also removes |this| from |pool_|. The returned
- // result describes what was done.
- CloseSessionResult DoCloseSession(Error err, const std::string& description);
-
- // Remove this session from its pool, which must exist. Must be
- // called only when the session is closed.
- //
- // Must be called only via Pump{Read,Write}Loop() or
- // DoCloseSession().
- void RemoveFromPool();
+ // If the session is already draining, does nothing. Otherwise, moves
+ // the session to the draining state.
+ void DoDrainSession(Error err, const std::string& description);
// Called right before closing a (possibly-inactive) stream for a
// reason other than being requested to by the stream.
@@ -776,7 +796,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE;
virtual void OnStreamError(SpdyStreamId stream_id,
const std::string& description) OVERRIDE;
- virtual void OnPing(uint32 unique_id) OVERRIDE;
+ virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE;
virtual void OnRstStream(SpdyStreamId stream_id,
SpdyRstStreamStatus status) OVERRIDE;
virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
@@ -794,11 +814,11 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
virtual void OnWindowUpdate(SpdyStreamId stream_id,
uint32 delta_window_size) OVERRIDE;
virtual void OnPushPromise(SpdyStreamId stream_id,
- SpdyStreamId promised_stream_id) OVERRIDE;
+ SpdyStreamId promised_stream_id,
+ const SpdyHeaderBlock& headers) OVERRIDE;
virtual void OnSynStream(SpdyStreamId stream_id,
SpdyStreamId associated_stream_id,
SpdyPriority priority,
- uint8 credential_slot,
bool fin,
bool unidirectional,
const SpdyHeaderBlock& headers) OVERRIDE;
@@ -913,12 +933,6 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// or NULL, if the transport is not SSL.
SSLClientSocket* GetSSLClientSocket() const;
- // Used for posting asynchronous IO tasks. We use this even though
- // SpdySession is refcounted because we don't need to keep the SpdySession
- // alive if the last reference is within a RunnableMethod. Just revoke the
- // method.
- base::WeakPtrFactory<SpdySession> weak_factory_;
-
// Whether Do{Read,Write}Loop() is in the call stack. Useful for
// making sure we don't destroy ourselves prematurely in that case.
bool in_io_loop_;
@@ -941,7 +955,7 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
// The read buffer used to read data from the socket.
scoped_refptr<IOBuffer> read_buffer_;
- int stream_hi_water_mark_; // The next stream id to use.
+ SpdyStreamId stream_hi_water_mark_; // The next stream id to use.
// Queue, for each priority, of pending stream requests that have
// not yet been satisfied.
@@ -999,10 +1013,10 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
ReadState read_state_;
WriteState write_state_;
- // If the session was closed (i.e., |availability_state_| is
- // STATE_CLOSED), then |error_on_close_| holds the error with which
- // it was closed, which is < ERR_IO_PENDING. Otherwise, it is set to
- // OK.
+ // If the session is closing (i.e., |availability_state_| is STATE_DRAINING),
+ // then |error_on_close_| holds the error with which it was closed, which
+ // may be OK (upon a polite GOAWAY) or an error < ERR_IO_PENDING otherwise.
+ // Initialized to OK.
Error error_on_close_;
// Limits
@@ -1114,6 +1128,12 @@ class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface,
HostPortPair trusted_spdy_proxy_;
TimeFunc time_func_;
+
+ // Used for posting asynchronous IO tasks. We use this even though
+ // SpdySession is refcounted because we don't need to keep the SpdySession
+ // alive if the last reference is within a RunnableMethod. Just revoke the
+ // method.
+ base::WeakPtrFactory<SpdySession> weak_factory_;
};
} // namespace net