1 // Copyright 2019 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 #include "quiche/quic/core/http/quic_send_control_stream.h"
6
7 #include <cstdint>
8 #include <memory>
9
10 #include "absl/base/macros.h"
11 #include "absl/strings/string_view.h"
12 #include "quiche/quic/core/crypto/quic_random.h"
13 #include "quiche/quic/core/http/http_constants.h"
14 #include "quiche/quic/core/http/quic_spdy_session.h"
15 #include "quiche/quic/core/quic_session.h"
16 #include "quiche/quic/core/quic_types.h"
17 #include "quiche/quic/core/quic_utils.h"
18 #include "quiche/quic/platform/api/quic_logging.h"
19
20 namespace quic {
21 namespace {
22
23 } // anonymous namespace
24
QuicSendControlStream(QuicStreamId id,QuicSpdySession * spdy_session,const SettingsFrame & settings)25 QuicSendControlStream::QuicSendControlStream(QuicStreamId id,
26 QuicSpdySession* spdy_session,
27 const SettingsFrame& settings)
28 : QuicStream(id, spdy_session, /*is_static = */ true, WRITE_UNIDIRECTIONAL),
29 settings_sent_(false),
30 settings_(settings),
31 spdy_session_(spdy_session) {}
32
OnStreamReset(const QuicRstStreamFrame &)33 void QuicSendControlStream::OnStreamReset(const QuicRstStreamFrame& /*frame*/) {
34 QUIC_BUG(quic_bug_10382_1)
35 << "OnStreamReset() called for write unidirectional stream.";
36 }
37
OnStopSending(QuicResetStreamError)38 bool QuicSendControlStream::OnStopSending(QuicResetStreamError /* code */) {
39 stream_delegate()->OnStreamError(
40 QUIC_HTTP_CLOSED_CRITICAL_STREAM,
41 "STOP_SENDING received for send control stream");
42 return false;
43 }
44
MaybeSendSettingsFrame()45 void QuicSendControlStream::MaybeSendSettingsFrame() {
46 if (settings_sent_) {
47 return;
48 }
49
50 QuicConnection::ScopedPacketFlusher flusher(session()->connection());
51 // Send the stream type on so the peer knows about this stream.
52 char data[sizeof(kControlStream)];
53 QuicDataWriter writer(ABSL_ARRAYSIZE(data), data);
54 writer.WriteVarInt62(kControlStream);
55 WriteOrBufferData(absl::string_view(writer.data(), writer.length()), false,
56 nullptr);
57
58 SettingsFrame settings = settings_;
59 // https://tools.ietf.org/html/draft-ietf-quic-http-25#section-7.2.4.1
60 // specifies that setting identifiers of 0x1f * N + 0x21 are reserved and
61 // greasing should be attempted.
62 if (!GetQuicFlag(quic_enable_http3_grease_randomness)) {
63 settings.values[0x40] = 20;
64 } else {
65 uint32_t result;
66 QuicRandom::GetInstance()->RandBytes(&result, sizeof(result));
67 uint64_t setting_id = 0x1fULL * static_cast<uint64_t>(result) + 0x21ULL;
68 QuicRandom::GetInstance()->RandBytes(&result, sizeof(result));
69 settings.values[setting_id] = result;
70 }
71
72 std::string settings_frame = HttpEncoder::SerializeSettingsFrame(settings);
73 QUIC_DVLOG(1) << "Control stream " << id() << " is writing settings frame "
74 << settings;
75 if (spdy_session_->debug_visitor()) {
76 spdy_session_->debug_visitor()->OnSettingsFrameSent(settings);
77 }
78 WriteOrBufferData(settings_frame, /*fin = */ false, nullptr);
79 settings_sent_ = true;
80
81 // https://tools.ietf.org/html/draft-ietf-quic-http-25#section-7.2.9
82 // specifies that a reserved frame type has no semantic meaning and should be
83 // discarded. A greasing frame is added here.
84 WriteOrBufferData(HttpEncoder::SerializeGreasingFrame(), /*fin = */ false,
85 nullptr);
86 }
87
WritePriorityUpdate(QuicStreamId stream_id,HttpStreamPriority priority)88 void QuicSendControlStream::WritePriorityUpdate(QuicStreamId stream_id,
89 HttpStreamPriority priority) {
90 QuicConnection::ScopedPacketFlusher flusher(session()->connection());
91 MaybeSendSettingsFrame();
92
93 const std::string priority_field_value =
94 SerializePriorityFieldValue(priority);
95 PriorityUpdateFrame priority_update_frame{stream_id, priority_field_value};
96 if (spdy_session_->debug_visitor()) {
97 spdy_session_->debug_visitor()->OnPriorityUpdateFrameSent(
98 priority_update_frame);
99 }
100
101 std::string frame =
102 HttpEncoder::SerializePriorityUpdateFrame(priority_update_frame);
103 QUIC_DVLOG(1) << "Control Stream " << id() << " is writing "
104 << priority_update_frame;
105 WriteOrBufferData(frame, false, nullptr);
106 }
107
SendGoAway(QuicStreamId id)108 void QuicSendControlStream::SendGoAway(QuicStreamId id) {
109 QuicConnection::ScopedPacketFlusher flusher(session()->connection());
110 MaybeSendSettingsFrame();
111
112 GoAwayFrame frame;
113 frame.id = id;
114 if (spdy_session_->debug_visitor()) {
115 spdy_session_->debug_visitor()->OnGoAwayFrameSent(id);
116 }
117
118 WriteOrBufferData(HttpEncoder::SerializeGoAwayFrame(frame), false, nullptr);
119 }
120
121 } // namespace quic
122