Commit c71361c6 authored by mef's avatar mef Committed by Commit bot

Add SetSupportsQuic method to explicitly specify server that supports QUIC.

BUG=411010
TEST=build/android/test_runner.py instrumentation --test-apk=CronetSampleTest -f *Quic*

Review URL: https://codereview.chromium.org/544223003

Cr-Commit-Position: refs/heads/master@{#295063}
parent 302290da
......@@ -411,7 +411,7 @@
'target_name': 'libcronet_tests',
'type': 'shared_library',
'sources': [
'cronet/android/test/cronet_tests_jni.cc',
'cronet/android/test/cronet_test_jni.cc',
],
'dependencies': [
'cronet_static',
......
......@@ -387,4 +387,16 @@ static void GetAllHeaders(JNIEnv* env,
env, object, headersMap, NULL, status_line.Release());
}
static jstring GetNegotiatedProtocol(JNIEnv* env,
jobject object,
jlong urlRequestAdapter) {
URLRequestAdapter* request =
reinterpret_cast<URLRequestAdapter*>(urlRequestAdapter);
if (request == NULL)
return ConvertUTF8ToJavaString(env, "").Release();
std::string negotiated_protocol = request->GetNegotiatedProtocol();
return ConvertUTF8ToJavaString(env, negotiated_protocol.c_str()).Release();
}
} // namespace cronet
......@@ -390,17 +390,26 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
}
}
@Override
public String getNegotiatedProtocol() {
validateNotRecycled();
validateHeadersAvailable();
return nativeGetNegotiatedProtocol(mUrlRequestAdapter);
}
public String getContentType() {
return mContentType;
}
public String getHeader(String name) {
validateNotRecycled();
validateHeadersAvailable();
return nativeGetHeader(mUrlRequestAdapter, name);
}
// All response headers.
public Map<String, List<String>> getAllHeaders() {
validateNotRecycled();
validateHeadersAvailable();
ResponseHeadersMap result = new ResponseHeadersMap();
nativeGetAllHeaders(mUrlRequestAdapter, result);
......@@ -647,7 +656,7 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
// Native methods are implemented in chromium_url_request.cc.
private native long nativeCreateRequestAdapter(
long ChromiumUrlRequestContextAdapter, String url, int priority);
long urlRequestContextAdapter, String url, int priority);
private native void nativeAddHeader(long urlRequestAdapter, String name,
String value);
......@@ -687,6 +696,8 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
private native void nativeGetAllHeaders(long urlRequestAdapter,
ResponseHeadersMap headers);
private native String nativeGetNegotiatedProtocol(long urlRequestAdapter);
// Explicit class to work around JNI-generator generics confusion.
private class ResponseHeadersMap extends HashMap<String, List<String>> {
}
......
......@@ -125,14 +125,14 @@ public class ChromiumUrlRequestContext {
String userAgent, int loggingLevel, String config);
private native void nativeReleaseRequestContextAdapter(
long ChromiumUrlRequestContextAdapter);
long chromiumUrlRequestContextAdapter);
private native void nativeInitializeStatistics();
private native String nativeGetStatisticsJSON(String filter);
private native void nativeStartNetLogToFile(
long ChromiumUrlRequestContextAdapter, String fileName);
long chromiumUrlRequestContextAdapter, String fileName);
private native void nativeStopNetLog(long ChromiumUrlRequestContextAdapter);
private native void nativeStopNetLog(long chromiumUrlRequestContextAdapter);
}
......@@ -421,6 +421,11 @@ class HttpUrlConnectionUrlRequest implements HttpUrlRequest {
}
}
@Override
public String getNegotiatedProtocol() {
return "";
}
@Override
public int getHttpStatusCode() {
int httpStatusCode = mHttpStatusCode;
......
......@@ -101,6 +101,14 @@ public interface HttpUrlRequest {
*/
boolean isCanceled();
/**
* Returns protocol (e.g. "quic/1+spdy/3") negotiated with server. Returns
* empty string if no protocol was negotiated, or the protocol is not known.
* Returns empty when using plain http or https. Must be called after
* onResponseStarted but before request is recycled.
*/
String getNegotiatedProtocol();
/**
* Returns the entire response as a ByteBuffer.
*/
......
......@@ -4,6 +4,7 @@
package org.chromium.net;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -85,6 +86,37 @@ public class HttpUrlRequestFactoryConfig {
return putString(UrlRequestContextConfig.STORAGE_PATH, value);
}
/**
* Explicitly mark |host| as supporting QUIC.
* Note that enableHttpCache(DISK) is needed to take advantage of 0-RTT
* connection establishment between sessions.
*
* @param host of the server that supports QUIC.
* @param port of the server that supports QUIC.
* @param alternatePort to use for QUIC.
*/
public HttpUrlRequestFactoryConfig addQuicHint(String host,
int port,
int alternatePort) {
try {
JSONArray quicHints = mConfig.optJSONArray(
UrlRequestContextConfig.QUIC_HINTS);
if (quicHints == null) {
quicHints = new JSONArray();
mConfig.put(UrlRequestContextConfig.QUIC_HINTS, quicHints);
}
JSONObject hint = new JSONObject();
hint.put(UrlRequestContextConfig.QUIC_HINT_HOST, host);
hint.put(UrlRequestContextConfig.QUIC_HINT_PORT, port);
hint.put(UrlRequestContextConfig.QUIC_HINT_ALT_PORT, alternatePort);
quicHints.put(hint);
} catch (JSONException e) {
;
}
return this;
}
/**
* Get JSON string representation of the config.
*/
......
......@@ -9,6 +9,7 @@ import android.os.ConditionVariable;
import android.test.suitebuilder.annotation.SmallTest;
import org.chromium.base.test.util.Feature;
import org.chromium.net.ChromiumUrlRequest;
import org.chromium.net.HttpUrlRequest;
import org.chromium.net.HttpUrlRequestFactoryConfig;
import org.chromium.net.HttpUrlRequestListener;
......@@ -94,27 +95,44 @@ public class CronetUrlTest extends CronetTestBase {
assertTrue(!file.exists());
}
class BadHttpUrlRequestListener implements HttpUrlRequestListener {
static final String THROW_TAG = "BadListener";
class SimpleHttpUrlRequestListener implements HttpUrlRequestListener {
ConditionVariable mComplete = new ConditionVariable();
public String negotiatedProtocol;
public int httpStatusCode = 0;
public BadHttpUrlRequestListener() {
public SimpleHttpUrlRequestListener() {
}
@Override
public void onResponseStarted(HttpUrlRequest request) {
throw new NullPointerException(THROW_TAG);
negotiatedProtocol = request.getNegotiatedProtocol();
httpStatusCode = request.getHttpStatusCode();
}
@Override
public void onRequestComplete(HttpUrlRequest request) {
mComplete.open();
throw new NullPointerException(THROW_TAG);
}
public void blockForComplete() {
mComplete.block();
}
public void resetComplete() {
mComplete.close();
}
}
class BadHttpUrlRequestListener extends SimpleHttpUrlRequestListener {
static final String THROW_TAG = "BadListener";
public BadHttpUrlRequestListener() {
}
@Override
public void onResponseStarted(HttpUrlRequest request) {
throw new NullPointerException(THROW_TAG);
}
}
@SmallTest
......@@ -165,6 +183,52 @@ public class CronetUrlTest extends CronetTestBase {
}
}
@SmallTest
@Feature({"Cronet"})
public void disabled_testQuicLoadUrl() throws Exception {
HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig();
// TODO(mef): Test Quic end-to-end using local QUIC server.
String quicURL = "https://www.google.com:443";
String quicNegotiatedProtocol = "quic/1+spdy/3";
config.enableQUIC(true);
config.addQuicHint("www.google.com", 443, 443);
String[] commandLineArgs = {
CronetTestActivity.CONFIG_KEY, config.toString() };
CronetTestActivity activity =
launchCronetTestAppWithUrlAndCommandLineArgs(quicURL,
commandLineArgs);
// Make sure the activity was created as expected.
assertNotNull(activity);
waitForActiveShellToBeDoneLoading();
HashMap<String, String> headers = new HashMap<String, String>();
SimpleHttpUrlRequestListener listener =
new SimpleHttpUrlRequestListener();
// Try several times as first request may not use QUIC.
// TODO(mef): Remove loop after adding http server properties manager.
for (int i = 0; i < 10; ++i) {
ChromiumUrlRequest request =
activity.mChromiumRequestFactory.createRequest(
quicURL,
HttpUrlRequest.REQUEST_PRIORITY_MEDIUM,
headers,
listener);
request.start();
listener.blockForComplete();
assertEquals(200, listener.httpStatusCode);
if (listener.negotiatedProtocol.equals(quicNegotiatedProtocol))
break;
Thread.sleep(1000);
listener.resetComplete();
}
assertEquals(quicNegotiatedProtocol, listener.negotiatedProtocol);
}
@SmallTest
@Feature({"Cronet"})
public void testLegacyLoadUrl() throws Exception {
......
......@@ -23,6 +23,9 @@ public class HttpUrlRequestFactoryTest extends CronetTestBase {
@Feature({"Cronet"})
public void testCreateFactory() throws Throwable {
HttpUrlRequestFactoryConfig config = new HttpUrlRequestFactoryConfig();
config.enableQUIC(true);
config.addQuicHint("www.google.com", 443, 443);
config.addQuicHint("www.youtube.com", 443, 443);
String[] commandLineArgs = {
CronetTestActivity.CONFIG_KEY, config.toString() };
CronetTestActivity activity =
......@@ -31,7 +34,6 @@ public class HttpUrlRequestFactoryTest extends CronetTestBase {
// Make sure the activity was created as expected.
assertNotNull(activity);
waitForActiveShellToBeDoneLoading();
HttpUrlRequestFactory factory = activity.mRequestFactory;
assertNotNull("Factory should be created", factory);
assertTrue("Factory should be Chromium/n.n.n.n@r but is " +
......
......@@ -33,7 +33,6 @@ public class CronetTestActivity extends Activity {
public static final String POST_DATA_KEY = "postData";
public static final String CONFIG_KEY = "config";
ChromiumUrlRequestFactory mChromiumRequestFactory;
HttpUrlRequestFactory mRequestFactory;
......@@ -170,5 +169,4 @@ public class CronetTestActivity extends Activity {
public void stopNetLog() {
mChromiumRequestFactory.getRequestContext().stopNetLog();
}
}
......@@ -100,6 +100,12 @@ net::HttpResponseHeaders* URLRequestAdapter::GetResponseHeaders() const {
return url_request_->response_headers();
}
std::string URLRequestAdapter::GetNegotiatedProtocol() const {
if (url_request_ == NULL)
return std::string();
return url_request_->response_info().npn_negotiated_protocol;
}
void URLRequestAdapter::Start() {
context_->GetNetworkTaskRunner()->PostTask(
FROM_HERE,
......
......@@ -109,6 +109,9 @@ class URLRequestAdapter : public net::URLRequest::Delegate {
// Returns a pointer to the downloaded data.
unsigned char* Data() const;
// Get NPN or ALPN Negotiated Protocol (if any) from HttpResponseInfo.
std::string GetNegotiatedProtocol() const;
virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
virtual void OnReadCompleted(net::URLRequest* request,
......
......@@ -13,7 +13,7 @@
#include "net/cert/cert_verifier.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_server_properties.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
......@@ -144,6 +144,42 @@ void URLRequestContextAdapter::InitializeURLRequestContext(
context_.reset(context_builder.Build());
// Currently (circa M39) enabling QUIC requires setting probability threshold.
if (config->enable_quic) {
context_->http_server_properties()
->SetAlternateProtocolProbabilityThreshold(1.0f);
for (size_t hint = 0; hint < config->quic_hints.size(); ++hint) {
const URLRequestContextConfig::QuicHint& quic_hint =
*config->quic_hints[hint];
if (quic_hint.host.empty()) {
LOG(ERROR) << "Empty QUIC hint host: " << quic_hint.host;
continue;
}
if (quic_hint.port <= std::numeric_limits<uint16>::min() ||
quic_hint.port > std::numeric_limits<uint16>::max()) {
LOG(ERROR) << "Invalid QUIC hint port: "
<< quic_hint.port;
continue;
}
if (quic_hint.alternate_port <= std::numeric_limits<uint16>::min() ||
quic_hint.alternate_port > std::numeric_limits<uint16>::max()) {
LOG(ERROR) << "Invalid QUIC hint alternate port: "
<< quic_hint.alternate_port;
continue;
}
net::HostPortPair quic_hint_host_port_pair(quic_hint.host,
quic_hint.port);
context_->http_server_properties()->SetAlternateProtocol(
quic_hint_host_port_pair,
static_cast<uint16>(quic_hint.alternate_port),
net::AlternateProtocol::QUIC,
1.0f);
}
}
if (VLOG_IS_ON(2)) {
net_log_observer_.reset(new NetLogObserver());
context_->net_log()->AddThreadSafeObserver(net_log_observer_.get(),
......
......@@ -77,7 +77,7 @@ class URLRequestContextAdapter : public net::URLRequestContextGetter {
virtual ~URLRequestContextAdapter();
// Initializes |context_| on the IO thread.
// Initializes |context_| on the Network thread.
void InitializeURLRequestContext(scoped_ptr<URLRequestContextConfig> config);
DISALLOW_COPY_AND_ASSIGN(URLRequestContextAdapter);
......
......@@ -44,15 +44,15 @@ def main():
if (options.command=='sync'):
return run ('git pull --rebase && ' + gyp_defines + ' gclient sync')
if (options.command=='build'):
return run ('ninja -C ' + out_dir + ' cronet_sample_test_apk')
return run ('ninja -C ' + out_dir + ' cronet_test_instrumentation_apk')
if (options.command=='install'):
return run ('build/android/adb_install_apk.py ' + release_arg + \
' --apk=CronetSample.apk')
' --apk=CronetTest.apk')
if (options.command=='proguard'):
return run ('ninja -C out/Release cronet_sample_proguard_apk')
return run ('ninja -C ' + out_dir + ' cronet_sample_proguard_apk')
if (options.command=='test'):
return run ('build/android/test_runner.py instrumentation '+ \
release_arg + ' --test-apk=CronetSampleTest')
release_arg + ' --test-apk=CronetTestInstrumentation')
parser.print_help()
return 1
......
......@@ -12,6 +12,25 @@ namespace cronet {
#include "components/cronet/url_request_context_config_list.h"
#undef DEFINE_CONTEXT_CONFIG
URLRequestContextConfig::QuicHint::QuicHint() {
}
URLRequestContextConfig::QuicHint::~QuicHint() {
}
// static
void URLRequestContextConfig::QuicHint::RegisterJSONConverter(
base::JSONValueConverter<URLRequestContextConfig::QuicHint>* converter) {
converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_QUIC_HINT_HOST,
&URLRequestContextConfig::QuicHint::host);
converter->RegisterIntField(
REQUEST_CONTEXT_CONFIG_QUIC_HINT_PORT,
&URLRequestContextConfig::QuicHint::port);
converter->RegisterIntField(
REQUEST_CONTEXT_CONFIG_QUIC_HINT_ALT_PORT,
&URLRequestContextConfig::QuicHint::alternate_port);
}
URLRequestContextConfig::URLRequestContextConfig() {
}
......@@ -54,6 +73,8 @@ void URLRequestContextConfig::RegisterJSONConverter(
&URLRequestContextConfig::http_cache_max_size);
converter->RegisterStringField(REQUEST_CONTEXT_CONFIG_STORAGE_PATH,
&URLRequestContextConfig::storage_path);
converter->RegisterRepeatedMessage(REQUEST_CONTEXT_CONFIG_QUIC_HINTS,
&URLRequestContextConfig::quic_hints);
}
} // namespace cronet
......@@ -8,6 +8,8 @@
#include <string>
#include "base/json/json_value_converter.h"
#include "base/macros.h"
#include "base/memory/scoped_vector.h"
namespace net {
class URLRequestContextBuilder;
......@@ -18,6 +20,26 @@ namespace cronet {
// Common configuration parameters used by Cronet to configure
// URLRequestContext. Can be parsed from JSON string passed through JNI.
struct URLRequestContextConfig {
// App-provided hint that server supports QUIC.
struct QuicHint {
QuicHint();
~QuicHint();
// Register |converter| for use in converter.Convert().
static void RegisterJSONConverter(
base::JSONValueConverter<QuicHint>* converter);
// Host name of the server that supports QUIC.
std::string host;
// Port of the server that supports QUIC.
int port;
// Alternate protocol port.
int alternate_port;
private:
DISALLOW_COPY_AND_ASSIGN(QuicHint);
};
URLRequestContextConfig();
~URLRequestContextConfig();
......@@ -40,6 +62,11 @@ struct URLRequestContextConfig {
int http_cache_max_size;
// Storage path for http cache and cookie storage.
std::string storage_path;
// App-provided list of servers that support QUIC.
ScopedVector<QuicHint> quic_hints;
private:
DISALLOW_COPY_AND_ASSIGN(URLRequestContextConfig);
};
} // namespace cronet
......
......@@ -18,3 +18,8 @@ DEFINE_CONTEXT_CONFIG(HTTP_CACHE_MAX_SIZE)
DEFINE_CONTEXT_CONFIG(HTTP_CACHE_DISABLED)
DEFINE_CONTEXT_CONFIG(HTTP_CACHE_DISK)
DEFINE_CONTEXT_CONFIG(HTTP_CACHE_MEMORY)
DEFINE_CONTEXT_CONFIG(QUIC_HINTS)
DEFINE_CONTEXT_CONFIG(QUIC_HINT_HOST)
DEFINE_CONTEXT_CONFIG(QUIC_HINT_PORT)
DEFINE_CONTEXT_CONFIG(QUIC_HINT_ALT_PORT)
......@@ -193,7 +193,8 @@ URLRequestContextBuilder::HttpNetworkSessionParams::HttpNetworkSessionParams()
testing_fixed_http_port(0),
testing_fixed_https_port(0),
next_protos(NextProtosDefaults()),
use_alternate_protocols(true) {
use_alternate_protocols(true),
enable_quic(false) {
}
URLRequestContextBuilder::HttpNetworkSessionParams::~HttpNetworkSessionParams()
......@@ -236,6 +237,7 @@ void URLRequestContextBuilder::SetSpdyAndQuicEnabled(bool spdy_enabled,
bool quic_enabled) {
http_network_session_params_.next_protos =
NextProtosWithSpdyAndQuic(spdy_enabled, quic_enabled);
http_network_session_params_.enable_quic = quic_enabled;
}
URLRequestContext* URLRequestContextBuilder::Build() {
......@@ -352,6 +354,7 @@ URLRequestContext* URLRequestContextBuilder::Build() {
network_session_params.trusted_spdy_proxy =
http_network_session_params_.trusted_spdy_proxy;
network_session_params.next_protos = http_network_session_params_.next_protos;
network_session_params.enable_quic = http_network_session_params_.enable_quic;
HttpTransactionFactory* http_transaction_factory = NULL;
if (http_cache_enabled_) {
......
......@@ -71,6 +71,7 @@ class NET_EXPORT URLRequestContextBuilder {
NextProtoVector next_protos;
std::string trusted_spdy_proxy;
bool use_alternate_protocols;
bool enable_quic;
};
URLRequestContextBuilder();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment