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 5 package org.chromium.content_public.browser; 6 7 import androidx.annotation.Nullable; 8 import androidx.annotation.VisibleForTesting; 9 10 import org.chromium.base.annotations.JNINamespace; 11 import org.chromium.base.annotations.NativeMethods; 12 import org.chromium.content_public.browser.navigation_controller.LoadURLType; 13 import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption; 14 import org.chromium.content_public.common.Referrer; 15 import org.chromium.content_public.common.ResourceRequestBody; 16 import org.chromium.ui.base.PageTransition; 17 import org.chromium.url.Origin; 18 19 import java.util.Locale; 20 import java.util.Map; 21 22 /** 23 * Holds parameters for NavigationController.LoadUrl. Parameters should match 24 * counterparts in NavigationController::LoadURLParams, including default 25 * values. 26 */ 27 @JNINamespace("content") 28 public class LoadUrlParams { 29 // Fields with counterparts in NavigationController::LoadURLParams. 30 // Package private so that NavigationController.loadUrl can pass them down to 31 // native code. Should not be accessed directly anywhere else outside of 32 // this class. 33 String mUrl; 34 Origin mInitiatorOrigin; 35 int mLoadUrlType; 36 int mTransitionType; 37 Referrer mReferrer; 38 private Map<String, String> mExtraHeaders; 39 private String mVerbatimHeaders; 40 int mUaOverrideOption; 41 ResourceRequestBody mPostData; 42 String mBaseUrlForDataUrl; 43 String mVirtualUrlForDataUrl; 44 String mDataUrlAsString; 45 boolean mCanLoadLocalResources; 46 boolean mIsRendererInitiated; 47 boolean mShouldReplaceCurrentEntry; 48 long mIntentReceivedTimestamp; 49 long mInputStartTimestamp; 50 boolean mHasUserGesture; 51 boolean mShouldClearHistoryList; 52 53 /** 54 * Creates an instance with default page transition type. 55 * @param url the url to be loaded 56 */ LoadUrlParams(String url)57 public LoadUrlParams(String url) { 58 this(url, PageTransition.LINK); 59 } 60 61 /** 62 * Creates an instance with the given page transition type. 63 * @param url the url to be loaded 64 * @param transitionType the PageTransitionType constant corresponding to the load 65 */ LoadUrlParams(String url, int transitionType)66 public LoadUrlParams(String url, int transitionType) { 67 mUrl = url; 68 mTransitionType = transitionType; 69 70 // Initialize other fields to defaults matching defaults of the native 71 // NavigationController::LoadUrlParams. 72 mLoadUrlType = LoadURLType.DEFAULT; 73 mUaOverrideOption = UserAgentOverrideOption.INHERIT; 74 mPostData = null; 75 mBaseUrlForDataUrl = null; 76 mVirtualUrlForDataUrl = null; 77 mDataUrlAsString = null; 78 } 79 80 /** 81 * Helper method to create a LoadUrlParams object for data url. 82 * @param data Data to be loaded. 83 * @param mimeType Mime type of the data. 84 * @param isBase64Encoded True if the data is encoded in Base 64 format. 85 */ createLoadDataParams( String data, String mimeType, boolean isBase64Encoded)86 public static LoadUrlParams createLoadDataParams( 87 String data, String mimeType, boolean isBase64Encoded) { 88 return createLoadDataParams(data, mimeType, isBase64Encoded, null); 89 } 90 91 /** 92 * Helper method to create a LoadUrlParams object for data url. 93 * @param data Data to be loaded. 94 * @param mimeType Mime type of the data. 95 * @param isBase64Encoded True if the data is encoded in Base 64 format. 96 * @param charset The character set for the data. Pass null if the mime type 97 * does not require a special charset. 98 */ createLoadDataParams( String data, String mimeType, boolean isBase64Encoded, String charset)99 public static LoadUrlParams createLoadDataParams( 100 String data, String mimeType, boolean isBase64Encoded, String charset) { 101 LoadUrlParams params = new LoadUrlParams( 102 buildDataUri(data, mimeType, isBase64Encoded, charset)); 103 params.setLoadType(LoadURLType.DATA); 104 params.setTransitionType(PageTransition.TYPED); 105 return params; 106 } 107 buildDataUri( String data, String mimeType, boolean isBase64Encoded, String charset)108 private static String buildDataUri( 109 String data, String mimeType, boolean isBase64Encoded, String charset) { 110 StringBuilder dataUrl = new StringBuilder("data:"); 111 dataUrl.append(mimeType); 112 if (charset != null && !charset.isEmpty()) { 113 dataUrl.append(";charset=" + charset); 114 } 115 if (isBase64Encoded) { 116 dataUrl.append(";base64"); 117 } 118 dataUrl.append(","); 119 dataUrl.append(data); 120 return dataUrl.toString(); 121 } 122 123 /** 124 * Helper method to create a LoadUrlParams object for data url with base 125 * and virtual url. 126 * @param data Data to be loaded. 127 * @param mimeType Mime type of the data. 128 * @param isBase64Encoded True if the data is encoded in Base 64 format. 129 * @param baseUrl Base url of this data load. Note that for WebView compatibility, 130 * baseUrl and historyUrl are ignored if this is a data: url. 131 * Defaults to about:blank if null. 132 * @param historyUrl History url for this data load. Note that for WebView compatibility, 133 * this is ignored if baseUrl is a data: url. Defaults to about:blank 134 * if null. 135 */ createLoadDataParamsWithBaseUrl( String data, String mimeType, boolean isBase64Encoded, String baseUrl, String historyUrl)136 public static LoadUrlParams createLoadDataParamsWithBaseUrl( 137 String data, String mimeType, boolean isBase64Encoded, 138 String baseUrl, String historyUrl) { 139 return createLoadDataParamsWithBaseUrl(data, mimeType, isBase64Encoded, 140 baseUrl, historyUrl, null); 141 } 142 143 /** 144 * Helper method to create a LoadUrlParams object for data url with base 145 * and virtual url. 146 * @param data Data to be loaded. 147 * @param mimeType Mime type of the data. 148 * @param isBase64Encoded True if the data is encoded in Base 64 format. 149 * @param baseUrl Base url of this data load. Note that for WebView compatibility, 150 * baseUrl and historyUrl are ignored if this is a data: url. 151 * Defaults to about:blank if null. 152 * @param historyUrl History url for this data load. Note that for WebView compatibility, 153 * this is ignored if baseUrl is a data: url. Defaults to about:blank 154 * if null. 155 * @param charset The character set for the data. Pass null if the mime type 156 * does not require a special charset. 157 */ createLoadDataParamsWithBaseUrl( String data, String mimeType, boolean isBase64Encoded, String baseUrl, String historyUrl, String charset)158 public static LoadUrlParams createLoadDataParamsWithBaseUrl( 159 String data, String mimeType, boolean isBase64Encoded, 160 String baseUrl, String historyUrl, String charset) { 161 LoadUrlParams params; 162 // For WebView compatibility, when the base URL has the 'data:' 163 // scheme, we treat it as a regular data URL load and skip setting 164 // baseUrl and historyUrl. 165 // TODO(joth): we should just append baseURL and historyURL here, and move the 166 // WebView specific transform up to a wrapper factory function in android_webview/. 167 if (baseUrl == null || !baseUrl.toLowerCase(Locale.US).startsWith("data:")) { 168 params = createLoadDataParams("", mimeType, isBase64Encoded, charset); 169 params.setBaseUrlForDataUrl(baseUrl != null ? baseUrl : "about:blank"); 170 params.setVirtualUrlForDataUrl(historyUrl != null ? historyUrl : "about:blank"); 171 params.setDataUrlAsString(buildDataUri(data, mimeType, isBase64Encoded, charset)); 172 } else { 173 params = createLoadDataParams(data, mimeType, isBase64Encoded, charset); 174 } 175 return params; 176 } 177 178 /** 179 * Helper method to create a LoadUrlParams object for an HTTP POST load. 180 * @param url URL of the load. 181 * @param postData Post data of the load. Can be null. 182 */ 183 @VisibleForTesting createLoadHttpPostParams( String url, byte[] postData)184 public static LoadUrlParams createLoadHttpPostParams( 185 String url, byte[] postData) { 186 LoadUrlParams params = new LoadUrlParams(url); 187 params.setLoadType(LoadURLType.HTTP_POST); 188 params.setTransitionType(PageTransition.TYPED); 189 params.setPostData(ResourceRequestBody.createFromBytes(postData)); 190 return params; 191 } 192 193 /** 194 * Sets the url. 195 */ setUrl(String url)196 public void setUrl(String url) { 197 mUrl = url; 198 } 199 200 /** 201 * Return the url. 202 */ getUrl()203 public String getUrl() { 204 return mUrl; 205 } 206 207 /** 208 * Sets the initiator origin. 209 */ setInitiatorOrigin(@ullable Origin initiatorOrigin)210 public void setInitiatorOrigin(@Nullable Origin initiatorOrigin) { 211 mInitiatorOrigin = initiatorOrigin; 212 } 213 214 /** 215 * Return the initiator origin. 216 */ getInitiatorOrigin()217 public @Nullable Origin getInitiatorOrigin() { 218 return mInitiatorOrigin; 219 } 220 221 /** 222 * Return the base url for a data url, otherwise null. 223 */ getBaseUrl()224 public String getBaseUrl() { 225 return mBaseUrlForDataUrl; 226 } 227 228 /** 229 * Set load type of this load. Defaults to LoadURLType.DEFAULT. 230 * @param loadType One of LOAD_TYPE static constants above. 231 */ setLoadType(int loadType)232 public void setLoadType(int loadType) { 233 mLoadUrlType = loadType; 234 } 235 236 /** 237 * Set transition type of this load. Defaults to PageTransition.LINK. 238 * @param transitionType One of PAGE_TRANSITION static constants in ContentView. 239 */ setTransitionType(int transitionType)240 public void setTransitionType(int transitionType) { 241 mTransitionType = transitionType; 242 } 243 244 /** 245 * Return the transition type. 246 */ getTransitionType()247 public int getTransitionType() { 248 return mTransitionType; 249 } 250 251 /** 252 * Sets the referrer of this load. 253 */ setReferrer(Referrer referrer)254 public void setReferrer(Referrer referrer) { 255 mReferrer = referrer; 256 } 257 258 /** 259 * @return the referrer of this load. 260 */ getReferrer()261 public Referrer getReferrer() { 262 return mReferrer; 263 } 264 265 /** 266 * Set extra headers for this load. 267 * @param extraHeaders Extra HTTP headers for this load. Note that these 268 * headers will never overwrite existing ones set by Chromium. 269 */ setExtraHeaders(Map<String, String> extraHeaders)270 public void setExtraHeaders(Map<String, String> extraHeaders) { 271 mExtraHeaders = extraHeaders; 272 } 273 274 /** 275 * Return the extra headers as a map. 276 */ getExtraHeaders()277 public Map<String, String> getExtraHeaders() { 278 return mExtraHeaders; 279 } 280 281 /** 282 * Return the extra headers as a single String separated by "\n", or null if no extra header is 283 * set. This form is suitable for passing to native 284 * NavigationController::LoadUrlParams::extra_headers. This will return the headers set in an 285 * exploded form through setExtraHeaders(). Embedders that work with extra headers in opaque 286 * collapsed form can use the setVerbatimHeaders() / getVerbatimHeaders() instead. 287 */ getExtraHeadersString()288 public String getExtraHeadersString() { 289 return getExtraHeadersString("\n", false); 290 } 291 292 /** 293 * Return the extra headers as a single String separated by "\r\n", or null if no extra header 294 * is set. This form is suitable for passing to native 295 * net::HttpRequestHeaders::AddHeadersFromString. 296 */ getExtraHttpRequestHeadersString()297 public String getExtraHttpRequestHeadersString() { 298 return getExtraHeadersString("\r\n", true); 299 } 300 getExtraHeadersString(String delimiter, boolean addTerminator)301 private String getExtraHeadersString(String delimiter, boolean addTerminator) { 302 if (mExtraHeaders == null) return null; 303 304 StringBuilder headerBuilder = new StringBuilder(); 305 for (Map.Entry<String, String> header : mExtraHeaders.entrySet()) { 306 if (headerBuilder.length() > 0) headerBuilder.append(delimiter); 307 308 // Header name should be lower case. 309 headerBuilder.append(header.getKey().toLowerCase(Locale.US)); 310 headerBuilder.append(":"); 311 headerBuilder.append(header.getValue()); 312 } 313 if (addTerminator) headerBuilder.append(delimiter); 314 315 return headerBuilder.toString(); 316 } 317 318 /** 319 * Sets the verbatim extra headers string. This is an alternative to storing the headers in 320 * a map (setExtraHeaders()) for the embedders that use collapsed headers strings. 321 */ setVerbatimHeaders(String headers)322 public void setVerbatimHeaders(String headers) { 323 mVerbatimHeaders = headers; 324 } 325 326 /** 327 * @return the verbatim extra headers string 328 */ getVerbatimHeaders()329 public String getVerbatimHeaders() { 330 return mVerbatimHeaders; 331 } 332 333 /** 334 * Set user agent override option of this load. Defaults to UserAgentOverrideOption.INHERIT. 335 * @param uaOption One of UA_OVERRIDE static constants above. 336 */ setOverrideUserAgent(int uaOption)337 public void setOverrideUserAgent(int uaOption) { 338 mUaOverrideOption = uaOption; 339 } 340 341 /** 342 * Get user agent override option of this load. Defaults to UserAgentOverrideOption.INHERIT. 343 * @param uaOption One of UA_OVERRIDE static constants above. 344 */ getUserAgentOverrideOption()345 public int getUserAgentOverrideOption() { 346 return mUaOverrideOption; 347 } 348 349 /** 350 * Set the post data of this load. This field is ignored unless load type is 351 * LoadURLType.HTTP_POST. 352 * @param postData Post data for this http post load. 353 */ setPostData(ResourceRequestBody postData)354 public void setPostData(ResourceRequestBody postData) { 355 mPostData = postData; 356 } 357 358 /** 359 * @return the data to be sent through POST 360 */ getPostData()361 public ResourceRequestBody getPostData() { 362 return mPostData; 363 } 364 365 /** 366 * Set the base url for data load. It is used both to resolve relative URLs 367 * and when applying JavaScript's same origin policy. It is ignored unless 368 * load type is LoadURLType.DATA. 369 * @param baseUrl The base url for this data load. 370 */ setBaseUrlForDataUrl(String baseUrl)371 public void setBaseUrlForDataUrl(String baseUrl) { 372 mBaseUrlForDataUrl = baseUrl; 373 } 374 375 /** 376 * Get the virtual url for data load. It is the url displayed to the user. 377 * It is ignored unless load type is LoadURLType.DATA. 378 * @return The virtual url for this data load. 379 */ getVirtualUrlForDataUrl()380 public String getVirtualUrlForDataUrl() { 381 return mVirtualUrlForDataUrl; 382 } 383 384 /** 385 * Set the virtual url for data load. It is the url displayed to the user. 386 * It is ignored unless load type is LoadURLType.DATA. 387 * @param virtualUrl The virtual url for this data load. 388 */ setVirtualUrlForDataUrl(String virtualUrl)389 public void setVirtualUrlForDataUrl(String virtualUrl) { 390 mVirtualUrlForDataUrl = virtualUrl; 391 } 392 393 /** 394 * Get the data for data load. This is then passed to the renderer as 395 * a string, not as a GURL object to circumvent GURL size restriction. 396 * @return The data url. 397 */ getDataUrlAsString()398 public String getDataUrlAsString() { 399 return mDataUrlAsString; 400 } 401 402 /** 403 * Set the data for data load. This is then passed to the renderer as 404 * a string, not as a GURL object to circumvent GURL size restriction. 405 * @param url The data url. 406 */ setDataUrlAsString(String url)407 public void setDataUrlAsString(String url) { 408 mDataUrlAsString = url; 409 } 410 411 /** 412 * Set whether the load should be able to access local resources. This 413 * defaults to false. 414 */ setCanLoadLocalResources(boolean canLoad)415 public void setCanLoadLocalResources(boolean canLoad) { 416 mCanLoadLocalResources = canLoad; 417 } 418 419 /** 420 * Get whether the load should be able to access local resources. This 421 * defaults to false. 422 */ getCanLoadLocalResources()423 public boolean getCanLoadLocalResources() { 424 return mCanLoadLocalResources; 425 } 426 getLoadUrlType()427 public int getLoadUrlType() { 428 return mLoadUrlType; 429 } 430 431 /** 432 * @param rendererInitiated Whether or not this load was initiated from a renderer. 433 */ setIsRendererInitiated(boolean rendererInitiated)434 public void setIsRendererInitiated(boolean rendererInitiated) { 435 mIsRendererInitiated = rendererInitiated; 436 } 437 438 /** 439 * @return Whether or not this load was initiated from a renderer or not. 440 */ getIsRendererInitiated()441 public boolean getIsRendererInitiated() { 442 return mIsRendererInitiated; 443 } 444 445 /** 446 * @param shouldReplaceCurrentEntry Whether this navigation should replace 447 * the current navigation entry. 448 */ setShouldReplaceCurrentEntry(boolean shouldReplaceCurrentEntry)449 public void setShouldReplaceCurrentEntry(boolean shouldReplaceCurrentEntry) { 450 mShouldReplaceCurrentEntry = shouldReplaceCurrentEntry; 451 } 452 453 /** 454 * @return Whether this navigation should replace the current navigation 455 * entry. 456 */ getShouldReplaceCurrentEntry()457 public boolean getShouldReplaceCurrentEntry() { 458 return mShouldReplaceCurrentEntry; 459 } 460 461 /** 462 * @param intentReceivedTimestamp the timestamp at which Chrome received the intent that 463 * triggered this URL load, as returned by System.currentMillis. 464 */ setIntentReceivedTimestamp(long intentReceivedTimestamp)465 public void setIntentReceivedTimestamp(long intentReceivedTimestamp) { 466 mIntentReceivedTimestamp = intentReceivedTimestamp; 467 } 468 469 /** 470 * @return The timestamp at which Chrome received the intent that triggered this URL load. 471 */ getIntentReceivedTimestamp()472 public long getIntentReceivedTimestamp() { 473 return mIntentReceivedTimestamp; 474 } 475 476 /** 477 * @param inputStartTimestamp the timestamp of the event in the location bar that triggered 478 * this URL load, as returned by System.currentMillis. 479 */ setInputStartTimestamp(long inputStartTimestamp)480 public void setInputStartTimestamp(long inputStartTimestamp) { 481 mInputStartTimestamp = inputStartTimestamp; 482 } 483 484 /** 485 * @return The timestamp of the event in the location bar that triggered this URL load. 486 */ getInputStartTimestamp()487 public long getInputStartTimestamp() { 488 return mInputStartTimestamp; 489 } 490 491 /** 492 * Set whether the load is initiated by a user gesture. 493 * 494 * @param hasUserGesture True if load is initiated by user gesture, or false otherwise. 495 */ setHasUserGesture(boolean hasUserGesture)496 public void setHasUserGesture(boolean hasUserGesture) { 497 mHasUserGesture = hasUserGesture; 498 } 499 500 /** 501 * @return Whether or not this load was initiated with a user gesture. 502 */ getHasUserGesture()503 public boolean getHasUserGesture() { 504 return mHasUserGesture; 505 } 506 507 /** Sets whether session history should be cleared once the navigation commits. */ setShouldClearHistoryList(boolean shouldClearHistoryList)508 public void setShouldClearHistoryList(boolean shouldClearHistoryList) { 509 mShouldClearHistoryList = shouldClearHistoryList; 510 } 511 512 /** Returns whether session history should be cleared once the navigation commits. */ getShouldClearHistoryList()513 public boolean getShouldClearHistoryList() { 514 return mShouldClearHistoryList; 515 } 516 isBaseUrlDataScheme()517 public boolean isBaseUrlDataScheme() { 518 // If there's no base url set, but this is a data load then 519 // treat the scheme as data:. 520 if (mBaseUrlForDataUrl == null && mLoadUrlType == LoadURLType.DATA) { 521 return true; 522 } 523 return LoadUrlParamsJni.get().isDataScheme(mBaseUrlForDataUrl); 524 } 525 526 @NativeMethods 527 interface Natives { 528 /** 529 * Parses |url| as a GURL on the native side, and 530 * returns true if it's scheme is data:. 531 */ isDataScheme(String url)532 boolean isDataScheme(String url); 533 } 534 } 535