1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_SPDY_SPDY_SESSION_H_ 6 #define NET_SPDY_SPDY_SESSION_H_ 7 8 #include <deque> 9 #include <map> 10 #include <set> 11 #include <string> 12 13 #include "base/basictypes.h" 14 #include "base/gtest_prod_util.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/time/time.h" 19 #include "net/base/io_buffer.h" 20 #include "net/base/load_states.h" 21 #include "net/base/net_errors.h" 22 #include "net/base/net_export.h" 23 #include "net/base/request_priority.h" 24 #include "net/socket/client_socket_handle.h" 25 #include "net/socket/client_socket_pool.h" 26 #include "net/socket/next_proto.h" 27 #include "net/socket/ssl_client_socket.h" 28 #include "net/socket/stream_socket.h" 29 #include "net/spdy/buffered_spdy_framer.h" 30 #include "net/spdy/spdy_buffer.h" 31 #include "net/spdy/spdy_credential_state.h" 32 #include "net/spdy/spdy_framer.h" 33 #include "net/spdy/spdy_header_block.h" 34 #include "net/spdy/spdy_protocol.h" 35 #include "net/spdy/spdy_session_pool.h" 36 #include "net/spdy/spdy_stream.h" 37 #include "net/spdy/spdy_write_queue.h" 38 #include "net/ssl/ssl_config_service.h" 39 #include "url/gurl.h" 40 41 namespace net { 42 43 // This is somewhat arbitrary and not really fixed, but it will always work 44 // reasonably with ethernet. Chop the world into 2-packet chunks. This is 45 // somewhat arbitrary, but is reasonably small and ensures that we elicit 46 // ACKs quickly from TCP (because TCP tries to only ACK every other packet). 47 const int kMss = 1430; 48 // The 8 is the size of the SPDY frame header. 49 const int kMaxSpdyFrameChunkSize = (2 * kMss) - 8; 50 51 // Maximum number of concurrent streams we will create, unless the server 52 // sends a SETTINGS frame with a different value. 53 const size_t kInitialMaxConcurrentStreams = 100; 54 55 // Specifies the maxiumum concurrent streams server could send (via push). 56 const int kMaxConcurrentPushedStreams = 1000; 57 58 // Specifies the maximum number of bytes to read synchronously before 59 // yielding. 60 const int kMaxReadBytesWithoutYielding = 32 * 1024; 61 62 // The initial receive window size for both streams and sessions. 63 const int32 kDefaultInitialRecvWindowSize = 10 * 1024 * 1024; // 10MB 64 65 class BoundNetLog; 66 struct LoadTimingInfo; 67 class SpdyStream; 68 class SSLInfo; 69 70 // NOTE: There's an enum of the same name (also with numeric suffixes) 71 // in histograms.xml. 72 // 73 // WARNING: DO NOT INSERT ENUMS INTO THIS LIST! Add only to the end. 74 enum SpdyProtocolErrorDetails { 75 // SpdyFramer::SpdyErrors 76 SPDY_ERROR_NO_ERROR, 77 SPDY_ERROR_INVALID_CONTROL_FRAME, 78 SPDY_ERROR_CONTROL_PAYLOAD_TOO_LARGE, 79 SPDY_ERROR_ZLIB_INIT_FAILURE, 80 SPDY_ERROR_UNSUPPORTED_VERSION, 81 SPDY_ERROR_DECOMPRESS_FAILURE, 82 SPDY_ERROR_COMPRESS_FAILURE, 83 SPDY_ERROR_CREDENTIAL_FRAME_CORRUPT, 84 SPDY_ERROR_INVALID_DATA_FRAME_FLAGS, 85 SPDY_ERROR_INVALID_CONTROL_FRAME_FLAGS, 86 // SpdyRstStreamStatus 87 STATUS_CODE_INVALID, 88 STATUS_CODE_PROTOCOL_ERROR, 89 STATUS_CODE_INVALID_STREAM, 90 STATUS_CODE_REFUSED_STREAM, 91 STATUS_CODE_UNSUPPORTED_VERSION, 92 STATUS_CODE_CANCEL, 93 STATUS_CODE_INTERNAL_ERROR, 94 STATUS_CODE_FLOW_CONTROL_ERROR, 95 STATUS_CODE_STREAM_IN_USE, 96 STATUS_CODE_STREAM_ALREADY_CLOSED, 97 STATUS_CODE_INVALID_CREDENTIALS, 98 STATUS_CODE_FRAME_TOO_LARGE, 99 // SpdySession errors 100 PROTOCOL_ERROR_UNEXPECTED_PING, 101 PROTOCOL_ERROR_RST_STREAM_FOR_NON_ACTIVE_STREAM, 102 PROTOCOL_ERROR_SPDY_COMPRESSION_FAILURE, 103 PROTOCOL_ERROR_REQUEST_FOR_SECURE_CONTENT_OVER_INSECURE_SESSION, 104 PROTOCOL_ERROR_SYN_REPLY_NOT_RECEIVED, 105 PROTOCOL_ERROR_INVALID_WINDOW_UPDATE_SIZE, 106 PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION, 107 NUM_SPDY_PROTOCOL_ERROR_DETAILS 108 }; 109 110 COMPILE_ASSERT(STATUS_CODE_INVALID == 111 static_cast<SpdyProtocolErrorDetails>(SpdyFramer::LAST_ERROR), 112 SpdyProtocolErrorDetails_SpdyErrors_mismatch); 113 114 COMPILE_ASSERT(PROTOCOL_ERROR_UNEXPECTED_PING == 115 static_cast<SpdyProtocolErrorDetails>( 116 RST_STREAM_NUM_STATUS_CODES + STATUS_CODE_INVALID), 117 SpdyProtocolErrorDetails_SpdyErrors_mismatch); 118 119 // A helper class used to manage a request to create a stream. 120 class NET_EXPORT_PRIVATE SpdyStreamRequest { 121 public: 122 SpdyStreamRequest(); 123 // Calls CancelRequest(). 124 ~SpdyStreamRequest(); 125 126 // Starts the request to create a stream. If OK is returned, then 127 // ReleaseStream() may be called. If ERR_IO_PENDING is returned, 128 // then when the stream is created, |callback| will be called, at 129 // which point ReleaseStream() may be called. Otherwise, the stream 130 // is not created, an error is returned, and ReleaseStream() may not 131 // be called. 132 // 133 // If OK is returned, must not be called again without 134 // ReleaseStream() being called first. If ERR_IO_PENDING is 135 // returned, must not be called again without CancelRequest() or 136 // ReleaseStream() being called first. Otherwise, in case of an 137 // immediate error, this may be called again. 138 int StartRequest(SpdyStreamType type, 139 const base::WeakPtr<SpdySession>& session, 140 const GURL& url, 141 RequestPriority priority, 142 const BoundNetLog& net_log, 143 const CompletionCallback& callback); 144 145 // Cancels any pending stream creation request. May be called 146 // repeatedly. 147 void CancelRequest(); 148 149 // Transfers the created stream (guaranteed to not be NULL) to the 150 // caller. Must be called at most once after StartRequest() returns 151 // OK or |callback| is called with OK. The caller must immediately 152 // set a delegate for the returned stream (except for test code). 153 base::WeakPtr<SpdyStream> ReleaseStream(); 154 155 private: 156 friend class SpdySession; 157 158 // Called by |session_| when the stream attempt has finished 159 // successfully. 160 void OnRequestCompleteSuccess(base::WeakPtr<SpdyStream>* stream); 161 162 // Called by |session_| when the stream attempt has finished with an 163 // error. Also called with ERR_ABORTED if |session_| is destroyed 164 // while the stream attempt is still pending. 165 void OnRequestCompleteFailure(int rv); 166 167 // Accessors called by |session_|. 168 SpdyStreamType type() const { return type_; } 169 const GURL& url() const { return url_; } 170 RequestPriority priority() const { return priority_; } 171 const BoundNetLog& net_log() const { return net_log_; } 172 173 void Reset(); 174 175 SpdyStreamType type_; 176 base::WeakPtr<SpdySession> session_; 177 base::WeakPtr<SpdyStream> stream_; 178 GURL url_; 179 RequestPriority priority_; 180 BoundNetLog net_log_; 181 CompletionCallback callback_; 182 183 DISALLOW_COPY_AND_ASSIGN(SpdyStreamRequest); 184 }; 185 186 class NET_EXPORT SpdySession : public BufferedSpdyFramerVisitorInterface, 187 public SpdyFramerDebugVisitorInterface, 188 public LayeredPool { 189 public: 190 // TODO(akalin): Use base::TickClock when it becomes available. 191 typedef base::TimeTicks (*TimeFunc)(void); 192 193 // How we handle flow control (version-dependent). 194 enum FlowControlState { 195 FLOW_CONTROL_NONE, 196 FLOW_CONTROL_STREAM, 197 FLOW_CONTROL_STREAM_AND_SESSION 198 }; 199 200 // Create a new SpdySession. 201 // |spdy_session_key| is the host/port that this session connects to, privacy 202 // and proxy configuration settings that it's using. 203 // |session| is the HttpNetworkSession. |net_log| is the NetLog that we log 204 // network events to. 205 SpdySession(const SpdySessionKey& spdy_session_key, 206 const base::WeakPtr<HttpServerProperties>& http_server_properties, 207 bool verify_domain_authentication, 208 bool enable_sending_initial_data, 209 bool enable_credential_frames, 210 bool enable_compression, 211 bool enable_ping_based_connection_checking, 212 NextProto default_protocol, 213 size_t stream_initial_recv_window_size, 214 size_t initial_max_concurrent_streams, 215 size_t max_concurrent_streams_limit, 216 TimeFunc time_func, 217 const HostPortPair& trusted_spdy_proxy, 218 NetLog* net_log); 219 220 virtual ~SpdySession(); 221 222 const HostPortPair& host_port_pair() const { 223 return spdy_session_key_.host_port_proxy_pair().first; 224 } 225 const HostPortProxyPair& host_port_proxy_pair() const { 226 return spdy_session_key_.host_port_proxy_pair(); 227 } 228 const SpdySessionKey& spdy_session_key() const { 229 return spdy_session_key_; 230 } 231 // Get a pushed stream for a given |url|. If the server initiates a 232 // stream, it might already exist for a given path. The server 233 // might also not have initiated the stream yet, but indicated it 234 // will via X-Associated-Content. Returns OK if a stream was found 235 // and put into |spdy_stream|, or if one was not found but it is 236 // okay to create a new stream (in which case |spdy_stream| is 237 // reset). Returns an error (not ERR_IO_PENDING) otherwise, and 238 // resets |spdy_stream|. 239 int GetPushStream( 240 const GURL& url, 241 base::WeakPtr<SpdyStream>* spdy_stream, 242 const BoundNetLog& stream_net_log); 243 244 // Initialize the session with the given connection. |is_secure| 245 // must indicate whether |connection| uses an SSL socket or not; it 246 // is usually true, but it can be false for testing or when SPDY is 247 // configured to work with non-secure sockets. 248 // 249 // |pool| is the SpdySessionPool that owns us. Its lifetime must 250 // strictly be greater than |this|. 251 // 252 // |certificate_error_code| must either be OK or less than 253 // ERR_IO_PENDING. 254 // 255 // Returns OK on success, or an error on failure. Never returns 256 // ERR_IO_PENDING. If an error is returned, the session must be 257 // destroyed immediately. 258 Error InitializeWithSocket(scoped_ptr<ClientSocketHandle> connection, 259 SpdySessionPool* pool, 260 bool is_secure, 261 int certificate_error_code); 262 263 // Returns the protocol used by this session. Always between 264 // kProtoSPDY2 and kProtoSPDYMaximumVersion. 265 // 266 // TODO(akalin): Change the lower bound to kProtoSPDYMinimumVersion 267 // once we stop supporting SPDY/1. 268 NextProto protocol() const { return protocol_; } 269 270 // Check to see if this SPDY session can support an additional domain. 271 // If the session is un-authenticated, then this call always returns true. 272 // For SSL-based sessions, verifies that the server certificate in use by 273 // this session provides authentication for the domain and no client 274 // certificate or channel ID was sent to the original server during the SSL 275 // handshake. NOTE: This function can have false negatives on some 276 // platforms. 277 // TODO(wtc): rename this function and the Net.SpdyIPPoolDomainMatch 278 // histogram because this function does more than verifying domain 279 // authentication now. 280 bool VerifyDomainAuthentication(const std::string& domain); 281 282 // Pushes the given producer into the write queue for 283 // |stream|. |stream| is guaranteed to be activated before the 284 // producer is used to produce its frame. 285 void EnqueueStreamWrite(const base::WeakPtr<SpdyStream>& stream, 286 SpdyFrameType frame_type, 287 scoped_ptr<SpdyBufferProducer> producer); 288 289 // Creates and returns a SYN frame for |stream_id|. 290 scoped_ptr<SpdyFrame> CreateSynStream( 291 SpdyStreamId stream_id, 292 RequestPriority priority, 293 uint8 credential_slot, 294 SpdyControlFlags flags, 295 const SpdyHeaderBlock& headers); 296 297 // Tries to create a CREDENTIAL frame. If successful, fills in 298 // |credential_frame| and returns OK. Returns the error (guaranteed 299 // to not be ERR_IO_PENDING) otherwise. 300 int CreateCredentialFrame(const std::string& origin, 301 const std::string& key, 302 const std::string& cert, 303 RequestPriority priority, 304 scoped_ptr<SpdyFrame>* credential_frame); 305 306 // Creates and returns a SpdyBuffer holding a data frame with the 307 // given data. May return NULL if stalled by flow control. 308 scoped_ptr<SpdyBuffer> CreateDataBuffer(SpdyStreamId stream_id, 309 IOBuffer* data, 310 int len, 311 SpdyDataFlags flags); 312 313 // Close the stream with the given ID, which must exist and be 314 // active. Note that that stream may hold the last reference to the 315 // session. 316 void CloseActiveStream(SpdyStreamId stream_id, int status); 317 318 // Close the given created stream, which must exist but not yet be 319 // active. Note that |stream| may hold the last reference to the 320 // session. 321 void CloseCreatedStream(const base::WeakPtr<SpdyStream>& stream, int status); 322 323 // Send a RST_STREAM frame with the given status code and close the 324 // stream with the given ID, which must exist and be active. Note 325 // that that stream may hold the last reference to the session. 326 void ResetStream(SpdyStreamId stream_id, 327 SpdyRstStreamStatus status, 328 const std::string& description); 329 330 // Check if a stream is active. 331 bool IsStreamActive(SpdyStreamId stream_id) const; 332 333 // The LoadState is used for informing the user of the current network 334 // status, such as "resolving host", "connecting", etc. 335 LoadState GetLoadState() const; 336 337 // Fills SSL info in |ssl_info| and returns true when SSL is in use. 338 bool GetSSLInfo(SSLInfo* ssl_info, 339 bool* was_npn_negotiated, 340 NextProto* protocol_negotiated); 341 342 // Fills SSL Certificate Request info |cert_request_info| and returns 343 // true when SSL is in use. 344 bool GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); 345 346 // Returns the ServerBoundCertService used by this Socket, or NULL 347 // if server bound certs are not supported in this session. 348 ServerBoundCertService* GetServerBoundCertService() const; 349 350 // Send a WINDOW_UPDATE frame for a stream. Called by a stream 351 // whenever receive window size is increased. 352 void SendStreamWindowUpdate(SpdyStreamId stream_id, 353 uint32 delta_window_size); 354 355 // Whether the stream is closed, i.e. it has stopped processing data 356 // and is about to be destroyed. 357 // 358 // TODO(akalin): This is only used in tests. Remove this function 359 // and have tests test the WeakPtr instead. 360 bool IsClosed() const { return availability_state_ == STATE_CLOSED; } 361 362 // Closes this session. This will close all active streams and mark 363 // the session as permanently closed. Callers must assume that the 364 // session is destroyed after this is called. (However, it may not 365 // be destroyed right away, e.g. when a SpdySession function is 366 // present in the call stack.) 367 // 368 // |err| should be < ERR_IO_PENDING; this function is intended to be 369 // called on error. 370 // |description| indicates the reason for the error. 371 void CloseSessionOnError(Error err, const std::string& description); 372 373 // Retrieves information on the current state of the SPDY session as a 374 // Value. Caller takes possession of the returned value. 375 base::Value* GetInfoAsValue() const; 376 377 // Indicates whether the session is being reused after having successfully 378 // used to send/receive data in the past. 379 bool IsReused() const; 380 381 // Returns true if the underlying transport socket ever had any reads or 382 // writes. 383 bool WasEverUsed() const { 384 return connection_->socket()->WasEverUsed(); 385 } 386 387 // Returns the load timing information from the perspective of the given 388 // stream. If it's not the first stream, the connection is considered reused 389 // for that stream. 390 // 391 // This uses a different notion of reuse than IsReused(). This function 392 // sets |socket_reused| to false only if |stream_id| is the ID of the first 393 // stream using the session. IsReused(), on the other hand, indicates if the 394 // session has been used to send/receive data at all. 395 bool GetLoadTimingInfo(SpdyStreamId stream_id, 396 LoadTimingInfo* load_timing_info) const; 397 398 // Returns true if session is not currently active 399 bool is_active() const { 400 return !active_streams_.empty() || !created_streams_.empty(); 401 } 402 403 // Access to the number of active and pending streams. These are primarily 404 // available for testing and diagnostics. 405 size_t num_active_streams() const { return active_streams_.size(); } 406 size_t num_unclaimed_pushed_streams() const { 407 return unclaimed_pushed_streams_.size(); 408 } 409 size_t num_created_streams() const { return created_streams_.size(); } 410 411 size_t pending_create_stream_queue_size(RequestPriority priority) const { 412 DCHECK_LT(priority, NUM_PRIORITIES); 413 return pending_create_stream_queues_[priority].size(); 414 } 415 416 // Returns the (version-dependent) flow control state. 417 FlowControlState flow_control_state() const { 418 return flow_control_state_; 419 } 420 421 // Returns the current |stream_initial_send_window_size_|. 422 int32 stream_initial_send_window_size() const { 423 return stream_initial_send_window_size_; 424 } 425 426 // Returns the current |stream_initial_recv_window_size_|. 427 int32 stream_initial_recv_window_size() const { 428 return stream_initial_recv_window_size_; 429 } 430 431 // Returns true if no stream in the session can send data due to 432 // session flow control. 433 bool IsSendStalled() const { 434 return 435 flow_control_state_ == FLOW_CONTROL_STREAM_AND_SESSION && 436 session_send_window_size_ == 0; 437 } 438 439 const BoundNetLog& net_log() const { return net_log_; } 440 441 int GetPeerAddress(IPEndPoint* address) const; 442 int GetLocalAddress(IPEndPoint* address) const; 443 444 // Returns true if requests on this session require credentials. 445 bool NeedsCredentials() const; 446 447 SpdyCredentialState* credential_state() { return &credential_state_; } 448 449 // Adds |alias| to set of aliases associated with this session. 450 void AddPooledAlias(const SpdySessionKey& alias_key); 451 452 // Returns the set of aliases associated with this session. 453 const std::set<SpdySessionKey>& pooled_aliases() const { 454 return pooled_aliases_; 455 } 456 457 int GetProtocolVersion() const; 458 459 size_t GetDataFrameMinimumSize() const { 460 return buffered_spdy_framer_->GetDataFrameMinimumSize(); 461 } 462 463 size_t GetControlFrameHeaderSize() const { 464 return buffered_spdy_framer_->GetControlFrameHeaderSize(); 465 } 466 467 size_t GetFrameMinimumSize() const { 468 return buffered_spdy_framer_->GetFrameMinimumSize(); 469 } 470 471 size_t GetFrameMaximumSize() const { 472 return buffered_spdy_framer_->GetFrameMaximumSize(); 473 } 474 475 size_t GetDataFrameMaximumPayload() const { 476 return buffered_spdy_framer_->GetDataFrameMaximumPayload(); 477 } 478 479 // Must be used only by |pool_|. 480 base::WeakPtr<SpdySession> GetWeakPtr(); 481 482 // LayeredPool implementation: 483 virtual bool CloseOneIdleConnection() OVERRIDE; 484 485 private: 486 friend class base::RefCounted<SpdySession>; 487 friend class SpdyStreamRequest; 488 friend class SpdySessionTest; 489 490 // Allow tests to access our innards for testing purposes. 491 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ClientPing); 492 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, FailedPing); 493 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, GetActivePushStream); 494 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, DeleteExpiredPushStreams); 495 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ProtocolNegotiation); 496 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ClearSettings); 497 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, AdjustRecvWindowSize); 498 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, AdjustSendWindowSize); 499 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlInactiveStream); 500 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoReceiveLeaks); 501 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlNoSendLeaks); 502 FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, SessionFlowControlEndToEnd); 503 504 typedef std::deque<SpdyStreamRequest*> PendingStreamRequestQueue; 505 typedef std::set<SpdyStreamRequest*> PendingStreamRequestCompletionSet; 506 507 struct ActiveStreamInfo { 508 ActiveStreamInfo(); 509 explicit ActiveStreamInfo(SpdyStream* stream); 510 ~ActiveStreamInfo(); 511 512 SpdyStream* stream; 513 bool waiting_for_syn_reply; 514 }; 515 typedef std::map<SpdyStreamId, ActiveStreamInfo> ActiveStreamMap; 516 517 struct PushedStreamInfo { 518 PushedStreamInfo(); 519 PushedStreamInfo(SpdyStreamId stream_id, base::TimeTicks creation_time); 520 ~PushedStreamInfo(); 521 522 SpdyStreamId stream_id; 523 base::TimeTicks creation_time; 524 }; 525 typedef std::map<GURL, PushedStreamInfo> PushedStreamMap; 526 527 typedef std::set<SpdyStream*> CreatedStreamSet; 528 529 enum AvailabilityState { 530 // The session is available in its socket pool and can be used 531 // freely. 532 STATE_AVAILABLE, 533 // The session can process data on existing streams but will 534 // refuse to create new ones. 535 STATE_GOING_AWAY, 536 // The session has been closed, is waiting to be deleted, and will 537 // refuse to process any more data. 538 STATE_CLOSED 539 }; 540 541 enum ReadState { 542 READ_STATE_DO_READ, 543 READ_STATE_DO_READ_COMPLETE, 544 }; 545 546 enum WriteState { 547 // There is no in-flight write and the write queue is empty. 548 WRITE_STATE_IDLE, 549 WRITE_STATE_DO_WRITE, 550 WRITE_STATE_DO_WRITE_COMPLETE, 551 }; 552 553 // The return value of DoCloseSession() describing what was done. 554 enum CloseSessionResult { 555 // The session was already closed so nothing was done. 556 SESSION_ALREADY_CLOSED, 557 // The session was moved into the closed state but was not removed 558 // from |pool_| (because we're in an IO loop). 559 SESSION_CLOSED_BUT_NOT_REMOVED, 560 // The session was moved into the closed state and removed from 561 // |pool_|. 562 SESSION_CLOSED_AND_REMOVED, 563 }; 564 565 // Checks whether a stream for the given |url| can be created or 566 // retrieved from the set of unclaimed push streams. Returns OK if 567 // so. Otherwise, the session is closed and an error < 568 // ERR_IO_PENDING is returned. 569 Error TryAccessStream(const GURL& url); 570 571 // Called by SpdyStreamRequest to start a request to create a 572 // stream. If OK is returned, then |stream| will be filled in with a 573 // valid stream. If ERR_IO_PENDING is returned, then 574 // |request->OnRequestComplete{Success,Failure}()| will be called 575 // when the stream is created (unless it is cancelled). Otherwise, 576 // no stream is created and the error is returned. 577 int TryCreateStream(SpdyStreamRequest* request, 578 base::WeakPtr<SpdyStream>* stream); 579 580 // Actually create a stream into |stream|. Returns OK if successful; 581 // otherwise, returns an error and |stream| is not filled. 582 int CreateStream(const SpdyStreamRequest& request, 583 base::WeakPtr<SpdyStream>* stream); 584 585 // Called by SpdyStreamRequest to remove |request| from the stream 586 // creation queue. 587 void CancelStreamRequest(SpdyStreamRequest* request); 588 589 // Called when there is room to create more streams (e.g., a stream 590 // was closed). Processes as many pending stream requests as 591 // possible. 592 void ProcessPendingStreamRequests(); 593 594 // Close the stream pointed to by the given iterator. Note that that 595 // stream may hold the last reference to the session. 596 void CloseActiveStreamIterator(ActiveStreamMap::iterator it, int status); 597 598 // Close the stream pointed to by the given iterator. Note that that 599 // stream may hold the last reference to the session. 600 void CloseCreatedStreamIterator(CreatedStreamSet::iterator it, int status); 601 602 // Calls EnqueueResetStreamFrame() and then 603 // CloseActiveStreamIterator(). 604 void ResetStreamIterator(ActiveStreamMap::iterator it, 605 SpdyRstStreamStatus status, 606 const std::string& description); 607 608 // Send a RST_STREAM frame with the given parameters. There should 609 // either be no active stream with the given ID, or that active 610 // stream should be closed shortly after this function is called. 611 // 612 // TODO(akalin): Rename this to EnqueueResetStreamFrame(). 613 void EnqueueResetStreamFrame(SpdyStreamId stream_id, 614 RequestPriority priority, 615 SpdyRstStreamStatus status, 616 const std::string& description); 617 618 // Calls DoReadLoop and then if |availability_state_| is 619 // STATE_CLOSED, calls RemoveFromPool(). 620 // 621 // Use this function instead of DoReadLoop when posting a task to 622 // pump the read loop. 623 void PumpReadLoop(ReadState expected_read_state, int result); 624 625 // Advance the ReadState state machine. |expected_read_state| is the 626 // expected starting read state. 627 // 628 // This function must always be called via PumpReadLoop() except for 629 // from InitializeWithSocket(). 630 int DoReadLoop(ReadState expected_read_state, int result); 631 // The implementations of the states of the ReadState state machine. 632 int DoRead(); 633 int DoReadComplete(int result); 634 635 // Calls DoWriteLoop and then if |availability_state_| is 636 // STATE_CLOSED, calls RemoveFromPool(). 637 // 638 // Use this function instead of DoWriteLoop when posting a task to 639 // pump the write loop. 640 void PumpWriteLoop(WriteState expected_write_state, int result); 641 642 // Advance the WriteState state machine. |expected_write_state| is 643 // the expected starting write state. 644 // 645 // This function must always be called via PumpWriteLoop(). 646 int DoWriteLoop(WriteState expected_write_state, int result); 647 // The implementations of the states of the WriteState state machine. 648 int DoWrite(); 649 int DoWriteComplete(int result); 650 651 // TODO(akalin): Rename the Send* and Write* functions below to 652 // Enqueue*. 653 654 // Send initial data. Called when a connection is successfully 655 // established in InitializeWithSocket() and 656 // |enable_sending_initial_data_| is true. 657 void SendInitialData(); 658 659 // Helper method to send a SETTINGS frame. 660 void SendSettings(const SettingsMap& settings); 661 662 // Handle SETTING. Either when we send settings, or when we receive a 663 // SETTINGS control frame, update our SpdySession accordingly. 664 void HandleSetting(uint32 id, uint32 value); 665 666 // Adjust the send window size of all ActiveStreams and PendingStreamRequests. 667 void UpdateStreamsSendWindowSize(int32 delta_window_size); 668 669 // Send the PING (preface-PING) frame. 670 void SendPrefacePingIfNoneInFlight(); 671 672 // Send PING if there are no PINGs in flight and we haven't heard from server. 673 void SendPrefacePing(); 674 675 // Send a single WINDOW_UPDATE frame. 676 void SendWindowUpdateFrame(SpdyStreamId stream_id, uint32 delta_window_size, 677 RequestPriority priority); 678 679 // Send the PING frame. 680 void WritePingFrame(uint32 unique_id); 681 682 // Post a CheckPingStatus call after delay. Don't post if there is already 683 // CheckPingStatus running. 684 void PlanToCheckPingStatus(); 685 686 // Check the status of the connection. It calls |CloseSessionOnError| if we 687 // haven't received any data in |kHungInterval| time period. 688 void CheckPingStatus(base::TimeTicks last_check_time); 689 690 // Get a new stream id. 691 int GetNewStreamId(); 692 693 // Pushes the given frame with the given priority into the write 694 // queue for the session. 695 void EnqueueSessionWrite(RequestPriority priority, 696 SpdyFrameType frame_type, 697 scoped_ptr<SpdyFrame> frame); 698 699 // Puts |producer| associated with |stream| onto the write queue 700 // with the given priority. 701 void EnqueueWrite(RequestPriority priority, 702 SpdyFrameType frame_type, 703 scoped_ptr<SpdyBufferProducer> producer, 704 const base::WeakPtr<SpdyStream>& stream); 705 706 // Inserts a newly-created stream into |created_streams_|. 707 void InsertCreatedStream(scoped_ptr<SpdyStream> stream); 708 709 // Activates |stream| (which must be in |created_streams_|) by 710 // assigning it an ID and returns it. 711 scoped_ptr<SpdyStream> ActivateCreatedStream(SpdyStream* stream); 712 713 // Inserts a newly-activated stream into |active_streams_|. 714 void InsertActivatedStream(scoped_ptr<SpdyStream> stream); 715 716 // Remove all internal references to |stream|, call OnClose() on it, 717 // and process any pending stream requests before deleting it. Note 718 // that |stream| may hold the last reference to the session. 719 void DeleteStream(scoped_ptr<SpdyStream> stream, int status); 720 721 // Check if we have a pending pushed-stream for this url 722 // Returns the stream if found (and returns it from the pending 723 // list). Returns NULL otherwise. 724 base::WeakPtr<SpdyStream> GetActivePushStream(const GURL& url); 725 726 // Delegates to |stream->OnInitialResponseHeadersReceived()|. If an 727 // error is returned, the last reference to |this| may have been 728 // released. 729 int OnInitialResponseHeadersReceived(const SpdyHeaderBlock& response_headers, 730 base::Time response_time, 731 base::TimeTicks recv_first_byte_time, 732 SpdyStream* stream); 733 734 void RecordPingRTTHistogram(base::TimeDelta duration); 735 void RecordHistograms(); 736 void RecordProtocolErrorHistogram(SpdyProtocolErrorDetails details); 737 738 // DCHECKs that |availability_state_| >= STATE_GOING_AWAY, that 739 // there are no pending stream creation requests, and that there are 740 // no created streams. 741 void DcheckGoingAway() const; 742 743 // Calls DcheckGoingAway(), then DCHECKs that |availability_state_| 744 // == STATE_CLOSED, |error_on_close_| has a valid value, that there 745 // are no active streams or unclaimed pushed streams, and that the 746 // write queue is empty. 747 void DcheckClosed() const; 748 749 // Closes all active streams with stream id's greater than 750 // |last_good_stream_id|, as well as any created or pending 751 // streams. Must be called only when |availability_state_| >= 752 // STATE_GOING_AWAY. After this function, DcheckGoingAway() will 753 // pass. May be called multiple times. 754 void StartGoingAway(SpdyStreamId last_good_stream_id, Error status); 755 756 // Must be called only when going away (i.e., DcheckGoingAway() 757 // passes). If there are no more active streams and the session 758 // isn't closed yet, close it. 759 void MaybeFinishGoingAway(); 760 761 // If the stream is already closed, does nothing. Otherwise, moves 762 // the session to a closed state. Then, if we're in an IO loop, 763 // returns (as the IO loop will do the pool removal itself when its 764 // done). Otherwise, also removes |this| from |pool_|. The returned 765 // result describes what was done. 766 CloseSessionResult DoCloseSession(Error err, const std::string& description); 767 768 // Remove this session from its pool, which must exist. Must be 769 // called only when the session is closed. 770 // 771 // Must be called only via Pump{Read,Write}Loop() or 772 // DoCloseSession(). 773 void RemoveFromPool(); 774 775 // Called right before closing a (possibly-inactive) stream for a 776 // reason other than being requested to by the stream. 777 void LogAbandonedStream(SpdyStream* stream, Error status); 778 779 // Called right before closing an active stream for a reason other 780 // than being requested to by the stream. 781 void LogAbandonedActiveStream(ActiveStreamMap::const_iterator it, 782 Error status); 783 784 // Invokes a user callback for stream creation. We provide this method so it 785 // can be deferred to the MessageLoop, so we avoid re-entrancy problems. 786 void CompleteStreamRequest(SpdyStreamRequest* pending_request); 787 788 // Remove old unclaimed pushed streams. 789 void DeleteExpiredPushedStreams(); 790 791 // BufferedSpdyFramerVisitorInterface: 792 virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE; 793 virtual void OnStreamError(SpdyStreamId stream_id, 794 const std::string& description) OVERRIDE; 795 virtual void OnPing(uint32 unique_id) OVERRIDE; 796 virtual void OnRstStream(SpdyStreamId stream_id, 797 SpdyRstStreamStatus status) OVERRIDE; 798 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 799 SpdyGoAwayStatus status) OVERRIDE; 800 virtual void OnStreamFrameData(SpdyStreamId stream_id, 801 const char* data, 802 size_t len, 803 bool fin) OVERRIDE; 804 virtual void OnSettings(bool clear_persisted) OVERRIDE; 805 virtual void OnSetting( 806 SpdySettingsIds id, uint8 flags, uint32 value) OVERRIDE; 807 virtual void OnWindowUpdate(SpdyStreamId stream_id, 808 uint32 delta_window_size) OVERRIDE; 809 virtual void OnPushPromise(SpdyStreamId stream_id, 810 SpdyStreamId promised_stream_id) OVERRIDE; 811 virtual void OnSynStream(SpdyStreamId stream_id, 812 SpdyStreamId associated_stream_id, 813 SpdyPriority priority, 814 uint8 credential_slot, 815 bool fin, 816 bool unidirectional, 817 const SpdyHeaderBlock& headers) OVERRIDE; 818 virtual void OnSynReply( 819 SpdyStreamId stream_id, 820 bool fin, 821 const SpdyHeaderBlock& headers) OVERRIDE; 822 virtual void OnHeaders( 823 SpdyStreamId stream_id, 824 bool fin, 825 const SpdyHeaderBlock& headers) OVERRIDE; 826 827 // SpdyFramerDebugVisitorInterface 828 virtual void OnSendCompressedFrame( 829 SpdyStreamId stream_id, 830 SpdyFrameType type, 831 size_t payload_len, 832 size_t frame_len) OVERRIDE; 833 virtual void OnReceiveCompressedFrame( 834 SpdyStreamId stream_id, 835 SpdyFrameType type, 836 size_t frame_len) OVERRIDE {} 837 838 // Called when bytes are consumed from a SpdyBuffer for a DATA frame 839 // that is to be written or is being written. Increases the send 840 // window size accordingly if some or all of the SpdyBuffer is being 841 // discarded. 842 // 843 // If session flow control is turned off, this must not be called. 844 void OnWriteBufferConsumed(size_t frame_payload_size, 845 size_t consume_size, 846 SpdyBuffer::ConsumeSource consume_source); 847 848 // Called by OnWindowUpdate() (which is in turn called by the 849 // framer) to increase this session's send window size by 850 // |delta_window_size| from a WINDOW_UPDATE frome, which must be at 851 // least 1. If |delta_window_size| would cause this session's send 852 // window size to overflow, does nothing. 853 // 854 // If session flow control is turned off, this must not be called. 855 void IncreaseSendWindowSize(int32 delta_window_size); 856 857 // If session flow control is turned on, called by CreateDataFrame() 858 // (which is in turn called by a stream) to decrease this session's 859 // send window size by |delta_window_size|, which must be at least 1 860 // and at most kMaxSpdyFrameChunkSize. |delta_window_size| must not 861 // cause this session's send window size to go negative. 862 // 863 // If session flow control is turned off, this must not be called. 864 void DecreaseSendWindowSize(int32 delta_window_size); 865 866 // Called when bytes are consumed by the delegate from a SpdyBuffer 867 // containing received data. Increases the receive window size 868 // accordingly. 869 // 870 // If session flow control is turned off, this must not be called. 871 void OnReadBufferConsumed(size_t consume_size, 872 SpdyBuffer::ConsumeSource consume_source); 873 874 // Called by OnReadBufferConsume to increase this session's receive 875 // window size by |delta_window_size|, which must be at least 1 and 876 // must not cause this session's receive window size to overflow, 877 // possibly also sending a WINDOW_UPDATE frame. Also called during 878 // initialization to set the initial receive window size. 879 // 880 // If session flow control is turned off, this must not be called. 881 void IncreaseRecvWindowSize(int32 delta_window_size); 882 883 // Called by OnStreamFrameData (which is in turn called by the 884 // framer) to decrease this session's receive window size by 885 // |delta_window_size|, which must be at least 1 and must not cause 886 // this session's receive window size to go negative. 887 // 888 // If session flow control is turned off, this must not be called. 889 void DecreaseRecvWindowSize(int32 delta_window_size); 890 891 // Queue a send-stalled stream for possibly resuming once we're not 892 // send-stalled anymore. 893 void QueueSendStalledStream(const SpdyStream& stream); 894 895 // Go through the queue of send-stalled streams and try to resume as 896 // many as possible. 897 void ResumeSendStalledStreams(); 898 899 // Returns the next stream to possibly resume, or 0 if the queue is 900 // empty. 901 SpdyStreamId PopStreamToPossiblyResume(); 902 903 // -------------------------- 904 // Helper methods for testing 905 // -------------------------- 906 907 void set_connection_at_risk_of_loss_time(base::TimeDelta duration) { 908 connection_at_risk_of_loss_time_ = duration; 909 } 910 911 void set_hung_interval(base::TimeDelta duration) { 912 hung_interval_ = duration; 913 } 914 915 int64 pings_in_flight() const { return pings_in_flight_; } 916 917 uint32 next_ping_id() const { return next_ping_id_; } 918 919 base::TimeTicks last_activity_time() const { return last_activity_time_; } 920 921 bool check_ping_status_pending() const { return check_ping_status_pending_; } 922 923 size_t max_concurrent_streams() const { return max_concurrent_streams_; } 924 925 // Returns the SSLClientSocket that this SPDY session sits on top of, 926 // or NULL, if the transport is not SSL. 927 SSLClientSocket* GetSSLClientSocket() const; 928 929 // Used for posting asynchronous IO tasks. We use this even though 930 // SpdySession is refcounted because we don't need to keep the SpdySession 931 // alive if the last reference is within a RunnableMethod. Just revoke the 932 // method. 933 base::WeakPtrFactory<SpdySession> weak_factory_; 934 935 // Whether Do{Read,Write}Loop() is in the call stack. Useful for 936 // making sure we don't destroy ourselves prematurely in that case. 937 bool in_io_loop_; 938 939 // The key used to identify this session. 940 const SpdySessionKey spdy_session_key_; 941 942 // Set set of SpdySessionKeys for which this session has serviced 943 // requests. 944 std::set<SpdySessionKey> pooled_aliases_; 945 946 // |pool_| owns us, therefore its lifetime must exceed ours. We set 947 // this to NULL after we are removed from the pool. 948 SpdySessionPool* pool_; 949 const base::WeakPtr<HttpServerProperties> http_server_properties_; 950 951 // The socket handle for this session. 952 scoped_ptr<ClientSocketHandle> connection_; 953 954 // The read buffer used to read data from the socket. 955 scoped_refptr<IOBuffer> read_buffer_; 956 957 int stream_hi_water_mark_; // The next stream id to use. 958 959 // Queue, for each priority, of pending stream requests that have 960 // not yet been satisfied. 961 PendingStreamRequestQueue pending_create_stream_queues_[NUM_PRIORITIES]; 962 963 // A set of requests that are waiting to be completed (i.e., for the 964 // stream to actually be created). This is necessary since we kick 965 // off the stream creation asynchronously, and so the request may be 966 // cancelled before the asynchronous task to create the stream runs. 967 PendingStreamRequestCompletionSet pending_stream_request_completions_; 968 969 // Map from stream id to all active streams. Streams are active in the sense 970 // that they have a consumer (typically SpdyNetworkTransaction and regardless 971 // of whether or not there is currently any ongoing IO [might be waiting for 972 // the server to start pushing the stream]) or there are still network events 973 // incoming even though the consumer has already gone away (cancellation). 974 // 975 // |active_streams_| owns all its SpdyStream objects. 976 // 977 // TODO(willchan): Perhaps we should separate out cancelled streams and move 978 // them into a separate ActiveStreamMap, and not deliver network events to 979 // them? 980 ActiveStreamMap active_streams_; 981 982 // (Bijective) map from the URL to the ID of the streams that have 983 // already started to be pushed by the server, but do not have 984 // consumers yet. Contains a subset of |active_streams_|. 985 PushedStreamMap unclaimed_pushed_streams_; 986 987 // Set of all created streams but that have not yet sent any frames. 988 // 989 // |created_streams_| owns all its SpdyStream objects. 990 CreatedStreamSet created_streams_; 991 992 // The write queue. 993 SpdyWriteQueue write_queue_; 994 995 // Data for the frame we are currently sending. 996 997 // The buffer we're currently writing. 998 scoped_ptr<SpdyBuffer> in_flight_write_; 999 // The type of the frame in |in_flight_write_|. 1000 SpdyFrameType in_flight_write_frame_type_; 1001 // The size of the frame in |in_flight_write_|. 1002 size_t in_flight_write_frame_size_; 1003 // The stream to notify when |in_flight_write_| has been written to 1004 // the socket completely. 1005 base::WeakPtr<SpdyStream> in_flight_write_stream_; 1006 1007 // Flag if we're using an SSL connection for this SpdySession. 1008 bool is_secure_; 1009 1010 // Certificate error code when using a secure connection. 1011 int certificate_error_code_; 1012 1013 // Spdy Frame state. 1014 scoped_ptr<BufferedSpdyFramer> buffered_spdy_framer_; 1015 1016 // The state variables. 1017 AvailabilityState availability_state_; 1018 ReadState read_state_; 1019 WriteState write_state_; 1020 1021 // If the session was closed (i.e., |availability_state_| is 1022 // STATE_CLOSED), then |error_on_close_| holds the error with which 1023 // it was closed, which is < ERR_IO_PENDING. Otherwise, it is set to 1024 // OK. 1025 Error error_on_close_; 1026 1027 // Limits 1028 size_t max_concurrent_streams_; // 0 if no limit 1029 size_t max_concurrent_streams_limit_; 1030 1031 // Some statistics counters for the session. 1032 int streams_initiated_count_; 1033 int streams_pushed_count_; 1034 int streams_pushed_and_claimed_count_; 1035 int streams_abandoned_count_; 1036 1037 // |total_bytes_received_| keeps track of all the bytes read by the 1038 // SpdySession. It is used by the |Net.SpdySettingsCwnd...| histograms. 1039 int total_bytes_received_; 1040 1041 bool sent_settings_; // Did this session send settings when it started. 1042 bool received_settings_; // Did this session receive at least one settings 1043 // frame. 1044 int stalled_streams_; // Count of streams that were ever stalled. 1045 1046 // Count of all pings on the wire, for which we have not gotten a response. 1047 int64 pings_in_flight_; 1048 1049 // This is the next ping_id (unique_id) to be sent in PING frame. 1050 uint32 next_ping_id_; 1051 1052 // This is the last time we have sent a PING. 1053 base::TimeTicks last_ping_sent_time_; 1054 1055 // This is the last time we had activity in the session. 1056 base::TimeTicks last_activity_time_; 1057 1058 // This is the next time that unclaimed push streams should be checked for 1059 // expirations. 1060 base::TimeTicks next_unclaimed_push_stream_sweep_time_; 1061 1062 // Indicate if we have already scheduled a delayed task to check the ping 1063 // status. 1064 bool check_ping_status_pending_; 1065 1066 // Whether to send the (HTTP/2) connection header prefix. 1067 bool send_connection_header_prefix_; 1068 1069 // The (version-dependent) flow control state. 1070 FlowControlState flow_control_state_; 1071 1072 // Initial send window size for this session's streams. Can be 1073 // changed by an arriving SETTINGS frame. Newly created streams use 1074 // this value for the initial send window size. 1075 int32 stream_initial_send_window_size_; 1076 1077 // Initial receive window size for this session's streams. There are 1078 // plans to add a command line switch that would cause a SETTINGS 1079 // frame with window size announcement to be sent on startup. Newly 1080 // created streams will use this value for the initial receive 1081 // window size. 1082 int32 stream_initial_recv_window_size_; 1083 1084 // Session flow control variables. All zero unless session flow 1085 // control is turned on. 1086 int32 session_send_window_size_; 1087 int32 session_recv_window_size_; 1088 int32 session_unacked_recv_window_bytes_; 1089 1090 // A queue of stream IDs that have been send-stalled at some point 1091 // in the past. 1092 std::deque<SpdyStreamId> stream_send_unstall_queue_[NUM_PRIORITIES]; 1093 1094 BoundNetLog net_log_; 1095 1096 // Outside of tests, these should always be true. 1097 bool verify_domain_authentication_; 1098 bool enable_sending_initial_data_; 1099 bool enable_credential_frames_; 1100 bool enable_compression_; 1101 bool enable_ping_based_connection_checking_; 1102 1103 // The SPDY protocol used. Always between kProtoSPDY2 and 1104 // kProtoSPDYMaximumVersion. 1105 // 1106 // TODO(akalin): Change the lower bound to kProtoSPDYMinimumVersion 1107 // once we stop supporting SPDY/1. 1108 NextProto protocol_; 1109 1110 SpdyCredentialState credential_state_; 1111 1112 // |connection_at_risk_of_loss_time_| is an optimization to avoid sending 1113 // wasteful preface pings (when we just got some data). 1114 // 1115 // If it is zero (the most conservative figure), then we always send the 1116 // preface ping (when none are in flight). 1117 // 1118 // It is common for TCP/IP sessions to time out in about 3-5 minutes. 1119 // Certainly if it has been more than 3 minutes, we do want to send a preface 1120 // ping. 1121 // 1122 // We don't think any connection will time out in under about 10 seconds. So 1123 // this might as well be set to something conservative like 10 seconds. Later, 1124 // we could adjust it to send fewer pings perhaps. 1125 base::TimeDelta connection_at_risk_of_loss_time_; 1126 1127 // The amount of time that we are willing to tolerate with no activity (of any 1128 // form), while there is a ping in flight, before we declare the connection to 1129 // be hung. TODO(rtenneti): When hung, instead of resetting connection, race 1130 // to build a new connection, and see if that completes before we (finally) 1131 // get a PING response (http://crbug.com/127812). 1132 base::TimeDelta hung_interval_; 1133 1134 // This SPDY proxy is allowed to push resources from origins that are 1135 // different from those of their associated streams. 1136 HostPortPair trusted_spdy_proxy_; 1137 1138 TimeFunc time_func_; 1139 }; 1140 1141 } // namespace net 1142 1143 #endif // NET_SPDY_SPDY_SESSION_H_ 1144