xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_server_stream_base.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2016 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_spdy_server_stream_base.h"
6 
7 #include "absl/strings/str_cat.h"
8 #include "absl/strings/string_view.h"
9 #include "quiche/quic/core/http/quic_spdy_session.h"
10 #include "quiche/quic/core/quic_error_codes.h"
11 #include "quiche/quic/platform/api/quic_flag_utils.h"
12 #include "quiche/quic/platform/api/quic_flags.h"
13 #include "quiche/quic/platform/api/quic_logging.h"
14 #include "quiche/common/quiche_text_utils.h"
15 
16 namespace quic {
17 
QuicSpdyServerStreamBase(QuicStreamId id,QuicSpdySession * session,StreamType type)18 QuicSpdyServerStreamBase::QuicSpdyServerStreamBase(QuicStreamId id,
19                                                    QuicSpdySession* session,
20                                                    StreamType type)
21     : QuicSpdyStream(id, session, type) {}
22 
QuicSpdyServerStreamBase(PendingStream * pending,QuicSpdySession * session)23 QuicSpdyServerStreamBase::QuicSpdyServerStreamBase(PendingStream* pending,
24                                                    QuicSpdySession* session)
25     : QuicSpdyStream(pending, session) {}
26 
CloseWriteSide()27 void QuicSpdyServerStreamBase::CloseWriteSide() {
28   if (!fin_received() && !rst_received() && sequencer()->ignore_read_data() &&
29       !rst_sent()) {
30     // Early cancel the stream if it has stopped reading before receiving FIN
31     // or RST.
32     QUICHE_DCHECK(fin_sent() || !session()->connection()->connected());
33     // Tell the peer to stop sending further data.
34     QUIC_DVLOG(1) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id();
35     MaybeSendStopSending(QUIC_STREAM_NO_ERROR);
36   }
37 
38   QuicSpdyStream::CloseWriteSide();
39 }
40 
StopReading()41 void QuicSpdyServerStreamBase::StopReading() {
42   if (!fin_received() && !rst_received() && write_side_closed() &&
43       !rst_sent()) {
44     QUICHE_DCHECK(fin_sent());
45     // Tell the peer to stop sending further data.
46     QUIC_DVLOG(1) << " Server: Send QUIC_STREAM_NO_ERROR on stream " << id();
47     MaybeSendStopSending(QUIC_STREAM_NO_ERROR);
48   }
49   QuicSpdyStream::StopReading();
50 }
51 
ValidateReceivedHeaders(const QuicHeaderList & header_list)52 bool QuicSpdyServerStreamBase::ValidateReceivedHeaders(
53     const QuicHeaderList& header_list) {
54   if (!QuicSpdyStream::ValidateReceivedHeaders(header_list)) {
55     return false;
56   }
57 
58   bool saw_connect = false;
59   bool saw_protocol = false;
60   bool saw_path = false;
61   bool saw_scheme = false;
62   bool saw_method = false;
63   bool saw_authority = false;
64   bool is_extended_connect = false;
65   // Check if it is missing any required headers and if there is any disallowed
66   // ones.
67   for (const std::pair<std::string, std::string>& pair : header_list) {
68     if (pair.first == ":method") {
69       saw_method = true;
70       if (pair.second == "CONNECT") {
71         saw_connect = true;
72         if (saw_protocol) {
73           is_extended_connect = true;
74         }
75       }
76     } else if (pair.first == ":protocol") {
77       saw_protocol = true;
78       if (saw_connect) {
79         is_extended_connect = true;
80       }
81     } else if (pair.first == ":scheme") {
82       saw_scheme = true;
83     } else if (pair.first == ":path") {
84       saw_path = true;
85     } else if (pair.first == ":authority") {
86       saw_authority = true;
87     } else if (absl::StrContains(pair.first, ":")) {
88       set_invalid_request_details(
89           absl::StrCat("Unexpected ':' in header ", pair.first, "."));
90       QUIC_DLOG(ERROR) << invalid_request_details();
91       return false;
92     }
93     if (is_extended_connect) {
94       if (!spdy_session()->allow_extended_connect()) {
95         set_invalid_request_details(
96             "Received extended-CONNECT request while it is disabled.");
97         QUIC_DLOG(ERROR) << invalid_request_details();
98         return false;
99       }
100     } else if (saw_method && !saw_connect) {
101       if (saw_protocol) {
102         set_invalid_request_details(
103             "Received non-CONNECT request with :protocol header.");
104         QUIC_DLOG(ERROR) << "Receive non-CONNECT request with :protocol.";
105         return false;
106       }
107     }
108   }
109 
110   if (is_extended_connect) {
111     if (saw_scheme && saw_path && saw_authority) {
112       // Saw all the required pseudo headers.
113       return true;
114     }
115     set_invalid_request_details(
116         "Missing required pseudo headers for extended-CONNECT.");
117     QUIC_DLOG(ERROR) << invalid_request_details();
118     return false;
119   }
120   // This is a vanilla CONNECT or non-CONNECT request.
121   if (saw_connect) {
122     // Check vanilla CONNECT.
123     if (saw_path || saw_scheme) {
124       set_invalid_request_details(
125           "Received invalid CONNECT request with disallowed pseudo header.");
126       QUIC_DLOG(ERROR) << invalid_request_details();
127       return false;
128     }
129     return true;
130   }
131   // Check non-CONNECT request.
132   if (saw_method && saw_authority && saw_path && saw_scheme) {
133     return true;
134   }
135   set_invalid_request_details("Missing required pseudo headers.");
136   QUIC_DLOG(ERROR) << invalid_request_details();
137   return false;
138 }
139 
140 }  // namespace quic
141