| // Copyright (c) 2011 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_SPDY_SPDY_STREAM_H_ |
| #define NET_SPDY_SPDY_STREAM_H_ |
| #pragma once |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "googleurl/src/gurl.h" |
| #include "net/base/bandwidth_metrics.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/upload_data.h" |
| #include "net/base/net_log.h" |
| #include "net/spdy/spdy_framer.h" |
| #include "net/spdy/spdy_protocol.h" |
| |
| namespace net { |
| |
| class AddressList; |
| class IPEndPoint; |
| class SpdySession; |
| class SSLCertRequestInfo; |
| class SSLInfo; |
| |
| // The SpdyStream is used by the SpdySession to represent each stream known |
| // on the SpdySession. This class provides interfaces for SpdySession to use. |
| // Streams can be created either by the client or by the server. When they |
| // are initiated by the client, both the SpdySession and client object (such as |
| // a SpdyNetworkTransaction) will maintain a reference to the stream. When |
| // initiated by the server, only the SpdySession will maintain any reference, |
| // until such a time as a client object requests a stream for the path. |
| class SpdyStream |
| : public base::RefCounted<SpdyStream>, |
| public ChunkCallback { |
| public: |
| // Delegate handles protocol specific behavior of spdy stream. |
| class Delegate { |
| public: |
| Delegate() {} |
| |
| // Called when SYN frame has been sent. |
| // Returns true if no more data to be sent after SYN frame. |
| virtual bool OnSendHeadersComplete(int status) = 0; |
| |
| // Called when stream is ready to send data. |
| // Returns network error code. OK when it successfully sent data. |
| virtual int OnSendBody() = 0; |
| |
| // Called when data has been sent. |status| indicates network error |
| // or number of bytes that has been sent. On return, |eof| is set to true |
| // if no more data is available to send in the request body. |
| // Returns network error code. OK when it successfully sent data. |
| virtual int OnSendBodyComplete(int status, bool* eof) = 0; |
| |
| // Called when the SYN_STREAM, SYN_REPLY, or HEADERS frames are received. |
| // Normal streams will receive a SYN_REPLY and optional HEADERS frames. |
| // Pushed streams will receive a SYN_STREAM and optional HEADERS frames. |
| // Because a stream may have a SYN_* frame and multiple HEADERS frames, |
| // this callback may be called multiple times. |
| // |status| indicates network error. Returns network error code. |
| virtual int OnResponseReceived(const spdy::SpdyHeaderBlock& response, |
| base::Time response_time, |
| int status) = 0; |
| |
| // Called when data is received. |
| virtual void OnDataReceived(const char* data, int length) = 0; |
| |
| // Called when data is sent. |
| virtual void OnDataSent(int length) = 0; |
| |
| // Called when SpdyStream is closed. |
| virtual void OnClose(int status) = 0; |
| |
| // Sets the callback to be invoked when a new chunk is available to upload. |
| virtual void set_chunk_callback(ChunkCallback* callback) = 0; |
| |
| protected: |
| friend class base::RefCounted<Delegate>; |
| virtual ~Delegate() {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(Delegate); |
| }; |
| |
| // SpdyStream constructor |
| SpdyStream(SpdySession* session, |
| spdy::SpdyStreamId stream_id, |
| bool pushed, |
| const BoundNetLog& net_log); |
| |
| // Set new |delegate|. |delegate| must not be NULL. |
| // If it already received SYN_REPLY or data, OnResponseReceived() or |
| // OnDataReceived() will be called. |
| void SetDelegate(Delegate* delegate); |
| Delegate* GetDelegate() { return delegate_; } |
| |
| // Detach delegate from the stream. It will cancel the stream if it was not |
| // cancelled yet. It is safe to call multiple times. |
| void DetachDelegate(); |
| |
| // Is this stream a pushed stream from the server. |
| bool pushed() const { return pushed_; } |
| |
| spdy::SpdyStreamId stream_id() const { return stream_id_; } |
| void set_stream_id(spdy::SpdyStreamId stream_id) { stream_id_ = stream_id; } |
| |
| bool response_received() const { return response_received_; } |
| void set_response_received() { response_received_ = true; } |
| |
| // For pushed streams, we track a path to identify them. |
| const std::string& path() const { return path_; } |
| void set_path(const std::string& path) { path_ = path; } |
| |
| int priority() const { return priority_; } |
| void set_priority(int priority) { priority_ = priority; } |
| |
| int send_window_size() const { return send_window_size_; } |
| void set_send_window_size(int window_size) { |
| send_window_size_ = window_size; |
| } |
| |
| int recv_window_size() const { return recv_window_size_; } |
| void set_recv_window_size(int window_size) { |
| recv_window_size_ = window_size; |
| } |
| |
| void set_stalled_by_flow_control(bool stalled) { |
| stalled_by_flow_control_ = stalled; |
| } |
| |
| // Increases |send_window_size_| with delta extracted from a WINDOW_UPDATE |
| // frame; sends a RST_STREAM if delta overflows |send_window_size_| and |
| // removes the stream from the session. |
| void IncreaseSendWindowSize(int delta_window_size); |
| |
| // Decreases |send_window_size_| by the given number of bytes. |
| void DecreaseSendWindowSize(int delta_window_size); |
| |
| int GetPeerAddress(AddressList* address) const; |
| int GetLocalAddress(IPEndPoint* address) const; |
| |
| // Returns true if the underlying transport socket ever had any reads or |
| // writes. |
| bool WasEverUsed() const; |
| |
| // Increases |recv_window_size_| by the given number of bytes, also sends |
| // a WINDOW_UPDATE frame. |
| void IncreaseRecvWindowSize(int delta_window_size); |
| |
| // Decreases |recv_window_size_| by the given number of bytes, called |
| // whenever data is read. May also send a RST_STREAM and remove the |
| // stream from the session if the resultant |recv_window_size_| is |
| // negative, since that would be a flow control violation. |
| void DecreaseRecvWindowSize(int delta_window_size); |
| |
| const BoundNetLog& net_log() const { return net_log_; } |
| |
| const linked_ptr<spdy::SpdyHeaderBlock>& spdy_headers() const; |
| void set_spdy_headers(const linked_ptr<spdy::SpdyHeaderBlock>& headers); |
| base::Time GetRequestTime() const; |
| void SetRequestTime(base::Time t); |
| |
| // Called by the SpdySession when a response (e.g. a SYN_STREAM or SYN_REPLY) |
| // has been received for this stream. Returns a status code. |
| int OnResponseReceived(const spdy::SpdyHeaderBlock& response); |
| |
| // Called by the SpdySession when late-bound headers are received for a |
| // stream. Returns a status code. |
| int OnHeaders(const spdy::SpdyHeaderBlock& headers); |
| |
| // Called by the SpdySession when response data has been received for this |
| // stream. This callback may be called multiple times as data arrives |
| // from the network, and will never be called prior to OnResponseReceived. |
| // |buffer| contains the data received. The stream must copy any data |
| // from this buffer before returning from this callback. |
| // |length| is the number of bytes received or an error. |
| // A zero-length count does not indicate end-of-stream. |
| void OnDataReceived(const char* buffer, int bytes); |
| |
| // Called by the SpdySession when a write has completed. This callback |
| // will be called multiple times for each write which completes. Writes |
| // include the SYN_STREAM write and also DATA frame writes. |
| // |result| is the number of bytes written or a net error code. |
| void OnWriteComplete(int bytes); |
| |
| // Called by the SpdySession when the request is finished. This callback |
| // will always be called at the end of the request and signals to the |
| // stream that the stream has no more network events. No further callbacks |
| // to the stream will be made after this call. |
| // |status| is an error code or OK. |
| void OnClose(int status); |
| |
| void Cancel(); |
| bool cancelled() const { return cancelled_; } |
| bool closed() const { return io_state_ == STATE_DONE; } |
| |
| // Interface for Spdy[Http|WebSocket]Stream to use. |
| |
| // Sends the request. |
| // For non push stream, it will send SYN_STREAM frame. |
| int SendRequest(bool has_upload_data); |
| |
| // Sends DATA frame. |
| int WriteStreamData(IOBuffer* data, int length, |
| spdy::SpdyDataFlags flags); |
| |
| // Fills SSL info in |ssl_info| and returns true when SSL is in use. |
| bool GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated); |
| |
| // Fills SSL Certificate Request info |cert_request_info| and returns |
| // true when SSL is in use. |
| bool GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info); |
| |
| bool is_idle() const { |
| return io_state_ == STATE_OPEN || io_state_ == STATE_DONE; |
| } |
| |
| int response_status() const { return response_status_; } |
| |
| // Returns true if the URL for this stream is known. |
| bool HasUrl() const; |
| |
| // Get the URL associated with this stream. Only valid when has_url() is |
| // true. |
| GURL GetUrl() const; |
| |
| // ChunkCallback methods. |
| virtual void OnChunkAvailable(); |
| |
| private: |
| enum State { |
| STATE_NONE, |
| STATE_SEND_HEADERS, |
| STATE_SEND_HEADERS_COMPLETE, |
| STATE_SEND_BODY, |
| STATE_SEND_BODY_COMPLETE, |
| STATE_WAITING_FOR_RESPONSE, |
| STATE_OPEN, |
| STATE_DONE |
| }; |
| |
| friend class base::RefCounted<SpdyStream>; |
| virtual ~SpdyStream(); |
| |
| // Try to make progress sending/receiving the request/response. |
| int DoLoop(int result); |
| |
| // The implementations of each state of the state machine. |
| int DoSendHeaders(); |
| int DoSendHeadersComplete(int result); |
| int DoSendBody(); |
| int DoSendBodyComplete(int result); |
| int DoReadHeaders(); |
| int DoReadHeadersComplete(int result); |
| int DoOpen(int result); |
| |
| // Update the histograms. Can safely be called repeatedly, but should only |
| // be called after the stream has completed. |
| void UpdateHistograms(); |
| |
| // When a server pushed stream is first created, this function is posted on |
| // the MessageLoop to replay all the data that the server has already sent. |
| void PushedStreamReplayData(); |
| |
| // There is a small period of time between when a server pushed stream is |
| // first created, and the pushed data is replayed. Any data received during |
| // this time should continue to be buffered. |
| bool continue_buffering_data_; |
| |
| spdy::SpdyStreamId stream_id_; |
| std::string path_; |
| int priority_; |
| |
| // Flow control variables. |
| bool stalled_by_flow_control_; |
| int send_window_size_; |
| int recv_window_size_; |
| |
| const bool pushed_; |
| ScopedBandwidthMetrics metrics_; |
| bool response_received_; |
| |
| scoped_refptr<SpdySession> session_; |
| |
| // The transaction should own the delegate. |
| SpdyStream::Delegate* delegate_; |
| |
| // The request to send. |
| linked_ptr<spdy::SpdyHeaderBlock> request_; |
| |
| // The time at which the request was made that resulted in this response. |
| // For cached responses, this time could be "far" in the past. |
| base::Time request_time_; |
| |
| linked_ptr<spdy::SpdyHeaderBlock> response_; |
| base::Time response_time_; |
| |
| State io_state_; |
| |
| // Since we buffer the response, we also buffer the response status. |
| // Not valid until the stream is closed. |
| int response_status_; |
| |
| bool cancelled_; |
| bool has_upload_data_; |
| |
| BoundNetLog net_log_; |
| |
| base::TimeTicks send_time_; |
| base::TimeTicks recv_first_byte_time_; |
| base::TimeTicks recv_last_byte_time_; |
| int send_bytes_; |
| int recv_bytes_; |
| // Data received before delegate is attached. |
| std::vector<scoped_refptr<IOBufferWithSize> > pending_buffers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SpdyStream); |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_SPDY_SPDY_STREAM_H_ |