#ifndef NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
#define NET_QUIC_QUIC_CHROMIUM_CLIENT_STREAM_H_
#include <stddef.h>
#include <memory>
#include <string_view>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "net/base/completion_once_callback.h"
#include "net/base/idempotency.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_info.h"
#include "net/http/http_stream.h"
#include "net/log/net_log_with_source.h"
#include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
#include "net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream.h"
#include "net/third_party/quiche/src/quiche/quic/core/quic_server_id.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace quic {
class QuicSpdyClientSessionBase;
}
namespace net {
class NET_EXPORT_PRIVATE QuicChromiumClientStream
: public quic::QuicSpdyStream {
public:
class NET_EXPORT_PRIVATE Handle {
public:
Handle(const Handle&) = delete;
Handle& operator=(const Handle&) = delete;
~Handle();
bool IsOpen() { return stream_ != nullptr; }
int ReadInitialHeaders(quiche::HttpHeaderBlock* header_block,
CompletionOnceCallback callback);
int ReadBody(IOBuffer* buffer,
int buffer_len,
CompletionOnceCallback callback);
int ReadTrailingHeaders(quiche::HttpHeaderBlock* header_block,
CompletionOnceCallback callback);
int WriteHeaders(
quiche::HttpHeaderBlock header_block,
bool fin,
quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
ack_notifier_delegate);
int WriteStreamData(std::string_view data,
bool fin,
CompletionOnceCallback callback);
int WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
const std::vector<int>& lengths,
bool fin,
CompletionOnceCallback callback);
int WriteConnectUdpPayload(std::string_view packet);
int Read(IOBuffer* buf, int buf_len);
void OnFinRead();
void DisableConnectionMigrationToCellularNetwork();
void SetPriority(const quic::QuicStreamPriority& priority);
void Reset(quic::QuicRstStreamErrorCode error_code);
void RegisterHttp3DatagramVisitor(Http3DatagramVisitor* visitor);
void UnregisterHttp3DatagramVisitor();
quic::QuicStreamId id() const;
quic::QuicErrorCode connection_error() const;
quic::QuicRstStreamErrorCode stream_error() const;
uint64_t connection_wire_error() const;
uint64_t ietf_application_error() const;
bool fin_sent() const;
bool fin_received() const;
uint64_t stream_bytes_read() const;
uint64_t stream_bytes_written() const;
size_t NumBytesConsumed() const;
bool HasBytesToRead() const;
bool IsDoneReading() const;
bool IsFirstStream() const;
base::TimeTicks first_early_hints_time() const {
return first_early_hints_time_;
}
base::TimeTicks headers_received_start_time() const {
return headers_received_start_time_;
}
bool can_migrate_to_cellular_network();
const NetLogWithSource& net_log() const;
void SetRequestIdempotency(Idempotency idempotency);
Idempotency GetRequestIdempotency() const;
quic::QuicPacketLength GetGuaranteedLargestMessagePayload() const;
bool SupportsH3Datagram() const {
return stream_ && stream_->SupportsH3Datagram();
}
private:
friend class QuicChromiumClientStream;
explicit Handle(QuicChromiumClientStream* stream);
void OnEarlyHintsAvailable();
void OnInitialHeadersAvailable();
void OnTrailingHeadersAvailable();
void OnDataAvailable();
void OnCanWrite();
void OnClose();
void OnError(int error);
void InvokeCallbacksOnClose(int error);
void SaveState();
void SetCallback(CompletionOnceCallback new_callback,
CompletionOnceCallback* callback);
void ResetAndRun(CompletionOnceCallback callback, int rv);
int HandleIOComplete(int rv);
raw_ptr<QuicChromiumClientStream> stream_;
bool may_invoke_callbacks_ = true;
CompletionOnceCallback read_headers_callback_;
raw_ptr<quiche::HttpHeaderBlock> read_headers_buffer_ = nullptr;
CompletionOnceCallback read_body_callback_;
scoped_refptr<IOBuffer> read_body_buffer_;
int read_body_buffer_len_ = 0;
CompletionOnceCallback write_callback_;
quic::QuicStreamId id_;
quic::QuicErrorCode connection_error_;
quic::QuicRstStreamErrorCode stream_error_;
uint64_t connection_wire_error_ = 0;
uint64_t ietf_application_error_ = 0;
bool fin_sent_;
bool fin_received_;
uint64_t stream_bytes_read_;
uint64_t stream_bytes_written_;
bool is_done_reading_;
bool is_first_stream_;
size_t num_bytes_consumed_;
Idempotency idempotency_ = DEFAULT_IDEMPOTENCY;
int net_error_ = ERR_UNEXPECTED;
NetLogWithSource net_log_;
base::TimeTicks first_early_hints_time_;
base::TimeTicks headers_received_start_time_;
base::WeakPtrFactory<Handle> weak_factory_{this};
};
QuicChromiumClientStream(
quic::QuicStreamId id,
quic::QuicSpdyClientSessionBase* session,
quic::QuicServerId server_id,
quic::StreamType type,
const NetLogWithSource& net_log,
const NetworkTrafficAnnotationTag& traffic_annotation);
QuicChromiumClientStream(
quic::PendingStream* pending,
quic::QuicSpdyClientSessionBase* session,
quic::QuicServerId server_id,
const NetLogWithSource& net_log,
const NetworkTrafficAnnotationTag& traffic_annotation);
QuicChromiumClientStream(const QuicChromiumClientStream&) = delete;
QuicChromiumClientStream& operator=(const QuicChromiumClientStream&) = delete;
~QuicChromiumClientStream() override;
void OnInitialHeadersComplete(
bool fin,
size_t frame_len,
const quic::QuicHeaderList& header_list) override;
void OnTrailingHeadersComplete(
bool fin,
size_t frame_len,
const quic::QuicHeaderList& header_list) override;
void OnBodyAvailable() override;
void OnClose() override;
void OnCanWrite() override;
size_t WriteHeaders(
quiche::HttpHeaderBlock header_block,
bool fin,
quiche::QuicheReferenceCountedPointer<quic::QuicAckListenerInterface>
ack_listener) override;
using quic::QuicSpdyStream::SetPriority;
bool WriteStreamData(std::string_view data, bool fin);
bool WritevStreamData(const std::vector<scoped_refptr<IOBuffer>>& buffers,
const std::vector<int>& lengths,
bool fin);
std::unique_ptr<QuicChromiumClientStream::Handle> CreateHandle();
void ClearHandle();
void OnError(int error);
int Read(IOBuffer* buf, int buf_len);
const NetLogWithSource& net_log() const { return net_log_; }
void DisableConnectionMigrationToCellularNetwork();
bool can_migrate_to_cellular_network() {
return can_migrate_to_cellular_network_;
}
bool SupportsH3Datagram() const;
quic::QuicPacketLength GetGuaranteedLargestMessagePayload() const;
bool IsFirstStream();
int DeliverEarlyHints(quiche::HttpHeaderBlock* header_block);
int DeliverInitialHeaders(quiche::HttpHeaderBlock* header_block);
bool DeliverTrailingHeaders(quiche::HttpHeaderBlock* header_block,
int* frame_len);
static constexpr char kHttp3DatagramDroppedHistogram[] =
"Net.QuicChromiumClientStream."
"Http3DatagramDroppedOnWriteConnectUdpPayload";
using quic::QuicSpdyStream::HasBufferedData;
using quic::QuicStream::sequencer;
private:
void NotifyHandleOfInitialHeadersAvailableLater();
void NotifyHandleOfInitialHeadersAvailable();
void NotifyHandleOfTrailingHeadersAvailableLater();
void NotifyHandleOfTrailingHeadersAvailable();
void NotifyHandleOfDataAvailableLater();
void NotifyHandleOfDataAvailable();
NetLogWithSource net_log_;
raw_ptr<Handle> handle_ = nullptr;
bool initial_headers_sent_ = false;
raw_ptr<quic::QuicSpdyClientSessionBase> session_;
const quic::QuicServerId server_id_;
quic::QuicTransportVersion quic_version_;
bool can_migrate_to_cellular_network_ = true;
bool initial_headers_arrived_ = false;
bool headers_delivered_ = false;
quiche::HttpHeaderBlock initial_headers_;
size_t initial_headers_frame_len_ = 0;
size_t trailing_headers_frame_len_ = 0;
struct EarlyHints {
EarlyHints(quiche::HttpHeaderBlock headers, size_t frame_len)
: headers(std::move(headers)), frame_len(frame_len) {}
EarlyHints(EarlyHints&& other) = default;
EarlyHints& operator=(EarlyHints&& other) = default;
EarlyHints(const EarlyHints& other) = delete;
EarlyHints& operator=(const EarlyHints& other) = delete;
quiche::HttpHeaderBlock headers;
size_t frame_len = 0;
};
base::circular_deque<EarlyHints> early_hints_;
base::WeakPtrFactory<QuicChromiumClientStream> weak_factory_{this};
};
}
#endif