1 // Copyright 2018 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 COMPONENTS_CRONET_NATIVE_URL_REQUEST_H_
6 #define COMPONENTS_CRONET_NATIVE_URL_REQUEST_H_
7 
8 #include <memory>
9 #include <string>
10 #include <unordered_set>
11 
12 #include "base/macros.h"
13 #include "base/synchronization/lock.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/thread_annotations.h"
16 #include "components/cronet/cronet_url_request.h"
17 #include "components/cronet/cronet_url_request_context.h"
18 #include "components/cronet/native/generated/cronet.idl_impl_interface.h"
19 
20 namespace net {
21 enum LoadState;
22 }  // namespace net
23 
24 namespace cronet {
25 
26 class Cronet_EngineImpl;
27 class Cronet_UploadDataSinkImpl;
28 
29 // Implementation of Cronet_UrlRequest that uses CronetURLRequestContext.
30 class Cronet_UrlRequestImpl : public Cronet_UrlRequest {
31  public:
32   Cronet_UrlRequestImpl();
33   ~Cronet_UrlRequestImpl() override;
34 
35   // Cronet_UrlRequest
36   Cronet_RESULT InitWithParams(Cronet_EnginePtr engine,
37                                Cronet_String url,
38                                Cronet_UrlRequestParamsPtr params,
39                                Cronet_UrlRequestCallbackPtr callback,
40                                Cronet_ExecutorPtr executor) override;
41   Cronet_RESULT Start() override;
42   Cronet_RESULT FollowRedirect() override;
43   Cronet_RESULT Read(Cronet_BufferPtr buffer) override;
44   void Cancel() override;
45   bool IsDone() override;
46   void GetStatus(Cronet_UrlRequestStatusListenerPtr listener) override;
47 
48   // Upload data provider has reported error while reading or rewinding
49   // so request must fail.
50   void OnUploadDataProviderError(const std::string& error_message);
51 
52  private:
53   class NetworkTasks;
54 
55   // Return |true| if request has started and is now done.
56   // Must be called under |lock_| held.
57   bool IsDoneLocked() const SHARED_LOCKS_REQUIRED(lock_);
58 
59   // Helper method to set final status of CronetUrlRequest and clean up the
60   // native request adapter. Returns true if request is already done, false
61   // request is not done and is destroyed.
62   bool DestroyRequestUnlessDone(
63       Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason);
64 
65   // Helper method to set final status of CronetUrlRequest and clean up the
66   // native request adapter. Returns true if request is already done, false
67   // request is not done and is destroyed. Must be called under |lock_| held.
68   bool DestroyRequestUnlessDoneLocked(
69       Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason)
70       EXCLUSIVE_LOCKS_REQUIRED(lock_);
71 
72   // Helper method to post |task| to the |executor_|.
73   void PostTaskToExecutor(base::OnceClosure task);
74 
75   // Helper methods to invoke application |callback_|.
76   void InvokeCallbackOnRedirectReceived(const std::string& new_location);
77   void InvokeCallbackOnResponseStarted();
78   void InvokeCallbackOnReadCompleted(
79       std::unique_ptr<Cronet_Buffer> cronet_buffer,
80       int bytes_read);
81   void InvokeCallbackOnSucceeded();
82   void InvokeCallbackOnFailed();
83   void InvokeCallbackOnCanceled();
84 
85   // Runs InvokeCallbackOnFailed() on the client executor.
86   void PostCallbackOnFailedToExecutor();
87 
88   // Invoke all members of |status_listeners_|. Should be called prior to
89   // invoking a final callback. Once a final callback has been called, |this|
90   // and |executor_| may be deleted and so the callbacks cannot be issued.
91   void InvokeAllStatusListeners();
92 
93   // Reports metrics if metrics were collected, otherwise does nothing. This
94   // method should only be called once on Callback's executor thread and before
95   // Callback's OnSucceeded, OnFailed and OnCanceled.
96   //
97   // Adds |finished_reason| to the reported RequestFinishedInfo. Also passes
98   // pointers to |response_info_| and |error_|.
99   //
100   // Also, the field |annotations_| is moved into the RequestFinishedInfo.
101   //
102   // |finished_reason|: Success / fail / cancel status of request.
103   void MaybeReportMetrics(
104       Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason);
105 
106   // Synchronize access to |request_| and other objects below from different
107   // threads.
108   base::Lock lock_;
109   // NetworkTask object lives on the network thread. Owned by |request_|.
110   // Outlives this.
111   NetworkTasks* network_tasks_ GUARDED_BY(lock_) = nullptr;
112   // Cronet URLRequest used for this operation.
113   CronetURLRequest* request_ GUARDED_BY(lock_) = nullptr;
114   bool started_ GUARDED_BY(lock_) = false;
115   bool waiting_on_redirect_ GUARDED_BY(lock_) = false;
116   bool waiting_on_read_ GUARDED_BY(lock_) = false;
117   // Set of status_listeners_ that have not yet been called back.
118   std::unordered_multiset<Cronet_UrlRequestStatusListenerPtr> status_listeners_
119       GUARDED_BY(lock_);
120 
121   // Report containing metrics and other information to send to attached
122   // RequestFinishedListener(s). A nullptr value indicates that metrics haven't
123   // been collected.
124   //
125   // Ownership is shared since we guarantee that the RequestFinishedInfo will
126   // be valid if its UrlRequest isn't destroyed. We also guarantee that it's
127   // valid in RequestFinishedListener.OnRequestFinished() even if the
128   // UrlRequest is destroyed (and furthermore, each listener finishes at
129   // different times).
130   //
131   // NOTE: this field isn't protected by |lock_| since we pass this field as a
132   // unowned pointer to OnRequestFinished(). The pointee of this field cannot
133   // be updated after that call is made.
134   scoped_refptr<base::RefCountedData<Cronet_RequestFinishedInfo>>
135       request_finished_info_;
136 
137   // Annotations passed via UrlRequestParams.annotations. These annotations
138   // aren't used by Cronet itself -- they're just moved into the
139   // RequestFinishedInfo passed to RequestFinishedInfoListener instances.
140   std::vector<Cronet_RawDataPtr> annotations_;
141 
142   // Optional; allows a listener to receive request info and stats.
143   //
144   // A nullptr value indicates that there is no RequestFinishedInfo listener
145   // specified for the request (however, the Engine may have additional
146   // listeners -- Engine listeners apply to all its UrlRequests).
147   //
148   // Owned by the app -- must outlive this UrlRequest.
149   Cronet_RequestFinishedInfoListenerPtr request_finished_listener_ = nullptr;
150 
151   // Executor upon which |request_finished_listener_| will run. If
152   // |request_finished_listener_| is not nullptr, this won't be nullptr either.
153   //
154   // Owned by the app -- must outlive this UrlRequest.
155   Cronet_ExecutorPtr request_finished_executor_ = nullptr;
156 
157   // Response info updated by callback with number of bytes received. May be
158   // nullptr, if no response has been received.
159   //
160   // Ownership is shared since we guarantee that the UrlResponseInfo will
161   // be valid if its UrlRequest isn't destroyed. We also guarantee that it's
162   // valid in RequestFinishedListener.OnRequestFinished() even if the
163   // UrlRequest is destroyed (and furthermore, each listener finishes at
164   // different times).
165   //
166   // NOTE: the synchronization of this field is complex -- it can't be
167   // completely protected by |lock_| since we pass this field as a unowned
168   // pointer to OnSucceed(), OnFailed(), and OnCanceled(). The pointee of this
169   // field cannot be updated after one of those callback calls is made.
170   scoped_refptr<base::RefCountedData<Cronet_UrlResponseInfo>> response_info_;
171 
172   // The error reported by request. May be nullptr if no error has occurred.
173   //
174   // Ownership is shared since we guarantee that the Error will be valid if its
175   // UrlRequest isn't destroyed. We also guarantee that it's valid in
176   // RequestFinishedListener.OnRequestFinished() even if the UrlRequest is
177   // destroyed (and furthermore, each listener finishes at different times).
178   //
179   // NOTE: the synchronization of this field is complex -- it can't be
180   // completely protected by |lock_| since we pass this field as an unowned
181   // pointer to OnSucceed(), OnFailed(), and OnCanceled(). The pointee of this
182   // field cannot be updated after one of those callback calls is made.
183   scoped_refptr<base::RefCountedData<Cronet_Error>> error_;
184 
185   // The upload data stream if specified.
186   std::unique_ptr<Cronet_UploadDataSinkImpl> upload_data_sink_;
187 
188   // Application callback interface, used, but not owned, by |this|.
189   Cronet_UrlRequestCallbackPtr callback_ = nullptr;
190   // Executor for application callback, used, but not owned, by |this|.
191   Cronet_ExecutorPtr executor_ = nullptr;
192 
193   // Cronet Engine used to run network operations. Not owned, accessed from
194   // client thread. Must outlive this request.
195   Cronet_EngineImpl* engine_ = nullptr;
196 
197 #if DCHECK_IS_ON()
198   // Event indicating Executor is properly destroying Runnables.
199   base::WaitableEvent runnable_destroyed_;
200 #endif  // DCHECK_IS_ON()
201 
202   DISALLOW_COPY_AND_ASSIGN(Cronet_UrlRequestImpl);
203 };
204 
205 }  // namespace cronet
206 
207 #endif  // COMPONENTS_CRONET_NATIVE_URL_REQUEST_H_
208