• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015 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 base class for the toy client, which connects to a specified port and sends
6 // QUIC request to that endpoint.
7 
8 #ifndef QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_
9 #define QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_
10 
11 #include <string>
12 
13 #include "absl/strings/string_view.h"
14 #include "quiche/quic/core/crypto/crypto_handshake.h"
15 #include "quiche/quic/core/http/quic_client_push_promise_index.h"
16 #include "quiche/quic/core/http/quic_spdy_client_session.h"
17 #include "quiche/quic/core/http/quic_spdy_client_stream.h"
18 #include "quiche/quic/core/quic_config.h"
19 #include "quiche/quic/platform/api/quic_socket_address.h"
20 #include "quiche/quic/tools/quic_client_base.h"
21 #include "quiche/spdy/core/http2_header_block.h"
22 
23 namespace quic {
24 
25 class ProofVerifier;
26 class QuicServerId;
27 class SessionCache;
28 
29 class QuicSpdyClientBase : public QuicClientBase,
30                            public QuicClientPushPromiseIndex::Delegate,
31                            public QuicSpdyStream::Visitor {
32  public:
33   // A ResponseListener is notified when a complete response is received.
34   class ResponseListener {
35    public:
ResponseListener()36     ResponseListener() {}
~ResponseListener()37     virtual ~ResponseListener() {}
38     virtual void OnCompleteResponse(
39         QuicStreamId id, const spdy::Http2HeaderBlock& response_headers,
40         absl::string_view response_body) = 0;
41   };
42 
43   // A piece of data that can be sent multiple times. For example, it can be a
44   // HTTP request that is resent after a connect=>version negotiation=>reconnect
45   // sequence.
46   class QuicDataToResend {
47    public:
48     // |headers| may be null, since it's possible to send data without headers.
49     QuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers,
50                      absl::string_view body, bool fin);
51     QuicDataToResend(const QuicDataToResend&) = delete;
52     QuicDataToResend& operator=(const QuicDataToResend&) = delete;
53 
54     virtual ~QuicDataToResend();
55 
56     // Must be overridden by specific classes with the actual method for
57     // re-sending data.
58     virtual void Resend() = 0;
59 
60    protected:
61     std::unique_ptr<spdy::Http2HeaderBlock> headers_;
62     absl::string_view body_;
63     bool fin_;
64   };
65 
66   QuicSpdyClientBase(const QuicServerId& server_id,
67                      const ParsedQuicVersionVector& supported_versions,
68                      const QuicConfig& config,
69                      QuicConnectionHelperInterface* helper,
70                      QuicAlarmFactory* alarm_factory,
71                      std::unique_ptr<NetworkHelper> network_helper,
72                      std::unique_ptr<ProofVerifier> proof_verifier,
73                      std::unique_ptr<SessionCache> session_cache);
74   QuicSpdyClientBase(const QuicSpdyClientBase&) = delete;
75   QuicSpdyClientBase& operator=(const QuicSpdyClientBase&) = delete;
76 
77   ~QuicSpdyClientBase() override;
78 
79   // QuicSpdyStream::Visitor
80   void OnClose(QuicSpdyStream* stream) override;
81 
82   // A spdy session has to call CryptoConnect on top of the regular
83   // initialization.
84   void InitializeSession() override;
85 
86   // Sends an HTTP request and does not wait for response before returning.
87   void SendRequest(const spdy::Http2HeaderBlock& headers,
88                    absl::string_view body, bool fin);
89 
90   // Sends an HTTP request and waits for response before returning.
91   void SendRequestAndWaitForResponse(const spdy::Http2HeaderBlock& headers,
92                                      absl::string_view body, bool fin);
93 
94   // Sends a request simple GET for each URL in |url_list|, and then waits for
95   // each to complete.
96   void SendRequestsAndWaitForResponse(const std::vector<std::string>& url_list);
97 
98   // Returns a newly created QuicSpdyClientStream.
99   virtual QuicSpdyClientStream* CreateClientStream();
100 
101   // Returns a the session used for this client downcasted to a
102   // QuicSpdyClientSession.
103   QuicSpdyClientSession* client_session();
104   const QuicSpdyClientSession* client_session() const;
105 
push_promise_index()106   QuicClientPushPromiseIndex* push_promise_index() {
107     return &push_promise_index_;
108   }
109 
110   bool CheckVary(const spdy::Http2HeaderBlock& client_request,
111                  const spdy::Http2HeaderBlock& promise_request,
112                  const spdy::Http2HeaderBlock& promise_response) override;
113   void OnRendezvousResult(QuicSpdyStream*) override;
114 
115   // If the crypto handshake has not yet been confirmed, adds the data to the
116   // queue of data to resend if the client receives a stateless reject.
117   // Otherwise, deletes the data.
118   void MaybeAddQuicDataToResend(
119       std::unique_ptr<QuicDataToResend> data_to_resend);
120 
set_store_response(bool val)121   void set_store_response(bool val) { store_response_ = val; }
122 
123   int latest_response_code() const;
124   const std::string& latest_response_headers() const;
125   const std::string& preliminary_response_headers() const;
126   const spdy::Http2HeaderBlock& latest_response_header_block() const;
127   const std::string& latest_response_body() const;
128   const std::string& latest_response_trailers() const;
129 
set_response_listener(std::unique_ptr<ResponseListener> listener)130   void set_response_listener(std::unique_ptr<ResponseListener> listener) {
131     response_listener_ = std::move(listener);
132   }
133 
set_drop_response_body(bool drop_response_body)134   void set_drop_response_body(bool drop_response_body) {
135     drop_response_body_ = drop_response_body;
136   }
drop_response_body()137   bool drop_response_body() const { return drop_response_body_; }
138 
set_enable_web_transport(bool enable_web_transport)139   void set_enable_web_transport(bool enable_web_transport) {
140     enable_web_transport_ = enable_web_transport;
141   }
enable_web_transport()142   bool enable_web_transport() const { return enable_web_transport_; }
143 
set_use_datagram_contexts(bool use_datagram_contexts)144   void set_use_datagram_contexts(bool use_datagram_contexts) {
145     use_datagram_contexts_ = use_datagram_contexts;
146   }
use_datagram_contexts()147   bool use_datagram_contexts() const { return use_datagram_contexts_; }
148 
149   // QuicClientBase methods.
150   bool goaway_received() const override;
151   bool EarlyDataAccepted() override;
152   bool ReceivedInchoateReject() override;
153 
set_max_inbound_header_list_size(size_t size)154   void set_max_inbound_header_list_size(size_t size) {
155     max_inbound_header_list_size_ = size;
156   }
157 
158  protected:
159   int GetNumSentClientHellosFromSession() override;
160   int GetNumReceivedServerConfigUpdatesFromSession() override;
161 
162   // Takes ownership of |connection|.
163   std::unique_ptr<QuicSession> CreateQuicClientSession(
164       const quic::ParsedQuicVersionVector& supported_versions,
165       QuicConnection* connection) override;
166 
167   void ClearDataToResend() override;
168 
169   void ResendSavedData() override;
170 
171   void AddPromiseDataToResend(const spdy::Http2HeaderBlock& headers,
172                               absl::string_view body, bool fin);
173   bool HasActiveRequests() override;
174 
175  private:
176   // Specific QuicClient class for storing data to resend.
177   class ClientQuicDataToResend : public QuicDataToResend {
178    public:
ClientQuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers,absl::string_view body,bool fin,QuicSpdyClientBase * client)179     ClientQuicDataToResend(std::unique_ptr<spdy::Http2HeaderBlock> headers,
180                            absl::string_view body, bool fin,
181                            QuicSpdyClientBase* client)
182         : QuicDataToResend(std::move(headers), body, fin), client_(client) {
183       QUICHE_DCHECK(headers_);
184       QUICHE_DCHECK(client);
185     }
186 
187     ClientQuicDataToResend(const ClientQuicDataToResend&) = delete;
188     ClientQuicDataToResend& operator=(const ClientQuicDataToResend&) = delete;
~ClientQuicDataToResend()189     ~ClientQuicDataToResend() override {}
190 
191     void Resend() override;
192 
193    private:
194     QuicSpdyClientBase* client_;
195   };
196 
197   void SendRequestInternal(spdy::Http2HeaderBlock sanitized_headers,
198                            absl::string_view body, bool fin);
199 
200   // Index of pending promised streams. Must outlive |session_|.
201   QuicClientPushPromiseIndex push_promise_index_;
202 
203   // If true, store the latest response code, headers, and body.
204   bool store_response_;
205   // HTTP response code from most recent response.
206   int latest_response_code_;
207   // HTTP/2 headers from most recent response.
208   std::string latest_response_headers_;
209   // preliminary 100 Continue HTTP/2 headers from most recent response, if any.
210   std::string preliminary_response_headers_;
211   // HTTP/2 headers from most recent response.
212   spdy::Http2HeaderBlock latest_response_header_block_;
213   // Body of most recent response.
214   std::string latest_response_body_;
215   // HTTP/2 trailers from most recent response.
216   std::string latest_response_trailers_;
217 
218   // Listens for full responses.
219   std::unique_ptr<ResponseListener> response_listener_;
220 
221   // Keeps track of any data that must be resent upon a subsequent successful
222   // connection, in case the client receives a stateless reject.
223   std::vector<std::unique_ptr<QuicDataToResend>> data_to_resend_on_connect_;
224 
225   std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
226 
227   bool drop_response_body_ = false;
228   bool enable_web_transport_ = false;
229   bool use_datagram_contexts_ = false;
230   // If not zero, used to set client's max inbound header size before session
231   // initialize.
232   size_t max_inbound_header_list_size_ = 0;
233 };
234 
235 }  // namespace quic
236 
237 #endif  // QUICHE_QUIC_TOOLS_QUIC_SPDY_CLIENT_BASE_H_
238