QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 1 | // Copyright (c) 2012 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 | // A toy server specific QuicSession subclass. |
| 6 | |
| 7 | #ifndef QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_ |
| 8 | #define QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_ |
| 9 | |
| 10 | #include <stdint.h> |
| 11 | |
| 12 | #include <list> |
| 13 | #include <memory> |
| 14 | #include <set> |
| 15 | #include <string> |
| 16 | #include <utility> |
| 17 | #include <vector> |
| 18 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 19 | #include "net/third_party/quiche/src/quic/core/http/quic_server_session_base.h" |
| 20 | #include "net/third_party/quiche/src/quic/core/http/quic_spdy_session.h" |
| 21 | #include "net/third_party/quiche/src/quic/core/quic_crypto_server_stream.h" |
| 22 | #include "net/third_party/quiche/src/quic/core/quic_packets.h" |
| 23 | #include "net/third_party/quiche/src/quic/platform/api/quic_containers.h" |
| 24 | #include "net/third_party/quiche/src/quic/tools/quic_backend_response.h" |
| 25 | #include "net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h" |
| 26 | #include "net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h" |
| 27 | |
| 28 | namespace quic { |
| 29 | |
| 30 | namespace test { |
| 31 | class QuicSimpleServerSessionPeer; |
| 32 | } // namespace test |
| 33 | |
| 34 | class QuicSimpleServerSession : public QuicServerSessionBase { |
| 35 | public: |
| 36 | // A PromisedStreamInfo is an element of the queue to store promised |
| 37 | // stream which hasn't been created yet. It keeps a mapping between promised |
| 38 | // stream id with its priority and the headers sent out in PUSH_PROMISE. |
| 39 | struct PromisedStreamInfo { |
| 40 | public: |
| 41 | PromisedStreamInfo(spdy::SpdyHeaderBlock request_headers, |
| 42 | QuicStreamId stream_id, |
fayang | 9a42376 | 2019-07-31 08:12:58 -0700 | [diff] [blame] | 43 | const spdy::SpdyStreamPrecedence& precedence) |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 44 | : request_headers(std::move(request_headers)), |
| 45 | stream_id(stream_id), |
fayang | 9a42376 | 2019-07-31 08:12:58 -0700 | [diff] [blame] | 46 | precedence(precedence), |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 47 | is_cancelled(false) {} |
| 48 | spdy::SpdyHeaderBlock request_headers; |
| 49 | QuicStreamId stream_id; |
fayang | 9a42376 | 2019-07-31 08:12:58 -0700 | [diff] [blame] | 50 | spdy::SpdyStreamPrecedence precedence; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 51 | bool is_cancelled; |
| 52 | }; |
| 53 | |
| 54 | // Takes ownership of |connection|. |
| 55 | QuicSimpleServerSession(const QuicConfig& config, |
| 56 | const ParsedQuicVersionVector& supported_versions, |
| 57 | QuicConnection* connection, |
| 58 | QuicSession::Visitor* visitor, |
nharper | 5f23a2d | 2020-02-20 10:44:09 -0800 | [diff] [blame] | 59 | QuicCryptoServerStreamBase::Helper* helper, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 60 | const QuicCryptoServerConfig* crypto_config, |
| 61 | QuicCompressedCertsCache* compressed_certs_cache, |
| 62 | QuicSimpleServerBackend* quic_simple_server_backend); |
| 63 | QuicSimpleServerSession(const QuicSimpleServerSession&) = delete; |
| 64 | QuicSimpleServerSession& operator=(const QuicSimpleServerSession&) = delete; |
| 65 | |
| 66 | ~QuicSimpleServerSession() override; |
| 67 | |
| 68 | // Override base class to detact client sending data on server push stream. |
| 69 | void OnStreamFrame(const QuicStreamFrame& frame) override; |
| 70 | |
| 71 | // Send out PUSH_PROMISE for all |resources| promised stream id in each frame |
| 72 | // will increase by 2 for each item in |resources|. |
| 73 | // And enqueue HEADERS block in those PUSH_PROMISED for sending push response |
| 74 | // later. |
| 75 | virtual void PromisePushResources( |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 76 | const std::string& request_url, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 77 | const std::list<QuicBackendResponse::ServerPushInfo>& resources, |
| 78 | QuicStreamId original_stream_id, |
fayang | 9a42376 | 2019-07-31 08:12:58 -0700 | [diff] [blame] | 79 | const spdy::SpdyStreamPrecedence& original_precedence, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 80 | const spdy::SpdyHeaderBlock& original_request_headers); |
| 81 | |
fkastenholz | 8556dc2 | 2019-07-18 12:42:38 -0700 | [diff] [blame] | 82 | void OnCanCreateNewOutgoingStream(bool unidirectional) override; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 83 | |
| 84 | protected: |
| 85 | // QuicSession methods: |
| 86 | QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override; |
renjietang | baea59c | 2019-05-29 15:08:14 -0700 | [diff] [blame] | 87 | QuicSpdyStream* CreateIncomingStream(PendingStream* pending) override; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 88 | QuicSimpleServerStream* CreateOutgoingBidirectionalStream() override; |
| 89 | QuicSimpleServerStream* CreateOutgoingUnidirectionalStream() override; |
| 90 | // Override to return true for locally preserved server push stream. |
| 91 | void HandleFrameOnNonexistentOutgoingStream(QuicStreamId stream_id) override; |
| 92 | // Override to handle reseting locally preserved streams. |
| 93 | void HandleRstOnValidNonexistentStream( |
| 94 | const QuicRstStreamFrame& frame) override; |
| 95 | |
| 96 | // QuicServerSessionBaseMethod: |
nharper | e5e28f9 | 2020-01-03 14:10:07 -0800 | [diff] [blame] | 97 | std::unique_ptr<QuicCryptoServerStreamBase> CreateQuicCryptoServerStream( |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 98 | const QuicCryptoServerConfig* crypto_config, |
| 99 | QuicCompressedCertsCache* compressed_certs_cache) override; |
| 100 | |
| 101 | QuicSimpleServerBackend* server_backend() { |
| 102 | return quic_simple_server_backend_; |
| 103 | } |
| 104 | |
renjietang | 1a33a0c | 2019-08-12 12:05:31 -0700 | [diff] [blame] | 105 | void MaybeInitializeHttp3UnidirectionalStreams() override; |
| 106 | |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 107 | private: |
| 108 | friend class test::QuicSimpleServerSessionPeer; |
| 109 | |
| 110 | // Create a server push headers block by copying request's headers block. |
| 111 | // But replace or add these pseudo-headers as they are specific to each |
| 112 | // request: |
| 113 | // :authority, :path, :method, :scheme, referer. |
| 114 | // Copying the rest headers ensures they are the same as the original |
| 115 | // request, especially cookies. |
| 116 | spdy::SpdyHeaderBlock SynthesizePushRequestHeaders( |
vasilvv | c48c871 | 2019-03-11 13:38:16 -0700 | [diff] [blame] | 117 | std::string request_url, |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 118 | QuicBackendResponse::ServerPushInfo resource, |
| 119 | const spdy::SpdyHeaderBlock& original_request_headers); |
| 120 | |
| 121 | // Send PUSH_PROMISE frame on headers stream. |
| 122 | void SendPushPromise(QuicStreamId original_stream_id, |
| 123 | QuicStreamId promised_stream_id, |
| 124 | spdy::SpdyHeaderBlock headers); |
| 125 | |
| 126 | // Fetch response from cache for request headers enqueued into |
| 127 | // promised_headers_and_streams_ and send them on dedicated stream until |
| 128 | // reaches max_open_stream_ limit. |
| 129 | // Called when return value of GetNumOpenOutgoingStreams() changes: |
| 130 | // CloseStreamInner(); |
| 131 | // StreamDraining(); |
| 132 | // Note that updateFlowControlOnFinalReceivedByteOffset() won't change the |
| 133 | // return value becasue all push streams are impossible to become locally |
| 134 | // closed. Since a locally preserved stream becomes remotely closed after |
| 135 | // HandlePromisedPushRequests() starts to process it, and if it is reset |
| 136 | // locally afterwards, it will be immediately become closed and never get into |
| 137 | // locally_closed_stream_highest_offset_. So all the streams in this map |
| 138 | // are not outgoing streams. |
| 139 | void HandlePromisedPushRequests(); |
| 140 | |
| 141 | // Keep track of the highest stream id which has been sent in PUSH_PROMISE. |
| 142 | QuicStreamId highest_promised_stream_id_; |
| 143 | |
| 144 | // Promised streams which hasn't been created yet because of max_open_stream_ |
| 145 | // limit. New element is added to the end of the queue. |
| 146 | // Since outgoing stream is created in sequence, stream_id of each element in |
| 147 | // the queue also increases by 2 from previous one's. The front element's |
| 148 | // stream_id is always next_outgoing_stream_id_, and the last one is always |
| 149 | // highest_promised_stream_id_. |
wub | a750aab | 2020-02-10 06:43:15 -0800 | [diff] [blame] | 150 | QuicCircularDeque<PromisedStreamInfo> promised_streams_; |
QUICHE team | a6ef0a6 | 2019-03-07 20:34:33 -0500 | [diff] [blame] | 151 | |
| 152 | QuicSimpleServerBackend* quic_simple_server_backend_; // Not owned. |
| 153 | }; |
| 154 | |
| 155 | } // namespace quic |
| 156 | |
| 157 | #endif // QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_SESSION_H_ |