1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// Copyright 2019 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.
#include "net/third_party/quiche/src/quic/core/http/quic_send_control_stream.h"
#include <memory>
#include "net/third_party/quiche/src/quic/core/http/http_constants.h"
#include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h"
#include "net/third_party/quiche/src/quic/core/quic_session.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
namespace quic {
QuicSendControlStream::QuicSendControlStream(
QuicStreamId id,
QuicSession* session,
uint64_t qpack_maximum_dynamic_table_capacity,
uint64_t qpack_maximum_blocked_streams,
uint64_t max_inbound_header_list_size)
: QuicStream(id, session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
settings_sent_(false),
qpack_maximum_dynamic_table_capacity_(
qpack_maximum_dynamic_table_capacity),
qpack_maximum_blocked_streams_(qpack_maximum_blocked_streams),
max_inbound_header_list_size_(max_inbound_header_list_size) {}
void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
// TODO(renjietang) Change the error code to H/3 specific
// HTTP_CLOSED_CRITICAL_STREAM.
session()->connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Attempt to reset send control stream",
ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
}
void QuicSendControlStream::MaybeSendSettingsFrame() {
if (settings_sent_) {
return;
}
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
// Send the stream type on so the peer knows about this stream.
char data[sizeof(kControlStream)];
QuicDataWriter writer(QUIC_ARRAYSIZE(data), data);
writer.WriteVarInt62(kControlStream);
WriteOrBufferData(QuicStringPiece(writer.data(), writer.length()), false,
nullptr);
SettingsFrame settings;
settings.values[SETTINGS_QPACK_MAX_TABLE_CAPACITY] =
qpack_maximum_dynamic_table_capacity_;
settings.values[SETTINGS_QPACK_BLOCKED_STREAMS] =
qpack_maximum_blocked_streams_;
settings.values[SETTINGS_MAX_HEADER_LIST_SIZE] =
max_inbound_header_list_size_;
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
HttpEncoder::SerializeSettingsFrame(settings, &buffer);
QUIC_DVLOG(1) << "Control stream " << id() << " is writing settings frame "
<< settings;
QuicSpdySession* spdy_session = static_cast<QuicSpdySession*>(session());
if (spdy_session->debug_visitor() != nullptr) {
spdy_session->debug_visitor()->OnSettingsFrameSent(settings);
}
WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length),
/*fin = */ false, nullptr);
settings_sent_ = true;
}
void QuicSendControlStream::WritePriority(const PriorityFrame& priority) {
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
MaybeSendSettingsFrame();
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
HttpEncoder::SerializePriorityFrame(priority, &buffer);
QUIC_DVLOG(1) << "Control Stream " << id() << " is writing " << priority;
WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), false,
nullptr);
}
void QuicSendControlStream::SendMaxPushIdFrame(PushId max_push_id) {
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
MaybeSendSettingsFrame();
MaxPushIdFrame frame;
frame.push_id = max_push_id;
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
HttpEncoder::SerializeMaxPushIdFrame(frame, &buffer);
WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length),
/*fin = */ false, nullptr);
}
void QuicSendControlStream::SendGoAway(QuicStreamId stream_id) {
QuicConnection::ScopedPacketFlusher flusher(session()->connection());
MaybeSendSettingsFrame();
GoAwayFrame frame;
// If the peer hasn't created any stream yet. Use stream id 0 to indicate no
// request is accepted.
if (stream_id ==
QuicUtils::GetInvalidStreamId(session()->transport_version())) {
stream_id = 0;
}
frame.stream_id = stream_id;
std::unique_ptr<char[]> buffer;
QuicByteCount frame_length =
HttpEncoder::SerializeGoAwayFrame(frame, &buffer);
WriteOrBufferData(QuicStringPiece(buffer.get(), frame_length), false,
nullptr);
}
} // namespace quic
|