Merge UrlRequest.java into ChromiumUrlRequest.java
BUG=390267 Review URL: https://codereview.chromium.org/458633002 Cr-Commit-Position: refs/heads/master@{#289894} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289894 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
components
cronet.gypi
cronet
android
chromium_url_request.ccchromium_url_request.hchromium_url_request_context.ccchromium_url_request_context.hchromium_url_request_error_list.hchromium_url_request_priority_list.hcronet_jni.cc
java
src
sample
javatests
src
org
chromium
cronet_sample_apk
src
org
chromium
cronet_sample_apk
@ -11,8 +11,8 @@
|
||||
'target_name': 'cronet_jni_headers',
|
||||
'type': 'none',
|
||||
'sources': [
|
||||
'cronet/android/java/src/org/chromium/net/UrlRequest.java',
|
||||
'cronet/android/java/src/org/chromium/net/UrlRequestContext.java',
|
||||
'cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java',
|
||||
'cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java',
|
||||
],
|
||||
'variables': {
|
||||
'jni_gen_package': 'cronet',
|
||||
@ -23,11 +23,11 @@
|
||||
'target_name': 'cronet_url_request_error_list',
|
||||
'type': 'none',
|
||||
'sources': [
|
||||
'cronet/android/java/src/org/chromium/net/UrlRequestError.template',
|
||||
'cronet/android/java/src/org/chromium/net/ChromiumUrlRequestError.template',
|
||||
],
|
||||
'variables': {
|
||||
'package_name': 'org/chromium/cronet',
|
||||
'template_deps': ['cronet/android/org_chromium_net_UrlRequest_error_list.h'],
|
||||
'template_deps': ['cronet/android/chromium_url_request_error_list.h'],
|
||||
},
|
||||
'includes': [ '../build/android/java_cpp_template.gypi' ],
|
||||
},
|
||||
@ -35,11 +35,11 @@
|
||||
'target_name': 'cronet_url_request_priority_list',
|
||||
'type': 'none',
|
||||
'sources': [
|
||||
'cronet/android/java/src/org/chromium/net/UrlRequestPriority.template',
|
||||
'cronet/android/java/src/org/chromium/net/ChromiumUrlRequestPriority.template',
|
||||
],
|
||||
'variables': {
|
||||
'package_name': 'org/chromium/cronet',
|
||||
'template_deps': ['cronet/android/org_chromium_net_UrlRequest_priority_list.h'],
|
||||
'template_deps': ['cronet/android/chromium_url_request_priority_list.h'],
|
||||
},
|
||||
'includes': [ '../build/android/java_cpp_template.gypi' ],
|
||||
},
|
||||
@ -110,14 +110,13 @@
|
||||
'cronet/url_request_context_config.cc',
|
||||
'cronet/url_request_context_config.h',
|
||||
'cronet/url_request_context_config_list.h',
|
||||
'cronet/android/chromium_url_request.cc',
|
||||
'cronet/android/chromium_url_request.h',
|
||||
'cronet/android/chromium_url_request_error_list.h',
|
||||
'cronet/android/chromium_url_request_priority_list.h',
|
||||
'cronet/android/chromium_url_request_context.cc',
|
||||
'cronet/android/chromium_url_request_context.h',
|
||||
'cronet/android/cronet_jni.cc',
|
||||
'cronet/android/org_chromium_net_UrlRequest.cc',
|
||||
'cronet/android/org_chromium_net_UrlRequest.h',
|
||||
'cronet/android/org_chromium_net_UrlRequest_error_list.h',
|
||||
'cronet/android/org_chromium_net_UrlRequest_priority_list.h',
|
||||
'cronet/android/org_chromium_net_UrlRequestContext.cc',
|
||||
'cronet/android/org_chromium_net_UrlRequestContext.h',
|
||||
'cronet/android/org_chromium_net_UrlRequestContext_config_list.h',
|
||||
'cronet/android/url_request_adapter.cc',
|
||||
'cronet/android/url_request_adapter.h',
|
||||
'cronet/android/url_request_context_adapter.cc',
|
||||
@ -190,13 +189,11 @@
|
||||
'java_in_dir': 'cronet/android/java',
|
||||
'javac_includes': [
|
||||
'**/ChromiumUrlRequest.java',
|
||||
'**/ChromiumUrlRequestContext.java',
|
||||
'**/ChromiumUrlRequestError.java',
|
||||
'**/ChromiumUrlRequestFactory.java',
|
||||
'**/ChromiumUrlRequestPriority.java',
|
||||
'**/LibraryLoader.java',
|
||||
# TODO(mef): Merge UrlRequest*.java into ChromiumUrlRequest*.java
|
||||
'**/UrlRequest.java',
|
||||
'**/UrlRequestContext.java',
|
||||
'**/UrlRequestError.java',
|
||||
'**/UrlRequestPriority.java',
|
||||
'**/UsedByReflection.java',
|
||||
],
|
||||
},
|
||||
|
@ -2,14 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest.h"
|
||||
#include "components/cronet/android/chromium_url_request.h"
|
||||
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/jni_string.h"
|
||||
#include "base/macros.h"
|
||||
#include "components/cronet/android/url_request_adapter.h"
|
||||
#include "components/cronet/android/url_request_context_adapter.h"
|
||||
#include "jni/UrlRequest_jni.h"
|
||||
#include "jni/ChromiumUrlRequest_jni.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "net/base/request_priority.h"
|
||||
#include "net/http/http_response_headers.h"
|
||||
@ -63,7 +63,7 @@ class JniURLRequestAdapterDelegate
|
||||
|
||||
virtual void OnResponseStarted(URLRequestAdapter* request) OVERRIDE {
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
cronet::Java_UrlRequest_onResponseStarted(env, owner_);
|
||||
cronet::Java_ChromiumUrlRequest_onResponseStarted(env, owner_);
|
||||
}
|
||||
|
||||
virtual void OnBytesRead(URLRequestAdapter* request) OVERRIDE {
|
||||
@ -72,13 +72,14 @@ class JniURLRequestAdapterDelegate
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
base::android::ScopedJavaLocalRef<jobject> java_buffer(
|
||||
env, env->NewDirectByteBuffer(request->Data(), bytes_read));
|
||||
cronet::Java_UrlRequest_onBytesRead(env, owner_, java_buffer.obj());
|
||||
cronet::Java_ChromiumUrlRequest_onBytesRead(
|
||||
env, owner_, java_buffer.obj());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnRequestFinished(URLRequestAdapter* request) OVERRIDE {
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
cronet::Java_UrlRequest_finish(env, owner_);
|
||||
cronet::Java_ChromiumUrlRequest_finish(env, owner_);
|
||||
}
|
||||
|
||||
virtual int ReadFromUploadChannel(net::IOBuffer* buf,
|
||||
@ -86,7 +87,7 @@ class JniURLRequestAdapterDelegate
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
base::android::ScopedJavaLocalRef<jobject> java_buffer(
|
||||
env, env->NewDirectByteBuffer(buf->data(), buf_length));
|
||||
jint bytes_read = cronet::Java_UrlRequest_readFromUploadChannel(
|
||||
jint bytes_read = cronet::Java_ChromiumUrlRequest_readFromUploadChannel(
|
||||
env, owner_, java_buffer.obj());
|
||||
return bytes_read;
|
||||
}
|
||||
@ -106,7 +107,9 @@ class JniURLRequestAdapterDelegate
|
||||
} // namespace
|
||||
|
||||
// Explicitly register static JNI functions.
|
||||
bool UrlRequestRegisterJni(JNIEnv* env) { return RegisterNativesImpl(env); }
|
||||
bool ChromiumUrlRequestRegisterJni(JNIEnv* env) {
|
||||
return RegisterNativesImpl(env);
|
||||
}
|
||||
|
||||
static jlong CreateRequestAdapter(JNIEnv* env,
|
||||
jobject object,
|
||||
@ -196,7 +199,6 @@ static void SetUploadChannel(JNIEnv* env,
|
||||
request->SetUploadChannel(env, content_length);
|
||||
}
|
||||
|
||||
|
||||
/* synchronized */
|
||||
static void Start(JNIEnv* env, jobject object, jlong urlRequestAdapter) {
|
||||
URLRequestAdapter* request =
|
||||
@ -353,7 +355,7 @@ static void GetAllHeaders(JNIEnv* env,
|
||||
ConvertUTF8ToJavaString(env, header_name);
|
||||
ScopedJavaLocalRef<jstring> value =
|
||||
ConvertUTF8ToJavaString(env, header_value);
|
||||
Java_UrlRequest_onAppendResponseHeader(
|
||||
Java_ChromiumUrlRequest_onAppendResponseHeader(
|
||||
env, object, headersMap, name.Release(), value.Release());
|
||||
}
|
||||
|
||||
@ -361,7 +363,7 @@ static void GetAllHeaders(JNIEnv* env,
|
||||
// null key; in HTTP's case, this maps to the HTTP status line.
|
||||
ScopedJavaLocalRef<jstring> status_line =
|
||||
ConvertUTF8ToJavaString(env, headers->GetStatusLine());
|
||||
Java_UrlRequest_onAppendResponseHeader(
|
||||
Java_ChromiumUrlRequest_onAppendResponseHeader(
|
||||
env, object, headersMap, NULL, status_line.Release());
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef COMPONENTS_CRONET_ANDROID_URLREQUEST_H_
|
||||
#define COMPONENTS_CRONET_ANDROID_URLREQUEST_H_
|
||||
#ifndef COMPONENTS_CRONET_ANDROID_CHROMIUM_URL_REQUEST_H_
|
||||
#define COMPONENTS_CRONET_ANDROID_CHROMIUM_URL_REQUEST_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
@ -13,7 +13,7 @@ namespace cronet {
|
||||
// way that ensures they're always the same than their Java counterpart.
|
||||
enum UrlRequestPriority {
|
||||
#define DEFINE_REQUEST_PRIORITY(x, y) REQUEST_PRIORITY_##x = y,
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest_priority_list.h"
|
||||
#include "components/cronet/android/chromium_url_request_priority_list.h"
|
||||
#undef DEFINE_REQUEST_PRIORITY
|
||||
};
|
||||
|
||||
@ -21,12 +21,12 @@ enum UrlRequestPriority {
|
||||
// way that ensures they're always the same than their Java counterpart.
|
||||
enum UrlRequestError {
|
||||
#define DEFINE_REQUEST_ERROR(x, y) REQUEST_ERROR_##x = y,
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest_error_list.h"
|
||||
#include "components/cronet/android/chromium_url_request_error_list.h"
|
||||
#undef DEFINE_REQUEST_ERROR
|
||||
};
|
||||
|
||||
bool UrlRequestRegisterJni(JNIEnv* env);
|
||||
bool ChromiumUrlRequestRegisterJni(JNIEnv* env);
|
||||
|
||||
} // namespace cronet
|
||||
|
||||
#endif // COMPONENTS_CRONET_ANDROID_URLREQUEST_H_
|
||||
#endif // COMPONENTS_CRONET_ANDROID_CHROMIUM_URL_REQUEST_H_
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequestContext.h"
|
||||
#include "components/cronet/android/chromium_url_request_context.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -13,11 +13,11 @@
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/metrics/statistics_recorder.h"
|
||||
#include "base/values.h"
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest.h"
|
||||
#include "components/cronet/android/chromium_url_request.h"
|
||||
#include "components/cronet/android/url_request_adapter.h"
|
||||
#include "components/cronet/android/url_request_context_adapter.h"
|
||||
#include "components/cronet/url_request_context_config.h"
|
||||
#include "jni/UrlRequestContext_jni.h"
|
||||
#include "jni/ChromiumUrlRequestContext_jni.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@ -33,7 +33,7 @@ class JniURLRequestContextAdapterDelegate
|
||||
virtual void OnContextInitialized(
|
||||
cronet::URLRequestContextAdapter* context) OVERRIDE {
|
||||
JNIEnv* env = base::android::AttachCurrentThread();
|
||||
cronet::Java_UrlRequestContext_initNetworkThread(env, owner_);
|
||||
cronet::Java_ChromiumUrlRequestContext_initNetworkThread(env, owner_);
|
||||
// TODO(dplotnikov): figure out if we need to detach from the thread.
|
||||
// The documentation says we should detach just before the thread exits.
|
||||
}
|
||||
@ -53,7 +53,7 @@ class JniURLRequestContextAdapterDelegate
|
||||
namespace cronet {
|
||||
|
||||
// Explicitly register static JNI functions.
|
||||
bool UrlRequestContextRegisterJni(JNIEnv* env) {
|
||||
bool ChromiumUrlRequestContextRegisterJni(JNIEnv* env) {
|
||||
return RegisterNativesImpl(env);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace cronet {
|
||||
|
||||
bool UrlRequestContextRegisterJni(JNIEnv* env);
|
||||
bool ChromiumUrlRequestContextRegisterJni(JNIEnv* env);
|
||||
|
||||
} // namespace cronet
|
||||
|
@ -6,8 +6,8 @@
|
||||
#include "base/android/jni_android.h"
|
||||
#include "base/android/jni_registrar.h"
|
||||
#include "base/at_exit.h"
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest.h"
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequestContext.h"
|
||||
#include "components/cronet/android/chromium_url_request.h"
|
||||
#include "components/cronet/android/chromium_url_request_context.h"
|
||||
#include "net/android/net_jni_registrar.h"
|
||||
#include "url/android/url_jni_registrar.h"
|
||||
|
||||
@ -18,11 +18,11 @@
|
||||
namespace {
|
||||
|
||||
const base::android::RegistrationMethod kCronetRegisteredMethods[] = {
|
||||
{"BaseAndroid", base::android::RegisterJni},
|
||||
{"NetAndroid", net::android::RegisterJni},
|
||||
{"UrlAndroid", url::android::RegisterJni},
|
||||
{"UrlRequest", cronet::UrlRequestRegisterJni},
|
||||
{"UrlRequestContext", cronet::UrlRequestContextRegisterJni},
|
||||
{"BaseAndroid", base::android::RegisterJni},
|
||||
{"ChromiumUrlRequest", cronet::ChromiumUrlRequestRegisterJni},
|
||||
{"ChromiumUrlRequestContext", cronet::ChromiumUrlRequestContextRegisterJni},
|
||||
{"NetAndroid", net::android::RegisterJni},
|
||||
{"UrlAndroid", url::android::RegisterJni},
|
||||
};
|
||||
|
||||
base::AtExitManager* g_at_exit_manager = NULL;
|
||||
|
@ -4,35 +4,63 @@
|
||||
|
||||
package org.chromium.net;
|
||||
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Network request using the native http stack implementation.
|
||||
*/
|
||||
public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
|
||||
@JNINamespace("cronet")
|
||||
public class ChromiumUrlRequest implements HttpUrlRequest {
|
||||
/**
|
||||
* Native adapter object, owned by UrlRequest.
|
||||
*/
|
||||
private long mUrlRequestAdapter;
|
||||
private final ChromiumUrlRequestContext mRequestContext;
|
||||
private final String mUrl;
|
||||
private final int mPriority;
|
||||
private final Map<String, String> mHeaders;
|
||||
private final WritableByteChannel mSink;
|
||||
private Map<String, String> mAdditionalHeaders;
|
||||
private String mUploadContentType;
|
||||
private String mMethod;
|
||||
private byte[] mUploadData;
|
||||
private ReadableByteChannel mUploadChannel;
|
||||
private WritableByteChannel mOutputChannel;
|
||||
private IOException mSinkException;
|
||||
private volatile boolean mStarted;
|
||||
private volatile boolean mCanceled;
|
||||
private volatile boolean mRecycled;
|
||||
private volatile boolean mFinished;
|
||||
private boolean mHeadersAvailable;
|
||||
private String mContentType;
|
||||
private long mUploadContentLength;
|
||||
private final HttpUrlRequestListener mListener;
|
||||
|
||||
private boolean mBufferFullResponse;
|
||||
|
||||
private long mOffset;
|
||||
|
||||
private long mContentLength;
|
||||
|
||||
private long mContentLengthLimit;
|
||||
|
||||
private boolean mCancelIfContentLengthOverLimit;
|
||||
|
||||
private boolean mContentLengthOverLimit;
|
||||
|
||||
private boolean mSkippingToOffset;
|
||||
|
||||
private long mSize;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
public ChromiumUrlRequest(UrlRequestContext requestContext,
|
||||
public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext,
|
||||
String url, int priority, Map<String, String> headers,
|
||||
HttpUrlRequestListener listener) {
|
||||
this(requestContext, url, priority, headers,
|
||||
@ -40,29 +68,35 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
mBufferFullResponse = true;
|
||||
}
|
||||
|
||||
public ChromiumUrlRequest(UrlRequestContext requestContext,
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param requestContext The context.
|
||||
* @param url The URL.
|
||||
* @param priority Request priority, e.g. {@link #REQUEST_PRIORITY_MEDIUM}.
|
||||
* @param headers HTTP headers.
|
||||
* @param sink The output channel into which downloaded content will be
|
||||
* written.
|
||||
*/
|
||||
public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext,
|
||||
String url, int priority, Map<String, String> headers,
|
||||
WritableByteChannel sink, HttpUrlRequestListener listener) {
|
||||
super(requestContext, url, convertRequestPriority(priority), headers,
|
||||
sink);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private static int convertRequestPriority(int priority) {
|
||||
switch (priority) {
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_IDLE:
|
||||
return UrlRequestPriority.IDLE;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_LOWEST:
|
||||
return UrlRequestPriority.LOWEST;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_LOW:
|
||||
return UrlRequestPriority.LOW;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_MEDIUM:
|
||||
return UrlRequestPriority.MEDIUM;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_HIGHEST:
|
||||
return UrlRequestPriority.HIGHEST;
|
||||
default:
|
||||
return UrlRequestPriority.MEDIUM;
|
||||
if (requestContext == null) {
|
||||
throw new NullPointerException("Context is required");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new NullPointerException("URL is required");
|
||||
}
|
||||
mRequestContext = requestContext;
|
||||
mUrl = url;
|
||||
mPriority = convertRequestPriority(priority);
|
||||
mHeaders = headers;
|
||||
mSink = sink;
|
||||
mUrlRequestAdapter = nativeCreateRequestAdapter(
|
||||
mRequestContext.getChromiumUrlRequestContextAdapter(),
|
||||
mUrl,
|
||||
mPriority);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,6 +107,13 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The compressed content length as reported by the server. May be -1 if
|
||||
* the server did not provide a length. Some servers may also report the
|
||||
* wrong number. Since this is the compressed content length, and only
|
||||
* uncompressed content is returned by the consumer, the consumer should
|
||||
* not rely on this value.
|
||||
*/
|
||||
@Override
|
||||
public long getContentLength() {
|
||||
return mContentLength;
|
||||
@ -85,10 +126,289 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseStarted() {
|
||||
super.onResponseStarted();
|
||||
public int getHttpStatusCode() {
|
||||
int httpStatusCode = nativeGetHttpStatusCode(mUrlRequestAdapter);
|
||||
|
||||
// TODO(mef): Investigate the following:
|
||||
// If we have been able to successfully resume a previously interrupted
|
||||
// download, the status code will be 206, not 200. Since the rest of the
|
||||
// application is expecting 200 to indicate success, we need to fake it.
|
||||
if (httpStatusCode == 206) {
|
||||
httpStatusCode = 200;
|
||||
}
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an exception if any, or null if the request was completed
|
||||
* successfully.
|
||||
*/
|
||||
@Override
|
||||
public IOException getException() {
|
||||
if (mSinkException != null) {
|
||||
return mSinkException;
|
||||
}
|
||||
|
||||
validateNotRecycled();
|
||||
|
||||
int errorCode = nativeGetErrorCode(mUrlRequestAdapter);
|
||||
switch (errorCode) {
|
||||
case ChromiumUrlRequestError.SUCCESS:
|
||||
if (mContentLengthOverLimit) {
|
||||
return new ResponseTooLargeException();
|
||||
}
|
||||
return null;
|
||||
case ChromiumUrlRequestError.UNKNOWN:
|
||||
return new IOException(
|
||||
nativeGetErrorString(mUrlRequestAdapter));
|
||||
case ChromiumUrlRequestError.MALFORMED_URL:
|
||||
return new MalformedURLException("Malformed URL: " + mUrl);
|
||||
case ChromiumUrlRequestError.CONNECTION_TIMED_OUT:
|
||||
return new ConnectTimeoutException("Connection timed out");
|
||||
case ChromiumUrlRequestError.UNKNOWN_HOST:
|
||||
String host;
|
||||
try {
|
||||
host = new URL(mUrl).getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host = mUrl;
|
||||
}
|
||||
return new UnknownHostException("Unknown host: " + host);
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Unrecognized error code: " + errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
return ((ChunkedWritableByteChannel)getSink()).getByteBuffer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getResponseAsBytes() {
|
||||
return ((ChunkedWritableByteChannel)getSink()).getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request header. Must be done before request has started.
|
||||
*/
|
||||
public void addHeader(String header, String value) {
|
||||
synchronized (mLock) {
|
||||
validateNotStarted();
|
||||
if (mAdditionalHeaders == null) {
|
||||
mAdditionalHeaders = new HashMap<String, String>();
|
||||
}
|
||||
mAdditionalHeaders.put(header, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data to upload as part of a POST or PUT request.
|
||||
*
|
||||
* @param contentType MIME type of the upload content or null if this is not
|
||||
* an upload.
|
||||
* @param data The content that needs to be uploaded.
|
||||
*/
|
||||
public void setUploadData(String contentType, byte[] data) {
|
||||
synchronized (mLock) {
|
||||
validateNotStarted();
|
||||
mUploadContentType = contentType;
|
||||
mUploadData = data;
|
||||
mUploadChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a readable byte channel to upload as part of a POST or PUT request.
|
||||
*
|
||||
* @param contentType MIME type of the upload content or null if this is not
|
||||
* an upload request.
|
||||
* @param channel The channel to read to read upload data from if this is an
|
||||
* upload request.
|
||||
* @param contentLength The length of data to upload.
|
||||
*/
|
||||
public void setUploadChannel(String contentType,
|
||||
ReadableByteChannel channel, long contentLength) {
|
||||
synchronized (mLock) {
|
||||
validateNotStarted();
|
||||
mUploadContentType = contentType;
|
||||
mUploadChannel = channel;
|
||||
mUploadContentLength = contentLength;
|
||||
mUploadData = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets HTTP method for upload request. Only PUT or POST are allowed.
|
||||
*/
|
||||
public void setHttpMethod(String method) {
|
||||
validateNotStarted();
|
||||
if (!("PUT".equals(method) || "POST".equals(method))) {
|
||||
throw new IllegalArgumentException("Only PUT or POST are allowed.");
|
||||
}
|
||||
mMethod = method;
|
||||
}
|
||||
|
||||
public WritableByteChannel getSink() {
|
||||
return mSink;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
synchronized (mLock) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
validateNotStarted();
|
||||
validateNotRecycled();
|
||||
|
||||
mStarted = true;
|
||||
|
||||
String method = mMethod;
|
||||
if (method == null &&
|
||||
((mUploadData != null && mUploadData.length > 0) ||
|
||||
mUploadChannel != null)) {
|
||||
// Default to POST if there is data to upload but no method was
|
||||
// specified.
|
||||
method = "POST";
|
||||
}
|
||||
|
||||
if (method != null) {
|
||||
nativeSetMethod(mUrlRequestAdapter, method);
|
||||
}
|
||||
|
||||
if (mHeaders != null && !mHeaders.isEmpty()) {
|
||||
for (Entry<String, String> entry : mHeaders.entrySet()) {
|
||||
nativeAddHeader(mUrlRequestAdapter, entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (mAdditionalHeaders != null) {
|
||||
for (Entry<String, String> entry :
|
||||
mAdditionalHeaders.entrySet()) {
|
||||
nativeAddHeader(mUrlRequestAdapter, entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (mUploadData != null && mUploadData.length > 0) {
|
||||
nativeSetUploadData(mUrlRequestAdapter, mUploadContentType,
|
||||
mUploadData);
|
||||
} else if (mUploadChannel != null) {
|
||||
nativeSetUploadChannel(mUrlRequestAdapter, mUploadContentType,
|
||||
mUploadContentLength);
|
||||
}
|
||||
|
||||
nativeStart(mUrlRequestAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (mLock) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCanceled = true;
|
||||
|
||||
if (!mRecycled) {
|
||||
nativeCancel(mUrlRequestAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
synchronized (mLock) {
|
||||
return mCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRecycled() {
|
||||
synchronized (mLock) {
|
||||
return mRecycled;
|
||||
}
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
public String getHeader(String name) {
|
||||
validateHeadersAvailable();
|
||||
return nativeGetHeader(mUrlRequestAdapter, name);
|
||||
}
|
||||
|
||||
// All response headers.
|
||||
public Map<String, List<String>> getAllHeaders() {
|
||||
validateHeadersAvailable();
|
||||
ResponseHeadersMap result = new ResponseHeadersMap();
|
||||
nativeGetAllHeaders(mUrlRequestAdapter, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
private static int convertRequestPriority(int priority) {
|
||||
switch (priority) {
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_IDLE:
|
||||
return ChromiumUrlRequestPriority.IDLE;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_LOWEST:
|
||||
return ChromiumUrlRequestPriority.LOWEST;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_LOW:
|
||||
return ChromiumUrlRequestPriority.LOW;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_MEDIUM:
|
||||
return ChromiumUrlRequestPriority.MEDIUM;
|
||||
case HttpUrlRequest.REQUEST_PRIORITY_HIGHEST:
|
||||
return ChromiumUrlRequestPriority.HIGHEST;
|
||||
default:
|
||||
return ChromiumUrlRequestPriority.MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
private void onContentLengthOverLimit() {
|
||||
mContentLengthOverLimit = true;
|
||||
cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback invoked when the response has been fully consumed.
|
||||
*/
|
||||
private void onRequestComplete() {
|
||||
mListener.onRequestComplete(this);
|
||||
}
|
||||
|
||||
private void validateNotRecycled() {
|
||||
if (mRecycled) {
|
||||
throw new IllegalStateException("Accessing recycled request");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNotStarted() {
|
||||
if (mStarted) {
|
||||
throw new IllegalStateException("Request already started");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateHeadersAvailable() {
|
||||
if (!mHeadersAvailable) {
|
||||
throw new IllegalStateException("Response headers not available");
|
||||
}
|
||||
}
|
||||
|
||||
// Private methods called by native library.
|
||||
|
||||
/**
|
||||
* A callback invoked when the first chunk of the response has arrived.
|
||||
*/
|
||||
@CalledByNative
|
||||
private void onResponseStarted() {
|
||||
mContentType = nativeGetContentType(mUrlRequestAdapter);
|
||||
mContentLength = nativeGetContentLength(mUrlRequestAdapter);
|
||||
mHeadersAvailable = true;
|
||||
|
||||
mContentLength = super.getContentLength();
|
||||
if (mContentLengthLimit > 0 && mContentLength > mContentLengthLimit
|
||||
&& mCancelIfContentLengthOverLimit) {
|
||||
onContentLengthOverLimit();
|
||||
@ -102,8 +422,11 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
}
|
||||
|
||||
if (mOffset != 0) {
|
||||
// The server may ignore the request for a byte range.
|
||||
if (super.getHttpStatusCode() == 200) {
|
||||
// The server may ignore the request for a byte range, in which case
|
||||
// status code will be 200, instead of 206. Note that we cannot call
|
||||
// getHttpStatusCode as it rewrites 206 into 200.
|
||||
if (nativeGetHttpStatusCode(mUrlRequestAdapter) == 200) {
|
||||
// TODO(mef): Revisit this logic.
|
||||
if (mContentLength != -1) {
|
||||
mContentLength -= mOffset;
|
||||
}
|
||||
@ -115,8 +438,15 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
mListener.onResponseStarted(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBytesRead(ByteBuffer buffer) {
|
||||
/**
|
||||
* Consumes a portion of the response.
|
||||
*
|
||||
* @param byteBuffer The ByteBuffer to append. Must be a direct buffer, and
|
||||
* no references to it may be retained after the method ends, as
|
||||
* it wraps code managed on the native heap.
|
||||
*/
|
||||
@CalledByNative
|
||||
private void onBytesRead(ByteBuffer buffer) {
|
||||
if (mContentLengthOverLimit) {
|
||||
return;
|
||||
}
|
||||
@ -132,58 +462,130 @@ public class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {
|
||||
}
|
||||
}
|
||||
|
||||
if (mContentLengthLimit != 0 && mSize > mContentLengthLimit) {
|
||||
boolean contentLengthOverLimit =
|
||||
(mContentLengthLimit != 0 && mSize > mContentLengthLimit);
|
||||
if (contentLengthOverLimit) {
|
||||
buffer.limit(size - (int)(mSize - mContentLengthLimit));
|
||||
super.onBytesRead(buffer);
|
||||
}
|
||||
|
||||
try {
|
||||
while (buffer.hasRemaining()) {
|
||||
mSink.write(buffer);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
mSinkException = e;
|
||||
cancel();
|
||||
}
|
||||
if (contentLengthOverLimit) {
|
||||
onContentLengthOverLimit();
|
||||
return;
|
||||
}
|
||||
|
||||
super.onBytesRead(buffer);
|
||||
}
|
||||
|
||||
private void onContentLengthOverLimit() {
|
||||
mContentLengthOverLimit = true;
|
||||
cancel();
|
||||
}
|
||||
/**
|
||||
* Notifies the listener, releases native data structures.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private void finish() {
|
||||
synchronized (mLock) {
|
||||
mFinished = true;
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() {
|
||||
mListener.onRequestComplete(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHttpStatusCode() {
|
||||
int httpStatusCode = super.getHttpStatusCode();
|
||||
|
||||
// TODO(mef): Investigate the following:
|
||||
// If we have been able to successfully resume a previously interrupted
|
||||
// download,
|
||||
// the status code will be 206, not 200. Since the rest of the
|
||||
// application is
|
||||
// expecting 200 to indicate success, we need to fake it.
|
||||
if (httpStatusCode == 206) {
|
||||
httpStatusCode = 200;
|
||||
if (mRecycled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mSink.close();
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
onRequestComplete();
|
||||
nativeDestroyRequestAdapter(mUrlRequestAdapter);
|
||||
mUrlRequestAdapter = 0;
|
||||
mRecycled = true;
|
||||
}
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOException getException() {
|
||||
IOException ex = super.getException();
|
||||
if (ex == null && mContentLengthOverLimit) {
|
||||
ex = new ResponseTooLargeException();
|
||||
/**
|
||||
* Appends header |name| with value |value| to |headersMap|.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private void onAppendResponseHeader(ResponseHeadersMap headersMap,
|
||||
String name, String value) {
|
||||
if (!headersMap.containsKey(name)) {
|
||||
headersMap.put(name, new ArrayList<String>());
|
||||
}
|
||||
return ex;
|
||||
headersMap.get(name).add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getByteBuffer() {
|
||||
return ((ChunkedWritableByteChannel)getSink()).getByteBuffer();
|
||||
/**
|
||||
* Reads a sequence of bytes from upload channel into the given buffer.
|
||||
* @param dest The buffer into which bytes are to be transferred.
|
||||
* @return Returns number of bytes read (could be 0) or -1 and closes
|
||||
* the channel if error occured.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private int readFromUploadChannel(ByteBuffer dest) {
|
||||
if (mUploadChannel == null || !mUploadChannel.isOpen())
|
||||
return -1;
|
||||
try {
|
||||
int result = mUploadChannel.read(dest);
|
||||
if (result < 0) {
|
||||
mUploadChannel.close();
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
mSinkException = e;
|
||||
try {
|
||||
mUploadChannel.close();
|
||||
} catch (IOException ignored) {
|
||||
// Ignore this exception.
|
||||
}
|
||||
cancel();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getResponseAsBytes() {
|
||||
return ((ChunkedWritableByteChannel)getSink()).getBytes();
|
||||
// Native methods are implemented in chromium_url_request.cc.
|
||||
|
||||
private native long nativeCreateRequestAdapter(
|
||||
long ChromiumUrlRequestContextAdapter, String url, int priority);
|
||||
|
||||
private native void nativeAddHeader(long urlRequestAdapter, String name,
|
||||
String value);
|
||||
|
||||
private native void nativeSetMethod(long urlRequestAdapter, String method);
|
||||
|
||||
private native void nativeSetUploadData(long urlRequestAdapter,
|
||||
String contentType, byte[] content);
|
||||
|
||||
private native void nativeSetUploadChannel(long urlRequestAdapter,
|
||||
String contentType, long contentLength);
|
||||
|
||||
private native void nativeStart(long urlRequestAdapter);
|
||||
|
||||
private native void nativeCancel(long urlRequestAdapter);
|
||||
|
||||
private native void nativeDestroyRequestAdapter(long urlRequestAdapter);
|
||||
|
||||
private native int nativeGetErrorCode(long urlRequestAdapter);
|
||||
|
||||
private native int nativeGetHttpStatusCode(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetErrorString(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetContentType(long urlRequestAdapter);
|
||||
|
||||
private native long nativeGetContentLength(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetHeader(long urlRequestAdapter, String name);
|
||||
|
||||
private native void nativeGetAllHeaders(long urlRequestAdapter,
|
||||
ResponseHeadersMap headers);
|
||||
|
||||
// Explicit class to work around JNI-generator generics confusion.
|
||||
private class ResponseHeadersMap extends HashMap<String, List<String>> {
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,16 @@ import org.chromium.base.JNINamespace;
|
||||
* Provides context for the native HTTP operations.
|
||||
*/
|
||||
@JNINamespace("cronet")
|
||||
public class UrlRequestContext {
|
||||
public class ChromiumUrlRequestContext {
|
||||
private static final int LOG_NONE = 3; // LOG(FATAL), no VLOG.
|
||||
private static final int LOG_DEBUG = -1; // LOG(FATAL...INFO), VLOG(1)
|
||||
private static final int LOG_VERBOSE = -2; // LOG(FATAL...INFO), VLOG(2)
|
||||
private static final String LOG_TAG = "ChromiumNetwork";
|
||||
|
||||
/**
|
||||
* Native adapter object, owned by UrlRequestContext.
|
||||
* Native adapter object, owned by ChromiumUrlRequestContext.
|
||||
*/
|
||||
private long mUrlRequestContextAdapter;
|
||||
private long mChromiumUrlRequestContextAdapter;
|
||||
|
||||
private final ConditionVariable mStarted = new ConditionVariable();
|
||||
|
||||
@ -33,11 +33,11 @@ public class UrlRequestContext {
|
||||
* Constructor.
|
||||
*
|
||||
*/
|
||||
protected UrlRequestContext(Context context, String userAgent,
|
||||
protected ChromiumUrlRequestContext(Context context, String userAgent,
|
||||
String config) {
|
||||
mUrlRequestContextAdapter = nativeCreateRequestContextAdapter(context,
|
||||
userAgent, getLoggingLevel(), config);
|
||||
if (mUrlRequestContextAdapter == 0)
|
||||
mChromiumUrlRequestContextAdapter = nativeCreateRequestContextAdapter(
|
||||
context, userAgent, getLoggingLevel(), config);
|
||||
if (mChromiumUrlRequestContextAdapter == 0)
|
||||
throw new NullPointerException("Context Adapter creation failed");
|
||||
|
||||
// TODO(mef): Revisit the need of block here.
|
||||
@ -75,7 +75,7 @@ public class UrlRequestContext {
|
||||
* If actively logging the call is ignored.
|
||||
*/
|
||||
public void startNetLogToFile(String fileName) {
|
||||
nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName);
|
||||
nativeStartNetLogToFile(mChromiumUrlRequestContextAdapter, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ public class UrlRequestContext {
|
||||
* not in progress this call is ignored.
|
||||
*/
|
||||
public void stopNetLog() {
|
||||
nativeStopNetLog(mUrlRequestContextAdapter);
|
||||
nativeStopNetLog(mChromiumUrlRequestContextAdapter);
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
@ -95,12 +95,12 @@ public class UrlRequestContext {
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
nativeReleaseRequestContextAdapter(mUrlRequestContextAdapter);
|
||||
nativeReleaseRequestContextAdapter(mChromiumUrlRequestContextAdapter);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
protected long getUrlRequestContextAdapter() {
|
||||
return mUrlRequestContextAdapter;
|
||||
protected long getChromiumUrlRequestContextAdapter() {
|
||||
return mChromiumUrlRequestContextAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,20 +119,20 @@ public class UrlRequestContext {
|
||||
return loggingLevel;
|
||||
}
|
||||
|
||||
// Returns an instance URLRequestContextAdapter to be stored in
|
||||
// mUrlRequestContextAdapter.
|
||||
// Returns an instance ChromiumUrlRequestContextAdapter to be stored in
|
||||
// mChromiumUrlRequestContextAdapter.
|
||||
private native long nativeCreateRequestContextAdapter(Context context,
|
||||
String userAgent, int loggingLevel, String config);
|
||||
|
||||
private native void nativeReleaseRequestContextAdapter(
|
||||
long urlRequestContextAdapter);
|
||||
long ChromiumUrlRequestContextAdapter);
|
||||
|
||||
private native void nativeInitializeStatistics();
|
||||
|
||||
private native String nativeGetStatisticsJSON(String filter);
|
||||
|
||||
private native void nativeStartNetLogToFile(long urlRequestContextAdapter,
|
||||
String fileName);
|
||||
private native void nativeStartNetLogToFile(
|
||||
long ChromiumUrlRequestContextAdapter, String fileName);
|
||||
|
||||
private native void nativeStopNetLog(long urlRequestContextAdapter);
|
||||
private native void nativeStopNetLog(long ChromiumUrlRequestContextAdapter);
|
||||
}
|
@ -5,10 +5,10 @@
|
||||
package org.chromium.net;
|
||||
|
||||
// A simple auto-generated interface used to list request errors as used by
|
||||
// both org.chromium.net.UrlRequest and
|
||||
// net/cronet/android/org_chromium_net_UrlRequest.h
|
||||
public interface UrlRequestError {
|
||||
// both org.chromium.net.ChromiumUrlRequest and
|
||||
// net/cronet/android/chromium_url_request_error_list.h
|
||||
public interface ChromiumUrlRequestError {
|
||||
#define DEFINE_REQUEST_ERROR(x,y) public static final int x = y;
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest_error_list.h"
|
||||
#include "components/cronet/android/chromium_url_request_error_list.h"
|
||||
#undef DEFINE_REQUEST_ERROR
|
||||
}
|
@ -15,14 +15,14 @@ import java.util.Map;
|
||||
*/
|
||||
@UsedByReflection("HttpUrlRequestFactory.java")
|
||||
public class ChromiumUrlRequestFactory extends HttpUrlRequestFactory {
|
||||
private UrlRequestContext mRequestContext;
|
||||
private ChromiumUrlRequestContext mRequestContext;
|
||||
|
||||
@UsedByReflection("HttpUrlRequestFactory.java")
|
||||
public ChromiumUrlRequestFactory(
|
||||
Context context, HttpUrlRequestFactoryConfig config) {
|
||||
if (isEnabled()) {
|
||||
System.loadLibrary("cronet");
|
||||
mRequestContext = new UrlRequestContext(
|
||||
mRequestContext = new ChromiumUrlRequestContext(
|
||||
context.getApplicationContext(), UserAgent.from(context),
|
||||
config.toString());
|
||||
}
|
||||
@ -35,7 +35,7 @@ public class ChromiumUrlRequestFactory extends HttpUrlRequestFactory {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Chromium/" + UrlRequestContext.getVersion();
|
||||
return "Chromium/" + ChromiumUrlRequestContext.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,4 +52,8 @@ public class ChromiumUrlRequestFactory extends HttpUrlRequestFactory {
|
||||
return new ChromiumUrlRequest(mRequestContext, url, requestPriority,
|
||||
headers, channel, listener);
|
||||
}
|
||||
|
||||
public ChromiumUrlRequestContext getRequestContext() {
|
||||
return mRequestContext;
|
||||
}
|
||||
}
|
||||
|
@ -5,10 +5,10 @@
|
||||
package org.chromium.net;
|
||||
|
||||
// A simple auto-generated interface used to list request priorities as used by
|
||||
// both org.chromium.net.UrlRequest and
|
||||
// net/cronet/android/org_chromium_net_UrlRequest.h
|
||||
public interface UrlRequestPriority {
|
||||
// both org.chromium.net.ChromiumUrlRequest and
|
||||
// net/cronet/android/chromium_url_request_priority_list.h
|
||||
public interface ChromiumUrlRequestPriority {
|
||||
#define DEFINE_REQUEST_PRIORITY(x,y) public static final int x = y;
|
||||
#include "components/cronet/android/org_chromium_net_UrlRequest_priority_list.h"
|
||||
#include "components/cronet/android/chromium_url_request_priority_list.h"
|
||||
#undef DEFINE_REQUEST_PRIORITY
|
||||
}
|
@ -1,452 +0,0 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.net;
|
||||
|
||||
import org.apache.http.conn.ConnectTimeoutException;
|
||||
import org.chromium.base.CalledByNative;
|
||||
import org.chromium.base.JNINamespace;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Network request using the native http stack implementation.
|
||||
*/
|
||||
@JNINamespace("cronet")
|
||||
public class UrlRequest {
|
||||
private static final class ContextLock {
|
||||
}
|
||||
|
||||
private final UrlRequestContext mRequestContext;
|
||||
private final String mUrl;
|
||||
private final int mPriority;
|
||||
private final Map<String, String> mHeaders;
|
||||
private final WritableByteChannel mSink;
|
||||
private Map<String, String> mAdditionalHeaders;
|
||||
private String mUploadContentType;
|
||||
private String mMethod;
|
||||
private byte[] mUploadData;
|
||||
private ReadableByteChannel mUploadChannel;
|
||||
private WritableByteChannel mOutputChannel;
|
||||
private IOException mSinkException;
|
||||
private volatile boolean mStarted;
|
||||
private volatile boolean mCanceled;
|
||||
private volatile boolean mRecycled;
|
||||
private volatile boolean mFinished;
|
||||
private boolean mHeadersAvailable;
|
||||
private String mContentType;
|
||||
private long mContentLength;
|
||||
private long mUploadContentLength;
|
||||
private final ContextLock mLock;
|
||||
|
||||
/**
|
||||
* Native adapter object, owned by UrlRequest.
|
||||
*/
|
||||
private long mUrlRequestAdapter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param requestContext The context.
|
||||
* @param url The URL.
|
||||
* @param priority Request priority, e.g. {@link #REQUEST_PRIORITY_MEDIUM}.
|
||||
* @param headers HTTP headers.
|
||||
* @param sink The output channel into which downloaded content will be
|
||||
* written.
|
||||
*/
|
||||
public UrlRequest(UrlRequestContext requestContext, String url,
|
||||
int priority, Map<String, String> headers,
|
||||
WritableByteChannel sink) {
|
||||
if (requestContext == null) {
|
||||
throw new NullPointerException("Context is required");
|
||||
}
|
||||
if (url == null) {
|
||||
throw new NullPointerException("URL is required");
|
||||
}
|
||||
mRequestContext = requestContext;
|
||||
mUrl = url;
|
||||
mPriority = priority;
|
||||
mHeaders = headers;
|
||||
mSink = sink;
|
||||
mLock = new ContextLock();
|
||||
mUrlRequestAdapter = nativeCreateRequestAdapter(
|
||||
mRequestContext.getUrlRequestContextAdapter(), mUrl, mPriority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a request header.
|
||||
*/
|
||||
public void addHeader(String header, String value) {
|
||||
validateNotStarted();
|
||||
if (mAdditionalHeaders == null) {
|
||||
mAdditionalHeaders = new HashMap<String, String>();
|
||||
}
|
||||
mAdditionalHeaders.put(header, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data to upload as part of a POST request.
|
||||
*
|
||||
* @param contentType MIME type of the post content or null if this is not a
|
||||
* POST.
|
||||
* @param data The content that needs to be uploaded if this is a POST
|
||||
* request.
|
||||
*/
|
||||
public void setUploadData(String contentType, byte[] data) {
|
||||
synchronized (mLock) {
|
||||
validateNotStarted();
|
||||
mUploadContentType = contentType;
|
||||
mUploadData = data;
|
||||
mUploadChannel = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a readable byte channel to upload as part of a POST request.
|
||||
*
|
||||
* @param contentType MIME type of the post content or null if this is not a
|
||||
* POST request.
|
||||
* @param channel The channel to read to read upload data from if this is a
|
||||
* POST request.
|
||||
* @param contentLength The length of data to upload.
|
||||
*/
|
||||
public void setUploadChannel(String contentType,
|
||||
ReadableByteChannel channel, long contentLength) {
|
||||
synchronized (mLock) {
|
||||
validateNotStarted();
|
||||
mUploadContentType = contentType;
|
||||
mUploadChannel = channel;
|
||||
mUploadContentLength = contentLength;
|
||||
mUploadData = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setHttpMethod(String method) {
|
||||
validateNotStarted();
|
||||
if (!("PUT".equals(method) || "POST".equals(method))) {
|
||||
throw new IllegalArgumentException("Only PUT or POST are allowed.");
|
||||
}
|
||||
mMethod = method;
|
||||
}
|
||||
|
||||
public WritableByteChannel getSink() {
|
||||
return mSink;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
synchronized (mLock) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
validateNotStarted();
|
||||
validateNotRecycled();
|
||||
|
||||
mStarted = true;
|
||||
|
||||
String method = mMethod;
|
||||
if (method == null &&
|
||||
((mUploadData != null && mUploadData.length > 0) ||
|
||||
mUploadChannel != null)) {
|
||||
// Default to POST if there is data to upload but no method was
|
||||
// specified.
|
||||
method = "POST";
|
||||
}
|
||||
|
||||
if (method != null) {
|
||||
nativeSetMethod(mUrlRequestAdapter, method);
|
||||
}
|
||||
|
||||
if (mHeaders != null && !mHeaders.isEmpty()) {
|
||||
for (Entry<String, String> entry : mHeaders.entrySet()) {
|
||||
nativeAddHeader(mUrlRequestAdapter, entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (mAdditionalHeaders != null) {
|
||||
for (Entry<String, String> entry :
|
||||
mAdditionalHeaders.entrySet()) {
|
||||
nativeAddHeader(mUrlRequestAdapter, entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (mUploadData != null && mUploadData.length > 0) {
|
||||
nativeSetUploadData(mUrlRequestAdapter, mUploadContentType,
|
||||
mUploadData);
|
||||
} else if (mUploadChannel != null) {
|
||||
nativeSetUploadChannel(mUrlRequestAdapter, mUploadContentType,
|
||||
mUploadContentLength);
|
||||
}
|
||||
|
||||
nativeStart(mUrlRequestAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
synchronized (mLock) {
|
||||
if (mCanceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCanceled = true;
|
||||
|
||||
if (!mRecycled) {
|
||||
nativeCancel(mUrlRequestAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
synchronized (mLock) {
|
||||
return mCanceled;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRecycled() {
|
||||
synchronized (mLock) {
|
||||
return mRecycled;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an exception if any, or null if the request was completed
|
||||
* successfully.
|
||||
*/
|
||||
public IOException getException() {
|
||||
if (mSinkException != null) {
|
||||
return mSinkException;
|
||||
}
|
||||
|
||||
validateNotRecycled();
|
||||
|
||||
int errorCode = nativeGetErrorCode(mUrlRequestAdapter);
|
||||
switch (errorCode) {
|
||||
case UrlRequestError.SUCCESS:
|
||||
return null;
|
||||
case UrlRequestError.UNKNOWN:
|
||||
return new IOException(
|
||||
nativeGetErrorString(mUrlRequestAdapter));
|
||||
case UrlRequestError.MALFORMED_URL:
|
||||
return new MalformedURLException("Malformed URL: " + mUrl);
|
||||
case UrlRequestError.CONNECTION_TIMED_OUT:
|
||||
return new ConnectTimeoutException("Connection timed out");
|
||||
case UrlRequestError.UNKNOWN_HOST:
|
||||
String host;
|
||||
try {
|
||||
host = new URL(mUrl).getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
host = mUrl;
|
||||
}
|
||||
return new UnknownHostException("Unknown host: " + host);
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Unrecognized error code: " + errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
public int getHttpStatusCode() {
|
||||
return nativeGetHttpStatusCode(mUrlRequestAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Content length as reported by the server. May be -1 or incorrect if the
|
||||
* server returns the wrong number, which happens even with Google servers.
|
||||
*/
|
||||
public long getContentLength() {
|
||||
return mContentLength;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return mContentType;
|
||||
}
|
||||
|
||||
public String getHeader(String name) {
|
||||
validateHeadersAvailable();
|
||||
return nativeGetHeader(mUrlRequestAdapter, name);
|
||||
}
|
||||
|
||||
// All response headers.
|
||||
public Map<String, List<String>> getAllHeaders() {
|
||||
validateHeadersAvailable();
|
||||
ResponseHeadersMap result = new ResponseHeadersMap();
|
||||
nativeGetAllHeaders(mUrlRequestAdapter, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback invoked when the first chunk of the response has arrived.
|
||||
*/
|
||||
@CalledByNative
|
||||
protected void onResponseStarted() {
|
||||
mContentType = nativeGetContentType(mUrlRequestAdapter);
|
||||
mContentLength = nativeGetContentLength(mUrlRequestAdapter);
|
||||
mHeadersAvailable = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback invoked when the response has been fully consumed.
|
||||
*/
|
||||
protected void onRequestComplete() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumes a portion of the response.
|
||||
*
|
||||
* @param byteBuffer The ByteBuffer to append. Must be a direct buffer, and
|
||||
* no references to it may be retained after the method ends, as
|
||||
* it wraps code managed on the native heap.
|
||||
*/
|
||||
@CalledByNative
|
||||
protected void onBytesRead(ByteBuffer byteBuffer) {
|
||||
try {
|
||||
while (byteBuffer.hasRemaining()) {
|
||||
mSink.write(byteBuffer);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
mSinkException = e;
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the listener, releases native data structures.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private void finish() {
|
||||
synchronized (mLock) {
|
||||
mFinished = true;
|
||||
|
||||
if (mRecycled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mSink.close();
|
||||
} catch (IOException e) {
|
||||
// Ignore
|
||||
}
|
||||
onRequestComplete();
|
||||
nativeDestroyRequestAdapter(mUrlRequestAdapter);
|
||||
mUrlRequestAdapter = 0;
|
||||
mRecycled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends header |name| with value |value| to |headersMap|.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private void onAppendResponseHeader(ResponseHeadersMap headersMap,
|
||||
String name, String value) {
|
||||
if (!headersMap.containsKey(name)) {
|
||||
headersMap.put(name, new ArrayList<String>());
|
||||
}
|
||||
headersMap.get(name).add(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a sequence of bytes from upload channel into the given buffer.
|
||||
* @param dest The buffer into which bytes are to be transferred.
|
||||
* @return Returns number of bytes read (could be 0) or -1 and closes
|
||||
* the channel if error occured.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@CalledByNative
|
||||
private int readFromUploadChannel(ByteBuffer dest) {
|
||||
if (mUploadChannel == null || !mUploadChannel.isOpen())
|
||||
return -1;
|
||||
try {
|
||||
int result = mUploadChannel.read(dest);
|
||||
if (result < 0) {
|
||||
mUploadChannel.close();
|
||||
return 0;
|
||||
}
|
||||
return result;
|
||||
} catch (IOException e) {
|
||||
mSinkException = e;
|
||||
try {
|
||||
mUploadChannel.close();
|
||||
} catch (IOException ignored) {
|
||||
// Ignore this exception.
|
||||
}
|
||||
cancel();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNotRecycled() {
|
||||
if (mRecycled) {
|
||||
throw new IllegalStateException("Accessing recycled request");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNotStarted() {
|
||||
if (mStarted) {
|
||||
throw new IllegalStateException("Request already started");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateHeadersAvailable() {
|
||||
if (!mHeadersAvailable) {
|
||||
throw new IllegalStateException("Response headers not available");
|
||||
}
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
|
||||
private native long nativeCreateRequestAdapter(
|
||||
long urlRequestContextAdapter, String url, int priority);
|
||||
|
||||
private native void nativeAddHeader(long urlRequestAdapter, String name,
|
||||
String value);
|
||||
|
||||
private native void nativeSetMethod(long urlRequestAdapter, String method);
|
||||
|
||||
private native void nativeSetUploadData(long urlRequestAdapter,
|
||||
String contentType, byte[] content);
|
||||
|
||||
private native void nativeSetUploadChannel(long urlRequestAdapter,
|
||||
String contentType, long contentLength);
|
||||
|
||||
private native void nativeStart(long urlRequestAdapter);
|
||||
|
||||
private native void nativeCancel(long urlRequestAdapter);
|
||||
|
||||
private native void nativeDestroyRequestAdapter(long urlRequestAdapter);
|
||||
|
||||
private native int nativeGetErrorCode(long urlRequestAdapter);
|
||||
|
||||
private native int nativeGetHttpStatusCode(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetErrorString(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetContentType(long urlRequestAdapter);
|
||||
|
||||
private native long nativeGetContentLength(long urlRequestAdapter);
|
||||
|
||||
private native String nativeGetHeader(long urlRequestAdapter, String name);
|
||||
|
||||
private native void nativeGetAllHeaders(long urlRequestAdapter,
|
||||
ResponseHeadersMap headers);
|
||||
|
||||
// Explicit class to work around JNI-generator generics confusion.
|
||||
private class ResponseHeadersMap extends HashMap<String, List<String>> {
|
||||
}
|
||||
}
|
@ -78,10 +78,11 @@ public class CronetSampleUrlTest extends CronetSampleTestBase {
|
||||
|
||||
waitForActiveShellToBeDoneLoading();
|
||||
File file = File.createTempFile("cronet", "json");
|
||||
activity.mRequestContext.startNetLogToFile(file.getPath());
|
||||
activity.startWithURL_UrlRequest(URL);
|
||||
activity.mChromiumRequestFactory.getRequestContext().startNetLogToFile(
|
||||
file.getPath());
|
||||
activity.startWithURL(URL);
|
||||
Thread.sleep(5000);
|
||||
activity.mRequestContext.stopNetLog();
|
||||
activity.mChromiumRequestFactory.getRequestContext().stopNetLog();
|
||||
assertTrue(file.exists());
|
||||
assertTrue(file.length() != 0);
|
||||
assertTrue(file.delete());
|
||||
|
@ -14,23 +14,19 @@ import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.chromium.net.ChromiumUrlRequestFactory;
|
||||
import org.chromium.net.HttpUrlRequest;
|
||||
import org.chromium.net.HttpUrlRequestFactory;
|
||||
import org.chromium.net.HttpUrlRequestFactoryConfig;
|
||||
import org.chromium.net.HttpUrlRequestListener;
|
||||
import org.chromium.net.LibraryLoader;
|
||||
import org.chromium.net.UrlRequest;
|
||||
import org.chromium.net.UrlRequestContext;
|
||||
import org.chromium.net.UrlRequestPriority;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Activity for managing the Cronet Sample.
|
||||
@ -43,8 +39,7 @@ public class CronetSampleActivity extends Activity {
|
||||
public static final String POST_DATA_KEY = "postData";
|
||||
public static final String CONFIG_KEY = "config";
|
||||
|
||||
UrlRequestContext mRequestContext;
|
||||
|
||||
ChromiumUrlRequestFactory mChromiumRequestFactory;
|
||||
HttpUrlRequestFactory mRequestFactory;
|
||||
|
||||
String mUrl;
|
||||
@ -53,43 +48,6 @@ public class CronetSampleActivity extends Activity {
|
||||
|
||||
int mHttpStatusCode = 0;
|
||||
|
||||
class SampleRequestContext extends UrlRequestContext {
|
||||
public SampleRequestContext() {
|
||||
super(getApplicationContext(), "Cronet Sample",
|
||||
new HttpUrlRequestFactoryConfig().toString());
|
||||
}
|
||||
}
|
||||
|
||||
class SampleRequest extends UrlRequest {
|
||||
public SampleRequest(UrlRequestContext requestContext, String url,
|
||||
int priority, Map<String, String> headers,
|
||||
WritableByteChannel sink) {
|
||||
super(requestContext, url, priority, headers, sink);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestComplete() {
|
||||
mHttpStatusCode = super.getHttpStatusCode();
|
||||
Log.i(TAG, "****** Request Complete, status code is "
|
||||
+ mHttpStatusCode);
|
||||
Intent intent = new Intent(getApplicationContext(),
|
||||
CronetSampleActivity.class);
|
||||
startActivity(intent);
|
||||
final String url = super.getUrl();
|
||||
final CharSequence text = "Completed " + url + " ("
|
||||
+ mHttpStatusCode + ")";
|
||||
CronetSampleActivity.this.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mLoading = false;
|
||||
Toast toast = Toast.makeText(getApplicationContext(), text,
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
promptForURL(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SampleHttpUrlRequestListener implements HttpUrlRequestListener {
|
||||
public SampleHttpUrlRequestListener() {
|
||||
}
|
||||
@ -136,7 +94,6 @@ public class CronetSampleActivity extends Activity {
|
||||
return;
|
||||
}
|
||||
|
||||
mRequestContext = new SampleRequestContext();
|
||||
HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig();
|
||||
config.enableHttpCache(HttpUrlRequestFactoryConfig.HttpCache.IN_MEMORY,
|
||||
100 * 1024)
|
||||
@ -159,6 +116,9 @@ public class CronetSampleActivity extends Activity {
|
||||
mRequestFactory = HttpUrlRequestFactory.createFactory(
|
||||
getApplicationContext(), config);
|
||||
|
||||
mChromiumRequestFactory = new ChromiumUrlRequestFactory(
|
||||
getApplicationContext(), config);
|
||||
|
||||
String appUrl = getUrlFromIntent(getIntent());
|
||||
if (appUrl == null) {
|
||||
promptForURL("https://");
|
||||
@ -219,7 +179,7 @@ public class CronetSampleActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void startWithURL(String url) {
|
||||
public void startWithURL(String url) {
|
||||
Log.i(TAG, "Cronet started: " + url);
|
||||
mUrl = url;
|
||||
mLoading = true;
|
||||
@ -227,36 +187,11 @@ public class CronetSampleActivity extends Activity {
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
HttpUrlRequestListener listener = new SampleHttpUrlRequestListener();
|
||||
HttpUrlRequest request = mRequestFactory.createRequest(
|
||||
url, UrlRequestPriority.MEDIUM, headers, listener);
|
||||
url, HttpUrlRequest.REQUEST_PRIORITY_MEDIUM, headers, listener);
|
||||
applyCommandLineToHttpUrlRequest(request);
|
||||
request.start();
|
||||
}
|
||||
|
||||
private void applyCommandLineToUrlRequest(UrlRequest request) {
|
||||
String postData = getCommandLineArg(POST_DATA_KEY);
|
||||
if (postData != null) {
|
||||
InputStream dataStream = new ByteArrayInputStream(
|
||||
postData.getBytes());
|
||||
ReadableByteChannel dataChannel = Channels.newChannel(dataStream);
|
||||
request.setUploadChannel("text/plain", dataChannel,
|
||||
postData.length());
|
||||
request.setHttpMethod("POST");
|
||||
}
|
||||
}
|
||||
|
||||
public void startWithURL_UrlRequest(String url) {
|
||||
Log.i(TAG, "Cronet started: " + url);
|
||||
mUrl = url;
|
||||
mLoading = true;
|
||||
|
||||
HashMap<String, String> headers = new HashMap<String, String>();
|
||||
WritableByteChannel sink = Channels.newChannel(System.out);
|
||||
UrlRequest request = new SampleRequest(mRequestContext, url,
|
||||
UrlRequestPriority.MEDIUM, headers, sink);
|
||||
applyCommandLineToUrlRequest(request);
|
||||
request.start();
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return mUrl;
|
||||
}
|
||||
@ -270,11 +205,12 @@ public class CronetSampleActivity extends Activity {
|
||||
}
|
||||
|
||||
public void startNetLog() {
|
||||
mRequestContext.startNetLogToFile(
|
||||
Environment.getExternalStorageDirectory().getPath() + "/cronet_sample_netlog.json");
|
||||
mChromiumRequestFactory.getRequestContext().startNetLogToFile(
|
||||
Environment.getExternalStorageDirectory().getPath() +
|
||||
"/cronet_sample_netlog.json");
|
||||
}
|
||||
|
||||
public void stopNetLog() {
|
||||
mRequestContext.stopNetLog();
|
||||
mChromiumRequestFactory.getRequestContext().stopNetLog();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user