Index: components/cronet/android/cronet_url_request_adapter.cc |
diff --git a/components/cronet/android/cronet_url_request_adapter.cc b/components/cronet/android/cronet_url_request_adapter.cc |
index ff36601caf397ea73e79e892620c55fee18fe6a3..237179984a92e5915d8c4e6736d261176cc77b03 100644 |
--- a/components/cronet/android/cronet_url_request_adapter.cc |
+++ b/components/cronet/android/cronet_url_request_adapter.cc |
@@ -8,122 +8,184 @@ |
#include "base/location.h" |
#include "base/logging.h" |
#include "components/cronet/android/cronet_url_request_context_adapter.h" |
-#include "components/cronet/android/wrapped_channel_upload_element_reader.h" |
+#include "jni/CronetUrlRequest_jni.h" |
#include "net/base/io_buffer.h" |
#include "net/base/load_flags.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/request_priority.h" |
+#include "net/http/http_response_headers.h" |
#include "net/http/http_status_code.h" |
+#include "net/http/http_util.h" |
#include "net/url_request/redirect_info.h" |
#include "net/url_request/url_request_context.h" |
+using base::android::ConvertUTF8ToJavaString; |
+ |
namespace cronet { |
static const int kReadBufferSize = 32768; |
+// Explicitly register static JNI functions. |
+bool CronetUrlRequestAdapterRegisterJni(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+static jlong CreateRequestAdapter(JNIEnv* env, |
+ jobject jurl_request, |
+ jlong jurl_request_context_adapter, |
+ jstring jurl_string, |
+ jint jpriority) { |
+ CronetURLRequestContextAdapter* context_adapter = |
+ reinterpret_cast<CronetURLRequestContextAdapter*>( |
+ jurl_request_context_adapter); |
+ DCHECK(context_adapter); |
+ |
+ GURL url(base::android::ConvertJavaStringToUTF8(env, jurl_string)); |
+ |
+ VLOG(1) << "New chromium network request_adapter: " |
+ << url.possibly_invalid_spec(); |
+ |
+ CronetURLRequestAdapter* adapter = |
+ new CronetURLRequestAdapter(context_adapter, env, jurl_request, url, |
+ static_cast<net::RequestPriority>(jpriority)); |
+ |
+ return reinterpret_cast<jlong>(adapter); |
+} |
+ |
CronetURLRequestAdapter::CronetURLRequestAdapter( |
CronetURLRequestContextAdapter* context, |
- scoped_ptr<CronetURLRequestAdapterDelegate> delegate, |
+ JNIEnv* env, |
+ jobject jurl_request, |
const GURL& url, |
net::RequestPriority priority) |
: context_(context), |
- delegate_(delegate.Pass()), |
initial_url_(url), |
initial_priority_(priority), |
initial_method_("GET"), |
load_flags_(context->default_load_flags()) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ owner_.Reset(env, jurl_request); |
} |
CronetURLRequestAdapter::~CronetURLRequestAdapter() { |
- DCHECK(IsOnNetworkThread()); |
+ DCHECK(context_->IsOnNetworkThread()); |
} |
-void CronetURLRequestAdapter::AddRequestHeader(const std::string& name, |
- const std::string& value) { |
- DCHECK(!IsOnNetworkThread()); |
- initial_request_headers_.SetHeader(name, value); |
+jboolean CronetURLRequestAdapter::SetHttpMethod(JNIEnv* env, |
+ jobject jcaller, |
+ jstring jmethod) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ std::string method(base::android::ConvertJavaStringToUTF8(env, jmethod)); |
+ // Http method is a token, just as header name. |
+ if (!net::HttpUtil::IsValidHeaderName(method)) |
+ return JNI_FALSE; |
+ initial_method_ = method; |
+ return JNI_TRUE; |
} |
-void CronetURLRequestAdapter::DisableCache() { |
- DCHECK(!IsOnNetworkThread()); |
- load_flags_ |= net::LOAD_DISABLE_CACHE; |
-} |
- |
-void CronetURLRequestAdapter::PostTaskToNetworkThread( |
- const tracked_objects::Location& from_here, |
- const base::Closure& task) { |
- DCHECK(!IsOnNetworkThread()); |
- context_->PostTaskToNetworkThread(from_here, task); |
+jboolean CronetURLRequestAdapter::AddRequestHeader(JNIEnv* env, |
+ jobject jcaller, |
+ jstring jname, |
+ jstring jvalue) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ std::string name(base::android::ConvertJavaStringToUTF8(env, jname)); |
+ std::string value(base::android::ConvertJavaStringToUTF8(env, jvalue)); |
+ if (!net::HttpUtil::IsValidHeaderName(name) || |
+ !net::HttpUtil::IsValidHeaderValue(value)) { |
+ return JNI_FALSE; |
+ } |
+ initial_request_headers_.SetHeader(name, value); |
+ return JNI_TRUE; |
} |
-bool CronetURLRequestAdapter::IsOnNetworkThread() const { |
- return context_->IsOnNetworkThread(); |
+void CronetURLRequestAdapter::DisableCache(JNIEnv* env, jobject jcaller) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ load_flags_ |= net::LOAD_DISABLE_CACHE; |
} |
void CronetURLRequestAdapter::SetUpload( |
scoped_ptr<net::UploadDataStream> upload) { |
- DCHECK(!IsOnNetworkThread()); |
+ DCHECK(!context_->IsOnNetworkThread()); |
DCHECK(!upload_); |
upload_ = upload.Pass(); |
} |
-void CronetURLRequestAdapter::Start() { |
- DCHECK(IsOnNetworkThread()); |
- VLOG(1) << "Starting chromium request: " |
- << initial_url_.possibly_invalid_spec().c_str() |
- << " priority: " << RequestPriorityToString(initial_priority_); |
- url_request_ = context_->GetURLRequestContext()->CreateRequest( |
- initial_url_, net::DEFAULT_PRIORITY, this); |
- url_request_->SetLoadFlags(load_flags_); |
- url_request_->set_method(initial_method_); |
- url_request_->SetExtraRequestHeaders(initial_request_headers_); |
- url_request_->SetPriority(initial_priority_); |
- if (upload_) |
- url_request_->set_upload(upload_.Pass()); |
- url_request_->Start(); |
+void CronetURLRequestAdapter::Start(JNIEnv* env, jobject jcaller) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ context_->PostTaskToNetworkThread( |
+ FROM_HERE, base::Bind(&CronetURLRequestAdapter::StartOnNetworkThread, |
+ base::Unretained(this))); |
} |
-void CronetURLRequestAdapter::FollowDeferredRedirect() { |
- DCHECK(IsOnNetworkThread()); |
+void CronetURLRequestAdapter::FollowDeferredRedirect(JNIEnv* env, |
+ jobject jcaller) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ context_->PostTaskToNetworkThread( |
+ FROM_HERE, |
+ base::Bind( |
+ &CronetURLRequestAdapter::FollowDeferredRedirectOnNetworkThread, |
+ base::Unretained(this))); |
+} |
- url_request_->FollowDeferredRedirect(); |
+void CronetURLRequestAdapter::ReadData(JNIEnv* env, jobject jcaller) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ context_->PostTaskToNetworkThread( |
+ FROM_HERE, base::Bind(&CronetURLRequestAdapter::ReadDataOnNetworkThread, |
+ base::Unretained(this))); |
} |
-void CronetURLRequestAdapter::ReadData() { |
- DCHECK(IsOnNetworkThread()); |
- if (!read_buffer_.get()) |
- read_buffer_ = new net::IOBufferWithSize(kReadBufferSize); |
+void CronetURLRequestAdapter::Destroy(JNIEnv* env, jobject jcaller) { |
+ DCHECK(!context_->IsOnNetworkThread()); |
+ context_->PostTaskToNetworkThread( |
+ FROM_HERE, base::Bind(&CronetURLRequestAdapter::DestroyOnNetworkThread, |
+ base::Unretained(this))); |
+} |
- int bytes_read = 0; |
- url_request_->Read(read_buffer_.get(), read_buffer_->size(), &bytes_read); |
- // If IO is pending, wait for the URLRequest to call OnReadCompleted. |
- if (url_request_->status().is_io_pending()) |
+void CronetURLRequestAdapter::PopulateResponseHeaders(JNIEnv* env, |
+ jobject jurl_request, |
+ jobject jheaders_list) { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ const net::HttpResponseHeaders* headers = url_request_->response_headers(); |
+ if (headers == nullptr) |
return; |
- OnReadCompleted(url_request_.get(), bytes_read); |
-} |
- |
-void CronetURLRequestAdapter::Destroy() { |
- DCHECK(IsOnNetworkThread()); |
- delete this; |
+ void* iter = nullptr; |
+ std::string header_name; |
+ std::string header_value; |
+ while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { |
+ base::android::ScopedJavaLocalRef<jstring> name = |
+ ConvertUTF8ToJavaString(env, header_name); |
+ base::android::ScopedJavaLocalRef<jstring> value = |
+ ConvertUTF8ToJavaString(env, header_value); |
+ Java_CronetUrlRequest_onAppendResponseHeader( |
+ env, jurl_request, jheaders_list, name.obj(), value.obj()); |
+ } |
} |
-const net::HttpResponseHeaders* |
-CronetURLRequestAdapter::GetResponseHeaders() const { |
- DCHECK(IsOnNetworkThread()); |
- return url_request_->response_headers(); |
+base::android::ScopedJavaLocalRef<jstring> |
+CronetURLRequestAdapter::GetHttpStatusText(JNIEnv* env, jobject jcaller) const { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ const net::HttpResponseHeaders* headers = url_request_->response_headers(); |
+ return ConvertUTF8ToJavaString(env, headers->GetStatusText()); |
} |
-const std::string& CronetURLRequestAdapter::GetNegotiatedProtocol() const { |
- DCHECK(IsOnNetworkThread()); |
- return url_request_->response_info().npn_negotiated_protocol; |
+base::android::ScopedJavaLocalRef<jstring> |
+CronetURLRequestAdapter::GetNegotiatedProtocol(JNIEnv* env, |
+ jobject jcaller) const { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ return ConvertUTF8ToJavaString( |
+ env, url_request_->response_info().npn_negotiated_protocol); |
} |
-bool CronetURLRequestAdapter::GetWasCached() const { |
- DCHECK(IsOnNetworkThread()); |
+jboolean CronetURLRequestAdapter::GetWasCached(JNIEnv* env, |
+ jobject jcaller) const { |
+ DCHECK(context_->IsOnNetworkThread()); |
return url_request_->response_info().was_cached; |
} |
-int64 CronetURLRequestAdapter::GetTotalReceivedBytes() const { |
- DCHECK(IsOnNetworkThread()); |
+int64 CronetURLRequestAdapter::GetTotalReceivedBytes(JNIEnv* env, |
+ jobject jcaller) const { |
+ DCHECK(context_->IsOnNetworkThread()); |
return url_request_->GetTotalReceivedBytes(); |
} |
@@ -133,40 +195,94 @@ void CronetURLRequestAdapter::OnReceivedRedirect( |
net::URLRequest* request, |
const net::RedirectInfo& redirect_info, |
bool* defer_redirect) { |
- DCHECK(IsOnNetworkThread()); |
+ DCHECK(context_->IsOnNetworkThread()); |
DCHECK(request->status().is_success()); |
- delegate_->OnRedirect(redirect_info.new_url, redirect_info.status_code); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ cronet::Java_CronetUrlRequest_onRedirect( |
+ env, owner_.obj(), |
+ ConvertUTF8ToJavaString(env, redirect_info.new_url.spec()).obj(), |
+ redirect_info.status_code); |
*defer_redirect = true; |
} |
void CronetURLRequestAdapter::OnResponseStarted(net::URLRequest* request) { |
- DCHECK(IsOnNetworkThread()); |
+ DCHECK(context_->IsOnNetworkThread()); |
if (MaybeReportError(request)) |
return; |
- delegate_->OnResponseStarted(request->GetResponseCode()); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ cronet::Java_CronetUrlRequest_onResponseStarted(env, owner_.obj(), |
+ request->GetResponseCode()); |
} |
void CronetURLRequestAdapter::OnReadCompleted(net::URLRequest* request, |
int bytes_read) { |
- DCHECK(IsOnNetworkThread()); |
+ DCHECK(context_->IsOnNetworkThread()); |
if (MaybeReportError(request)) |
return; |
if (bytes_read != 0) { |
- delegate_->OnBytesRead( |
- reinterpret_cast<unsigned char*>(read_buffer_->data()), bytes_read); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ base::android::ScopedJavaLocalRef<jobject> java_buffer( |
+ env, env->NewDirectByteBuffer(read_buffer_->data(), bytes_read)); |
+ cronet::Java_CronetUrlRequest_onDataReceived(env, owner_.obj(), |
+ java_buffer.obj()); |
} else { |
- delegate_->OnRequestFinished(); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ cronet::Java_CronetUrlRequest_onSucceeded(env, owner_.obj()); |
} |
} |
+void CronetURLRequestAdapter::StartOnNetworkThread() { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ VLOG(1) << "Starting chromium request: " |
+ << initial_url_.possibly_invalid_spec().c_str() |
+ << " priority: " << RequestPriorityToString(initial_priority_); |
+ url_request_ = context_->GetURLRequestContext()->CreateRequest( |
+ initial_url_, net::DEFAULT_PRIORITY, this); |
+ url_request_->SetLoadFlags(load_flags_); |
+ url_request_->set_method(initial_method_); |
+ url_request_->SetExtraRequestHeaders(initial_request_headers_); |
+ url_request_->SetPriority(initial_priority_); |
+ if (upload_) |
+ url_request_->set_upload(upload_.Pass()); |
+ url_request_->Start(); |
+} |
+ |
+void CronetURLRequestAdapter::FollowDeferredRedirectOnNetworkThread() { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ url_request_->FollowDeferredRedirect(); |
+} |
+ |
+void CronetURLRequestAdapter::ReadDataOnNetworkThread() { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ if (!read_buffer_.get()) |
+ read_buffer_ = new net::IOBufferWithSize(kReadBufferSize); |
+ |
+ int bytes_read = 0; |
+ url_request_->Read(read_buffer_.get(), read_buffer_->size(), &bytes_read); |
+ // If IO is pending, wait for the URLRequest to call OnReadCompleted. |
+ if (url_request_->status().is_io_pending()) |
+ return; |
+ |
+ OnReadCompleted(url_request_.get(), bytes_read); |
+} |
+ |
+void CronetURLRequestAdapter::DestroyOnNetworkThread() { |
+ DCHECK(context_->IsOnNetworkThread()); |
+ delete this; |
+} |
+ |
bool CronetURLRequestAdapter::MaybeReportError(net::URLRequest* request) const { |
DCHECK_NE(net::URLRequestStatus::IO_PENDING, url_request_->status().status()); |
DCHECK_EQ(request, url_request_); |
if (url_request_->status().is_success()) |
return false; |
- VLOG(1) << "Error " << url_request_->status().error() |
+ int net_error = url_request_->status().error(); |
+ VLOG(1) << "Error " << net::ErrorToString(net_error) |
<< " on chromium request: " << initial_url_.possibly_invalid_spec(); |
- delegate_->OnError(url_request_->status().error()); |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ cronet::Java_CronetUrlRequest_onError( |
+ env, owner_.obj(), net_error, |
+ ConvertUTF8ToJavaString(env, net::ErrorToString(net_error)).obj()); |
return true; |
} |