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