1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.android_webview.test; 6 7import android.test.suitebuilder.annotation.SmallTest; 8import android.util.Pair; 9 10import org.apache.http.Header; 11import org.apache.http.HttpRequest; 12import org.chromium.android_webview.AwContents; 13import org.chromium.android_webview.AwSettings; 14import org.chromium.android_webview.test.util.CommonResources; 15import org.chromium.android_webview.test.util.JSUtils; 16import org.chromium.base.test.util.Feature; 17import org.chromium.content.browser.test.util.CallbackHelper; 18import org.chromium.content.browser.test.util.HistoryUtils; 19import org.chromium.content_public.browser.LoadUrlParams; 20import org.chromium.net.test.util.TestWebServer; 21 22import java.util.ArrayList; 23import java.util.HashMap; 24import java.util.List; 25import java.util.Locale; 26import java.util.Map; 27import java.util.concurrent.TimeUnit; 28 29/** 30 * Test suite for loadUrl(). 31 */ 32public class LoadUrlTest extends AwTestBase { 33 @SmallTest 34 @Feature({"AndroidWebView"}) 35 public void testDataUrl() throws Throwable { 36 final String expectedTitle = "dataUrlTest"; 37 final String data = 38 "<html><head><title>" + expectedTitle + "</title></head><body>foo</body></html>"; 39 40 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 41 final AwTestContainerView testContainerView = 42 createAwTestContainerViewOnMainSync(contentsClient); 43 final AwContents awContents = testContainerView.getAwContents(); 44 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), data, 45 "text/html", false); 46 assertEquals(expectedTitle, getTitleOnUiThread(awContents)); 47 } 48 49 @SmallTest 50 @Feature({"AndroidWebView"}) 51 public void testDataUrlBase64() throws Throwable { 52 final String expectedTitle = "dataUrlTestBase64"; 53 final String data = "PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48" + 54 "L2hlYWQ+PC9odG1sPg=="; 55 56 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 57 final AwTestContainerView testContainerView = 58 createAwTestContainerViewOnMainSync(contentsClient); 59 final AwContents awContents = testContainerView.getAwContents(); 60 loadDataSync(awContents, contentsClient.getOnPageFinishedHelper(), data, 61 "text/html", true); 62 assertEquals(expectedTitle, getTitleOnUiThread(awContents)); 63 } 64 65 @SmallTest 66 @Feature({"AndroidWebView"}) 67 public void testDataUrlCharset() throws Throwable { 68 // Note that the \u00a3 (pound sterling) is the important character in the following 69 // string as it's not in the US_ASCII character set. 70 final String expectedTitle = "You win \u00a3100!"; 71 final String data = 72 "<html><head><title>" + expectedTitle + "</title></head><body>foo</body></html>"; 73 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 74 final AwTestContainerView testContainerView = 75 createAwTestContainerViewOnMainSync(contentsClient); 76 final AwContents awContents = testContainerView.getAwContents(); 77 loadDataSyncWithCharset(awContents, contentsClient.getOnPageFinishedHelper(), data, 78 "text/html", false, "UTF-8"); 79 assertEquals(expectedTitle, getTitleOnUiThread(awContents)); 80 } 81 82 /** 83 * Loads url on the UI thread and blocks until onPageFinished is called. 84 */ 85 protected void loadUrlWithExtraHeadersSync( 86 final AwContents awContents, 87 CallbackHelper onPageFinishedHelper, 88 final String url, 89 final Map<String, String> extraHeaders) throws Throwable { 90 int currentCallCount = onPageFinishedHelper.getCallCount(); 91 runTestOnUiThread(new Runnable() { 92 @Override 93 public void run() { 94 LoadUrlParams params = new LoadUrlParams(url); 95 params.setExtraHeaders(extraHeaders); 96 awContents.loadUrl(params); 97 } 98 }); 99 onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_MS, 100 TimeUnit.MILLISECONDS); 101 } 102 103 private static List<Pair<String, String>> createHeadersList(String[] namesAndValues) { 104 List<Pair<String, String>> result = new ArrayList<Pair<String, String>>(); 105 for (int i = 0; i < namesAndValues.length; i += 2) 106 result.add(Pair.create(namesAndValues[i], namesAndValues[i + 1])); 107 return result; 108 } 109 110 private static Map<String, String> createHeadersMap(String[] namesAndValues) { 111 Map<String, String> result = new HashMap<String, String>(); 112 for (int i = 0; i < namesAndValues.length; i += 2) 113 result.put(namesAndValues[i], namesAndValues[i + 1]); 114 return result; 115 } 116 117 private void validateRequestHeaders(String[] refNamesAndValues, 118 HttpRequest request) { 119 for (int i = 0; i < refNamesAndValues.length; i += 2) { 120 Header[] matchingHeaders = request.getHeaders(refNamesAndValues[i]); 121 assertEquals(1, matchingHeaders.length); 122 123 Header header = matchingHeaders[0]; 124 assertEquals(refNamesAndValues[i].toLowerCase(Locale.ENGLISH), header.getName()); 125 assertEquals(refNamesAndValues[i + 1], header.getValue()); 126 } 127 } 128 129 private void validateNoRequestHeaders(String[] refNamesAndValues, 130 HttpRequest request) { 131 for (int i = 0; i < refNamesAndValues.length; i += 2) { 132 Header[] matchingHeaders = request.getHeaders(refNamesAndValues[i]); 133 assertEquals(0, matchingHeaders.length); 134 } 135 } 136 137 @SmallTest 138 @Feature({"AndroidWebView"}) 139 public void testLoadUrlWithExtraHeaders() throws Throwable { 140 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 141 final AwTestContainerView testContainerView = 142 createAwTestContainerViewOnMainSync(contentsClient); 143 final AwContents awContents = testContainerView.getAwContents(); 144 145 TestWebServer webServer = null; 146 try { 147 webServer = new TestWebServer(false); 148 final String imagePath = "/" + CommonResources.FAVICON_FILENAME; 149 webServer.setResponseBase64(imagePath, 150 CommonResources.FAVICON_DATA_BASE64, CommonResources.getImagePngHeaders(true)); 151 final String path = "/load_url_with_extra_headers_test.html"; 152 final String url = webServer.setResponse( 153 path, 154 CommonResources.getOnImageLoadedHtml(CommonResources.FAVICON_FILENAME), 155 null); 156 String[] extraHeaders = { 157 "X-ExtraHeaders1", "extra-header-data1", 158 "x-extraHeaders2", "EXTRA-HEADER-DATA2" 159 }; 160 161 loadUrlWithExtraHeadersSync(awContents, 162 contentsClient.getOnPageFinishedHelper(), 163 url, 164 createHeadersMap(extraHeaders)); 165 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 166 // Verify that extra headers are only passed for the main resource. 167 validateNoRequestHeaders(extraHeaders, webServer.getLastRequest(imagePath)); 168 } finally { 169 if (webServer != null) webServer.shutdown(); 170 } 171 } 172 173 @SmallTest 174 @Feature({"AndroidWebView"}) 175 public void testNoOverridingOfExistingHeaders() throws Throwable { 176 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 177 final AwTestContainerView testContainerView = 178 createAwTestContainerViewOnMainSync(contentsClient); 179 final AwContents awContents = testContainerView.getAwContents(); 180 181 TestWebServer webServer = null; 182 try { 183 webServer = new TestWebServer(false); 184 final String path = "/no_overriding_of_existing_headers_test.html"; 185 final String url = webServer.setResponse( 186 path, 187 "<html><body>foo</body></html>", 188 null); 189 String[] extraHeaders = { 190 "user-agent", "007" 191 }; 192 193 loadUrlWithExtraHeadersSync(awContents, 194 contentsClient.getOnPageFinishedHelper(), 195 url, 196 createHeadersMap(extraHeaders)); 197 Header[] matchingHeaders = webServer.getLastRequest(path).getHeaders(extraHeaders[0]); 198 assertEquals(1, matchingHeaders.length); 199 Header header = matchingHeaders[0]; 200 assertEquals(extraHeaders[0].toLowerCase(Locale.ENGLISH), 201 header.getName().toLowerCase(Locale.ENGLISH)); 202 // Just check that the value is there, and it's not the one we provided. 203 assertTrue(header.getValue().length() > 0); 204 assertFalse(extraHeaders[1].equals(header.getValue())); 205 } finally { 206 if (webServer != null) webServer.shutdown(); 207 } 208 } 209 210 @SmallTest 211 @Feature({"AndroidWebView"}) 212 public void testReloadWithExtraHeaders() throws Throwable { 213 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 214 final AwTestContainerView testContainerView = 215 createAwTestContainerViewOnMainSync(contentsClient); 216 final AwContents awContents = testContainerView.getAwContents(); 217 218 TestWebServer webServer = null; 219 try { 220 webServer = new TestWebServer(false); 221 final String path = "/reload_with_extra_headers_test.html"; 222 final String url = webServer.setResponse(path, 223 "<html><body>foo</body></html>", 224 createHeadersList(new String[] { "cache-control", "no-cache, no-store" })); 225 String[] extraHeaders = { 226 "X-ExtraHeaders1", "extra-header-data1", 227 "x-extraHeaders2", "EXTRA-HEADER-DATA2" 228 }; 229 230 loadUrlWithExtraHeadersSync(awContents, 231 contentsClient.getOnPageFinishedHelper(), 232 url, 233 createHeadersMap(extraHeaders)); 234 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 235 236 reloadSync(awContents, contentsClient.getOnPageFinishedHelper()); 237 assertEquals(2, webServer.getRequestCount(path)); 238 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 239 } finally { 240 if (webServer != null) webServer.shutdown(); 241 } 242 } 243 244 @SmallTest 245 @Feature({"AndroidWebView"}) 246 public void testRedirectAndReloadWithExtraHeaders() throws Throwable { 247 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 248 final AwTestContainerView testContainerView = 249 createAwTestContainerViewOnMainSync(contentsClient); 250 final AwContents awContents = testContainerView.getAwContents(); 251 252 TestWebServer webServer = null; 253 try { 254 webServer = new TestWebServer(false); 255 final String path = "/redirect_and_reload_with_extra_headers_test.html"; 256 final String url = webServer.setResponse(path, 257 "<html><body>foo</body></html>", 258 createHeadersList(new String[] { "cache-control", "no-cache, no-store" })); 259 final String redirectedPath = "/redirected.html"; 260 final String redirectedUrl = webServer.setRedirect(redirectedPath, path); 261 String[] extraHeaders = { 262 "X-ExtraHeaders1", "extra-header-data1", 263 "x-extraHeaders2", "EXTRA-HEADER-DATA2" 264 }; 265 266 loadUrlWithExtraHeadersSync(awContents, 267 contentsClient.getOnPageFinishedHelper(), 268 redirectedUrl, 269 createHeadersMap(extraHeaders)); 270 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 271 validateRequestHeaders(extraHeaders, webServer.getLastRequest(redirectedPath)); 272 273 // WebView will only reload the main page. 274 reloadSync(awContents, contentsClient.getOnPageFinishedHelper()); 275 assertEquals(2, webServer.getRequestCount(path)); 276 // No extra headers. This is consistent with legacy behavior. 277 validateNoRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 278 } finally { 279 if (webServer != null) webServer.shutdown(); 280 } 281 } 282 283 @SmallTest 284 @Feature({"AndroidWebView"}) 285 public void testRendererNavigationAndGoBackWithExtraHeaders() throws Throwable { 286 final TestAwContentsClient contentsClient = new TestAwContentsClient(); 287 final AwTestContainerView testContainerView = 288 createAwTestContainerViewOnMainSync(contentsClient); 289 final AwContents awContents = testContainerView.getAwContents(); 290 final AwSettings settings = getAwSettingsOnUiThread(awContents); 291 settings.setJavaScriptEnabled(true); 292 293 TestWebServer webServer = null; 294 try { 295 webServer = new TestWebServer(false); 296 final String nextPath = "/next.html"; 297 final String nextUrl = webServer.setResponse(nextPath, 298 "<html><body>Next!</body></html>", 299 null); 300 final String path = "/renderer_nav_and_go_back_with_extra_headers_test.html"; 301 final String url = webServer.setResponse(path, 302 "<html><body><a id=\"next\" href=\"next.html\">Next!</a></body></html>", 303 createHeadersList(new String[] { "cache-control", "no-cache, no-store" })); 304 String[] extraHeaders = { 305 "X-ExtraHeaders1", "extra-header-data1", 306 "x-extraHeaders2", "EXTRA-HEADER-DATA2" 307 }; 308 309 loadUrlWithExtraHeadersSync(awContents, 310 contentsClient.getOnPageFinishedHelper(), 311 url, 312 createHeadersMap(extraHeaders)); 313 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 314 315 int currentCallCount = contentsClient.getOnPageFinishedHelper().getCallCount(); 316 JSUtils.clickOnLinkUsingJs(this, 317 awContents, 318 contentsClient.getOnEvaluateJavaScriptResultHelper(), 319 "next"); 320 contentsClient.getOnPageFinishedHelper().waitForCallback( 321 currentCallCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 322 // No extra headers for the page navigated via clicking. 323 validateNoRequestHeaders(extraHeaders, webServer.getLastRequest(nextPath)); 324 325 HistoryUtils.goBackSync(getInstrumentation(), 326 awContents.getWebContents(), 327 contentsClient.getOnPageFinishedHelper()); 328 assertEquals(2, webServer.getRequestCount(path)); 329 validateRequestHeaders(extraHeaders, webServer.getLastRequest(path)); 330 } finally { 331 if (webServer != null) webServer.shutdown(); 332 } 333 } 334} 335