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

content / browser / loader / reconnectable_url_loader_factory.h [blame]

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_LOADER_RECONNECTABLE_URL_LOADER_FACTORY_H_
#define CONTENT_BROWSER_LOADER_RECONNECTABLE_URL_LOADER_FACTORY_H_

#include "base/memory/ref_counted.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"

namespace content {

// SharedURLLoaderFactory that caches and reuses a URLLoaderFactory remote
// created by its `CreateCallback`, and re-create and reconnect if the cached
// remote is disconnected.
// All methods (including the `CreateCallback` and the destructor) must be/are
// called on the original sequence.
// TODO(crbug.com/40947547): Merge `ReconnectableURLLoaderFactoryForIOThread`
// and rename the file.
class CONTENT_EXPORT ReconnectableURLLoaderFactory final
    : public network::SharedURLLoaderFactory {
 public:
  // On success:
  //   Creates and assigns a new URLLoaderFactory to the output parameter.
  //
  // On failure (e.g., underlying network context is gone):
  //   Leaves the output parameter unchanged.
  //   Cancellation of the callback is usually achieved by binding a WeakPtr to
  //   it in the caller's context.
  using CreateCallback = base::RepeatingCallback<void(
      mojo::PendingRemote<network::mojom::URLLoaderFactory>*)>;

  // The constructor doesn't call `create_url_loader_factory_callback`
  // synchronously.
  explicit ReconnectableURLLoaderFactory(
      CreateCallback create_url_loader_factory_callback);

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

  void Reset();
  void FlushForTesting();

  // mojom::URLLoaderFactory implementation:
  void CreateLoaderAndStart(
      mojo::PendingReceiver<network::mojom::URLLoader> receiver,
      int32_t request_id,
      uint32_t options,
      const network::ResourceRequest& url_request,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
      override;
  void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
      override;

  // SharedURLLoaderFactory implementation:
  std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override;

 private:
  friend class base::RefCounted<ReconnectableURLLoaderFactory>;
  ~ReconnectableURLLoaderFactory() override;

  // URLLoaderFactory caching mechanism only accessed from the original thread.
  network::mojom::URLLoaderFactory* GetURLLoaderFactory();
  mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
  bool is_test_url_loader_factory_ = false;

  const CreateCallback create_url_loader_factory_callback_;

  SEQUENCE_CHECKER(sequence_checker_);
};

// Similar to `ReconnectableURLLoaderFactory`, but this IO-thread-only version
// caches a URLLoaderFactory on IO thread at
// `ReconnectableURLLoaderFactoryForIOThread::url_loader_factory_` and
// re-creates and reconnects it if needed.
//
// `ReconnectableURLLoaderFactoryForIOThread` must live on UI thread (just
// because it is hard-coded using `GetUIThreadTaskRunner`).
class CONTENT_EXPORT ReconnectableURLLoaderFactoryForIOThread final
    : public base::RefCountedThreadSafe<
          ReconnectableURLLoaderFactoryForIOThread,
          BrowserThread::DeleteOnIOThread> {
 public:
  using CreateCallback = ReconnectableURLLoaderFactory::CreateCallback;

  // Initializes this object on the UI thread. Similar to
  // `ReconnectableURLLoaderFactory`, this caches and reuses a URLLoaderFactory
  // remote created by its `CreateCallback`, and re-create and reconnect if the
  // cached remote is disconnected.
  // The constructor doesn't call `create_url_loader_factory_callback`
  // synchronously.
  // `create_url_loader_factory_callback` is always called on UI thread, but can
  // be destroyed either on UI or IO thread.
  explicit ReconnectableURLLoaderFactoryForIOThread(
      CreateCallback create_url_loader_factory_callback);

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

  // Eagerly trigger initialization for the use for IO thread. Note that, even
  // if `Initialize()` is not called, `CloneForIOThread()` still can
  // be used and is lazily initialized when the created
  // `PendingSharedURLLoaderFactory` is actually used.
  void Initialize();

  // Called on the UI thread to create a PendingSharedURLLoaderFactory that
  // holds a reference to this ReconnectableURLLoaderFactoryForIOThread, which
  // can be used on IO thread to construct a SharedURLLoaderFactory that can be
  // used to access the URLLoaderFactory to the network service and supports
  // auto-reconnect after crash.
  std::unique_ptr<network::PendingSharedURLLoaderFactory> CloneForIOThread();

  void Reset();

  // Call |url_loader_factory_.FlushForTesting()| on IO thread. For test use
  // only.
  void FlushForTesting();

 private:
  class PendingURLLoaderFactoryForIOThread;
  class URLLoaderFactoryForIOThread;

  friend class base::DeleteHelper<ReconnectableURLLoaderFactoryForIOThread>;
  friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;

  ~ReconnectableURLLoaderFactoryForIOThread();

  void InitializeOnIOThread(
      mojo::PendingRemote<network::mojom::URLLoaderFactory> network_factory);

  // Moves |network_factory| to |url_loader_factory_| and sets up an error
  // handler.
  void ReinitializeOnIOThread(
      mojo::Remote<network::mojom::URLLoaderFactory> network_factory);

  // Send |network_factory_request| to cached |StoragePartitionImpl|.
  void HandleNetworkFactoryRequestOnUIThread(
      mojo::PendingReceiver<network::mojom::URLLoaderFactory>
          network_factory_receiver);

  // Called on the IO thread to get the URLLoaderFactory to the network service.
  // The pointer shouldn't be cached.
  network::mojom::URLLoaderFactory* GetURLLoaderFactory();

  // Call |url_loader_factory_.FlushForTesting()|. For test use only. When the
  // flush is complete, |callback| will be called.
  void FlushOnIOThreadForTesting(base::OnceClosure callback);

  // Cached URLLoaderFactory only used from the IO thread.
  mojo::Remote<network::mojom::URLLoaderFactory> url_loader_factory_;
  bool is_test_url_loader_factory_ = false;

  // Only accessed on UI thread.
  const CreateCallback create_url_loader_factory_callback_;
};

// Bundles `ReconnectableURLLoaderFactoryForIOThread` and
// `ReconnectableURLLoaderFactory`. The two classes are held separately by this
// wrapper instead of e.g. being merged into a single object, so that
// `scoped_refptr` for one of them doesn't affect the lifetime of the other.
class CONTENT_EXPORT ReconnectableURLLoaderFactoryForIOThreadWrapper final {
 public:
  using CreateCallback = ReconnectableURLLoaderFactory::CreateCallback;

  // The constructor doesn't call `create_url_loader_factory_callback`
  // synchronously.
  // `create_url_loader_factory_callback` is always called on UI thread, but can
  // be destroyed either on UI or IO thread.
  explicit ReconnectableURLLoaderFactoryForIOThreadWrapper(
      CreateCallback create_url_loader_factory_callback);

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

  ~ReconnectableURLLoaderFactoryForIOThreadWrapper();

  // Always non-null.
  const scoped_refptr<ReconnectableURLLoaderFactory>& factory() const {
    return factory_;
  }
  const scoped_refptr<ReconnectableURLLoaderFactoryForIOThread>&
  factory_for_io_thread() const {
    return factory_for_io_thread_;
  }

 private:
  scoped_refptr<ReconnectableURLLoaderFactory> factory_;
  scoped_refptr<ReconnectableURLLoaderFactoryForIOThread>
      factory_for_io_thread_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_LOADER_RECONNECTABLE_URL_LOADER_FACTORY_H_