File: http_stream_factory_job.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (522 lines) | stat: -rw-r--r-- 19,845 bytes parent folder | download | duplicates (5)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_
#define NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_

#include <memory>
#include <utility>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "net/base/completion_repeating_callback.h"
#include "net/base/net_export.h"
#include "net/base/request_priority.h"
#include "net/dns/public/resolve_error_info.h"
#include "net/dns/public/secure_dns_policy.h"
#include "net/http/bidirectional_stream_impl.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_controller.h"
#include "net/http/http_stream_factory.h"
#include "net/http/http_stream_request.h"
#include "net/quic/quic_session_pool.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/socket/next_proto.h"
#include "net/socket/ssl_client_socket.h"
#include "net/spdy/spdy_session_key.h"
#include "net/spdy/spdy_session_pool.h"
#include "net/ssl/ssl_config.h"
#include "url/gurl.h"
#include "url/scheme_host_port.h"

namespace net {

namespace test {

class HttpStreamFactoryJobPeer;

}  // namespace test

class ClientSocketHandle;
class HttpAuthController;
class HttpNetworkSession;
class HttpStream;
class SpdySessionPool;
class NetLog;
struct SSLConfig;

// An HttpStreamRequest exists for each stream which is in progress of being
// created for the HttpStreamFactory.
class HttpStreamFactory::Job
    : public SpdySessionPool::SpdySessionRequest::Delegate {
 public:
  // For jobs issued simultaneously to an HTTP/2 supported server, a delay is
  // applied to avoid unnecessary socket connection establishments.
  // https://crbug.com/718576
  static const int kHTTP2ThrottleMs = 300;

  // Delegate to report Job's status to HttpStreamRequest and HttpStreamFactory.
  class NET_EXPORT_PRIVATE Delegate {
   public:
    virtual ~Delegate() = default;

    // Invoked when |job| has an HttpStream ready.
    virtual void OnStreamReady(Job* job) = 0;

    // Invoked when |job| has a BidirectionalStream ready.
    virtual void OnBidirectionalStreamImplReady(
        Job* job,
        const ProxyInfo& used_proxy_info) = 0;

    // Invoked when |job| has a WebSocketHandshakeStream ready.
    virtual void OnWebSocketHandshakeStreamReady(
        Job* job,
        const ProxyInfo& used_proxy_info,
        std::unique_ptr<WebSocketHandshakeStreamBase> stream) = 0;

    // Invoked when a QUIC job finished a DNS resolution.
    virtual void OnQuicHostResolution(
        const url::SchemeHostPort& destination,
        base::TimeTicks dns_resolution_start_time,
        base::TimeTicks dns_resolution_end_time) = 0;

    // Invoked when |job| fails to create a stream.
    virtual void OnStreamFailed(Job* job, int status) = 0;

    // Invoked when |job| fails on the default network.
    virtual void OnFailedOnDefaultNetwork(Job* job) = 0;

    // Invoked when |job| has a certificate error for the HttpStreamRequest.
    virtual void OnCertificateError(Job* job,
                                    int status,
                                    const SSLInfo& ssl_info) = 0;

    // Invoked when |job| raises failure for SSL Client Auth.
    virtual void OnNeedsClientAuth(Job* job, SSLCertRequestInfo* cert_info) = 0;

    // Invoked when |job| needs proxy authentication.
    virtual void OnNeedsProxyAuth(Job* job,
                                  const HttpResponseInfo& proxy_response,
                                  const ProxyInfo& used_proxy_info,
                                  HttpAuthController* auth_controller) = 0;

    // Invoked when the |job| finishes pre-connecting sockets.
    virtual void OnPreconnectsComplete(Job* job, int result) = 0;

    // Invoked to record connection attempts made by the socket layer to
    // HttpStreamRequest if |job| is associated with HttpStreamRequest.
    virtual void AddConnectionAttemptsToRequest(
        Job* job,
        const ConnectionAttempts& attempts) = 0;

    // Invoked when |job| finishes initiating a connection. This may occur
    // before the handshake is complete, and provides the delegate an
    // early chance to handle any errors.
    virtual void OnConnectionInitialized(Job* job, int rv) = 0;

    // Return false if |job| can advance to the next state. Otherwise, |job|
    // will wait for Job::Resume() to be called before advancing.
    virtual bool ShouldWait(Job* job) = 0;

    virtual const NetLogWithSource* GetNetLog() const = 0;

    virtual WebSocketHandshakeStreamBase::CreateHelper*
    websocket_handshake_stream_create_helper() = 0;

    virtual void MaybeSetWaitTimeForMainJob(const base::TimeDelta& delay) = 0;
  };

  // Job is owned by |delegate|, hence |delegate| is valid for the lifetime of
  // the Job.
  //
  // |alternative_protocol| is the protocol required by Alternative Service, if
  // any:
  // * |alternative_protocol == kProtoUnknown| means that the Job can pool to an
  //   existing SpdySession, or bind to a idle TCP socket that might use either
  //   HTTP/1.1 or HTTP/2.
  // * |alternative_protocol == kProtoHTTP2| means that the Job can pool to an
  //   existing SpdySession, or bind to a idle TCP socket.  In the latter case,
  //   if the socket does not use HTTP/2, then the Job fails.
  // * |alternative_protocol == kProtoQUIC| means that the Job can pool to an
  //   existing QUIC connection or open a new one.
  // Note that this can be overwritten by specifying a QUIC proxy in
  // |proxy_info|, or by setting
  // HttpNetworkSession::Params::origins_to_force_quic_on.
  Job(Delegate* delegate,
      JobType job_type,
      HttpNetworkSession* session,
      const StreamRequestInfo& request_info,
      RequestPriority priority,
      const ProxyInfo& proxy_info,
      const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
      url::SchemeHostPort destination,
      GURL origin_url,
      NextProto alternative_protocol,
      quic::ParsedQuicVersion quic_version,
      bool is_websocket,
      bool enable_ip_based_pooling,
      std::optional<ConnectionManagementConfig> management_config,
      NetLog* net_log);

  Job(const Job&) = delete;
  Job& operator=(const Job&) = delete;

  ~Job() override;

  // Start initiates the process of creating a new HttpStream.
  // |delegate_| will be notified upon completion.
  void Start(HttpStreamRequest::StreamType stream_type);

  // Preconnect will attempt to request |num_streams| sockets from the
  // appropriate ClientSocketPool.
  int Preconnect(int num_streams);

  int RestartTunnelWithProxyAuth();
  LoadState GetLoadState() const;

  // Tells |this| that |delegate_| has determined it still needs to continue
  // connecting.
  virtual void Resume();

  // Called when |this| is orphaned by Delegate. This is valid for
  // ALTERNATIVE job and DNS_ALPN_H3 job.
  void Orphan();

  void SetPriority(RequestPriority priority);

  // Returns true if the current request can be immediately sent on a existing
  // spdy session.
  bool HasAvailableSpdySession() const;

  // Returns true if the current request can be immediately sent on a existing
  // QUIC session.
  bool HasAvailableQuicSession() const;

  // Returns true if a connected (idle or handed out) or connecting socket
  // exists for the job. This method is not supported for WebSocket and QUIC.
  bool TargettedSocketGroupHasActiveSocket() const;

  const GURL& origin_url() const { return origin_url_; }
  RequestPriority priority() const { return priority_; }
  NextProto negotiated_protocol() const;
  const NetLogWithSource& net_log() const { return net_log_; }
  HttpStreamRequest::StreamType stream_type() const { return stream_type_; }

  std::unique_ptr<HttpStream> ReleaseStream() { return std::move(stream_); }

  std::unique_ptr<BidirectionalStreamImpl> ReleaseBidirectionalStream() {
    return std::move(bidirectional_stream_impl_);
  }

  bool is_waiting() const { return next_state_ == STATE_WAIT_COMPLETE; }
  const ProxyInfo& proxy_info() const;
  ResolveErrorInfo resolve_error_info() const;

  JobType job_type() const { return job_type_; }

  bool using_existing_quic_session() const {
    return using_existing_quic_session_;
  }

  bool expect_on_quic_session_created() const {
    return expect_on_quic_session_created_;
  }

  bool expect_on_quic_host_resolution_for_tests() const {
    return expect_on_quic_host_resolution_;
  }

  bool using_quic() const { return using_quic_; }

  bool should_reconsider_proxy() const { return should_reconsider_proxy_; }

  NetErrorDetails* net_error_details() { return &net_error_details_; }

 private:
  friend class test::HttpStreamFactoryJobPeer;

  enum State {
    STATE_START,
    // The main and alternative jobs are started in parallel.  The main job
    // can wait if it's paused. The alternative job never waits.
    //
    // An HTTP/2 alternative job notifies the JobController in DoInitConnection
    // unless it can pool to an existing SpdySession.  JobController, in turn,
    // resumes the main job.
    //
    // A QUIC alternative job notifies the JobController in DoInitConnection
    // regardless of whether it pools to an existing QUIC session, but the main
    // job is only resumed after some delay.
    //
    // If the main job is resumed, then it races the alternative job.
    STATE_WAIT,
    STATE_WAIT_COMPLETE,

    STATE_INIT_CONNECTION,
    STATE_INIT_CONNECTION_COMPLETE,
    STATE_WAITING_USER_ACTION,
    STATE_CREATE_STREAM,
    STATE_CREATE_STREAM_COMPLETE,
    STATE_DONE,
    STATE_NONE,
  };

  void OnStreamReadyCallback();
  void OnBidirectionalStreamImplReadyCallback();
  void OnWebSocketHandshakeStreamReadyCallback();
  // This callback function is called when a new SPDY session is created.
  void OnNewSpdySessionReadyCallback();
  void OnStreamFailedCallback(int result);
  void OnCertificateErrorCallback(int result, const SSLInfo& ssl_info);
  void OnNeedsProxyAuthCallback(const HttpResponseInfo& response_info,
                                HttpAuthController* auth_controller,
                                base::OnceClosure restart_with_auth_callback);
  void OnNeedsClientAuthCallback(SSLCertRequestInfo* cert_info);
  void OnPreconnectsComplete(int result);

  void OnIOComplete(int result);
  // RunLoop() finishes asynchronously and invokes one of the On* methods (see
  // above) when done.
  void RunLoop(int result);
  int DoLoop(int result);
  int StartInternal();
  int DoInitConnectionImpl();
  // `server_cert_verifier_flags` are the cert verifier flags if connecting to a
  // QUIC server. If making non-tunnelled requests to a QUIC proxy, they will be
  // ignored.
  int DoInitConnectionImplQuic(int server_cert_verifier_flags);

  // If this is a QUIC alt job, then this function is called when host
  // resolution completes. It's called with the next result after host
  // resolution, not the result of host resolution itself.
  void OnQuicHostResolution(int result);

  // If this is a QUIC alt job, this function is called when the QUIC session is
  // created. It's called with the result of either failed session creation or
  // an attempted crypto connection.
  void OnQuicSessionCreated(int result);

  // Invoked when the underlying connection fails on the default network.
  void OnFailedOnDefaultNetwork(int result);

  // Each of these methods corresponds to a State value.  Those with an input
  // argument receive the result from the previous state.  If a method returns
  // ERR_IO_PENDING, then the result from OnIOComplete will be passed to the
  // next state method as the result arg.
  int DoStart();
  int DoWait();
  int DoWaitComplete(int result);
  int DoInitConnection();
  int DoInitConnectionComplete(int result);
  int DoWaitingUserAction(int result);
  int DoCreateStream();
  int DoCreateStreamComplete(int result);

  void ResumeInitConnection();

  // Creates a SpdyHttpStream or a BidirectionalStreamImpl from the given values
  // and sets to |stream_| or |bidirectional_stream_impl_| respectively. Does
  // nothing if |stream_factory_| is for WebSocket.
  int SetSpdyHttpStreamOrBidirectionalStreamImpl(
      base::WeakPtr<SpdySession> session);

  // SpdySessionPool::SpdySessionRequest::Delegate implementation:
  void OnSpdySessionAvailable(base::WeakPtr<SpdySession> spdy_session) override;

  // Retrieve SSLInfo from our SSL Socket.
  // This must only be called when we are using an SSLSocket.
  void GetSSLInfo(SSLInfo* ssl_info);

  // Returns true if the resulting stream will use an HTTP GET to the final
  // proxy in the chain, instead of a CONNECT to the endpoint.
  bool UsingHttpProxyWithoutTunnel() const;

  // Returns true if the current request can use an existing spdy session.
  bool CanUseExistingSpdySession() const;

  // Called when we encounter a network error that could be resolved by trying
  // a new proxy configuration.  If there is another proxy configuration to try
  // then this method sets next_state_ appropriately and returns either OK or
  // ERR_IO_PENDING depending on whether or not the new proxy configuration is
  // available synchronously or asynchronously.  Otherwise, the given error
  // code is simply returned.
  int ReconsiderProxyAfterError(int error);

  void MaybeCopyConnectionAttemptsFromHandle();

  // Returns true if the request should be throttled to allow for only one
  // connection attempt to be made to an H2 server at a time.
  bool ShouldThrottleConnectForSpdy() const;

  // True if Job actually uses HTTP/2. Note this describes both using HTTP/2
  // with an HTTPS origin, and proxying a cleartext HTTP request over an HTTP/2
  // proxy. This differs from `using_ssl_`, which only describes the origin.
  bool using_spdy() const;

  // Calculates SchemeHostPort for HttpServerProperties::{Set,Get}SupportsSpdy()
  // calls.
  url::SchemeHostPort SchemeHostPortForSupportsSpdy() const;

  bool disable_cert_verification_network_fetches() const;

  void RecordPreconnectHistograms(int result);

  // Records histograms required at the end of the execution.
  void RecordCompletionHistograms(int result);

  const StreamRequestInfo request_info_;
  RequestPriority priority_;
  const ProxyInfo proxy_info_;
  const std::vector<SSLConfig::CertAndStatus> allowed_bad_certs_;
  const NetLogWithSource net_log_;

  const CompletionRepeatingCallback io_callback_;
  std::unique_ptr<ClientSocketHandle> connection_;
  const raw_ptr<HttpNetworkSession> session_;

  State next_state_ = STATE_NONE;

  bool started_ = false;

  // The server we are trying to reach, could be that of the origin or of the
  // alternative service (after applying host mapping rules). The scheme of this
  // is always HTTP or HTTPS, even for websockets requests.
  const url::SchemeHostPort destination_;

  // The origin url we're trying to reach. This url may be different from the
  // original request when host mapping rules are set-up. It has the original
  // scheme, so may be HTTP, HTTPS, WS, or WSS. It does not change when there's
  // an alternate service, but it does take into account host mapping rules,
  // unlike `request_info_.url`.
  const GURL origin_url_;

  // True if request is for Websocket.
  const bool is_websocket_;

  // True if WebSocket request is allowed to use a WebSocket-capable existing
  // HTTP/2 connection.  In this case FindAvailableSession() must be called with
  // |enable_websocket = true|.
  const bool try_websocket_over_http2_;

  // Enable pooling to a SpdySession with matching IP and certificate
  // even if the SpdySessionKey is different.
  const bool enable_ip_based_pooling_;

  // Unowned. |this| job is owned by |delegate_|.
  const raw_ptr<Delegate> delegate_;

  const JobType job_type_;

  // True if handling a HTTPS request. Note this only describes the origin URL.
  // If false (an HTTP request), the request may still be sent over an HTTPS
  // proxy. This differs from `using_quic_` and `using_spdy()`, which also
  // describe some proxy cases.
  const bool using_ssl_;

  // True if Job actually uses QUIC. Note this describes both using QUIC
  // with an HTTPS origin, and proxying a cleartext HTTP request over an QUIC
  // proxy. This differs from `using_ssl_`, which only describes the origin.
  const bool using_quic_;

  // quic::ParsedQuicVersion that should be used to connect to the QUIC
  // server if Job uses QUIC.
  quic::ParsedQuicVersion quic_version_;

  // True if Alternative Service protocol field requires that HTTP/2 is used.
  // In this case, Job fails if it cannot pool to an existing SpdySession and
  // the server does not negotiate HTTP/2 on a new socket.
  const bool expect_spdy_;

  // True if this job might succeed with a different proxy config.
  bool should_reconsider_proxy_ = false;

  QuicSessionRequest quic_request_;

  // Only valid for a QUIC job. Set when a QUIC connection is started. If true,
  // then OnQuicHostResolution() is expected to be called in the future.
  bool expect_on_quic_host_resolution_ = false;

  // Only valid for a QUIC job. Set when a QUIC connection is started. If true,
  // OnQuicSessionCreated() is expected to be called in the future.
  bool expect_on_quic_session_created_ = false;

  // True if this job used an existing QUIC session.
  bool using_existing_quic_session_ = false;

  // True when the tunnel is in the process of being established - we can't
  // read from the socket until the tunnel is done.
  bool establishing_tunnel_ = false;

  std::unique_ptr<HttpStream> stream_;
  std::unique_ptr<WebSocketHandshakeStreamBase> websocket_stream_;
  std::unique_ptr<BidirectionalStreamImpl> bidirectional_stream_impl_;

  // Protocol negotiated with the server.
  NextProto negotiated_protocol_ = NextProto::kProtoUnknown;

  // 0 if we're not preconnecting. Otherwise, the number of streams to
  // preconnect.
  int num_streams_ = 0;

  // Initialized when we have an existing SpdySession.
  base::WeakPtr<SpdySession> existing_spdy_session_;

  // Which SpdySessions in the pool to use. Note that, if requesting an HTTP URL
  // through an HTTPS proxy, this key corresponds to the last proxy in the proxy
  // chain and not the origin server.
  const SpdySessionKey spdy_session_key_;

  // Type of stream that is requested.
  HttpStreamRequest::StreamType stream_type_ =
      HttpStreamRequest::BIDIRECTIONAL_STREAM;

  // Whether Job has continued to DoInitConnection().
  bool init_connection_already_resumed_ = false;

  base::OnceClosure restart_with_auth_callback_;

  NetErrorDetails net_error_details_;

  ResolveErrorInfo resolve_error_info_;

  std::unique_ptr<SpdySessionPool::SpdySessionRequest> spdy_session_request_;

  // Keeps track of the connection management config.
  std::optional<ConnectionManagementConfig> management_config_;

  base::WeakPtrFactory<Job> ptr_factory_{this};
};

// Factory for creating Jobs.
class HttpStreamFactory::JobFactory {
 public:
  JobFactory();

  virtual ~JobFactory();

  virtual std::unique_ptr<HttpStreamFactory::Job> CreateJob(
      HttpStreamFactory::Job::Delegate* delegate,
      HttpStreamFactory::JobType job_type,
      HttpNetworkSession* session,
      const StreamRequestInfo& request_info,
      RequestPriority priority,
      const ProxyInfo& proxy_info,
      const std::vector<SSLConfig::CertAndStatus>& allowed_bad_certs,
      url::SchemeHostPort destination,
      GURL origin_url,
      bool is_websocket,
      bool enable_ip_based_pooling,
      NetLog* net_log,
      NextProto alternative_protocol,
      quic::ParsedQuicVersion quic_version,
      std::optional<ConnectionManagementConfig> management_config);
};

}  // namespace net

#endif  // NET_HTTP_HTTP_STREAM_FACTORY_JOB_H_