summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/http/quic_send_control_stream.cc
blob: ed7cd7ffb40c8b1da3aebcd634aeb8386f51778e (plain)
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