diff options
author | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 19:59:55 +0000 |
---|---|---|
committer | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 19:59:55 +0000 |
commit | e41d59c24d4f65a227f9ada2c99d8006744515bb (patch) | |
tree | bdabd3c5927cd0993876ba8f2984c7f838f4cefb /android_webview | |
parent | 43a8e7b4c3c7d6f32c4c13b9e68907d817ec668a (diff) | |
download | chromium_src-e41d59c24d4f65a227f9ada2c99d8006744515bb.zip chromium_src-e41d59c24d4f65a227f9ada2c99d8006744515bb.tar.gz chromium_src-e41d59c24d4f65a227f9ada2c99d8006744515bb.tar.bz2 |
[android_webview] Add more params to request intercepting.
This adds the following to the shouldInterceptRequest params:
- isMainFrame
- hasUserGesture
- method
- headers
This adds the following to InterceptedRequestData:
- status code
- response phrase
- headers
BUG=387086
android_webview-only CL, trybots are happy.
NOTRY=true
Review URL: https://codereview.chromium.org/284123004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278806 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
31 files changed, 728 insertions, 293 deletions
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp index 2d7c31f..3a7959f 100644 --- a/android_webview/android_webview.gyp +++ b/android_webview/android_webview.gyp @@ -154,6 +154,8 @@ 'browser/aw_result_codes.h', 'browser/aw_web_preferences_populater.cc', 'browser/aw_web_preferences_populater.h', + 'browser/aw_web_resource_response.cc', + 'browser/aw_web_resource_response.h', 'browser/browser_view_renderer.cc', 'browser/browser_view_renderer.h', 'browser/browser_view_renderer_client.h', @@ -171,8 +173,6 @@ 'browser/icon_helper.cc', 'browser/icon_helper.h', 'browser/input_stream.h', - 'browser/intercepted_request_data.cc', - 'browser/intercepted_request_data.h', 'browser/jni_dependency_factory.h', 'browser/gl_view_renderer_manager.cc', 'browser/gl_view_renderer_manager.h', diff --git a/android_webview/browser/aw_contents_io_thread_client.h b/android_webview/browser/aw_contents_io_thread_client.h index 0ac29fc..cb8bc26 100644 --- a/android_webview/browser/aw_contents_io_thread_client.h +++ b/android_webview/browser/aw_contents_io_thread_client.h @@ -17,7 +17,7 @@ class URLRequest; namespace android_webview { -class InterceptedRequestData; +class AwWebResourceResponse; // This class provides a means of calling Java methods on an instance that has // a 1:1 relationship with a WebContents instance directly from the IO thread. @@ -68,7 +68,7 @@ class AwContentsIoThreadClient { int child_render_frame_id); // This method is called on the IO thread only. - virtual scoped_ptr<InterceptedRequestData> ShouldInterceptRequest( + virtual scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest( const GURL& location, const net::URLRequest* request) = 0; diff --git a/android_webview/browser/aw_request_interceptor.cc b/android_webview/browser/aw_request_interceptor.cc index a53061b..381a8ab 100644 --- a/android_webview/browser/aw_request_interceptor.cc +++ b/android_webview/browser/aw_request_interceptor.cc @@ -5,7 +5,7 @@ #include "android_webview/browser/aw_request_interceptor.h" #include "android_webview/browser/aw_contents_io_thread_client.h" -#include "android_webview/browser/intercepted_request_data.h" +#include "android_webview/browser/aw_web_resource_response.h" #include "base/android/jni_string.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/browser_thread.h" @@ -34,21 +34,21 @@ AwRequestInterceptor::AwRequestInterceptor() { AwRequestInterceptor::~AwRequestInterceptor() { } -scoped_ptr<InterceptedRequestData> -AwRequestInterceptor::QueryForInterceptedRequestData( +scoped_ptr<AwWebResourceResponse> +AwRequestInterceptor::QueryForAwWebResourceResponse( const GURL& location, net::URLRequest* request) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); int render_process_id, render_frame_id; if (!ResourceRequestInfo::GetRenderFrameForRequest( request, &render_process_id, &render_frame_id)) - return scoped_ptr<InterceptedRequestData>(); + return scoped_ptr<AwWebResourceResponse>(); scoped_ptr<AwContentsIoThreadClient> io_thread_client = AwContentsIoThreadClient::FromID(render_process_id, render_frame_id); if (!io_thread_client.get()) - return scoped_ptr<InterceptedRequestData>(); + return scoped_ptr<AwWebResourceResponse>(); return io_thread_client->ShouldInterceptRequest(location, request).Pass(); } @@ -58,7 +58,7 @@ net::URLRequestJob* AwRequestInterceptor::MaybeInterceptRequest( net::NetworkDelegate* network_delegate) const { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - // See if we've already found out the intercepted_request_data for this + // See if we've already found out the aw_web_resource_response for this // request. // This is done not only for efficiency reasons, but also for correctness // as it is possible for the Interceptor chain to be invoked more than once @@ -70,15 +70,15 @@ net::URLRequestJob* AwRequestInterceptor::MaybeInterceptRequest( request->SetUserData(kRequestAlreadyQueriedDataKey, new base::SupportsUserData::Data()); - scoped_ptr<InterceptedRequestData> intercepted_request_data = - QueryForInterceptedRequestData(request->url(), request); + scoped_ptr<AwWebResourceResponse> aw_web_resource_response = + QueryForAwWebResourceResponse(request->url(), request); - if (!intercepted_request_data) + if (!aw_web_resource_response) return NULL; - // The newly created job will own the InterceptedRequestData. - return InterceptedRequestData::CreateJobFor( - intercepted_request_data.Pass(), request, network_delegate); + // The newly created job will own the AwWebResourceResponse. + return AwWebResourceResponse::CreateJobFor( + aw_web_resource_response.Pass(), request, network_delegate); } } // namespace android_webview diff --git a/android_webview/browser/aw_request_interceptor.h b/android_webview/browser/aw_request_interceptor.h index b83ab32..813abbe 100644 --- a/android_webview/browser/aw_request_interceptor.h +++ b/android_webview/browser/aw_request_interceptor.h @@ -19,7 +19,7 @@ class NetworkDelegate; namespace android_webview { -class InterceptedRequestData; +class AwWebResourceResponse; // This class allows the Java-side embedder to substitute the default // URLRequest of a given request for an alternative job that will read data @@ -35,7 +35,7 @@ class AwRequestInterceptor : public net::URLRequestInterceptor { net::NetworkDelegate* network_delegate) const OVERRIDE; private: - scoped_ptr<InterceptedRequestData> QueryForInterceptedRequestData( + scoped_ptr<AwWebResourceResponse> QueryForAwWebResourceResponse( const GURL& location, net::URLRequest* request) const; diff --git a/android_webview/browser/intercepted_request_data.cc b/android_webview/browser/aw_web_resource_response.cc index 6e25ce1..412d9c2 100644 --- a/android_webview/browser/intercepted_request_data.cc +++ b/android_webview/browser/aw_web_resource_response.cc @@ -1,11 +1,13 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// 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. -#include "android_webview/browser/intercepted_request_data.h" +#include "android_webview/browser/aw_web_resource_response.h" #include "android_webview/browser/input_stream.h" #include "android_webview/browser/net/android_stream_reader_url_request_job.h" +#include "base/strings/string_number_conversions.h" +#include "net/http/http_response_headers.h" namespace android_webview { @@ -15,14 +17,14 @@ class StreamReaderJobDelegateImpl : public AndroidStreamReaderURLRequestJob::Delegate { public: StreamReaderJobDelegateImpl( - scoped_ptr<InterceptedRequestData> intercepted_request_data) - : intercepted_request_data_(intercepted_request_data.Pass()) { - DCHECK(intercepted_request_data_); + scoped_ptr<AwWebResourceResponse> aw_web_resource_response) + : aw_web_resource_response_(aw_web_resource_response.Pass()) { + DCHECK(aw_web_resource_response_); } virtual scoped_ptr<InputStream> OpenInputStream(JNIEnv* env, const GURL& url) OVERRIDE { - return intercepted_request_data_->GetInputStream(env).Pass(); + return aw_web_resource_response_->GetInputStream(env).Pass(); } virtual void OnInputStreamOpenFailed(net::URLRequest* request, @@ -34,28 +36,44 @@ class StreamReaderJobDelegateImpl net::URLRequest* request, android_webview::InputStream* stream, std::string* mime_type) OVERRIDE { - return intercepted_request_data_->GetMimeType(env, mime_type); + return aw_web_resource_response_->GetMimeType(env, mime_type); } virtual bool GetCharset(JNIEnv* env, net::URLRequest* request, android_webview::InputStream* stream, std::string* charset) OVERRIDE { - return intercepted_request_data_->GetCharset(env, charset); + return aw_web_resource_response_->GetCharset(env, charset); + } + + virtual void AppendResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) OVERRIDE { + int status_code; + std::string reason_phrase; + if (aw_web_resource_response_->GetStatusInfo( + env, &status_code, &reason_phrase)) { + std::string status_line("HTTP/1.1 "); + status_line.append(base::IntToString(status_code)); + status_line.append(" "); + status_line.append(reason_phrase); + headers->ReplaceStatusLine(status_line); + } + aw_web_resource_response_->GetResponseHeaders(env, headers); } private: - scoped_ptr<InterceptedRequestData> intercepted_request_data_; + scoped_ptr<AwWebResourceResponse> aw_web_resource_response_; }; } // namespace // static -net::URLRequestJob* InterceptedRequestData::CreateJobFor( - scoped_ptr<InterceptedRequestData> intercepted_request_data, +net::URLRequestJob* AwWebResourceResponse::CreateJobFor( + scoped_ptr<AwWebResourceResponse> aw_web_resource_response, net::URLRequest* request, net::NetworkDelegate* network_delegate) { - DCHECK(intercepted_request_data); + DCHECK(aw_web_resource_response); DCHECK(request); DCHECK(network_delegate); @@ -63,7 +81,7 @@ net::URLRequestJob* InterceptedRequestData::CreateJobFor( request, network_delegate, make_scoped_ptr( - new StreamReaderJobDelegateImpl(intercepted_request_data.Pass())) + new StreamReaderJobDelegateImpl(aw_web_resource_response.Pass())) .PassAs<AndroidStreamReaderURLRequestJob::Delegate>()); } diff --git a/android_webview/browser/intercepted_request_data.h b/android_webview/browser/aw_web_resource_response.h index acf031d..3496360 100644 --- a/android_webview/browser/intercepted_request_data.h +++ b/android_webview/browser/aw_web_resource_response.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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. @@ -11,9 +11,10 @@ #include "base/memory/scoped_ptr.h" namespace net { +class HttpResponseHeaders; +class NetworkDelegate; class URLRequest; class URLRequestJob; -class NetworkDelegate; } namespace android_webview { @@ -22,28 +23,36 @@ class InputStream; // This class represents the Java-side data that is to be used to complete a // particular URLRequest. -class InterceptedRequestData { +class AwWebResourceResponse { public: - virtual ~InterceptedRequestData() {} + virtual ~AwWebResourceResponse() {} virtual scoped_ptr<InputStream> GetInputStream(JNIEnv* env) const = 0; virtual bool GetMimeType(JNIEnv* env, std::string* mime_type) const = 0; virtual bool GetCharset(JNIEnv* env, std::string* charset) const = 0; + virtual bool GetStatusInfo(JNIEnv* env, + int* status_code, + std::string* reason_phrase) const = 0; + // If true is returned then |headers| contain the headers, if false is + // returned |headers| were not updated. + virtual bool GetResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) const = 0; // This creates a URLRequestJob for the |request| wich will read data from - // the |intercepted_request_data| structure (instead of going to the network + // the |aw_web_resource_response| structure (instead of going to the network // or to the cache). - // The newly created job takes ownership of |intercepted_request_data|. + // The newly created job takes ownership of |aw_web_resource_response|. static net::URLRequestJob* CreateJobFor( - scoped_ptr<InterceptedRequestData> intercepted_request_data, + scoped_ptr<AwWebResourceResponse> aw_web_resource_response, net::URLRequest* request, net::NetworkDelegate* network_delegate); protected: - InterceptedRequestData() {} + AwWebResourceResponse() {} private: - DISALLOW_COPY_AND_ASSIGN(InterceptedRequestData); + DISALLOW_COPY_AND_ASSIGN(AwWebResourceResponse); }; } // namespace android_webview diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.cc b/android_webview/browser/net/android_stream_reader_url_request_job.cc index d7b407e..5af452e 100644 --- a/android_webview/browser/net/android_stream_reader_url_request_job.cc +++ b/android_webview/browser/net/android_stream_reader_url_request_job.cc @@ -324,6 +324,10 @@ void AndroidStreamReaderURLRequestJob::HeadersComplete( } } + JNIEnv* env = AttachCurrentThread(); + DCHECK(env); + delegate_->AppendResponseHeaders(env, headers); + // Indicate that the response had been obtained via shouldInterceptRequest. headers->AddHeader(kResponseHeaderViaShouldInterceptRequest); diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.h b/android_webview/browser/net/android_stream_reader_url_request_job.h index c516b76..b7d6a62 100644 --- a/android_webview/browser/net/android_stream_reader_url_request_job.h +++ b/android_webview/browser/net/android_stream_reader_url_request_job.h @@ -26,6 +26,7 @@ class TaskRunner; } namespace net { +class HttpResponseHeaders; class HttpResponseInfo; class URLRequest; } @@ -66,6 +67,9 @@ class AndroidStreamReaderURLRequestJob : public net::URLRequestJob { android_webview::InputStream* stream, std::string* charset) = 0; + virtual void AppendResponseHeaders(JNIEnv* env, + net::HttpResponseHeaders* headers) = 0; + virtual ~Delegate() {} }; diff --git a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc index f09b5c5..e419dd1d 100644 --- a/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc +++ b/android_webview/browser/net/android_stream_reader_url_request_job_unittest.cc @@ -12,6 +12,7 @@ #include "base/strings/stringprintf.h" #include "net/base/request_priority.h" #include "net/http/http_byte_range.h" +#include "net/http/http_response_headers.h" #include "net/url_request/url_request_job_factory_impl.h" #include "net/url_request/url_request_test_util.h" @@ -93,6 +94,12 @@ class StreamReaderDelegate : std::string* charset) OVERRIDE { return false; } + + virtual void AppendResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) OVERRIDE { + // no-op + } }; class NullStreamReaderDelegate : public StreamReaderDelegate { @@ -106,6 +113,34 @@ class NullStreamReaderDelegate : public StreamReaderDelegate { } }; +class HeaderAlteringStreamReaderDelegate : public NullStreamReaderDelegate { + public: + HeaderAlteringStreamReaderDelegate() {} + + virtual void AppendResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) OVERRIDE { + headers->ReplaceStatusLine(kStatusLine); + std::string headerLine(kCustomHeaderName); + headerLine.append(": "); + headerLine.append(kCustomHeaderValue); + headers->AddHeader(headerLine); + } + + static const int kResponseCode; + static const char* kStatusLine; + static const char* kCustomHeaderName; + static const char* kCustomHeaderValue; +}; + +const int HeaderAlteringStreamReaderDelegate::kResponseCode = 401; +const char* HeaderAlteringStreamReaderDelegate::kStatusLine = + "HTTP/1.1 401 Gone"; +const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderName = + "X-Test-Header"; +const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderValue = + "TestHeaderValue"; + class MockInputStreamReader : public InputStreamReader { public: MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {} @@ -245,6 +280,35 @@ TEST_F(AndroidStreamReaderURLRequestJobTest, ReadWithNullStream) { EXPECT_EQ(404, req_->GetResponseCode()); } +TEST_F(AndroidStreamReaderURLRequestJobTest, ModifyHeadersAndStatus) { + SetUpTestJob(scoped_ptr<InputStreamReader>(), + make_scoped_ptr(new HeaderAlteringStreamReaderDelegate()) + .PassAs<AndroidStreamReaderURLRequestJob::Delegate>()); + req_->Start(); + + // The TestDelegate will quit the message loop on request completion. + base::MessageLoop::current()->Run(); + + // The request_failed() method is named confusingly but all it checks is + // whether the request got as far as calling NotifyHeadersComplete. + EXPECT_FALSE(url_request_delegate_.request_failed()); + EXPECT_EQ(1, network_delegate_.completed_requests()); + // A null input stream shouldn't result in an error. See crbug.com/180950. + EXPECT_EQ(0, network_delegate_.error_count()); + EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode, + req_->GetResponseCode()); + EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine, + req_->response_headers()->GetStatusLine()); + EXPECT_TRUE(req_->response_headers()->HasHeader( + HeaderAlteringStreamReaderDelegate::kCustomHeaderName)); + std::string header_value; + EXPECT_TRUE(req_->response_headers()->EnumerateHeader( + NULL, HeaderAlteringStreamReaderDelegate::kCustomHeaderName, + &header_value)); + EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue, + header_value); +} + TEST_F(AndroidStreamReaderURLRequestJobTest, ReadPartOfStream) { const int bytes_available = 128; const int offset = 32; diff --git a/android_webview/buildbot/aosp_manifest.xml b/android_webview/buildbot/aosp_manifest.xml index f83ae35..aaae29c 100644 --- a/android_webview/buildbot/aosp_manifest.xml +++ b/android_webview/buildbot/aosp_manifest.xml @@ -261,7 +261,7 @@ <project name="platform/frameworks/support" path="frameworks/support" revision="1e3d0c89282627f8b0d66d2bdae4efc2287ab043"/> <project name="platform/frameworks/testing" path="frameworks/testing" revision="5c8e0271db889518f5969b142a37faa01a4ee54d"/> <project name="platform/frameworks/volley" path="frameworks/volley" revision="a53cb80bea6fc83edfa73e7a850e83f4020fcf07"/> - <project name="platform/frameworks/webview" path="frameworks/webview" revision="69047640da7b4efa4b0de2cb2b9559fde5f31a21"/> + <project name="platform/frameworks/webview" path="frameworks/webview" revision="2b4719f12bac2f9f71d99567f09f46916903edf8"/> <project name="platform/frameworks/wilhelm" path="frameworks/wilhelm" revision="a62c3572e60ae0446632de15418a65089cccf551"/> <project name="platform/hardware/akm" path="hardware/akm" revision="32838ef838d1341aa8b77022869b801fb0bbb26c"/> <project groups="pdk" name="platform/hardware/broadcom/libbt" path="hardware/broadcom/libbt" revision="55ddd0cce019e88829f92b2fe4e17d5869daa9b9"/> diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 98a1d1c..340e18cc 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -252,7 +252,7 @@ public class AwContents { private CleanupReference mCleanupReference; //-------------------------------------------------------------------------------------------- - private class IoThreadClientImpl implements AwContentsIoThreadClient { + private class IoThreadClientImpl extends AwContentsIoThreadClient { // All methods are called on the IO thread. @Override @@ -261,21 +261,22 @@ public class AwContents { } @Override - public InterceptedRequestData shouldInterceptRequest(final String url, - boolean isMainFrame) { - InterceptedRequestData interceptedRequestData; + public AwWebResourceResponse shouldInterceptRequest( + AwContentsClient.ShouldInterceptRequestParams params) { + String url = params.url; + AwWebResourceResponse awWebResourceResponse; // Return the response directly if the url is default video poster url. - interceptedRequestData = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url); - if (interceptedRequestData != null) return interceptedRequestData; + awWebResourceResponse = mDefaultVideoPosterRequestHandler.shouldInterceptRequest(url); + if (awWebResourceResponse != null) return awWebResourceResponse; - interceptedRequestData = mContentsClient.shouldInterceptRequest(url); + awWebResourceResponse = mContentsClient.shouldInterceptRequest(params); - if (interceptedRequestData == null) { + if (awWebResourceResponse == null) { mContentsClient.getCallbackHelper().postOnLoadResource(url); } - if (isMainFrame && interceptedRequestData != null && - interceptedRequestData.getData() == null) { + if (params.isMainFrame && awWebResourceResponse != null && + awWebResourceResponse.getData() == null) { // In this case the intercepted URLRequest job will simulate an empty response // which doesn't trigger the onReceivedError callback. For WebViewClassic // compatibility we synthesize that callback. http://crbug.com/180950 @@ -283,7 +284,7 @@ public class AwContents { ErrorCodeConversionHelper.ERROR_UNKNOWN, null /* filled in by the glue layer */, url); } - return interceptedRequestData; + return awWebResourceResponse; } @Override diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java index 4b95283..5c41d62 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java @@ -10,6 +10,7 @@ import android.graphics.Picture; import android.net.http.SslError; import android.os.Looper; import android.os.Message; +import android.util.ArrayMap; import android.view.KeyEvent; import android.view.View; import android.webkit.ConsoleMessage; @@ -148,13 +149,30 @@ public abstract class AwContentsClient { public boolean capture; } + /** + * Parameters for the {@link AwContentsClient#shouldInterceptRequest} method. + */ + public static class ShouldInterceptRequestParams { + // Url of the request. + public String url; + // Is this for the main frame or a child iframe? + public boolean isMainFrame; + // Was a gesture associated with the request? Don't trust can easily be spoofed. + public boolean hasUserGesture; + // Method used (GET/POST/OPTIONS) + public String method; + // Headers that would have been sent to server. + public ArrayMap<String, String> requestHeaders; + } + public abstract void getVisitedHistory(ValueCallback<String[]> callback); public abstract void doUpdateVisitedHistory(String url, boolean isReload); public abstract void onProgressChanged(int progress); - public abstract InterceptedRequestData shouldInterceptRequest(String url); + public abstract AwWebResourceResponse shouldInterceptRequest( + ShouldInterceptRequestParams params); public abstract boolean shouldOverrideKeyEvent(KeyEvent event); diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java index fe59d2b..087e017 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java @@ -4,6 +4,9 @@ package org.chromium.android_webview; +import android.util.ArrayMap; + +import org.chromium.android_webview.AwContentsClient; import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; @@ -14,29 +17,48 @@ import org.chromium.base.JNINamespace; * provided functionality. */ @JNINamespace("android_webview") -public interface AwContentsIoThreadClient { +public abstract class AwContentsIoThreadClient { @CalledByNative - public int getCacheMode(); + public abstract int getCacheMode(); @CalledByNative - public InterceptedRequestData shouldInterceptRequest(String url, boolean isMainFrame); + public abstract boolean shouldBlockContentUrls(); @CalledByNative - public boolean shouldBlockContentUrls(); + public abstract boolean shouldBlockFileUrls(); @CalledByNative - public boolean shouldBlockFileUrls(); + public abstract boolean shouldBlockNetworkLoads(); @CalledByNative - public boolean shouldBlockNetworkLoads(); + public abstract boolean shouldAcceptThirdPartyCookies(); @CalledByNative - public boolean shouldAcceptThirdPartyCookies(); + public abstract void onDownloadStart(String url, String userAgent, + String contentDisposition, String mimeType, long contentLength); @CalledByNative - public void onDownloadStart(String url, String userAgent, - String contentDisposition, String mimeType, long contentLength); + public abstract void newLoginRequest(String realm, String account, String args); + + public abstract AwWebResourceResponse shouldInterceptRequest( + AwContentsClient.ShouldInterceptRequestParams params); + + // Protected methods --------------------------------------------------------------------------- @CalledByNative - public void newLoginRequest(String realm, String account, String args); + protected AwWebResourceResponse shouldInterceptRequest(String url, boolean isMainFrame, + boolean hasUserGesture, String method, String[] requestHeaderNames, + String[] requestHeaderValues) { + AwContentsClient.ShouldInterceptRequestParams params = + new AwContentsClient.ShouldInterceptRequestParams(); + params.url = url; + params.isMainFrame = isMainFrame; + params.hasUserGesture = hasUserGesture; + params.method = method; + params.requestHeaders = new ArrayMap<String, String>(requestHeaderNames.length); + for (int i = 0; i < requestHeaderNames.length; ++i) { + params.requestHeaders.put(requestHeaderNames[i], requestHeaderValues[i]); + } + return shouldInterceptRequest(params); + } } diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebResourceResponse.java b/android_webview/java/src/org/chromium/android_webview/AwWebResourceResponse.java new file mode 100644 index 0000000..1b861c0 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/AwWebResourceResponse.java @@ -0,0 +1,83 @@ +// 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.android_webview; + +import org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; + +import java.io.InputStream; +import java.util.Map; + +/** + * The response information that is to be returned for a particular resource fetch. + */ +@JNINamespace("android_webview") +public class AwWebResourceResponse { + private String mMimeType; + private String mCharset; + private InputStream mData; + private int mStatusCode; + private String mReasonPhrase; + private String[] mResponseHeaderNames; + private String[] mResponseHeaderValues; + + public AwWebResourceResponse(String mimeType, String encoding, InputStream data) { + mMimeType = mimeType; + mCharset = encoding; + mData = data; + } + + public AwWebResourceResponse(String mimeType, String encoding, InputStream data, + int statusCode, String reasonPhrase, Map<String, String> responseHeaders) { + this(mimeType, encoding, data); + + mStatusCode = statusCode; + mReasonPhrase = reasonPhrase; + + mResponseHeaderNames = new String[responseHeaders.size()]; + mResponseHeaderValues = new String[responseHeaders.size()]; + int i = 0; + for (Map.Entry<String, String> entry : responseHeaders.entrySet()) { + mResponseHeaderNames[i] = entry.getKey(); + mResponseHeaderValues[i] = entry.getValue(); + i++; + } + } + + @CalledByNative + public String getMimeType() { + return mMimeType; + } + + @CalledByNative + public String getCharset() { + return mCharset; + } + + @CalledByNative + public InputStream getData() { + return mData; + } + + @CalledByNative + public int getStatusCode() { + return mStatusCode; + } + + @CalledByNative + public String getReasonPhrase() { + return mReasonPhrase; + } + + @CalledByNative + public String[] getResponseHeaderNames() { + return mResponseHeaderNames; + } + + @CalledByNative + public String[] getResponseHeaderValues() { + return mResponseHeaderValues; + } +} diff --git a/android_webview/java/src/org/chromium/android_webview/DefaultVideoPosterRequestHandler.java b/android_webview/java/src/org/chromium/android_webview/DefaultVideoPosterRequestHandler.java index df2290a..aaed9f8 100644 --- a/android_webview/java/src/org/chromium/android_webview/DefaultVideoPosterRequestHandler.java +++ b/android_webview/java/src/org/chromium/android_webview/DefaultVideoPosterRequestHandler.java @@ -81,14 +81,14 @@ public class DefaultVideoPosterRequestHandler { * Used to get the image if the url is mDefaultVideoPosterURL. * * @param url the url requested - * @return InterceptedRequestData which caller can get the image if the url is + * @return AwWebResourceResponse which caller can get the image if the url is * the default video poster URL, otherwise null is returned. */ - public InterceptedRequestData shouldInterceptRequest(final String url) { + public AwWebResourceResponse shouldInterceptRequest(final String url) { if (!mDefaultVideoPosterURL.equals(url)) return null; try { - return new InterceptedRequestData("image/png", null, getInputStream(mContentClient)); + return new AwWebResourceResponse("image/png", null, getInputStream(mContentClient)); } catch (IOException e) { Log.e(TAG, null, e); return null; diff --git a/android_webview/java/src/org/chromium/android_webview/InterceptedRequestData.java b/android_webview/java/src/org/chromium/android_webview/InterceptedRequestData.java deleted file mode 100644 index 78f9382..0000000 --- a/android_webview/java/src/org/chromium/android_webview/InterceptedRequestData.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2012 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.android_webview; - -import org.chromium.base.CalledByNative; -import org.chromium.base.JNINamespace; - -import java.io.InputStream; - -/** - * The response information that is to be returned for a particular resource fetch. - */ -@JNINamespace("android_webview") -public class InterceptedRequestData { - private String mMimeType; - private String mCharset; - private InputStream mData; - - public InterceptedRequestData(String mimeType, String encoding, InputStream data) { - mMimeType = mimeType; - mCharset = encoding; - mData = data; - } - - @CalledByNative - public String getMimeType() { - return mMimeType; - } - - @CalledByNative - public String getCharset() { - return mCharset; - } - - @CalledByNative - public InputStream getData() { - return mData; - } -} diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetDefaultVideoPosterTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetDefaultVideoPosterTest.java index 8891fb9..fea72ff 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetDefaultVideoPosterTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetDefaultVideoPosterTest.java @@ -10,8 +10,8 @@ import android.graphics.BitmapFactory; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; +import org.chromium.android_webview.AwWebResourceResponse; import org.chromium.android_webview.DefaultVideoPosterRequestHandler; -import org.chromium.android_webview.InterceptedRequestData; import org.chromium.base.test.util.Feature; import org.chromium.content.browser.test.util.CallbackHelper; @@ -77,7 +77,7 @@ public class AwContentsClientGetDefaultVideoPosterTest extends AwTestBase { new DefaultVideoPosterClient(getInstrumentation().getTargetContext()); DefaultVideoPosterRequestHandler handler = new DefaultVideoPosterRequestHandler(contentsClient); - InterceptedRequestData requestData = + AwWebResourceResponse requestData = handler.shouldInterceptRequest(handler.getDefaultVideoPosterURL()); assertTrue(requestData.getMimeType().equals("image/png")); Bitmap bitmap = BitmapFactory.decodeStream(requestData.getData()); @@ -94,7 +94,7 @@ public class AwContentsClientGetDefaultVideoPosterTest extends AwTestBase { NullContentsClient contentsClient = new NullContentsClient(); DefaultVideoPosterRequestHandler handler = new DefaultVideoPosterRequestHandler(contentsClient); - InterceptedRequestData requestData = + AwWebResourceResponse requestData = handler.shouldInterceptRequest(handler.getDefaultVideoPosterURL()); assertTrue(requestData.getMimeType().equals("image/png")); InputStream in = requestData.getData(); diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java index fff12d2..e1bcb59 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldInterceptRequestTest.java @@ -8,8 +8,10 @@ import android.test.suitebuilder.annotation.SmallTest; import android.util.Pair; import org.chromium.android_webview.AwContents; -import org.chromium.android_webview.InterceptedRequestData; +import org.chromium.android_webview.AwContentsClient.ShouldInterceptRequestParams; +import org.chromium.android_webview.AwWebResourceResponse; import org.chromium.android_webview.test.util.CommonResources; +import org.chromium.android_webview.test.util.JSUtils; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.TestFileUtil; import org.chromium.content.browser.test.util.CallbackHelper; @@ -20,7 +22,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; @@ -35,27 +39,35 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { public static class ShouldInterceptRequestHelper extends CallbackHelper { private List<String> mShouldInterceptRequestUrls = new ArrayList<String>(); - private ConcurrentHashMap<String, InterceptedRequestData> mReturnValuesByUrls - = new ConcurrentHashMap<String, InterceptedRequestData>(); + private ConcurrentHashMap<String, AwWebResourceResponse> mReturnValuesByUrls + = new ConcurrentHashMap<String, AwWebResourceResponse>(); + private ConcurrentHashMap<String, ShouldInterceptRequestParams> mParamsByUrls + = new ConcurrentHashMap<String, ShouldInterceptRequestParams>(); // This is read from the IO thread, so needs to be marked volatile. - private volatile InterceptedRequestData mShouldInterceptRequestReturnValue = null; - void setReturnValue(InterceptedRequestData value) { + private volatile AwWebResourceResponse mShouldInterceptRequestReturnValue = null; + void setReturnValue(AwWebResourceResponse value) { mShouldInterceptRequestReturnValue = value; } - void setReturnValueForUrl(String url, InterceptedRequestData value) { + void setReturnValueForUrl(String url, AwWebResourceResponse value) { mReturnValuesByUrls.put(url, value); } public List<String> getUrls() { assert getCallCount() > 0; return mShouldInterceptRequestUrls; } - public InterceptedRequestData getReturnValue(String url) { - InterceptedRequestData value = mReturnValuesByUrls.get(url); + public AwWebResourceResponse getReturnValue(String url) { + AwWebResourceResponse value = mReturnValuesByUrls.get(url); if (value != null) return value; return mShouldInterceptRequestReturnValue; } - public void notifyCalled(String url) { - mShouldInterceptRequestUrls.add(url); + public ShouldInterceptRequestParams getParamsForUrl(String url) { + assert getCallCount() > 0; + assert mParamsByUrls.containsKey(url); + return mParamsByUrls.get(url); + } + public void notifyCalled(ShouldInterceptRequestParams params) { + mShouldInterceptRequestUrls.add(params.url); + mParamsByUrls.put(params.url, params); notifyCalled(); } } @@ -75,9 +87,10 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { } @Override - public InterceptedRequestData shouldInterceptRequest(String url) { - InterceptedRequestData returnValue = mShouldInterceptRequestHelper.getReturnValue(url); - mShouldInterceptRequestHelper.notifyCalled(url); + public AwWebResourceResponse shouldInterceptRequest(ShouldInterceptRequestParams params) { + AwWebResourceResponse returnValue = + mShouldInterceptRequestHelper.getReturnValue(params.url); + mShouldInterceptRequestHelper.notifyCalled(params); return returnValue; } @@ -104,6 +117,9 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { } } + final int teapotStatusCode = 418; + final String teapotResponsePhrase = "I'm a teapot"; + private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) { List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); headers.add(Pair.create("Content-Type", "text/html")); @@ -116,11 +132,11 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { CommonResources.ABOUT_HTML); } - private InterceptedRequestData stringToInterceptedRequestData(String input) throws Throwable { + private AwWebResourceResponse stringToAwWebResourceResponse(String input) throws Throwable { final String mimeType = "text/html"; final String encoding = "UTF-8"; - return new InterceptedRequestData( + return new AwWebResourceResponse( mimeType, encoding, new ByteArrayInputStream(input.getBytes(encoding))); } @@ -150,14 +166,13 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { @SmallTest @Feature({"AndroidWebView"}) - public void testCalledWithCorrectUrl() throws Throwable { + public void testCalledWithCorrectUrlParam() throws Throwable { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); - int callCount = mShouldInterceptRequestHelper.getCallCount(); int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount(); + int callCount = mShouldInterceptRequestHelper.getCallCount(); loadUrlAsync(mAwContents, aboutPageUrl); - mShouldInterceptRequestHelper.waitForCallback(callCount); assertEquals(1, mShouldInterceptRequestHelper.getUrls().size()); assertEquals(aboutPageUrl, @@ -169,6 +184,95 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { @SmallTest @Feature({"AndroidWebView"}) + public void testCalledWithCorrectIsMainFrameParam() throws Throwable { + final String subframeUrl = addAboutPageToTestServer(mWebServer); + final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html", + CommonResources.makeHtmlPageFrom("", + "<iframe src=\"" + subframeUrl + "\"/>")); + + int callCount = mShouldInterceptRequestHelper.getCallCount(); + loadUrlAsync(mAwContents, pageWithIframeUrl); + mShouldInterceptRequestHelper.waitForCallback(callCount, 2); + assertEquals(2, mShouldInterceptRequestHelper.getUrls().size()); + assertEquals(false, + mShouldInterceptRequestHelper.getParamsForUrl(subframeUrl).isMainFrame); + assertEquals(true, + mShouldInterceptRequestHelper.getParamsForUrl(pageWithIframeUrl).isMainFrame); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testCalledWithCorrectMethodParam() throws Throwable { + final String pageToPostToUrl = addAboutPageToTestServer(mWebServer); + final String pageWithFormUrl = addPageToTestServer(mWebServer, "/page_with_form.html", + CommonResources.makeHtmlPageWithSimplePostFormTo(pageToPostToUrl)); + enableJavaScriptOnUiThread(mAwContents); + + int callCount = mShouldInterceptRequestHelper.getCallCount(); + loadUrlAsync(mAwContents, pageWithFormUrl); + mShouldInterceptRequestHelper.waitForCallback(callCount); + assertEquals("GET", + mShouldInterceptRequestHelper.getParamsForUrl(pageWithFormUrl).method); + + callCount = mShouldInterceptRequestHelper.getCallCount(); + JSUtils.clickOnLinkUsingJs(this, mAwContents, + mContentsClient.getOnEvaluateJavaScriptResultHelper(), "link"); + mShouldInterceptRequestHelper.waitForCallback(callCount); + assertEquals("POST", + mShouldInterceptRequestHelper.getParamsForUrl(pageToPostToUrl).method); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testCalledWithCorrectHasUserGestureParam() throws Throwable { + final String aboutPageUrl = addAboutPageToTestServer(mWebServer); + final String pageWithLinkUrl = addPageToTestServer(mWebServer, "/page_with_link.html", + CommonResources.makeHtmlPageWithSimpleLinkTo(aboutPageUrl)); + enableJavaScriptOnUiThread(mAwContents); + + int callCount = mShouldInterceptRequestHelper.getCallCount(); + loadUrlAsync(mAwContents, pageWithLinkUrl); + mShouldInterceptRequestHelper.waitForCallback(callCount); + assertEquals(false, + mShouldInterceptRequestHelper.getParamsForUrl(pageWithLinkUrl).hasUserGesture); + + callCount = mShouldInterceptRequestHelper.getCallCount(); + JSUtils.clickOnLinkUsingJs(this, mAwContents, + mContentsClient.getOnEvaluateJavaScriptResultHelper(), "link"); + mShouldInterceptRequestHelper.waitForCallback(callCount); + assertEquals(true, + mShouldInterceptRequestHelper.getParamsForUrl(aboutPageUrl).hasUserGesture); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testCalledWithCorrectHeadersParam() throws Throwable { + final String headerName = "X-Test-Header-Name"; + final String headerValue = "TestHeaderValue"; + final String syncGetUrl = addPageToTestServer(mWebServer, "/intercept_me", + CommonResources.ABOUT_HTML); + final String mainPageUrl = addPageToTestServer(mWebServer, "/main", + CommonResources.makeHtmlPageFrom("", + "<script>" + + " var xhr = new XMLHttpRequest();" + + " xhr.open('GET', '" + syncGetUrl + "', false);" + + " xhr.setRequestHeader('" + headerName + "', '" + headerValue + "'); " + + " xhr.send(null);" + + "</script>")); + enableJavaScriptOnUiThread(mAwContents); + + int callCount = mShouldInterceptRequestHelper.getCallCount(); + loadUrlAsync(mAwContents, mainPageUrl); + mShouldInterceptRequestHelper.waitForCallback(callCount, 2); + + Map<String, String> headers = + mShouldInterceptRequestHelper.getParamsForUrl(syncGetUrl).requestHeaders; + assertTrue(headers.containsKey(headerName)); + assertEquals(headerValue, headers.get(headerName)); + } + + @SmallTest + @Feature({"AndroidWebView"}) public void testOnLoadResourceCalledWithCorrectUrl() throws Throwable { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); final TestAwContentsClient.OnLoadResourceHelper onLoadResourceHelper = @@ -188,19 +292,19 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", null)); + new AwWebResourceResponse("text/html", "UTF-8", null)); int callCount = mShouldInterceptRequestHelper.getCallCount(); loadUrlAsync(mAwContents, aboutPageUrl); mShouldInterceptRequestHelper.waitForCallback(callCount); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData(null, null, new ByteArrayInputStream(new byte[0]))); + new AwWebResourceResponse(null, null, new ByteArrayInputStream(new byte[0]))); callCount = mShouldInterceptRequestHelper.getCallCount(); loadUrlAsync(mAwContents, aboutPageUrl); mShouldInterceptRequestHelper.waitForCallback(callCount); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData(null, null, null)); + new AwWebResourceResponse(null, null, null)); callCount = mShouldInterceptRequestHelper.getCallCount(); loadUrlAsync(mAwContents, aboutPageUrl); mShouldInterceptRequestHelper.waitForCallback(callCount); @@ -241,7 +345,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", new EmptyInputStream())); + new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream())); int shouldInterceptRequestCallCount = mShouldInterceptRequestHelper.getCallCount(); int onPageFinishedCallCount = mContentsClient.getOnPageFinishedHelper().getCallCount(); @@ -251,11 +355,11 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { mContentsClient.getOnPageFinishedHelper().waitForCallback(onPageFinishedCallCount); } - private static class SlowInterceptedRequestData extends InterceptedRequestData { + private static class SlowAwWebResourceResponse extends AwWebResourceResponse { private CallbackHelper mReadStartedCallbackHelper = new CallbackHelper(); private CountDownLatch mLatch = new CountDownLatch(1); - public SlowInterceptedRequestData(String mimeType, String encoding, InputStream data) { + public SlowAwWebResourceResponse(String mimeType, String encoding, InputStream data) { super(mimeType, encoding, data); } @@ -285,14 +389,14 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); final String aboutPageData = makePageWithTitle("some title"); final String encoding = "UTF-8"; - final SlowInterceptedRequestData slowInterceptedRequestData = - new SlowInterceptedRequestData("text/html", encoding, + final SlowAwWebResourceResponse slowAwWebResourceResponse = + new SlowAwWebResourceResponse("text/html", encoding, new ByteArrayInputStream(aboutPageData.getBytes(encoding))); - mShouldInterceptRequestHelper.setReturnValue(slowInterceptedRequestData); - int callCount = slowInterceptedRequestData.getReadStartedCallbackHelper().getCallCount(); + mShouldInterceptRequestHelper.setReturnValue(slowAwWebResourceResponse); + int callCount = slowAwWebResourceResponse.getReadStartedCallbackHelper().getCallCount(); loadUrlAsync(mAwContents, aboutPageUrl); - slowInterceptedRequestData.getReadStartedCallbackHelper().waitForCallback(callCount); + slowAwWebResourceResponse.getReadStartedCallbackHelper().waitForCallback(callCount); // Now the AwContents is "stuck" waiting for the SlowInputStream to finish reading so we // delete it to make sure that the dangling 'read' task doesn't cause a crash. Unfortunately @@ -312,12 +416,12 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { } }); - slowInterceptedRequestData.unblockReads(); + slowAwWebResourceResponse.unblockReads(); } @SmallTest @Feature({"AndroidWebView"}) - public void testHttpStatusField() throws Throwable { + public void testHttpStatusCodeAndText() throws Throwable { final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me"); final String syncGetJs = "(function() {" + @@ -325,7 +429,8 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { " xhr.open('GET', '" + syncGetUrl + "', false);" + " xhr.send(null);" + " console.info('xhr.status = ' + xhr.status);" + - " return xhr.status;" + + " console.info('xhr.statusText = ' + xhr.statusText);" + + " return '[' + xhr.status + '][' + xhr.statusText + ']';" + "})();"; enableJavaScriptOnUiThread(mAwContents); @@ -333,32 +438,47 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", null)); - assertEquals("404", + new AwWebResourceResponse("text/html", "UTF-8", null)); + assertEquals("\"[404][Not Found]\"", executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs)); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", new EmptyInputStream())); - assertEquals("200", + new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream())); + assertEquals("\"[200][OK]\"", + executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs)); + + mShouldInterceptRequestHelper.setReturnValue( + new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream(), + teapotStatusCode, teapotResponsePhrase, new HashMap<String, String>())); + assertEquals("\"[" + teapotStatusCode + "][" + teapotResponsePhrase + "]\"", executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs)); } - @SmallTest - @Feature({"AndroidWebView"}) - public void testHttpResponseClientHeader() throws Throwable { - final String clientResponseHeaderName = "Client-Via"; - // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes - // around returned strings. - final String clientResponseHeaderValue = "\"shouldInterceptRequest\""; - final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me"); + private String getHeaderValue(AwContents awContents, TestAwContentsClient contentsClient, + String url, String headerName) throws Exception { final String syncGetJs = "(function() {" + " var xhr = new XMLHttpRequest();" + - " xhr.open('GET', '" + syncGetUrl + "', false);" + + " xhr.open('GET', '" + url + "', false);" + " xhr.send(null);" + " console.info(xhr.getAllResponseHeaders());" + - " return xhr.getResponseHeader('" + clientResponseHeaderName + "');" + + " return xhr.getResponseHeader('" + headerName + "');" + "})();"; + String header = executeJavaScriptAndWaitForResult(awContents, contentsClient, syncGetJs); + // JSON stringification applied by executeJavaScriptAndWaitForResult adds quotes + // around returned strings. + assertTrue(header.length() > 2); + assertEquals('"', header.charAt(0)); + assertEquals('"', header.charAt(header.length() - 1)); + return header.substring(1, header.length() - 1); + } + + @SmallTest + @Feature({"AndroidWebView"}) + public void testHttpResponseClientViaHeader() throws Throwable { + final String clientResponseHeaderName = "Client-Via"; + final String clientResponseHeaderValue = "shouldInterceptRequest"; + final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me"); enableJavaScriptOnUiThread(mAwContents); final String aboutPageUrl = addAboutPageToTestServer(mWebServer); @@ -367,15 +487,34 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { // The response header is set regardless of whether the embedder has provided a // valid resource stream. mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", null)); + new AwWebResourceResponse("text/html", "UTF-8", null)); assertEquals(clientResponseHeaderValue, - executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs)); + getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName)); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", new EmptyInputStream())); + new AwWebResourceResponse("text/html", "UTF-8", new EmptyInputStream())); assertEquals(clientResponseHeaderValue, - executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, syncGetJs)); + getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName)); + } + @SmallTest + @Feature({"AndroidWebView"}) + public void testHttpResponseHeader() throws Throwable { + final String clientResponseHeaderName = "X-Test-Header-Name"; + final String clientResponseHeaderValue = "TestHeaderValue"; + final String syncGetUrl = mWebServer.getResponseUrl("/intercept_me"); + final Map<String, String> headers = new HashMap<String, String>(); + headers.put(clientResponseHeaderName, clientResponseHeaderValue); + enableJavaScriptOnUiThread(mAwContents); + + final String aboutPageUrl = addAboutPageToTestServer(mWebServer); + loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), aboutPageUrl); + + mShouldInterceptRequestHelper.setReturnValue( + new AwWebResourceResponse("text/html", "UTF-8", null, 0, null, headers)); + assertEquals(clientResponseHeaderValue, + getHeaderValue(mAwContents, mContentsClient, syncGetUrl, clientResponseHeaderName)); + } private String makePageWithTitle(String title) { return CommonResources.makeHtmlPageFrom("<title>" + title + "</title>", @@ -389,7 +528,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { final String expectedPage = makePageWithTitle(expectedTitle); mShouldInterceptRequestHelper.setReturnValue( - stringToInterceptedRequestData(expectedPage)); + stringToAwWebResourceResponse(expectedPage)); final String aboutPageUrl = addAboutPageToTestServer(mWebServer); @@ -403,7 +542,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { @Feature({"AndroidWebView"}) public void testDoesNotChangeReportedUrl() throws Throwable { mShouldInterceptRequestHelper.setReturnValue( - stringToInterceptedRequestData(makePageWithTitle("some title"))); + stringToAwWebResourceResponse(makePageWithTitle("some title"))); final String aboutPageUrl = addAboutPageToTestServer(mWebServer); @@ -420,7 +559,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { mContentsClient.getOnReceivedErrorHelper(); mShouldInterceptRequestHelper.setReturnValue( - new InterceptedRequestData("text/html", "UTF-8", null)); + new AwWebResourceResponse("text/html", "UTF-8", null)); final String aboutPageUrl = addAboutPageToTestServer(mWebServer); final int callCount = onReceivedErrorHelper.getCallCount(); @@ -451,7 +590,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { @SmallTest @Feature({"AndroidWebView"}) public void testOnReceivedErrorCallback() throws Throwable { - mShouldInterceptRequestHelper.setReturnValue(new InterceptedRequestData(null, null, null)); + mShouldInterceptRequestHelper.setReturnValue(new AwWebResourceResponse(null, null, null)); OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper(); int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount(); loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), "foo://bar"); @@ -468,7 +607,7 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { addPageToTestServer(mWebServer, "/page_with_image.html", CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME)); mShouldInterceptRequestHelper.setReturnValueForUrl( - imageUrl, new InterceptedRequestData(null, null, null)); + imageUrl, new AwWebResourceResponse(null, null, null)); OnReceivedErrorHelper onReceivedErrorHelper = mContentsClient.getOnReceivedErrorHelper(); int onReceivedErrorHelperCallCount = onReceivedErrorHelper.getCallCount(); loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithImage); @@ -479,12 +618,12 @@ public class AwContentsClientShouldInterceptRequestTest extends AwTestBase { @Feature({"AndroidWebView"}) public void testCalledForIframe() throws Throwable { final String aboutPageUrl = addAboutPageToTestServer(mWebServer); - final String pageWithIframe = addPageToTestServer(mWebServer, "/page_with_iframe.html", + final String pageWithIframeUrl = addPageToTestServer(mWebServer, "/page_with_iframe.html", CommonResources.makeHtmlPageFrom("", "<iframe src=\"" + aboutPageUrl + "\"/>")); int callCount = mShouldInterceptRequestHelper.getCallCount(); - loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithIframe); + loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageWithIframeUrl); mShouldInterceptRequestHelper.waitForCallback(callCount, 2); assertEquals(2, mShouldInterceptRequestHelper.getUrls().size()); assertEquals(aboutPageUrl, mShouldInterceptRequestHelper.getUrls().get(1)); diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java index 5ccc6eb..8656e42 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java @@ -64,15 +64,12 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { }); } - private String makeHtmlPageFrom(String headers, String body) { - return CommonResources.makeHtmlPageFrom("<title>" + TITLE + "</title> " + headers, body); + private String getTestPageCommonHeaders() { + return "<title>" + TITLE + "</title> "; } - private String getHtmlForPageWithSimpleLinkTo(String destination) { - return makeHtmlPageFrom("", - "<a href=\"" + destination + "\" id=\"link\">" + - "<img class=\"big\" />" + - "</a>"); + private String makeHtmlPageFrom(String headers, String body) { + return CommonResources.makeHtmlPageFrom(getTestPageCommonHeaders() + headers, body); } private String getHtmlForPageWithJsAssignLinkTo(String url) { @@ -104,13 +101,6 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { method, timeout)); } - private String getHtmlForPageWithSimplePostFormTo(String destination) { - return makeHtmlPageFrom("", - "<form action=\"" + destination + "\" method=\"post\">" + - "<input type=\"submit\" value=\"post\" id=\"link\">" + - "</form>"); - } - private String addPageToTestServer(TestWebServer webServer, String httpPath, String html) { List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); headers.add(Pair.create("Content-Type", "text/html")); @@ -134,7 +124,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { contentsClient.getShouldOverrideUrlLoadingHelper(); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false); assertEquals(0, shouldOverrideUrlLoadingHelper.getCallCount()); } @@ -217,7 +207,8 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { setShouldOverrideUrlLoadingReturnValueOnUiThread(shouldOverrideUrlLoadingHelper, true); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(getTestPageCommonHeaders(), + DATA_URL), "text/html", false); assertEquals(TITLE, getTitleOnUiThread(awContents)); } @@ -234,7 +225,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { OnPageStartedHelper onPageStartedHelper = contentsClient.getOnPageStartedHelper(); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false); final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); final int onPageStartedCallCount = onPageStartedHelper.getCallCount(); @@ -259,7 +250,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final int onReceivedErrorCallCount = onReceivedErrorHelper.getCallCount(); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false); final int shouldOverrideUrlLoadingCallCount = shouldOverrideUrlLoadingHelper.getCallCount(); @@ -301,11 +292,11 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String anchorLinkPath = "/anchor_link.html"; final String anchorLinkUrl = mWebServer.getResponseUrl(anchorLinkPath); addPageToTestServer(mWebServer, anchorLinkPath, - getHtmlForPageWithSimpleLinkTo(anchorLinkUrl + "#anchor")); + CommonResources.makeHtmlPageWithSimpleLinkTo(anchorLinkUrl + "#anchor")); if (useLoadData) { loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo("#anchor"), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo("#anchor"), "text/html", false); } else { loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), anchorLinkUrl); } @@ -335,7 +326,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { // We can't go to about:blank from here because we'd get a cross-origin error. loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", false); int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); @@ -357,7 +348,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String httpPath = "/page_with_about_blank_navigation"; final String httpPathOnServer = mWebServer.getResponseUrl(httpPath); addPageToTestServer(mWebServer, httpPath, - getHtmlForPageWithSimpleLinkTo(ABOUT_BLANK_URL)); + CommonResources.makeHtmlPageWithSimpleLinkTo(ABOUT_BLANK_URL)); loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), httpPathOnServer); @@ -384,7 +375,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String httpPath = "/page_with_link_to_self.html"; final String httpPathOnServer = mWebServer.getResponseUrl(httpPath); addPageToTestServer(mWebServer, httpPath, - getHtmlForPageWithSimpleLinkTo(httpPathOnServer)); + CommonResources.makeHtmlPageWithSimpleLinkTo(httpPathOnServer)); loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), httpPathOnServer); @@ -454,7 +445,8 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String redirectTargetUrl = createRedirectTargetPage(mWebServer); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(redirectTargetUrl), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl), "text/html", + false); int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); clickOnLinkUsingJs(awContents, contentsClient); @@ -477,11 +469,11 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String pageWithLinkToIgnorePath = "/page_with_link_to_ignore.html"; final String pageWithLinkToIgnoreUrl = addPageToTestServer(mWebServer, pageWithLinkToIgnorePath, - getHtmlForPageWithSimpleLinkTo(redirectTargetUrl)); + CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl)); final String synchronizationPath = "/sync.html"; final String synchronizationUrl = addPageToTestServer(mWebServer, synchronizationPath, - getHtmlForPageWithSimpleLinkTo(redirectTargetUrl)); + CommonResources.makeHtmlPageWithSimpleLinkTo(redirectTargetUrl)); loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), pageWithLinkToIgnoreUrl); @@ -518,7 +510,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = contentsClient.getShouldOverrideUrlLoadingHelper(); loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(dataUrl), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(dataUrl), "text/html", false); int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); clickOnLinkUsingJs(awContents, contentsClient); @@ -541,7 +533,8 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { contentsClient.getShouldOverrideUrlLoadingHelper(); final String unsupportedSchemeUrl = "foobar://resource/1"; loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), - getHtmlForPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html", false); + CommonResources.makeHtmlPageWithSimpleLinkTo(unsupportedSchemeUrl), "text/html", + false); int callCount = shouldOverrideUrlLoadingHelper.getCallCount(); clickOnLinkUsingJs(awContents, contentsClient); @@ -564,7 +557,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String redirectTargetUrl = createRedirectTargetPage(mWebServer); final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html", - getHtmlForPageWithSimplePostFormTo(redirectTargetUrl)); + CommonResources.makeHtmlPageWithSimplePostFormTo(redirectTargetUrl)); loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl); @@ -603,7 +596,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final String redirectTargetUrl = createRedirectTargetPage(mWebServer); final String postToGetRedirectUrl = mWebServer.setRedirect("/302.html", redirectTargetUrl); final String postLinkUrl = addPageToTestServer(mWebServer, "/page_with_post_link.html", - getHtmlForPageWithSimplePostFormTo(postToGetRedirectUrl)); + CommonResources.makeHtmlPageWithSimplePostFormTo(postToGetRedirectUrl)); loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), postLinkUrl); @@ -702,7 +695,7 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { final AwContents awContents = testContainerView.getAwContents(); final String pageWithLinkToRedirectUrl = addPageToTestServer(webServer, "/page_with_link_to_redirect.html", - getHtmlForPageWithSimpleLinkTo(redirectUrl)); + CommonResources.makeHtmlPageWithSimpleLinkTo(redirectUrl)); enableJavaScriptOnUiThread(awContents); TestAwContentsClient.ShouldOverrideUrlLoadingHelper shouldOverrideUrlLoadingHelper = @@ -813,7 +806,8 @@ public class AwContentsClientShouldOverrideUrlLoadingTest extends AwTestBase { @Override public void run() { awContents.loadUrl(LoadUrlParams.createLoadDataParams( - getHtmlForPageWithSimpleLinkTo(DATA_URL), "text/html", false)); + CommonResources.makeHtmlPageWithSimpleLinkTo(DATA_URL), "text/html", + false)); awContents.loadUrl(new LoadUrlParams(jsUrl)); } }); diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java index 4943bf8..38bfbd1 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java @@ -21,9 +21,10 @@ import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; import org.apache.http.Header; import org.apache.http.HttpRequest; import org.chromium.android_webview.AwContents; +import org.chromium.android_webview.AwContentsClient.ShouldInterceptRequestParams; import org.chromium.android_webview.AwSettings; import org.chromium.android_webview.AwSettings.LayoutAlgorithm; -import org.chromium.android_webview.InterceptedRequestData; +import org.chromium.android_webview.AwWebResourceResponse; import org.chromium.android_webview.test.util.CommonResources; import org.chromium.android_webview.test.util.ImagePageGenerator; import org.chromium.android_webview.test.util.VideoTestUtil; @@ -2568,8 +2569,9 @@ public class AwSettingsTest extends AwTestBase { final String DEFAULT_VIDEO_POSTER_URL = "http://default_video_poster/"; TestAwContentsClient client = new TestAwContentsClient() { @Override - public InterceptedRequestData shouldInterceptRequest(String url) { - if (url.equals(DEFAULT_VIDEO_POSTER_URL)) { + public AwWebResourceResponse shouldInterceptRequest( + ShouldInterceptRequestParams params) { + if (params.url.equals(DEFAULT_VIDEO_POSTER_URL)) { videoPosterAccessedCallbackHelper.notifyCalled(); } return null; diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java index d365319..9f597e6 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/CookieManagerStartupTest.java @@ -11,7 +11,7 @@ import android.test.suitebuilder.annotation.SmallTest; import org.chromium.android_webview.AwBrowserProcess; import org.chromium.android_webview.AwContents; import org.chromium.android_webview.AwCookieManager; -import org.chromium.android_webview.InterceptedRequestData; +import org.chromium.android_webview.AwWebResourceResponse; import org.chromium.android_webview.test.util.CommonResources; import org.chromium.android_webview.test.util.CookieUtils; import org.chromium.base.test.util.Feature; @@ -120,7 +120,8 @@ public class CookieManagerStartupTest extends AwTestBase { String url = "http://www.example.com"; TestAwContentsClient contentsClient = new TestAwContentsClient() { @Override - public InterceptedRequestData shouldInterceptRequest(String url) { + public AwWebResourceResponse shouldInterceptRequest( + ShouldInterceptRequestParams params) { (new AwCookieManager()).getCookie("www.example.com"); return null; } diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/util/CommonResources.java b/android_webview/javatests/src/org/chromium/android_webview/test/util/CommonResources.java index 5fae61c..2f8e900 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/util/CommonResources.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/util/CommonResources.java @@ -105,4 +105,22 @@ public class CommonResources { "</body>" + "</html>"; } + + public static String makeHtmlPageWithSimpleLinkTo(String headers, String destination) { + return makeHtmlPageFrom(headers, + "<a href=\"" + destination + "\" id=\"link\">" + + "<img class=\"big\" />" + + "</a>"); + } + + public static String makeHtmlPageWithSimpleLinkTo(String destination) { + return makeHtmlPageWithSimpleLinkTo("", destination); + } + + public static String makeHtmlPageWithSimplePostFormTo(String destination) { + return makeHtmlPageFrom("", + "<form action=\"" + destination + "\" method=\"post\">" + + "<input type=\"submit\" value=\"post\" id=\"link\">" + + "</form>"); + } } diff --git a/android_webview/native/android_protocol_handler.cc b/android_webview/native/android_protocol_handler.cc index ac57ae9..bc25e36 100644 --- a/android_webview/native/android_protocol_handler.cc +++ b/android_webview/native/android_protocol_handler.cc @@ -77,6 +77,10 @@ class AndroidStreamReaderURLRequestJobDelegateImpl InputStream* stream, std::string* charset) OVERRIDE; + virtual void AppendResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) OVERRIDE; + virtual ~AndroidStreamReaderURLRequestJobDelegateImpl(); }; @@ -198,6 +202,12 @@ bool AndroidStreamReaderURLRequestJobDelegateImpl::GetCharset( return false; } +void AndroidStreamReaderURLRequestJobDelegateImpl::AppendResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) { + // no-op +} + // AndroidRequestInterceptorBase ---------------------------------------------- net::URLRequestJob* AndroidRequestInterceptorBase::MaybeInterceptRequest( diff --git a/android_webview/native/android_webview_jni_registrar.cc b/android_webview/native/android_webview_jni_registrar.cc index 3f2e85b..8db9713 100644 --- a/android_webview/native/android_webview_jni_registrar.cc +++ b/android_webview/native/android_webview_jni_registrar.cc @@ -19,10 +19,10 @@ #include "android_webview/native/aw_resource.h" #include "android_webview/native/aw_settings.h" #include "android_webview/native/aw_web_contents_delegate.h" +#include "android_webview/native/aw_web_resource_response_impl.h" #include "android_webview/native/cookie_manager.h" #include "android_webview/native/external_video_surface_container_impl.h" #include "android_webview/native/input_stream_impl.h" -#include "android_webview/native/intercepted_request_data_impl.h" #include "android_webview/native/java_browser_view_renderer_helper.h" #include "android_webview/native/permission/aw_permission_request.h" #include "base/android/jni_android.h" @@ -53,7 +53,7 @@ static base::android::RegistrationMethod kWebViewRegisteredMethods[] = { #if defined(VIDEO_HOLE) { "ExternalVideoSurfaceContainer", RegisterExternalVideoSurfaceContainer }, #endif - { "InterceptedRequestDataImpl", RegisterInterceptedRequestData }, + { "AwWebResourceResponseImpl", RegisterAwWebResourceResponse }, { "InputStream", RegisterInputStream }, { "JavaBrowserViewRendererHelper", RegisterJavaBrowserViewRendererHelper }, }; diff --git a/android_webview/native/aw_contents_io_thread_client_impl.cc b/android_webview/native/aw_contents_io_thread_client_impl.cc index fd47138..a6912a8 100644 --- a/android_webview/native/aw_contents_io_thread_client_impl.cc +++ b/android_webview/native/aw_contents_io_thread_client_impl.cc @@ -8,7 +8,8 @@ #include <utility> #include "android_webview/common/devtools_instrumentation.h" -#include "android_webview/native/intercepted_request_data_impl.h" +#include "android_webview/native/aw_web_resource_response_impl.h" +#include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/jni_weak_ref.h" #include "base/lazy_instance.h" @@ -23,6 +24,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" #include "jni/AwContentsIoThreadClient_jni.h" +#include "net/http/http_request_headers.h" #include "net/url_request/url_request.h" #include "url/gurl.h" @@ -30,12 +32,15 @@ using base::android::AttachCurrentThread; using base::android::ConvertUTF8ToJavaString; using base::android::JavaRef; using base::android::ScopedJavaLocalRef; +using base::android::ToJavaArrayOfStrings; using base::LazyInstance; using content::BrowserThread; using content::RenderFrameHost; using content::WebContents; using std::map; using std::pair; +using std::string; +using std::vector; namespace android_webview { @@ -227,30 +232,57 @@ AwContentsIoThreadClientImpl::GetCacheMode() const { env, java_object_.obj())); } -scoped_ptr<InterceptedRequestData> +scoped_ptr<AwWebResourceResponse> AwContentsIoThreadClientImpl::ShouldInterceptRequest( const GURL& location, const net::URLRequest* request) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (java_object_.is_null()) - return scoped_ptr<InterceptedRequestData>(); + return scoped_ptr<AwWebResourceResponse>(); const content::ResourceRequestInfo* info = content::ResourceRequestInfo::ForRequest(request); bool is_main_frame = info && info->GetResourceType() == ResourceType::MAIN_FRAME; + bool has_user_gesture = info && info->HasUserGesture(); + + vector<string> headers_names; + vector<string> headers_values; + { + net::HttpRequestHeaders headers; + if (!request->GetFullRequestHeaders(&headers)) + headers = request->extra_request_headers(); + net::HttpRequestHeaders::Iterator headers_iterator(headers); + while (headers_iterator.GetNext()) { + headers_names.push_back(headers_iterator.name()); + headers_values.push_back(headers_iterator.value()); + } + } JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> jstring_url = ConvertUTF8ToJavaString(env, location.spec()); + ScopedJavaLocalRef<jstring> jstring_method = + ConvertUTF8ToJavaString(env, request->method()); + ScopedJavaLocalRef<jobjectArray> jstringArray_headers_names = + ToJavaArrayOfStrings(env, headers_names); + ScopedJavaLocalRef<jobjectArray> jstringArray_headers_values = + ToJavaArrayOfStrings(env, headers_values); devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback( "shouldInterceptRequest"); ScopedJavaLocalRef<jobject> ret = Java_AwContentsIoThreadClient_shouldInterceptRequest( - env, java_object_.obj(), jstring_url.obj(), is_main_frame); + env, + java_object_.obj(), + jstring_url.obj(), + is_main_frame, + has_user_gesture, + jstring_method.obj(), + jstringArray_headers_names.obj(), + jstringArray_headers_values.obj()); if (ret.is_null()) - return scoped_ptr<InterceptedRequestData>(); - return scoped_ptr<InterceptedRequestData>( - new InterceptedRequestDataImpl(ret)); + return scoped_ptr<AwWebResourceResponse>(); + return scoped_ptr<AwWebResourceResponse>( + new AwWebResourceResponseImpl(ret)); } bool AwContentsIoThreadClientImpl::ShouldBlockContentUrls() const { @@ -295,9 +327,9 @@ bool AwContentsIoThreadClientImpl::ShouldBlockNetworkLoads() const { void AwContentsIoThreadClientImpl::NewDownload( const GURL& url, - const std::string& user_agent, - const std::string& content_disposition, - const std::string& mime_type, + const string& user_agent, + const string& content_disposition, + const string& mime_type, int64 content_length) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (java_object_.is_null()) @@ -323,9 +355,9 @@ void AwContentsIoThreadClientImpl::NewDownload( content_length); } -void AwContentsIoThreadClientImpl::NewLoginRequest(const std::string& realm, - const std::string& account, - const std::string& args) { +void AwContentsIoThreadClientImpl::NewLoginRequest(const string& realm, + const string& account, + const string& args) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (java_object_.is_null()) return; diff --git a/android_webview/native/aw_contents_io_thread_client_impl.h b/android_webview/native/aw_contents_io_thread_client_impl.h index c783b2b..27ce4e5 100644 --- a/android_webview/native/aw_contents_io_thread_client_impl.h +++ b/android_webview/native/aw_contents_io_thread_client_impl.h @@ -15,6 +15,7 @@ class GURL; namespace content { +class ResourceRequestInfo; class WebContents; } @@ -24,7 +25,7 @@ class URLRequest; namespace android_webview { -class InterceptedRequestData; +class AwWebResourceResponse; class AwContentsIoThreadClientImpl : public AwContentsIoThreadClient { public: @@ -46,7 +47,7 @@ class AwContentsIoThreadClientImpl : public AwContentsIoThreadClient { // Implementation of AwContentsIoThreadClient. virtual bool PendingAssociation() const OVERRIDE; virtual CacheMode GetCacheMode() const OVERRIDE; - virtual scoped_ptr<InterceptedRequestData> ShouldInterceptRequest( + virtual scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest( const GURL& location, const net::URLRequest* request) OVERRIDE; virtual bool ShouldBlockContentUrls() const OVERRIDE; diff --git a/android_webview/native/aw_web_resource_response_impl.cc b/android_webview/native/aw_web_resource_response_impl.cc new file mode 100644 index 0000000..caaac83 --- /dev/null +++ b/android_webview/native/aw_web_resource_response_impl.cc @@ -0,0 +1,104 @@ +// 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. + +#include "android_webview/native/aw_web_resource_response_impl.h" + +#include "android_webview/native/input_stream_impl.h" +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "jni/AwWebResourceResponse_jni.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_job.h" + +using base::android::ScopedJavaLocalRef; +using base::android::AppendJavaStringArrayToStringVector; + +namespace android_webview { + +AwWebResourceResponseImpl::AwWebResourceResponseImpl( + const base::android::JavaRef<jobject>& obj) + : java_object_(obj) { +} + +AwWebResourceResponseImpl::~AwWebResourceResponseImpl() { +} + +scoped_ptr<InputStream> +AwWebResourceResponseImpl::GetInputStream(JNIEnv* env) const { + ScopedJavaLocalRef<jobject> jstream = + Java_AwWebResourceResponse_getData(env, java_object_.obj()); + if (jstream.is_null()) + return scoped_ptr<InputStream>(); + return make_scoped_ptr<InputStream>(new InputStreamImpl(jstream)); +} + +bool AwWebResourceResponseImpl::GetMimeType(JNIEnv* env, + std::string* mime_type) const { + ScopedJavaLocalRef<jstring> jstring_mime_type = + Java_AwWebResourceResponse_getMimeType(env, java_object_.obj()); + if (jstring_mime_type.is_null()) + return false; + *mime_type = ConvertJavaStringToUTF8(jstring_mime_type); + return true; +} + +bool AwWebResourceResponseImpl::GetCharset( + JNIEnv* env, std::string* charset) const { + ScopedJavaLocalRef<jstring> jstring_charset = + Java_AwWebResourceResponse_getCharset(env, java_object_.obj()); + if (jstring_charset.is_null()) + return false; + *charset = ConvertJavaStringToUTF8(jstring_charset); + return true; +} + +bool AwWebResourceResponseImpl::GetStatusInfo( + JNIEnv* env, + int* status_code, + std::string* reason_phrase) const { + int status = + Java_AwWebResourceResponse_getStatusCode(env, java_object_.obj()); + ScopedJavaLocalRef<jstring> jstring_reason_phrase = + Java_AwWebResourceResponse_getReasonPhrase(env, java_object_.obj()); + if (status < 100 || status >= 600 || jstring_reason_phrase.is_null()) + return false; + *status_code = status; + *reason_phrase = ConvertJavaStringToUTF8(jstring_reason_phrase); + return true; +} + +bool AwWebResourceResponseImpl::GetResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) const { + ScopedJavaLocalRef<jobjectArray> jstringArray_headerNames = + Java_AwWebResourceResponse_getResponseHeaderNames(env, + java_object_.obj()); + ScopedJavaLocalRef<jobjectArray> jstringArray_headerValues = + Java_AwWebResourceResponse_getResponseHeaderValues(env, + java_object_.obj()); + if (jstringArray_headerNames.is_null() || jstringArray_headerValues.is_null()) + return false; + std::vector<std::string> header_names; + std::vector<std::string> header_values; + AppendJavaStringArrayToStringVector( + env, jstringArray_headerNames.obj(), &header_names); + AppendJavaStringArrayToStringVector( + env, jstringArray_headerValues.obj(), &header_values); + DCHECK(header_names.size() == header_values.size()); + for(size_t i = 0; i < header_names.size(); ++i) { + std::string header_line(header_names[i]); + header_line.append(": "); + header_line.append(header_values[i]); + headers->AddHeader(header_line); + } + return true; +} + +bool RegisterAwWebResourceResponse(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace android_webview diff --git a/android_webview/native/intercepted_request_data_impl.h b/android_webview/native/aw_web_resource_response_impl.h index 598b319..2cef1c0 100644 --- a/android_webview/native/intercepted_request_data_impl.h +++ b/android_webview/native/aw_web_resource_response_impl.h @@ -1,37 +1,47 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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. #ifndef ANDROID_WEBVIEW_NATIVE_INTERCEPTED_REQUEST_DATA_IMPL_H_ #define ANDROID_WEBVIEW_NATIVE_INTERCEPTED_REQUEST_DATA_IMPL_H_ -#include "android_webview/browser/intercepted_request_data.h" +#include "android_webview/browser/aw_web_resource_response.h" #include "base/android/scoped_java_ref.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +namespace net { +class HttpResponseHeaders; +} + namespace android_webview { class InputStream; -class InterceptedRequestDataImpl : public InterceptedRequestData { +class AwWebResourceResponseImpl : public AwWebResourceResponse { public: // It is expected that |obj| is an instance of the Java-side - // org.chromium.android_webview.InterceptedRequestData class. - InterceptedRequestDataImpl(const base::android::JavaRef<jobject>& obj); - virtual ~InterceptedRequestDataImpl(); + // org.chromium.android_webview.AwWebResourceResponse class. + AwWebResourceResponseImpl(const base::android::JavaRef<jobject>& obj); + virtual ~AwWebResourceResponseImpl(); virtual scoped_ptr<InputStream> GetInputStream(JNIEnv* env) const OVERRIDE; virtual bool GetMimeType(JNIEnv* env, std::string* mime_type) const OVERRIDE; virtual bool GetCharset(JNIEnv* env, std::string* charset) const OVERRIDE; + virtual bool GetStatusInfo(JNIEnv* env, + int* status_code, + std::string* reason_phrase) const OVERRIDE; + virtual bool GetResponseHeaders( + JNIEnv* env, + net::HttpResponseHeaders* headers) const OVERRIDE; private: base::android::ScopedJavaGlobalRef<jobject> java_object_; - DISALLOW_COPY_AND_ASSIGN(InterceptedRequestDataImpl); + DISALLOW_COPY_AND_ASSIGN(AwWebResourceResponseImpl); }; -bool RegisterInterceptedRequestData(JNIEnv* env); +bool RegisterAwWebResourceResponse(JNIEnv* env); } // namespace android_webview diff --git a/android_webview/native/intercepted_request_data_impl.cc b/android_webview/native/intercepted_request_data_impl.cc deleted file mode 100644 index 8b583df..0000000 --- a/android_webview/native/intercepted_request_data_impl.cc +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2012 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. - -#include "android_webview/native/intercepted_request_data_impl.h" - -#include "android_webview/native/input_stream_impl.h" -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "jni/InterceptedRequestData_jni.h" -#include "net/url_request/url_request.h" -#include "net/url_request/url_request_job.h" - -using base::android::ScopedJavaLocalRef; - -namespace android_webview { - -InterceptedRequestDataImpl::InterceptedRequestDataImpl( - const base::android::JavaRef<jobject>& obj) - : java_object_(obj) { -} - -InterceptedRequestDataImpl::~InterceptedRequestDataImpl() { -} - -scoped_ptr<InputStream> -InterceptedRequestDataImpl::GetInputStream(JNIEnv* env) const { - ScopedJavaLocalRef<jobject> jstream = - Java_InterceptedRequestData_getData(env, java_object_.obj()); - if (jstream.is_null()) - return scoped_ptr<InputStream>(); - return make_scoped_ptr<InputStream>(new InputStreamImpl(jstream)); -} - -bool InterceptedRequestDataImpl::GetMimeType(JNIEnv* env, - std::string* mime_type) const { - ScopedJavaLocalRef<jstring> jstring_mime_type = - Java_InterceptedRequestData_getMimeType(env, java_object_.obj()); - if (jstring_mime_type.is_null()) - return false; - *mime_type = ConvertJavaStringToUTF8(jstring_mime_type); - return true; -} - -bool InterceptedRequestDataImpl::GetCharset( - JNIEnv* env, std::string* charset) const { - ScopedJavaLocalRef<jstring> jstring_charset = - Java_InterceptedRequestData_getCharset(env, java_object_.obj()); - if (jstring_charset.is_null()) - return false; - *charset = ConvertJavaStringToUTF8(jstring_charset); - return true; -} - -bool RegisterInterceptedRequestData(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android_webview diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 48a2a40..3a332ec 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp @@ -70,12 +70,12 @@ 'aw_web_contents_view_delegate.h', 'aw_web_preferences_populater_impl.cc', 'aw_web_preferences_populater_impl.h', + 'aw_web_resource_response_impl.cc', + 'aw_web_resource_response_impl.h', 'cookie_manager.cc', 'cookie_manager.h', 'input_stream_impl.cc', 'input_stream_impl.h', - 'intercepted_request_data_impl.cc', - 'intercepted_request_data_impl.h', 'java_browser_view_renderer_helper.cc', 'java_browser_view_renderer_helper.h', 'net_init_native_callback.cc', @@ -141,8 +141,8 @@ '../java/src/org/chromium/android_webview/AwResource.java', '../java/src/org/chromium/android_webview/AwSettings.java', '../java/src/org/chromium/android_webview/AwWebContentsDelegate.java', + '../java/src/org/chromium/android_webview/AwWebResourceResponse.java', '../java/src/org/chromium/android_webview/ExternalVideoSurfaceContainer.java', - '../java/src/org/chromium/android_webview/InterceptedRequestData.java', '../java/src/org/chromium/android_webview/JavaBrowserViewRendererHelper.java', '../java/src/org/chromium/android_webview/permission/AwPermissionRequest.java', ], diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java b/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java index 85c994b..b4f7a48 100644 --- a/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java +++ b/android_webview/test/shell/src/org/chromium/android_webview/test/NullContentsClient.java @@ -20,7 +20,7 @@ import android.webkit.WebChromeClient; import org.chromium.android_webview.AwContentsClient; import org.chromium.android_webview.AwContentsClientBridge; import org.chromium.android_webview.AwHttpAuthHandler; -import org.chromium.android_webview.InterceptedRequestData; +import org.chromium.android_webview.AwWebResourceResponse; import org.chromium.android_webview.JsPromptResultReceiver; import org.chromium.android_webview.JsResultReceiver; import org.chromium.android_webview.permission.AwPermissionRequest; @@ -66,7 +66,8 @@ public class NullContentsClient extends AwContentsClient { } @Override - public InterceptedRequestData shouldInterceptRequest(String url) { + public AwWebResourceResponse shouldInterceptRequest( + AwContentsClient.ShouldInterceptRequestParams params) { return null; } |