1 // Copyright 2017 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 #ifndef CONTENT_RENDERER_LOADER_SYNC_LOAD_CONTEXT_H_
6 #define CONTENT_RENDERER_LOADER_SYNC_LOAD_CONTEXT_H_
7 
8 #include "base/macros.h"
9 #include "base/optional.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/synchronization/waitable_event_watcher.h"
12 #include "base/timer/timer.h"
13 #include "content/common/content_export.h"
14 #include "content/public/renderer/request_peer.h"
15 #include "content/renderer/loader/resource_dispatcher.h"
16 #include "mojo/public/cpp/bindings/remote.h"
17 #include "mojo/public/cpp/system/data_pipe.h"
18 #include "mojo/public/cpp/system/simple_watcher.h"
19 #include "net/traffic_annotation/network_traffic_annotation.h"
20 #include "services/network/public/cpp/shared_url_loader_factory.h"
21 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
22 
23 namespace base {
24 class WaitableEvent;
25 }
26 
27 namespace network {
28 struct ResourceRequest;
29 }
30 
31 namespace blink {
32 class ResourceLoadInfoNotifierWrapper;
33 class URLLoaderThrottle;
34 struct SyncLoadResponse;
35 }
36 
37 namespace content {
38 
39 // This class owns the context necessary to perform an asynchronous request
40 // while the main thread is blocked so that it appears to be synchronous.
41 // There are a couple of modes to load a request:
42 //   1) kDataPipe; body is received on a data pipe passed on
43 //      OnStartLoadingResponseBody(), and the body is set to response_.data.
44 //   2) kBlob: body is received on a data pipe passed on
45 //      OnStartLoadingResponseBody(), and wraps the data pipe with a
46 //      SerializedBlobPtr.
47 class CONTENT_EXPORT SyncLoadContext : public RequestPeer {
48  public:
49   // Begins a new asynchronous request on whatever sequence this method is
50   // called on. |completed_event| will be signalled when the request is complete
51   // and |response| will be populated with the response data. |abort_event|
52   // will be signalled from the main thread to abort the sync request on a
53   // worker thread when the worker thread is being terminated.
54   // The pointer whose address is `context_for_redirect` is held by the caller
55   // that is blocked on this method, so it will remain valid until the operation
56   // completes. If there are redirects, `context_for_redirect` will point to the
57   // callee context.
58   // If |download_to_blob_registry| is not null, it is used to
59   // redirect the download to a blob, with the resulting blob populated in
60   // |response|.
61   static void StartAsyncWithWaitableEvent(
62       std::unique_ptr<network::ResourceRequest> request,
63       int routing_id,
64       scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner,
65       const net::NetworkTrafficAnnotationTag& traffic_annotation,
66       uint32_t loader_options,
67       std::unique_ptr<network::PendingSharedURLLoaderFactory>
68           pending_url_loader_factory,
69       std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles,
70       blink::SyncLoadResponse* response,
71       SyncLoadContext** context_for_redirect,
72       base::WaitableEvent* completed_event,
73       base::WaitableEvent* abort_event,
74       base::TimeDelta timeout,
75       mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
76       const std::vector<std::string>& cors_exempt_header_list,
77       std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
78           resource_load_info_notifier_wrapper);
79 
80   ~SyncLoadContext() override;
81 
82   void FollowRedirect();
83   void CancelRedirect();
84 
85  private:
86   friend class SyncLoadContextTest;
87 
88   SyncLoadContext(
89       network::ResourceRequest* request,
90       std::unique_ptr<network::PendingSharedURLLoaderFactory>
91           url_loader_factory,
92       blink::SyncLoadResponse* response,
93       SyncLoadContext** context_for_redirect,
94       base::WaitableEvent* completed_event,
95       base::WaitableEvent* abort_event,
96       base::TimeDelta timeout,
97       mojo::PendingRemote<blink::mojom::BlobRegistry> download_to_blob_registry,
98       scoped_refptr<base::SingleThreadTaskRunner> task_runner,
99       const std::vector<std::string>& cors_exempt_header_list);
100   // RequestPeer implementation:
101   void OnUploadProgress(uint64_t position, uint64_t size) override;
102   bool OnReceivedRedirect(const net::RedirectInfo& redirect_info,
103                           network::mojom::URLResponseHeadPtr head,
104                           std::vector<std::string>*) override;
105   void OnReceivedResponse(network::mojom::URLResponseHeadPtr head) override;
106   void OnStartLoadingResponseBody(
107       mojo::ScopedDataPipeConsumerHandle body) override;
108   void OnTransferSizeUpdated(int transfer_size_diff) override;
109   void OnCompletedRequest(
110       const network::URLLoaderCompletionStatus& status) override;
111   void EvictFromBackForwardCache(blink::mojom::RendererEvictionReason) override;
112 
113   void OnFinishCreatingBlob(blink::mojom::SerializedBlobPtr blob);
114 
115   void OnBodyReadable(MojoResult, const mojo::HandleSignalsState&);
116 
117   void OnAbort(base::WaitableEvent* event);
118   void OnTimeout();
119 
120   void CompleteRequest();
121   bool Completed() const;
122 
123   // This raw pointer will remain valid for the lifetime of this object because
124   // it remains on the stack until |event_| is signaled.
125   // Set to null after CompleteRequest() is called.
126   blink::SyncLoadResponse* response_;
127 
128   // This raw pointer will be set to `this` when receiving redirects on
129   // independent thread and set to nullptr in `FollowRedirect()` or
130   // `CancelRedirect()` on the same thread after `redirect_or_response_event_`
131   // is signaled, which protects it against race condition.
132   SyncLoadContext** context_for_redirect_;
133 
134   enum class Mode { kInitial, kDataPipe, kBlob };
135   Mode mode_ = Mode::kInitial;
136 
137   // Used when Mode::kDataPipe.
138   mojo::ScopedDataPipeConsumerHandle body_handle_;
139   mojo::SimpleWatcher body_watcher_;
140 
141   // State necessary to run a request on an independent thread.
142   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
143   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
144 
145   // State for downloading to a blob.
146   mojo::Remote<blink::mojom::BlobRegistry> download_to_blob_registry_;
147   bool blob_response_started_ = false;
148   bool blob_finished_ = false;
149   bool request_completed_ = false;
150 
151   int request_id_;
152 
153   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
154 
155   class SignalHelper;
156   std::unique_ptr<SignalHelper> signals_;
157 
158   DISALLOW_COPY_AND_ASSIGN(SyncLoadContext);
159 };
160 
161 }  // namespace content
162 
163 #endif  // CONTENT_RENDERER_LOADER_SYNC_LOAD_CONTEXT_H_
164