OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cronet_url_request_adapter.h" | 5 #include "cronet_url_request_adapter.h" |
6 | 6 |
7 #include <jni.h> | |
mmenke
2015/04/02 21:07:05
nit: Not needed (included in header file)
xunjieli
2015/04/02 21:50:13
Done.
| |
8 | |
9 #include "base/android/jni_android.h" | |
10 #include "base/android/jni_string.h" | |
mmenke
2015/04/02 21:07:05
nit: These two are used in the header
xunjieli
2015/04/02 21:50:13
Done.
| |
7 #include "base/bind.h" | 11 #include "base/bind.h" |
8 #include "base/location.h" | 12 #include "base/location.h" |
9 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/macros.h" | |
mmenke
2015/04/02 21:07:05
nit: in header
xunjieli
2015/04/02 21:50:13
Done.
| |
10 #include "components/cronet/android/cronet_url_request_context_adapter.h" | 15 #include "components/cronet/android/cronet_url_request_context_adapter.h" |
11 #include "components/cronet/android/wrapped_channel_upload_element_reader.h" | 16 #include "jni/CronetUrlRequest_jni.h" |
12 #include "net/base/io_buffer.h" | 17 #include "net/base/io_buffer.h" |
13 #include "net/base/load_flags.h" | 18 #include "net/base/load_flags.h" |
19 #include "net/base/net_errors.h" | |
20 #include "net/base/request_priority.h" | |
21 #include "net/http/http_response_headers.h" | |
14 #include "net/http/http_status_code.h" | 22 #include "net/http/http_status_code.h" |
23 #include "net/http/http_util.h" | |
15 #include "net/url_request/redirect_info.h" | 24 #include "net/url_request/redirect_info.h" |
16 #include "net/url_request/url_request_context.h" | 25 #include "net/url_request/url_request_context.h" |
17 | 26 |
27 using base::android::ConvertUTF8ToJavaString; | |
28 | |
18 namespace cronet { | 29 namespace cronet { |
19 | 30 |
31 namespace { | |
32 | |
20 static const int kReadBufferSize = 32768; | 33 static const int kReadBufferSize = 32768; |
21 | 34 |
35 } // namespace | |
mmenke
2015/04/02 21:07:05
nit: Either need static or anonymous namespace, n
xunjieli
2015/04/02 21:50:12
Done.
| |
36 | |
37 // Explicitly register static JNI functions. | |
38 bool CronetUrlRequestAdapterRegisterJni(JNIEnv* env) { | |
39 return RegisterNativesImpl(env); | |
40 } | |
41 | |
42 static jlong CreateRequestAdapter(JNIEnv* env, | |
43 jobject jurl_request, | |
44 jlong jurl_request_context_adapter, | |
45 jstring jurl_string, | |
46 jint jpriority) { | |
47 CronetURLRequestContextAdapter* context_adapter = | |
48 reinterpret_cast<CronetURLRequestContextAdapter*>( | |
49 jurl_request_context_adapter); | |
50 DCHECK(context_adapter); | |
51 | |
52 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl_string)); | |
53 | |
54 VLOG(1) << "New chromium network request_adapter: " | |
55 << url.possibly_invalid_spec(); | |
56 | |
57 CronetURLRequestAdapter* adapter = | |
58 new CronetURLRequestAdapter(context_adapter, env, jurl_request, url, | |
59 static_cast<net::RequestPriority>(jpriority)); | |
60 | |
61 return reinterpret_cast<jlong>(adapter); | |
62 } | |
63 | |
22 CronetURLRequestAdapter::CronetURLRequestAdapter( | 64 CronetURLRequestAdapter::CronetURLRequestAdapter( |
23 CronetURLRequestContextAdapter* context, | 65 CronetURLRequestContextAdapter* context, |
24 scoped_ptr<CronetURLRequestAdapterDelegate> delegate, | 66 JNIEnv* env, |
67 jobject jurl_request, | |
25 const GURL& url, | 68 const GURL& url, |
26 net::RequestPriority priority) | 69 net::RequestPriority priority) |
27 : context_(context), | 70 : context_(context), |
28 delegate_(delegate.Pass()), | |
29 initial_url_(url), | 71 initial_url_(url), |
30 initial_priority_(priority), | 72 initial_priority_(priority), |
31 initial_method_("GET"), | 73 initial_method_("GET"), |
32 load_flags_(context->default_load_flags()) { | 74 load_flags_(context->default_load_flags()) { |
75 owner_.Reset(env, jurl_request); | |
mmenke
2015/04/02 21:07:05
DCHECK(!context_->IsOnNetworkThread());?
xunjieli
2015/04/02 21:50:13
Done.
| |
33 } | 76 } |
34 | 77 |
35 CronetURLRequestAdapter::~CronetURLRequestAdapter() { | 78 CronetURLRequestAdapter::~CronetURLRequestAdapter() { |
36 DCHECK(IsOnNetworkThread()); | 79 DCHECK(context_->IsOnNetworkThread()); |
37 } | 80 } |
38 | 81 |
39 void CronetURLRequestAdapter::AddRequestHeader(const std::string& name, | 82 jboolean CronetURLRequestAdapter::SetHttpMethod(JNIEnv* env, |
40 const std::string& value) { | 83 jobject jcaller, |
41 DCHECK(!IsOnNetworkThread()); | 84 jstring jmethod) { |
42 initial_request_headers_.SetHeader(name, value); | 85 DCHECK(!context_->IsOnNetworkThread()); |
86 std::string method(base::android::ConvertJavaStringToUTF8(env, jmethod)); | |
87 // Http method is a token, just as header name. | |
88 if (!net::HttpUtil::IsValidHeaderName(method)) | |
89 return JNI_FALSE; | |
90 initial_method_ = method; | |
91 return JNI_TRUE; | |
43 } | 92 } |
44 | 93 |
45 void CronetURLRequestAdapter::DisableCache() { | 94 jboolean CronetURLRequestAdapter::AddRequestHeader(JNIEnv* env, |
46 DCHECK(!IsOnNetworkThread()); | 95 jobject jcaller, |
47 load_flags_ |= net::LOAD_DISABLE_CACHE; | 96 jstring jname, |
48 } | 97 jstring jvalue) { |
49 | 98 DCHECK(!context_->IsOnNetworkThread()); |
50 void CronetURLRequestAdapter::PostTaskToNetworkThread( | 99 std::string name(base::android::ConvertJavaStringToUTF8(env, jname)); |
51 const tracked_objects::Location& from_here, | 100 std::string value(base::android::ConvertJavaStringToUTF8(env, jvalue)); |
52 const base::Closure& task) { | 101 if (!net::HttpUtil::IsValidHeaderName(name) || |
53 DCHECK(!IsOnNetworkThread()); | 102 !net::HttpUtil::IsValidHeaderValue(value)) { |
54 context_->PostTaskToNetworkThread(from_here, task); | 103 return JNI_FALSE; |
55 } | 104 } |
56 | 105 initial_request_headers_.SetHeader(name, value); |
57 bool CronetURLRequestAdapter::IsOnNetworkThread() const { | 106 return JNI_TRUE; |
58 return context_->IsOnNetworkThread(); | |
59 } | 107 } |
60 | 108 |
61 void CronetURLRequestAdapter::SetUpload( | 109 void CronetURLRequestAdapter::SetUpload( |
62 scoped_ptr<net::UploadDataStream> upload) { | 110 scoped_ptr<net::UploadDataStream> upload) { |
63 DCHECK(!IsOnNetworkThread()); | 111 DCHECK(!context_->IsOnNetworkThread()); |
64 DCHECK(!upload_); | 112 DCHECK(!upload_); |
65 upload_ = upload.Pass(); | 113 upload_ = upload.Pass(); |
66 } | 114 } |
67 | 115 |
68 void CronetURLRequestAdapter::Start() { | 116 void CronetURLRequestAdapter::Start(JNIEnv* env, jobject jcaller) { |
69 DCHECK(IsOnNetworkThread()); | 117 DCHECK(!context_->IsOnNetworkThread()); |
118 context_->PostTaskToNetworkThread( | |
119 FROM_HERE, base::Bind(&CronetURLRequestAdapter::StartOnNetworkThread, | |
120 base::Unretained(this))); | |
121 } | |
122 | |
123 void CronetURLRequestAdapter::StartOnNetworkThread() { | |
mmenke
2015/04/02 21:07:05
For this, ReadDataOnNetworkThread, and DestroyOnNe
xunjieli
2015/04/02 21:50:12
Done.
| |
124 DCHECK(context_->IsOnNetworkThread()); | |
70 VLOG(1) << "Starting chromium request: " | 125 VLOG(1) << "Starting chromium request: " |
71 << initial_url_.possibly_invalid_spec().c_str() | 126 << initial_url_.possibly_invalid_spec().c_str() |
72 << " priority: " << RequestPriorityToString(initial_priority_); | 127 << " priority: " << RequestPriorityToString(initial_priority_); |
73 url_request_ = context_->GetURLRequestContext()->CreateRequest( | 128 url_request_ = context_->GetURLRequestContext()->CreateRequest( |
74 initial_url_, net::DEFAULT_PRIORITY, this); | 129 initial_url_, net::DEFAULT_PRIORITY, this); |
75 url_request_->SetLoadFlags(load_flags_); | 130 url_request_->SetLoadFlags(load_flags_); |
76 url_request_->set_method(initial_method_); | 131 url_request_->set_method(initial_method_); |
77 url_request_->SetExtraRequestHeaders(initial_request_headers_); | 132 url_request_->SetExtraRequestHeaders(initial_request_headers_); |
78 url_request_->SetPriority(initial_priority_); | 133 url_request_->SetPriority(initial_priority_); |
79 if (upload_) | 134 if (upload_) |
80 url_request_->set_upload(upload_.Pass()); | 135 url_request_->set_upload(upload_.Pass()); |
81 url_request_->Start(); | 136 url_request_->Start(); |
82 } | 137 } |
83 | 138 |
84 void CronetURLRequestAdapter::FollowDeferredRedirect() { | 139 void CronetURLRequestAdapter::ReadData(JNIEnv* env, jobject jcaller) { |
85 DCHECK(IsOnNetworkThread()); | 140 DCHECK(!context_->IsOnNetworkThread()); |
86 | 141 context_->PostTaskToNetworkThread( |
87 url_request_->FollowDeferredRedirect(); | 142 FROM_HERE, base::Bind(&CronetURLRequestAdapter::ReadDataOnNetworkThread, |
143 base::Unretained(this))); | |
88 } | 144 } |
89 | 145 |
90 void CronetURLRequestAdapter::ReadData() { | 146 void CronetURLRequestAdapter::ReadDataOnNetworkThread() { |
91 DCHECK(IsOnNetworkThread()); | 147 DCHECK(context_->IsOnNetworkThread()); |
92 if (!read_buffer_.get()) | 148 if (!read_buffer_.get()) |
93 read_buffer_ = new net::IOBufferWithSize(kReadBufferSize); | 149 read_buffer_ = new net::IOBufferWithSize(kReadBufferSize); |
94 | 150 |
95 int bytes_read = 0; | 151 int bytes_read = 0; |
96 url_request_->Read(read_buffer_.get(), read_buffer_->size(), &bytes_read); | 152 url_request_->Read(read_buffer_.get(), read_buffer_->size(), &bytes_read); |
97 // If IO is pending, wait for the URLRequest to call OnReadCompleted. | 153 // If IO is pending, wait for the URLRequest to call OnReadCompleted. |
98 if (url_request_->status().is_io_pending()) | 154 if (url_request_->status().is_io_pending()) |
99 return; | 155 return; |
100 | 156 |
101 OnReadCompleted(url_request_.get(), bytes_read); | 157 OnReadCompleted(url_request_.get(), bytes_read); |
102 } | 158 } |
103 | 159 |
104 void CronetURLRequestAdapter::Destroy() { | 160 void CronetURLRequestAdapter::Destroy(JNIEnv* env, jobject jcaller) { |
105 DCHECK(IsOnNetworkThread()); | 161 DCHECK(!context_->IsOnNetworkThread()); |
162 context_->PostTaskToNetworkThread( | |
163 FROM_HERE, base::Bind(&CronetURLRequestAdapter::DestroyOnNetworkThread, | |
164 base::Unretained(this))); | |
165 } | |
166 | |
167 void CronetURLRequestAdapter::DestroyOnNetworkThread() { | |
168 DCHECK(context_->IsOnNetworkThread()); | |
106 delete this; | 169 delete this; |
107 } | 170 } |
108 | 171 |
109 const net::HttpResponseHeaders* | 172 void CronetURLRequestAdapter::PopulateResponseHeaders(JNIEnv* env, |
110 CronetURLRequestAdapter::GetResponseHeaders() const { | 173 jobject jurl_request, |
111 DCHECK(IsOnNetworkThread()); | 174 jobject jheaders_list) { |
112 return url_request_->response_headers(); | 175 DCHECK(context_->IsOnNetworkThread()); |
176 const net::HttpResponseHeaders* headers = url_request_->response_headers(); | |
177 if (headers == nullptr) | |
178 return; | |
179 | |
180 void* iter = nullptr; | |
181 std::string header_name; | |
182 std::string header_value; | |
183 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { | |
184 base::android::ScopedJavaLocalRef<jstring> name = | |
185 ConvertUTF8ToJavaString(env, header_name); | |
186 base::android::ScopedJavaLocalRef<jstring> value = | |
187 ConvertUTF8ToJavaString(env, header_value); | |
188 Java_CronetUrlRequest_onAppendResponseHeader( | |
189 env, jurl_request, jheaders_list, name.obj(), value.obj()); | |
190 } | |
113 } | 191 } |
114 | 192 |
115 const std::string& CronetURLRequestAdapter::GetNegotiatedProtocol() const { | 193 void CronetURLRequestAdapter::FollowDeferredRedirect(JNIEnv* env, |
116 DCHECK(IsOnNetworkThread()); | 194 jobject jcaller) { |
117 return url_request_->response_info().npn_negotiated_protocol; | 195 DCHECK(!context_->IsOnNetworkThread()); |
196 context_->PostTaskToNetworkThread( | |
197 FROM_HERE, base::Bind(&net::URLRequest::FollowDeferredRedirect, | |
198 base::Unretained(url_request_.get()))); | |
mmenke
2015/04/02 21:07:05
While this works, I think it's a little ugly and m
xunjieli
2015/04/02 21:50:13
Done.
| |
118 } | 199 } |
119 | 200 |
120 bool CronetURLRequestAdapter::GetWasCached() const { | 201 void CronetURLRequestAdapter::DisableCache(JNIEnv* env, jobject jcaller) { |
121 DCHECK(IsOnNetworkThread()); | 202 DCHECK(!context_->IsOnNetworkThread()); |
203 load_flags_ |= net::LOAD_DISABLE_CACHE; | |
204 } | |
205 | |
206 base::android::ScopedJavaLocalRef<jstring> | |
207 CronetURLRequestAdapter::GetHttpStatusText(JNIEnv* env, jobject jcaller) const { | |
208 DCHECK(context_->IsOnNetworkThread()); | |
209 const net::HttpResponseHeaders* headers = url_request_->response_headers(); | |
210 return ConvertUTF8ToJavaString(env, headers->GetStatusText()); | |
211 } | |
212 | |
213 base::android::ScopedJavaLocalRef<jstring> | |
214 CronetURLRequestAdapter::GetNegotiatedProtocol(JNIEnv* env, | |
215 jobject jcaller) const { | |
216 DCHECK(context_->IsOnNetworkThread()); | |
217 return ConvertUTF8ToJavaString( | |
218 env, url_request_->response_info().npn_negotiated_protocol); | |
219 } | |
220 | |
221 jboolean CronetURLRequestAdapter::GetWasCached(JNIEnv* env, | |
222 jobject jcaller) const { | |
223 DCHECK(context_->IsOnNetworkThread()); | |
122 return url_request_->response_info().was_cached; | 224 return url_request_->response_info().was_cached; |
123 } | 225 } |
124 | 226 |
125 int64 CronetURLRequestAdapter::GetTotalReceivedBytes() const { | 227 int64 CronetURLRequestAdapter::GetTotalReceivedBytes(JNIEnv* env, |
126 DCHECK(IsOnNetworkThread()); | 228 jobject jcaller) const { |
229 DCHECK(context_->IsOnNetworkThread()); | |
127 return url_request_->GetTotalReceivedBytes(); | 230 return url_request_->GetTotalReceivedBytes(); |
128 } | 231 } |
129 | 232 |
130 // net::URLRequest::Delegate overrides (called on network thread). | 233 // net::URLRequest::Delegate overrides (called on network thread). |
131 | 234 |
132 void CronetURLRequestAdapter::OnReceivedRedirect( | 235 void CronetURLRequestAdapter::OnReceivedRedirect( |
133 net::URLRequest* request, | 236 net::URLRequest* request, |
134 const net::RedirectInfo& redirect_info, | 237 const net::RedirectInfo& redirect_info, |
135 bool* defer_redirect) { | 238 bool* defer_redirect) { |
136 DCHECK(IsOnNetworkThread()); | 239 DCHECK(context_->IsOnNetworkThread()); |
137 DCHECK(request->status().is_success()); | 240 DCHECK(request->status().is_success()); |
138 delegate_->OnRedirect(redirect_info.new_url, redirect_info.status_code); | 241 JNIEnv* env = base::android::AttachCurrentThread(); |
242 cronet::Java_CronetUrlRequest_onRedirect( | |
243 env, owner_.obj(), | |
244 ConvertUTF8ToJavaString(env, redirect_info.new_url.spec()).obj(), | |
245 redirect_info.status_code); | |
139 *defer_redirect = true; | 246 *defer_redirect = true; |
140 } | 247 } |
141 | 248 |
142 void CronetURLRequestAdapter::OnResponseStarted(net::URLRequest* request) { | 249 void CronetURLRequestAdapter::OnResponseStarted(net::URLRequest* request) { |
143 DCHECK(IsOnNetworkThread()); | 250 DCHECK(context_->IsOnNetworkThread()); |
144 if (MaybeReportError(request)) | 251 if (MaybeReportError(request)) |
145 return; | 252 return; |
146 delegate_->OnResponseStarted(request->GetResponseCode()); | 253 JNIEnv* env = base::android::AttachCurrentThread(); |
254 cronet::Java_CronetUrlRequest_onResponseStarted(env, owner_.obj(), | |
255 request->GetResponseCode()); | |
147 } | 256 } |
148 | 257 |
149 void CronetURLRequestAdapter::OnReadCompleted(net::URLRequest* request, | 258 void CronetURLRequestAdapter::OnReadCompleted(net::URLRequest* request, |
150 int bytes_read) { | 259 int bytes_read) { |
151 DCHECK(IsOnNetworkThread()); | 260 DCHECK(context_->IsOnNetworkThread()); |
152 if (MaybeReportError(request)) | 261 if (MaybeReportError(request)) |
153 return; | 262 return; |
154 if (bytes_read != 0) { | 263 if (bytes_read != 0) { |
155 delegate_->OnBytesRead( | 264 JNIEnv* env = base::android::AttachCurrentThread(); |
156 reinterpret_cast<unsigned char*>(read_buffer_->data()), bytes_read); | 265 base::android::ScopedJavaLocalRef<jobject> java_buffer( |
266 env, env->NewDirectByteBuffer(read_buffer_->data(), bytes_read)); | |
267 cronet::Java_CronetUrlRequest_onDataReceived(env, owner_.obj(), | |
268 java_buffer.obj()); | |
157 } else { | 269 } else { |
158 delegate_->OnRequestFinished(); | 270 JNIEnv* env = base::android::AttachCurrentThread(); |
271 cronet::Java_CronetUrlRequest_onSucceeded(env, owner_.obj()); | |
159 } | 272 } |
160 } | 273 } |
161 | 274 |
162 bool CronetURLRequestAdapter::MaybeReportError(net::URLRequest* request) const { | 275 bool CronetURLRequestAdapter::MaybeReportError(net::URLRequest* request) const { |
163 DCHECK_NE(net::URLRequestStatus::IO_PENDING, url_request_->status().status()); | 276 DCHECK_NE(net::URLRequestStatus::IO_PENDING, url_request_->status().status()); |
164 DCHECK_EQ(request, url_request_); | 277 DCHECK_EQ(request, url_request_); |
165 if (url_request_->status().is_success()) | 278 if (url_request_->status().is_success()) |
166 return false; | 279 return false; |
167 VLOG(1) << "Error " << url_request_->status().error() | 280 int net_error = url_request_->status().error(); |
281 VLOG(1) << "Error " << net::ErrorToString(net_error) | |
168 << " on chromium request: " << initial_url_.possibly_invalid_spec(); | 282 << " on chromium request: " << initial_url_.possibly_invalid_spec(); |
169 delegate_->OnError(url_request_->status().error()); | 283 JNIEnv* env = base::android::AttachCurrentThread(); |
284 cronet::Java_CronetUrlRequest_onError( | |
285 env, owner_.obj(), net_error, | |
286 ConvertUTF8ToJavaString(env, net::ErrorToString(net_error)).obj()); | |
170 return true; | 287 return true; |
171 } | 288 } |
172 | 289 |
173 } // namespace cronet | 290 } // namespace cronet |
OLD | NEW |