mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-24 14:26:09 +03:00
536 lines
20 KiB
C++
536 lines
20 KiB
C++
// Copyright (c) 2012 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_CHROMIUM_SPDY_STREAM_H_
|
|
#define NET_SPDY_CHROMIUM_SPDY_STREAM_H_
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "base/compiler_specific.h"
|
|
#include "base/macros.h"
|
|
#include "base/memory/ref_counted.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "net/base/io_buffer.h"
|
|
#include "net/base/net_export.h"
|
|
#include "net/base/request_priority.h"
|
|
#include "net/log/net_log_source.h"
|
|
#include "net/log/net_log_with_source.h"
|
|
#include "net/socket/next_proto.h"
|
|
#include "net/socket/ssl_client_socket.h"
|
|
#include "net/spdy/chromium/spdy_buffer.h"
|
|
#include "net/spdy/core/spdy_framer.h"
|
|
#include "net/spdy/core/spdy_header_block.h"
|
|
#include "net/spdy/core/spdy_protocol.h"
|
|
#include "net/spdy/platform/api/spdy_string.h"
|
|
#include "net/ssl/ssl_client_cert_type.h"
|
|
#include "url/gurl.h"
|
|
|
|
namespace net {
|
|
|
|
class IPEndPoint;
|
|
struct LoadTimingInfo;
|
|
class SSLInfo;
|
|
class SpdySession;
|
|
|
|
enum SpdyStreamType {
|
|
// The most general type of stream; there are no restrictions on
|
|
// when data can be sent and received.
|
|
SPDY_BIDIRECTIONAL_STREAM,
|
|
// A stream where the client sends a request with possibly a body,
|
|
// and the server then sends a response with a body.
|
|
SPDY_REQUEST_RESPONSE_STREAM,
|
|
// A server-initiated stream where the server just sends a response
|
|
// with a body and the client does not send anything.
|
|
SPDY_PUSH_STREAM
|
|
};
|
|
|
|
// Passed to some SpdyStream functions to indicate whether there's
|
|
// more data to send.
|
|
enum SpdySendStatus {
|
|
MORE_DATA_TO_SEND,
|
|
NO_MORE_DATA_TO_SEND
|
|
};
|
|
|
|
// SpdyStream is owned by SpdySession and is used 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 NET_EXPORT_PRIVATE SpdyStream {
|
|
public:
|
|
// Delegate handles protocol specific behavior of spdy stream.
|
|
class NET_EXPORT_PRIVATE Delegate {
|
|
public:
|
|
Delegate() {}
|
|
|
|
// Called when the request headers have been sent. Never called
|
|
// for push streams. Must not cause the stream to be closed.
|
|
virtual void OnHeadersSent() = 0;
|
|
|
|
// OnHeadersReceived(), OnDataReceived(), OnTrailers(), and OnClose()
|
|
// are guaranteed to be called in the following order:
|
|
// - OnHeadersReceived() exactly once;
|
|
// - OnDataReceived() zero or more times;
|
|
// - OnTrailers() zero or one times;
|
|
// - OnClose() exactly once.
|
|
|
|
// Called when headers have been received.
|
|
virtual void OnHeadersReceived(const SpdyHeaderBlock& response_headers) = 0;
|
|
|
|
// Called when data is received. |buffer| may be NULL, which signals EOF.
|
|
// May cause the stream to be closed.
|
|
virtual void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer) = 0;
|
|
|
|
// Called when data is sent. Must not cause the stream to be closed.
|
|
virtual void OnDataSent() = 0;
|
|
|
|
// Called when trailers are received.
|
|
virtual void OnTrailers(const SpdyHeaderBlock& trailers) = 0;
|
|
|
|
// Called when SpdyStream is closed. No other delegate functions
|
|
// will be called after this is called, and the delegate must not
|
|
// access the stream after this is called. Must not cause the
|
|
// stream to be (re-)closed.
|
|
//
|
|
// TODO(akalin): Allow this function to re-close the stream and
|
|
// handle it gracefully.
|
|
virtual void OnClose(int status) = 0;
|
|
|
|
virtual NetLogSource source_dependency() const = 0;
|
|
|
|
protected:
|
|
virtual ~Delegate() {}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(Delegate);
|
|
};
|
|
|
|
// SpdyStream constructor
|
|
SpdyStream(SpdyStreamType type,
|
|
const base::WeakPtr<SpdySession>& session,
|
|
const GURL& url,
|
|
RequestPriority priority,
|
|
int32_t initial_send_window_size,
|
|
int32_t max_recv_window_size,
|
|
const NetLogWithSource& net_log);
|
|
|
|
~SpdyStream();
|
|
|
|
// Set the delegate, which must not be NULL. Must not be called more
|
|
// than once. For push streams, calling this may cause buffered data
|
|
// to be sent to the delegate (from a posted task).
|
|
void SetDelegate(Delegate* delegate);
|
|
|
|
// Detach the delegate from the stream, which must not yet be
|
|
// closed, and cancel it.
|
|
void DetachDelegate();
|
|
|
|
// The time at which the first bytes of the response were received
|
|
// from the server, or null if the response hasn't been received
|
|
// yet.
|
|
base::Time response_time() const { return response_time_; }
|
|
|
|
SpdyStreamType type() const { return type_; }
|
|
|
|
SpdyStreamId stream_id() const { return stream_id_; }
|
|
void set_stream_id(SpdyStreamId stream_id) { stream_id_ = stream_id; }
|
|
|
|
const GURL& url() const { return url_; }
|
|
|
|
RequestPriority priority() const { return priority_; }
|
|
void set_priority(RequestPriority p) { priority_ = p; }
|
|
|
|
int32_t send_window_size() const { return send_window_size_; }
|
|
|
|
int32_t recv_window_size() const { return recv_window_size_; }
|
|
|
|
bool send_stalled_by_flow_control() const {
|
|
return send_stalled_by_flow_control_;
|
|
}
|
|
|
|
void set_send_stalled_by_flow_control(bool stalled) {
|
|
send_stalled_by_flow_control_ = stalled;
|
|
}
|
|
|
|
// Called by the session to adjust this stream's send window size by
|
|
// |delta_window_size|, which is the difference between the
|
|
// SETTINGS_INITIAL_WINDOW_SIZE in the most recent SETTINGS frame
|
|
// and the previous initial send window size, possibly unstalling
|
|
// this stream. Although |delta_window_size| may cause this stream's
|
|
// send window size to go negative, it must not cause it to wrap
|
|
// around in either direction. Does nothing if the stream is already
|
|
// closed.
|
|
// Returns true if successful. Returns false if |send_window_size_|
|
|
// would exceed 2^31-1 after the update, see RFC7540 Section 6.9.2.
|
|
// Note that |send_window_size_| should not possibly underflow.
|
|
bool AdjustSendWindowSize(int32_t delta_window_size) WARN_UNUSED_RESULT;
|
|
|
|
// Called when bytes are consumed from a SpdyBuffer for a DATA frame
|
|
// that is to be written or is being written. Increases the send
|
|
// window size accordingly if some or all of the SpdyBuffer is being
|
|
// discarded.
|
|
//
|
|
// If stream flow control is turned off, this must not be called.
|
|
void OnWriteBufferConsumed(size_t frame_payload_size,
|
|
size_t consume_size,
|
|
SpdyBuffer::ConsumeSource consume_source);
|
|
|
|
// Called by the session to increase this stream's send window size
|
|
// by |delta_window_size| (which must be at least 1) from a received
|
|
// WINDOW_UPDATE frame or from a dropped DATA frame that was
|
|
// intended to be sent, possibly unstalling this stream. If
|
|
// |delta_window_size| would cause this stream's send window size to
|
|
// overflow, calls into the session to reset this stream. Does
|
|
// nothing if the stream is already closed.
|
|
//
|
|
// If stream flow control is turned off, this must not be called.
|
|
void IncreaseSendWindowSize(int32_t delta_window_size);
|
|
|
|
// If stream flow control is turned on, called by the session to
|
|
// decrease this stream's send window size by |delta_window_size|,
|
|
// which must be at least 0 and at most kMaxSpdyFrameChunkSize.
|
|
// |delta_window_size| must not cause this stream's send window size
|
|
// to go negative. Does nothing if the stream is already closed.
|
|
//
|
|
// If stream flow control is turned off, this must not be called.
|
|
void DecreaseSendWindowSize(int32_t delta_window_size);
|
|
|
|
// Called when bytes are consumed by the delegate from a SpdyBuffer
|
|
// containing received data. Increases the receive window size
|
|
// accordingly.
|
|
//
|
|
// If stream flow control is turned off, this must not be called.
|
|
void OnReadBufferConsumed(size_t consume_size,
|
|
SpdyBuffer::ConsumeSource consume_source);
|
|
|
|
// Called by OnReadBufferConsume to increase this stream's receive
|
|
// window size by |delta_window_size|, which must be at least 1 and
|
|
// must not cause this stream's receive window size to overflow,
|
|
// possibly also sending a WINDOW_UPDATE frame. Does nothing if the
|
|
// stream is not active.
|
|
//
|
|
// If stream flow control is turned off, this must not be called.
|
|
void IncreaseRecvWindowSize(int32_t delta_window_size);
|
|
|
|
// Called by OnDataReceived or OnPaddingConsumed (which are in turn called by
|
|
// the session) to decrease this stream's receive window size by
|
|
// |delta_window_size|, which must be at least 1. May close the stream on
|
|
// flow control error.
|
|
//
|
|
// If stream flow control is turned off or the stream is not active,
|
|
// this must not be called.
|
|
void DecreaseRecvWindowSize(int32_t delta_window_size);
|
|
|
|
int GetPeerAddress(IPEndPoint* address) const;
|
|
int GetLocalAddress(IPEndPoint* address) const;
|
|
|
|
// Returns true if the underlying transport socket ever had any reads or
|
|
// writes.
|
|
bool WasEverUsed() const;
|
|
|
|
const NetLogWithSource& net_log() const { return net_log_; }
|
|
|
|
base::Time GetRequestTime() const;
|
|
void SetRequestTime(base::Time t);
|
|
|
|
// Called by SpdySession when headers are received for this stream. May close
|
|
// the stream.
|
|
void OnHeadersReceived(const SpdyHeaderBlock& response_headers,
|
|
base::Time response_time,
|
|
base::TimeTicks recv_first_byte_time);
|
|
|
|
// Called by the SpdySession when a frame carrying request headers opening a
|
|
// push stream is received. Stream transits to STATE_RESERVED_REMOTE state.
|
|
void OnPushPromiseHeadersReceived(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
|
|
// OnResponseHeadersReceived.
|
|
//
|
|
// |buffer| contains the data received, or NULL if the stream is
|
|
// being closed. The stream must copy any data from this
|
|
// buffer before returning from this callback.
|
|
//
|
|
// |length| is the number of bytes received (at most 2^24 - 1) or 0 if
|
|
// the stream is being closed.
|
|
void OnDataReceived(std::unique_ptr<SpdyBuffer> buffer);
|
|
|
|
// Called by the SpdySession when padding is consumed to allow for the stream
|
|
// receiving window to be updated.
|
|
void OnPaddingConsumed(size_t len);
|
|
|
|
// Called by the SpdySession when a frame has been successfully and completely
|
|
// written. |frame_size| is the total size of the logical frame in bytes,
|
|
// including framing overhead. For fragmented headers, this is the total size
|
|
// of the HEADERS or PUSH_PROMISE frame and subsequent CONTINUATION frames.
|
|
void OnFrameWriteComplete(SpdyFrameType frame_type, size_t frame_size);
|
|
|
|
// HEADERS-specific write handler invoked by OnFrameWriteComplete().
|
|
int OnHeadersSent();
|
|
|
|
// DATA-specific write handler invoked by OnFrameWriteComplete().
|
|
// If more data is already available to be written, the next write is
|
|
// queued and ERR_IO_PENDING is returned. Returns OK otherwise.
|
|
int OnDataSent(size_t frame_size);
|
|
|
|
// 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. Must be called before
|
|
// SpdyStream is destroyed.
|
|
// |status| is an error code or OK.
|
|
void OnClose(int status);
|
|
|
|
// Called by the SpdySession to log stream related errors.
|
|
void LogStreamError(int error, const SpdyString& description);
|
|
|
|
// If this stream is active, reset it, and close it otherwise. In
|
|
// either case the stream is deleted.
|
|
void Cancel();
|
|
|
|
// Close this stream without sending a RST_STREAM and delete
|
|
// it.
|
|
void Close();
|
|
|
|
// Must be used only by |session_|.
|
|
base::WeakPtr<SpdyStream> GetWeakPtr();
|
|
|
|
// Interface for the delegate to use.
|
|
|
|
// Only one send can be in flight at a time, except for push
|
|
// streams, which must not send anything.
|
|
|
|
// Sends the request headers. The delegate is called back via OnHeadersSent()
|
|
// when the request headers have completed sending. |send_status| must be
|
|
// MORE_DATA_TO_SEND for bidirectional streams; for request/response streams,
|
|
// it must be MORE_DATA_TO_SEND if the request has data to upload, or
|
|
// NO_MORE_DATA_TO_SEND if not.
|
|
int SendRequestHeaders(SpdyHeaderBlock request_headers,
|
|
SpdySendStatus send_status);
|
|
|
|
// Sends a DATA frame. The delegate will be notified via
|
|
// OnDataSent() when the send is complete. |send_status| must be
|
|
// MORE_DATA_TO_SEND for bidirectional streams; for request/response
|
|
// streams, it must be MORE_DATA_TO_SEND if there is more data to
|
|
// upload, or NO_MORE_DATA_TO_SEND if not.
|
|
void SendData(IOBuffer* data, int length, SpdySendStatus send_status);
|
|
|
|
// Fills SSL info in |ssl_info| and returns true when SSL is in use.
|
|
bool GetSSLInfo(SSLInfo* ssl_info) const;
|
|
|
|
// Returns true if ALPN was negotiated for the underlying socket.
|
|
bool WasAlpnNegotiated() const;
|
|
|
|
// Returns the protocol negotiated via ALPN for the underlying socket.
|
|
NextProto GetNegotiatedProtocol() const;
|
|
|
|
// If the stream is stalled on sending data, but the session is not
|
|
// stalled on sending data and |send_window_size_| is positive, then
|
|
// set |send_stalled_by_flow_control_| to false and unstall the data
|
|
// sending. Called by the session or by the stream itself. Must be
|
|
// called only when the stream is still open.
|
|
enum ShouldRequeueStream { Requeue, DoNotRequeue };
|
|
ShouldRequeueStream PossiblyResumeIfSendStalled();
|
|
|
|
// Returns whether or not this stream is closed. Note that the only
|
|
// time a stream is closed and not deleted is in its delegate's
|
|
// OnClose() method.
|
|
bool IsClosed() const;
|
|
|
|
// Returns whether the streams local endpoint is closed.
|
|
// The remote endpoint may still be active.
|
|
bool IsLocallyClosed() const;
|
|
|
|
// Returns whether this stream is IDLE: request and response headers
|
|
// have neither been sent nor receieved.
|
|
bool IsIdle() const;
|
|
|
|
// Returns whether or not this stream is fully open: that request and
|
|
// response headers are complete, and it is not in a half-closed state.
|
|
bool IsOpen() const;
|
|
|
|
// Returns whether the stream is reserved by remote endpoint: server has sent
|
|
// intended request headers for a pushed stream, but haven't started response
|
|
// yet.
|
|
bool IsReservedRemote() const;
|
|
|
|
int response_status() const { return response_status_; }
|
|
|
|
void AddRawReceivedBytes(size_t received_bytes);
|
|
void AddRawSentBytes(size_t sent_bytes);
|
|
|
|
int64_t raw_received_bytes() const { return raw_received_bytes_; }
|
|
int64_t raw_sent_bytes() const { return raw_sent_bytes_; }
|
|
int recv_bytes() const { return recv_bytes_; }
|
|
|
|
bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const;
|
|
|
|
// Get the URL from the appropriate stream headers, or the empty
|
|
// GURL() if it is unknown.
|
|
const GURL& GetUrlFromHeaders() const { return url_from_header_block_; }
|
|
|
|
// Returns the estimate of dynamically allocated memory in bytes.
|
|
size_t EstimateMemoryUsage() const;
|
|
|
|
private:
|
|
class HeadersBufferProducer;
|
|
|
|
// SpdyStream states and transitions are modeled
|
|
// on the HTTP/2 stream state machine. All states and transitions
|
|
// are modeled, with the exceptions of RESERVED_LOCAL (the client
|
|
// cannot initate push streams), and the transition to OPEN due to
|
|
// a remote HEADERS (the client can only initate streams).
|
|
enum State {
|
|
STATE_IDLE,
|
|
STATE_OPEN,
|
|
STATE_HALF_CLOSED_LOCAL_UNCLAIMED,
|
|
STATE_HALF_CLOSED_LOCAL,
|
|
STATE_HALF_CLOSED_REMOTE,
|
|
STATE_RESERVED_REMOTE,
|
|
STATE_CLOSED,
|
|
};
|
|
|
|
// Per RFC 7540 Section 8.1, an HTTP response consists of:
|
|
// * zero or more header blocks with informational (1xx) HTTP status,
|
|
// * one header block,
|
|
// * zero or more DATA frames,
|
|
// * zero or one header block ("trailers").
|
|
// Each header block must have a ":status" header field. SpdyStream enforces
|
|
// these requirements, and resets the stream if they are not met.
|
|
enum ResponseState {
|
|
READY_FOR_HEADERS,
|
|
READY_FOR_DATA_OR_TRAILERS,
|
|
TRAILERS_RECEIVED
|
|
};
|
|
|
|
// Update the histograms. Can safely be called repeatedly, but should only
|
|
// be called after the stream has completed.
|
|
void UpdateHistograms();
|
|
|
|
// When a server-push stream is claimed by SetDelegate(), this function is
|
|
// posted on the current MessageLoop to replay everything the server has sent.
|
|
// From the perspective of SpdyStream's state machine, headers, data, and
|
|
// FIN states received prior to the delegate being attached have not yet been
|
|
// read. While buffered by |pending_recv_data_| it's not until
|
|
// PushedStreamReplay() is invoked that reads are considered
|
|
// to have occurred, driving the state machine forward.
|
|
void PushedStreamReplay();
|
|
|
|
// Produces the HEADERS frame for the stream. The stream must
|
|
// already be activated.
|
|
std::unique_ptr<SpdySerializedFrame> ProduceHeadersFrame();
|
|
|
|
// Queues the send for next frame of the remaining data in
|
|
// |pending_send_data_|. Must be called only when
|
|
// |pending_send_data_| is set.
|
|
void QueueNextDataFrame();
|
|
|
|
// Saves the given headers into |response_headers_| and calls
|
|
// OnHeadersReceived() on the delegate if attached.
|
|
void SaveResponseHeaders(const SpdyHeaderBlock& response_headers);
|
|
|
|
static SpdyString DescribeState(State state);
|
|
|
|
const SpdyStreamType type_;
|
|
|
|
SpdyStreamId stream_id_;
|
|
const GURL url_;
|
|
RequestPriority priority_;
|
|
|
|
bool send_stalled_by_flow_control_;
|
|
|
|
// Current send window size.
|
|
int32_t send_window_size_;
|
|
|
|
// Maximum receive window size. Each time a WINDOW_UPDATE is sent, it
|
|
// restores the receive window size to this value.
|
|
int32_t max_recv_window_size_;
|
|
|
|
// Sum of |session_unacked_recv_window_bytes_| and current receive window
|
|
// size.
|
|
// TODO(bnc): Rename or change semantics so that |window_size_| is actual
|
|
// window size.
|
|
int32_t recv_window_size_;
|
|
|
|
// When bytes are consumed, SpdyIOBuffer destructor calls back to SpdySession,
|
|
// and this member keeps count of them until the corresponding WINDOW_UPDATEs
|
|
// are sent.
|
|
int32_t unacked_recv_window_bytes_;
|
|
|
|
const base::WeakPtr<SpdySession> session_;
|
|
|
|
// The transaction should own the delegate.
|
|
SpdyStream::Delegate* delegate_;
|
|
|
|
// The headers for the request to send.
|
|
bool request_headers_valid_;
|
|
SpdyHeaderBlock request_headers_;
|
|
|
|
// The URL from the request headers.
|
|
GURL url_from_header_block_;
|
|
|
|
// Data waiting to be sent, and the close state of the local endpoint
|
|
// after the data is fully written.
|
|
scoped_refptr<DrainableIOBuffer> pending_send_data_;
|
|
SpdySendStatus pending_send_status_;
|
|
|
|
// Data waiting to be received, and the close state of the remote endpoint
|
|
// after the data is fully read. Specifically, data received before the
|
|
// delegate is attached must be buffered and later replayed. A remote FIN
|
|
// is represented by a final, zero-length buffer.
|
|
std::vector<std::unique_ptr<SpdyBuffer>> pending_recv_data_;
|
|
|
|
// 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_;
|
|
|
|
SpdyHeaderBlock response_headers_;
|
|
ResponseState response_state_;
|
|
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_;
|
|
|
|
NetLogWithSource net_log_;
|
|
|
|
base::TimeTicks send_time_;
|
|
base::TimeTicks recv_first_byte_time_;
|
|
base::TimeTicks recv_last_byte_time_;
|
|
|
|
// Number of bytes that have been received on this stream, including frame
|
|
// overhead and headers.
|
|
int64_t raw_received_bytes_;
|
|
// Number of bytes that have been sent on this stream, including frame
|
|
// overhead and headers.
|
|
int64_t raw_sent_bytes_;
|
|
|
|
// Number of data bytes that have been sent/received on this stream, not
|
|
// including frame overhead. Note that this does not count headers.
|
|
int send_bytes_;
|
|
int recv_bytes_;
|
|
|
|
// Guards calls of delegate write handlers ensuring |this| is not destroyed.
|
|
// TODO(jgraettinger): Consider removing after crbug.com/35511 is tracked
|
|
// down.
|
|
bool write_handler_guard_;
|
|
|
|
base::WeakPtrFactory<SpdyStream> weak_ptr_factory_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SpdyStream);
|
|
};
|
|
|
|
} // namespace net
|
|
|
|
#endif // NET_SPDY_CHROMIUM_SPDY_STREAM_H_
|