1 // Copyright 2014 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 #include "components/cronet/android/cronet_url_request_adapter.h"
6 
7 #include <limits>
8 #include <utility>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "components/cronet/android/cronet_jni_headers/CronetUrlRequest_jni.h"
15 #include "components/cronet/android/cronet_url_request_context_adapter.h"
16 #include "components/cronet/android/io_buffer_with_byte_buffer.h"
17 #include "components/cronet/android/url_request_error.h"
18 #include "components/cronet/metrics_util.h"
19 #include "net/base/idempotency.h"
20 #include "net/base/load_flags.h"
21 #include "net/base/load_states.h"
22 #include "net/base/net_errors.h"
23 #include "net/base/proxy_server.h"
24 #include "net/base/request_priority.h"
25 #include "net/cert/cert_status_flags.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_status_code.h"
28 #include "net/http/http_util.h"
29 #include "net/ssl/ssl_info.h"
30 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
31 #include "net/url_request/redirect_info.h"
32 #include "net/url_request/url_request_context.h"
33 
34 using base::android::ConvertUTF8ToJavaString;
35 using base::android::JavaParamRef;
36 
37 namespace {
38 
ConvertResponseHeadersToJava(JNIEnv * env,const net::HttpResponseHeaders * headers)39 base::android::ScopedJavaLocalRef<jobjectArray> ConvertResponseHeadersToJava(
40     JNIEnv* env,
41     const net::HttpResponseHeaders* headers) {
42   std::vector<std::string> response_headers;
43   // Returns an empty array if |headers| is nullptr.
44   if (headers != nullptr) {
45     size_t iter = 0;
46     std::string header_name;
47     std::string header_value;
48     while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
49       response_headers.push_back(header_name);
50       response_headers.push_back(header_value);
51     }
52   }
53   return base::android::ToJavaArrayOfStrings(env, response_headers);
54 }
55 
56 }  // namespace
57 
58 namespace cronet {
59 
JNI_CronetUrlRequest_CreateRequestAdapter(JNIEnv * env,const JavaParamRef<jobject> & jurl_request,jlong jurl_request_context_adapter,const JavaParamRef<jstring> & jurl_string,jint jpriority,jboolean jdisable_cache,jboolean jdisable_connection_migration,jboolean jenable_metrics,jboolean jtraffic_stats_tag_set,jint jtraffic_stats_tag,jboolean jtraffic_stats_uid_set,jint jtraffic_stats_uid,jint jidempotency)60 static jlong JNI_CronetUrlRequest_CreateRequestAdapter(
61     JNIEnv* env,
62     const JavaParamRef<jobject>& jurl_request,
63     jlong jurl_request_context_adapter,
64     const JavaParamRef<jstring>& jurl_string,
65     jint jpriority,
66     jboolean jdisable_cache,
67     jboolean jdisable_connection_migration,
68     jboolean jenable_metrics,
69     jboolean jtraffic_stats_tag_set,
70     jint jtraffic_stats_tag,
71     jboolean jtraffic_stats_uid_set,
72     jint jtraffic_stats_uid,
73     jint jidempotency) {
74   CronetURLRequestContextAdapter* context_adapter =
75       reinterpret_cast<CronetURLRequestContextAdapter*>(
76           jurl_request_context_adapter);
77   DCHECK(context_adapter);
78 
79   GURL url(base::android::ConvertJavaStringToUTF8(env, jurl_string));
80 
81   VLOG(1) << "New chromium network request_adapter: "
82           << url.possibly_invalid_spec();
83 
84   CronetURLRequestAdapter* adapter = new CronetURLRequestAdapter(
85       context_adapter, env, jurl_request, url,
86       static_cast<net::RequestPriority>(jpriority), jdisable_cache,
87       jdisable_connection_migration, jenable_metrics, jtraffic_stats_tag_set,
88       jtraffic_stats_tag, jtraffic_stats_uid_set, jtraffic_stats_uid,
89       static_cast<net::Idempotency>(jidempotency));
90 
91   return reinterpret_cast<jlong>(adapter);
92 }
93 
CronetURLRequestAdapter(CronetURLRequestContextAdapter * context,JNIEnv * env,jobject jurl_request,const GURL & url,net::RequestPriority priority,jboolean jdisable_cache,jboolean jdisable_connection_migration,jboolean jenable_metrics,jboolean jtraffic_stats_tag_set,jint jtraffic_stats_tag,jboolean jtraffic_stats_uid_set,jint jtraffic_stats_uid,net::Idempotency idempotency)94 CronetURLRequestAdapter::CronetURLRequestAdapter(
95     CronetURLRequestContextAdapter* context,
96     JNIEnv* env,
97     jobject jurl_request,
98     const GURL& url,
99     net::RequestPriority priority,
100     jboolean jdisable_cache,
101     jboolean jdisable_connection_migration,
102     jboolean jenable_metrics,
103     jboolean jtraffic_stats_tag_set,
104     jint jtraffic_stats_tag,
105     jboolean jtraffic_stats_uid_set,
106     jint jtraffic_stats_uid,
107     net::Idempotency idempotency)
108     : request_(
109           new CronetURLRequest(context->cronet_url_request_context(),
110                                std::unique_ptr<CronetURLRequestAdapter>(this),
111                                url,
112                                priority,
113                                jdisable_cache == JNI_TRUE,
114                                jdisable_connection_migration == JNI_TRUE,
115                                jenable_metrics == JNI_TRUE,
116                                jtraffic_stats_tag_set == JNI_TRUE,
117                                jtraffic_stats_tag,
118                                jtraffic_stats_uid_set == JNI_TRUE,
119                                jtraffic_stats_uid,
120                                idempotency)) {
121   owner_.Reset(env, jurl_request);
122 }
123 
~CronetURLRequestAdapter()124 CronetURLRequestAdapter::~CronetURLRequestAdapter() {
125 }
126 
SetHttpMethod(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jstring> & jmethod)127 jboolean CronetURLRequestAdapter::SetHttpMethod(
128     JNIEnv* env,
129     const JavaParamRef<jobject>& jcaller,
130     const JavaParamRef<jstring>& jmethod) {
131   std::string method(base::android::ConvertJavaStringToUTF8(env, jmethod));
132   return request_->SetHttpMethod(method) ? JNI_TRUE : JNI_FALSE;
133 }
134 
AddRequestHeader(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jstring> & jname,const JavaParamRef<jstring> & jvalue)135 jboolean CronetURLRequestAdapter::AddRequestHeader(
136     JNIEnv* env,
137     const JavaParamRef<jobject>& jcaller,
138     const JavaParamRef<jstring>& jname,
139     const JavaParamRef<jstring>& jvalue) {
140   std::string name(base::android::ConvertJavaStringToUTF8(env, jname));
141   std::string value(base::android::ConvertJavaStringToUTF8(env, jvalue));
142   return request_->AddRequestHeader(name, value) ? JNI_TRUE : JNI_FALSE;
143 }
144 
SetUpload(std::unique_ptr<net::UploadDataStream> upload)145 void CronetURLRequestAdapter::SetUpload(
146     std::unique_ptr<net::UploadDataStream> upload) {
147   request_->SetUpload(std::move(upload));
148 }
149 
Start(JNIEnv * env,const JavaParamRef<jobject> & jcaller)150 void CronetURLRequestAdapter::Start(JNIEnv* env,
151                                     const JavaParamRef<jobject>& jcaller) {
152   request_->Start();
153 }
154 
GetStatus(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jobject> & jstatus_listener)155 void CronetURLRequestAdapter::GetStatus(
156     JNIEnv* env,
157     const JavaParamRef<jobject>& jcaller,
158     const JavaParamRef<jobject>& jstatus_listener) {
159   base::android::ScopedJavaGlobalRef<jobject> status_listener_ref;
160   status_listener_ref.Reset(env, jstatus_listener);
161   request_->GetStatus(base::BindOnce(&CronetURLRequestAdapter::OnStatus,
162                                      base::Unretained(this),
163                                      status_listener_ref));
164 }
165 
FollowDeferredRedirect(JNIEnv * env,const JavaParamRef<jobject> & jcaller)166 void CronetURLRequestAdapter::FollowDeferredRedirect(
167     JNIEnv* env,
168     const JavaParamRef<jobject>& jcaller) {
169   request_->FollowDeferredRedirect();
170 }
171 
ReadData(JNIEnv * env,const JavaParamRef<jobject> & jcaller,const JavaParamRef<jobject> & jbyte_buffer,jint jposition,jint jlimit)172 jboolean CronetURLRequestAdapter::ReadData(
173     JNIEnv* env,
174     const JavaParamRef<jobject>& jcaller,
175     const JavaParamRef<jobject>& jbyte_buffer,
176     jint jposition,
177     jint jlimit) {
178   DCHECK_LT(jposition, jlimit);
179 
180   void* data = env->GetDirectBufferAddress(jbyte_buffer);
181   if (!data)
182     return JNI_FALSE;
183 
184   IOBufferWithByteBuffer* read_buffer =
185       new IOBufferWithByteBuffer(env, jbyte_buffer, data, jposition, jlimit);
186 
187   int remaining_capacity = jlimit - jposition;
188   request_->ReadData(read_buffer, remaining_capacity);
189   return JNI_TRUE;
190 }
191 
Destroy(JNIEnv * env,const JavaParamRef<jobject> & jcaller,jboolean jsend_on_canceled)192 void CronetURLRequestAdapter::Destroy(JNIEnv* env,
193                                       const JavaParamRef<jobject>& jcaller,
194                                       jboolean jsend_on_canceled) {
195   // Destroy could be called from any thread, including network thread (if
196   // posting task to executor throws an exception), but is posted, so |this|
197   // is valid until calling task is complete. Destroy() is always called from
198   // within a synchronized java block that guarantees no future posts to the
199   // network thread with the adapter pointer.
200   request_->Destroy(jsend_on_canceled == JNI_TRUE);
201 }
202 
OnReceivedRedirect(const std::string & new_location,int http_status_code,const std::string & http_status_text,const net::HttpResponseHeaders * headers,bool was_cached,const std::string & negotiated_protocol,const std::string & proxy_server,int64_t received_byte_count)203 void CronetURLRequestAdapter::OnReceivedRedirect(
204     const std::string& new_location,
205     int http_status_code,
206     const std::string& http_status_text,
207     const net::HttpResponseHeaders* headers,
208     bool was_cached,
209     const std::string& negotiated_protocol,
210     const std::string& proxy_server,
211     int64_t received_byte_count) {
212   JNIEnv* env = base::android::AttachCurrentThread();
213   cronet::Java_CronetUrlRequest_onRedirectReceived(
214       env, owner_, ConvertUTF8ToJavaString(env, new_location), http_status_code,
215       ConvertUTF8ToJavaString(env, http_status_text),
216       ConvertResponseHeadersToJava(env, headers),
217       was_cached ? JNI_TRUE : JNI_FALSE,
218       ConvertUTF8ToJavaString(env, negotiated_protocol),
219       ConvertUTF8ToJavaString(env, proxy_server), received_byte_count);
220 }
221 
OnResponseStarted(int http_status_code,const std::string & http_status_text,const net::HttpResponseHeaders * headers,bool was_cached,const std::string & negotiated_protocol,const std::string & proxy_server,int64_t received_byte_count)222 void CronetURLRequestAdapter::OnResponseStarted(
223     int http_status_code,
224     const std::string& http_status_text,
225     const net::HttpResponseHeaders* headers,
226     bool was_cached,
227     const std::string& negotiated_protocol,
228     const std::string& proxy_server,
229     int64_t received_byte_count) {
230   JNIEnv* env = base::android::AttachCurrentThread();
231   cronet::Java_CronetUrlRequest_onResponseStarted(
232       env, owner_, http_status_code,
233       ConvertUTF8ToJavaString(env, http_status_text),
234       ConvertResponseHeadersToJava(env, headers),
235       was_cached ? JNI_TRUE : JNI_FALSE,
236       ConvertUTF8ToJavaString(env, negotiated_protocol),
237       ConvertUTF8ToJavaString(env, proxy_server), received_byte_count);
238 }
239 
OnReadCompleted(scoped_refptr<net::IOBuffer> buffer,int bytes_read,int64_t received_byte_count)240 void CronetURLRequestAdapter::OnReadCompleted(
241     scoped_refptr<net::IOBuffer> buffer,
242     int bytes_read,
243     int64_t received_byte_count) {
244   IOBufferWithByteBuffer* read_buffer =
245       reinterpret_cast<IOBufferWithByteBuffer*>(buffer.get());
246   JNIEnv* env = base::android::AttachCurrentThread();
247   cronet::Java_CronetUrlRequest_onReadCompleted(
248       env, owner_, read_buffer->byte_buffer(), bytes_read,
249       read_buffer->initial_position(), read_buffer->initial_limit(),
250       received_byte_count);
251 }
252 
OnSucceeded(int64_t received_byte_count)253 void CronetURLRequestAdapter::OnSucceeded(int64_t received_byte_count) {
254   JNIEnv* env = base::android::AttachCurrentThread();
255   cronet::Java_CronetUrlRequest_onSucceeded(env, owner_, received_byte_count);
256 }
257 
OnError(int net_error,int quic_error,const std::string & error_string,int64_t received_byte_count)258 void CronetURLRequestAdapter::OnError(int net_error,
259                                       int quic_error,
260                                       const std::string& error_string,
261                                       int64_t received_byte_count) {
262   JNIEnv* env = base::android::AttachCurrentThread();
263   cronet::Java_CronetUrlRequest_onError(
264       env, owner_, NetErrorToUrlRequestError(net_error), net_error, quic_error,
265       ConvertUTF8ToJavaString(env, error_string), received_byte_count);
266 }
267 
OnCanceled()268 void CronetURLRequestAdapter::OnCanceled() {
269   JNIEnv* env = base::android::AttachCurrentThread();
270   cronet::Java_CronetUrlRequest_onCanceled(env, owner_);
271 }
272 
OnDestroyed()273 void CronetURLRequestAdapter::OnDestroyed() {
274   JNIEnv* env = base::android::AttachCurrentThread();
275   cronet::Java_CronetUrlRequest_onNativeAdapterDestroyed(env, owner_);
276   // |this| adapter will be destroyed by the owner after return from this call.
277 }
278 
OnStatus(const base::android::ScopedJavaGlobalRef<jobject> & status_listener_ref,net::LoadState load_status)279 void CronetURLRequestAdapter::OnStatus(
280     const base::android::ScopedJavaGlobalRef<jobject>& status_listener_ref,
281     net::LoadState load_status) {
282   JNIEnv* env = base::android::AttachCurrentThread();
283   cronet::Java_CronetUrlRequest_onStatus(env, owner_, status_listener_ref,
284                                          load_status);
285 }
286 
OnMetricsCollected(const base::Time & start_time,const base::TimeTicks & start_ticks,const base::TimeTicks & dns_start,const base::TimeTicks & dns_end,const base::TimeTicks & connect_start,const base::TimeTicks & connect_end,const base::TimeTicks & ssl_start,const base::TimeTicks & ssl_end,const base::TimeTicks & send_start,const base::TimeTicks & send_end,const base::TimeTicks & push_start,const base::TimeTicks & push_end,const base::TimeTicks & receive_headers_end,const base::TimeTicks & request_end,bool socket_reused,int64_t sent_bytes_count,int64_t received_bytes_count)287 void CronetURLRequestAdapter::OnMetricsCollected(
288     const base::Time& start_time,
289     const base::TimeTicks& start_ticks,
290     const base::TimeTicks& dns_start,
291     const base::TimeTicks& dns_end,
292     const base::TimeTicks& connect_start,
293     const base::TimeTicks& connect_end,
294     const base::TimeTicks& ssl_start,
295     const base::TimeTicks& ssl_end,
296     const base::TimeTicks& send_start,
297     const base::TimeTicks& send_end,
298     const base::TimeTicks& push_start,
299     const base::TimeTicks& push_end,
300     const base::TimeTicks& receive_headers_end,
301     const base::TimeTicks& request_end,
302     bool socket_reused,
303     int64_t sent_bytes_count,
304     int64_t received_bytes_count) {
305   JNIEnv* env = base::android::AttachCurrentThread();
306   Java_CronetUrlRequest_onMetricsCollected(
307       env, owner_,
308       metrics_util::ConvertTime(start_ticks, start_ticks, start_time),
309       metrics_util::ConvertTime(dns_start, start_ticks, start_time),
310       metrics_util::ConvertTime(dns_end, start_ticks, start_time),
311       metrics_util::ConvertTime(connect_start, start_ticks, start_time),
312       metrics_util::ConvertTime(connect_end, start_ticks, start_time),
313       metrics_util::ConvertTime(ssl_start, start_ticks, start_time),
314       metrics_util::ConvertTime(ssl_end, start_ticks, start_time),
315       metrics_util::ConvertTime(send_start, start_ticks, start_time),
316       metrics_util::ConvertTime(send_end, start_ticks, start_time),
317       metrics_util::ConvertTime(push_start, start_ticks, start_time),
318       metrics_util::ConvertTime(push_end, start_ticks, start_time),
319       metrics_util::ConvertTime(receive_headers_end, start_ticks, start_time),
320       metrics_util::ConvertTime(request_end, start_ticks, start_time),
321       socket_reused ? JNI_TRUE : JNI_FALSE, sent_bytes_count,
322       received_bytes_count);
323 }
324 
325 }  // namespace cronet
326