0

Document usage of various URLs for loadDataWithBaseURL navs

There are a lot of URLs involved in loadDataWithBaseURL navigations, and
it's not really clear which URLs are used in various cases. This CL
tries to add more documentation around this, and adds TODOs to resolve
or investigate various potential bugs.

See doc for more details:
https://docs.google.com/document/d/1n_1uJktx-AfavP0IB-RbQ5p5jEolq2_b0VMEXnH5UQQ/edit?ts=60cd4f09#heading=h.kpvauwm3kdab

Bug: 1068965, 1223403
Change-Id: Ic52bd1baa9cfa6039f0392f9c189066649f6af49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2971664
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Richard Coles <torne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#895877}
This commit is contained in:
Rakina Zata Amni
2021-06-25 01:34:23 +00:00
committed by Chromium LUCI CQ
parent a4f1b9c9d5
commit 5d2ef8aa49
8 changed files with 226 additions and 101 deletions

@@ -272,15 +272,8 @@ absl::optional<url::Origin> GetCommittedOriginForFrameEntry(
// URL used for the navigation.
// TODO(https://crbug.com/1198406): Save committed origin in
// FrameNavigationEntry for this case too.
absl::optional<std::string> data_url_as_string;
#if defined(OS_ANDROID)
data_url_as_string = request->commit_params().data_url_as_string;
#endif
if (NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL(
request->IsInMainFrame(), request->common_params(),
data_url_as_string)) {
if (request->IsLoadDataWithBaseURLAndHasUnreachableURL())
return absl::nullopt;
}
return absl::make_optional(params.origin);
}

@@ -801,6 +801,8 @@ NavigationEntryImpl::ConstructCommonNavigationParams(
if (IsViewSourceMode())
download_policy.SetDisallowed(blink::NavigationDownloadType::kViewSource);
// TODO(https://crbug.com/1223394): Stop setting `base_url_for_data_url` and
// `history_url_for_data_url` for subframe history navigations.
return mojom::CommonNavigationParams::New(
dest_url, frame_entry.initiator_origin(), std::move(dest_referrer),
GetTransitionType(), navigation_type, download_policy,

@@ -5349,46 +5349,46 @@ bool NavigationRequest::WasEarlyHintsPreloadLinkHeaderReceived() {
return was_early_hints_preload_link_header_received_;
}
// static
bool NavigationRequest::IsLoadDataWithBaseURL(const GURL& url,
const GURL& base_url) {
return url.SchemeIs(url::kDataScheme) && !base_url.is_empty();
}
// static
bool NavigationRequest::IsLoadDataWithBaseURL(
const mojom::CommonNavigationParams& common_params) {
return IsLoadDataWithBaseURL(common_params.url,
common_params.base_url_for_data_url);
// TODO(https://crbug.com/1223394): This should probably check if the
// navigation is happening on a main frame too, since subframe history
// navigations can have a non-empty `base_url_for_data_url` (since it will use
// the base URL saved in the NavigationEntry).
// TODO(https://crbug.com/1223403): Make this consistent with the other
// LoadDataWithBaseURL checks.
return common_params.url.SchemeIs(url::kDataScheme) &&
!common_params.base_url_for_data_url.is_empty();
}
// static
bool NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL(
bool is_main_frame,
const mojom::CommonNavigationParams& common_params,
const absl::optional<std::string>& data_url_as_string) {
if (!is_main_frame || !IsLoadDataWithBaseURL(common_params))
return false;
bool NavigationRequest::IsLoadDataWithBaseURLAndHasUnreachableURL() {
// On loadDataURLWithBaseURL navigations, `history_url_for_data_url`
// is saved in WebNavigationParams' and DocumentLoader's `unreachable_url` in
// the renderer, unless the navigation is not treated as a loadDataWithBaseURL
// navigation (and instead treated like a normal data: URL navigation).
return IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer() &&
!common_params_->history_url_for_data_url.is_empty();
}
// On main frame loadDataURLWithBaseURL navigations, history_url_for_data_url
// is saved in WebNavigationParams' unreachable_url in the renderer and sent
// back to the browser, unless the base_url is invalid and data_url_as_string
// is not used. See https://crbug.com/522567 and handling of data: URLs in
// RenderFrameImpl::CommitNavigation() for more details.
const bool has_history_url_for_data_url =
!common_params.history_url_for_data_url.is_empty();
const bool has_non_empty_data_url_as_string =
data_url_as_string.has_value() && !data_url_as_string.value().empty();
if (has_history_url_for_data_url) {
// history_url_for_data_url must only be set if we originally set
// base_url_for_data_url or data_url_as_string.
DCHECK(!common_params.base_url_for_data_url.is_empty() ||
has_non_empty_data_url_as_string);
bool NavigationRequest::
IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer() {
// A navigation is treated as a loadDataWithBaseURL if it's a successful main
// frame navigation, and either the supplied base URL is not empty/invalid, or
// `data_url_as_string` is set. See the ShouldLoadDataWithBaseURL() function
// in render_frame_impl.cc for more details.
if (!IsInMainFrame() || DidEncounterError()) {
return false;
}
return (common_params.base_url_for_data_url.is_valid() ||
has_non_empty_data_url_as_string) &&
has_history_url_for_data_url;
absl::optional<std::string> data_url_as_string;
#if defined(OS_ANDROID)
data_url_as_string = commit_params_->data_url_as_string;
#endif
return common_params_->base_url_for_data_url.is_valid() ||
(data_url_as_string.has_value() &&
!data_url_as_string.value().empty());
}
url::Origin NavigationRequest::GetOriginForURLLoaderFactory() {

@@ -744,23 +744,48 @@ class CONTENT_EXPORT NavigationRequest
// Returns the coop status information relevant to the current navigation.
CrossOriginOpenerPolicyStatus& coop_status() { return coop_status_; }
// Returns true if |url| and |base_url| represent a WebView
// loadDataWithBaseUrl navigation.
static bool IsLoadDataWithBaseURL(const GURL& url, const GURL& base_url);
// Returns true if |common_params| represents a WebView loadDataWithBaseUrl
// navigation.
// navigation. Note that this may sometimes return a different result from
// IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer(), as the renderer
// applies additional checks before possibly entering the special
// loadDataWithBaseUrl path tha will try to use the supplied base URL and
// history URL (instead of just using the data: URL like a normal data: URL
// navigation).
// NOTE: To ensure consistency with other browser-side checks that already
// use IsLoadDataWithBaseURL(), prefer to use IsLoadDataWithBaseURL() for now.
// IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer() and
// IsLoadDataWithBaseURLAndHasUnreachableURL() are both currently only used to
// simulate renderer-side calculations. In the future, the plan is to remove
// those two functions and combine all the checks into just one function.
// TODO(rakina): Maybe combine all three functions to
// GetLoadDataWithBaseURLInfo() that will return a struct containing relevant
// information (e.g. "has_unreachable_url", "base_url_used", etc.)
// TODO(https://crbug.com/1223403): Inspect whether current callers for
// IsLoadDataWithBaseURL() should use
// IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer() instead.
static bool IsLoadDataWithBaseURL(
const mojom::CommonNavigationParams& common_params);
// Returns true if the params represent a WebView loadDataWithBaseUrl
// navigation that has a non-empty unreachable URL in the renderer. See
// https://crbug.com/522567 and handling of data: URLs in
// RenderFrameImpl::CommitNavigation() for more details.
static bool IsLoadDataWithBaseURLAndUnreachableURL(
bool is_main_frame,
const mojom::CommonNavigationParams& common_params,
const absl::optional<std::string>& data_url_as_string);
// Returns true if the navigation is treated as a loadDataWithBaseURL
// navigation in the renderer, different than other data: URL navigation.
// In particular, whether the renderer will try to use the supplied base URL
// and history URL as the "document URL" and "history URL", instead of just
// using the data: URL used to commit like it would on normal data: URL
// navigations. Note that this does not say anything about whether the
// supplied base URL & history URL will actually be used (as they can be
// empty/invalid etc), just whether the renderer will go through the special
// path that *tries* to use those URLs.
// NOTE: This function is currently only used for simulating renderer-side
// calculations. Do not use it to make actual decisions. For most cases, the
// IsLoadDataWithBaseURL() function above should be used.
bool IsNavigationTreatedAsLoadDataWithBaseURLInTheRenderer();
// Returns true if the navigation is a WebView loadDataWithBaseUrl
// navigation that has a non-empty "unreachable URL" in the renderer, set to
// the "history URL" supplied with the loadDataWithBaseUrl call.
// NOTE: This function is currently only used for simulating renderer-side
// calculations. Do not use it to make actual decisions.
bool IsLoadDataWithBaseURLAndHasUnreachableURL();
// Will calculate an *approximation* of the origin that this NavigationRequest
// will commit. (An "approximation", because sandboxing is not taken into

@@ -9973,22 +9973,18 @@ void RenderFrameHostImpl::TakeNewDocumentPropertiesFromNavigation(
is_overriding_user_agent_ = navigation_request->is_overriding_user_agent() &&
frame_tree_node_->IsMainFrame();
// Mark whether the document is loaded with loadDataWithBaseURL or not. If
// |is_loaded_from_load_data_with_base_url_| is true, we will bypass checks
// Mark whether then navigation was intended as a loadDataWithBaseURL or not.
// If |is_loaded_from_load_data_with_base_url_| is true, we will bypass checks
// in VerifyDidCommitParams for same-document navigations in the loaded
// document.
// document. Note that the renderer might not have actually gone through the
// special "loadDataWithBaseURL" path that tries to set the base URL and
// history URL with user-supplied URLs even if this is true.
is_loaded_from_load_data_with_base_url_ =
NavigationRequest::IsLoadDataWithBaseURL(
navigation_request->common_params());
absl::optional<std::string> data_url_as_string;
#if defined(OS_ANDROID)
data_url_as_string = navigation_request->commit_params().data_url_as_string;
#endif
is_loaded_from_load_data_with_base_url_and_unreachable_url_ =
NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL(
frame_tree_node_->IsMainFrame(), navigation_request->common_params(),
data_url_as_string);
document_has_unreachable_url_from_load_data_with_base_url_ =
navigation_request->IsLoadDataWithBaseURLAndHasUnreachableURL();
// If we still have a PeakGpuMemoryTracker, then the loading it was observing
// never completed. Cancel it's callback so that we don't report partial
@@ -10642,30 +10638,24 @@ const std::string CalculateMethod(
return nav_request_method;
}
bool CalculateURLIsUnreachable(
NavigationRequest* request,
bool is_error_page,
bool is_loaded_from_load_data_with_base_url_and_unreachable_url) {
bool CalculateURLIsUnreachable(NavigationRequest* request,
bool is_error_page,
bool prev_document_has_unreachable_url) {
// url_is_unreachable should only be true in two cases:
// 1) The navigation is for an error page
if (is_error_page)
return true;
// 2) This is a main frame navigation to a data: URL document with a base_url
// (either an initial load or a same-document navigation).
// and history URL (either an initial load or a same-document navigation).
// For same-document navigations, we can know this by checking the value
// of |is_loaded_from_load_data_with_base_url_and_unreachable_url|, which was
// set when the document was initially loaded.
// of |prev_document_has_unreachable_url|, which was set when the document
// was initially loaded.
if (request->IsSameDocument())
return is_loaded_from_load_data_with_base_url_and_unreachable_url;
return prev_document_has_unreachable_url;
// For cross-document navigations, we can know by checking
// NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL().
absl::optional<std::string> data_url_as_string;
#if defined(OS_ANDROID)
data_url_as_string = request->commit_params().data_url_as_string;
#endif
return NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL(
request->IsInMainFrame(), request->common_params(), data_url_as_string);
// NavigationRequest::IsLoadDataWithBaseURLAndHasUnreachableURL().
return request->IsLoadDataWithBaseURLAndHasUnreachableURL();
}
int CalculateHTTPStatusCode(NavigationRequest* request,
@@ -10864,7 +10854,7 @@ void RenderFrameHostImpl::
const bool browser_url_is_unreachable = CalculateURLIsUnreachable(
request, is_error_page,
is_loaded_from_load_data_with_base_url_and_unreachable_url_);
document_has_unreachable_url_from_load_data_with_base_url_);
const bool is_same_document_navigation = !!same_document_params;
const bool is_same_document_history_api_navigation =
@@ -10931,7 +10921,7 @@ void RenderFrameHostImpl::
is_loaded_from_load_data_with_base_url_);
SCOPED_CRASH_KEY_BOOL(
"VerifyDidCommit", "prev_ldwbu",
is_loaded_from_load_data_with_base_url_and_unreachable_url_);
document_has_unreachable_url_from_load_data_with_base_url_);
SCOPED_CRASH_KEY_BOOL(
"VerifyDidCommit", "base_url_fdu_empty",
request->common_params().base_url_for_data_url.is_empty());

@@ -3514,11 +3514,10 @@ class CONTENT_EXPORT RenderFrameHostImpl
// loadDataWithBaseURL API or not.
bool is_loaded_from_load_data_with_base_url_ = false;
// Whether the currently committed document is a result of webview's
// loadDataWithBaseURL API and the renderer has a non-empty unreachable URL.
// See NavigationRequest::IsLoadDataWithBaseURLAndUnreachableURL for more
// details.
bool is_loaded_from_load_data_with_base_url_and_unreachable_url_ = false;
// Whether the current document has a non-empty "unreachable URL" as a result
// of a loadDataWithBaseURL navigation. For more details, see
// NavigationRequest::IsLoadDataWithBaseURLAndHasUnreachableURL().
bool document_has_unreachable_url_from_load_data_with_base_url_ = false;
// The last reported character encoding, not canonicalized.
std::string last_reported_encoding_;

@@ -36,6 +36,12 @@ class CONTENT_EXPORT DocumentState : public blink::WebDocumentLoader::ExtraData,
// is set to true and |data_url_| is set to the data URL of the navigation.
// Otherwise, |was_load_data_with_base_url_request_| is false and |data_url_|
// is empty.
// NOTE: This does not actually cover all cases of LoadDataWithBaseURL
// navigations, see comments in render_frame_impl.cc's
// ShouldLoadDataWithBaseURL() and BuildDocumentStateFromParams() for more
// details. Prefer calling ShouldLoadDataWithBaseURL() instead of this method.
// TODO(https://crbug.com/1223403, https://crbug.com/1223408): Make this
// consistent with the other LoadDataWithBaseURL checks.
void set_was_load_data_with_base_url_request(bool value) {
was_load_data_with_base_url_request_ = value;
}

@@ -378,17 +378,28 @@ bool MaybeGetOverriddenURL(WebDocumentLoader* document_loader, GURL* output) {
DocumentState* document_state =
DocumentState::FromDocumentLoader(document_loader);
// If load was from a data URL, then the saved data URL, not the history
// URL, should be the URL of the data source.
// If this document is loaded by a loadDataWithBaseURL request, then the URLs
// saved in the DocumentLoader will be the user-supplied base URL (used as the
// "document URL") and history URL (used as the "unreachable URL"/"URL for
// history"). However, we want to return the data: URL (the URL originally
// sent by the browser to commit the navigation) here.
// TODO(https://crbug.com/1223408): Since the DocumentState stays as long as
// the Document stays the same, this means the data: URL will be returned even
// after same-document navigations. Investigate whether this is intended or
// not.
if (document_state->was_load_data_with_base_url_request()) {
*output = document_state->data_url();
return true;
}
// WebDocumentLoader has unreachable URL means that the frame is loaded
// through blink::WebFrame::loadData(), and the base URL will be in the
// redirect chain. However, we never visited the baseURL. So in this case, we
// should use the unreachable URL as the original URL.
// The "unreachable URL" is only set in two cases:
// - An error page, where the "unreachable URL" is set to the URL that failed
// to load. We want the URL bar to show that URL, and the session history
// entry should also use that URL (instead of "chrome-error://chromewebdata"
// which is used as the "document URL" for the DocumentLoader).
// - A loadDataWithBaseURL, where the "unreachable URL" is set to the "history
// URL". This case should never reach this point as it's handled above, where
// we return the original data: URL instead.
if (document_loader->HasUnreachableURL()) {
*output = document_loader->UnreachableURL();
return true;
@@ -833,6 +844,31 @@ mojo::PendingRemote<blink::mojom::BlobURLToken> CloneBlobURLToken(
return cloned_token;
}
// Whether the navigation should be treated as a "loadDataWithBaseURL"
// navigation, where the "document URL" is set to the supplied base URL instead
// of the data URL set in CommonNavigationParams' `url` and the "unreachable
// URL" is set to the supplied history URL. If this returns false, the data:
// URL will still be loaded, but we won't try to use the supplied base URL and
// history URL.
bool ShouldLoadDataWithBaseURL(
bool is_main_frame,
const mojom::CommonNavigationParams& common_params,
const mojom::CommitNavigationParams& commit_params) {
if (!is_main_frame)
return false;
// If no base URL is supplied, we should treat this as a normal data: URL
// navigation, except when `data_url_as_string` should be used, as the `url`
// in CommonNavigationParams will just contain the data header with no actual
// data, and the `data_url_as_string` code is only available in the
// loadDataWithBaseURL path.
bool should_load_data_url = !common_params.base_url_for_data_url.is_empty();
#if defined(OS_ANDROID)
should_load_data_url |= !commit_params.data_url_as_string.empty();
#endif
DCHECK(!should_load_data_url || common_params.url.SchemeIs(url::kDataScheme));
return should_load_data_url;
}
// Creates a fully functional DocumentState in the case where we do not have
// navigation parameters available.
std::unique_ptr<DocumentState> BuildDocumentState() {
@@ -866,6 +902,16 @@ std::unique_ptr<DocumentState> BuildDocumentStateFromParams(
mojom::NavigationType::RELOAD_ORIGINAL_REQUEST_URL);
internal_data->set_request_id(request_id);
// If this is a loadDataWithBaseURL request, save the commit URL so that we
// can send a DidCommit message with the URL that was originally sent by the
// browser in CommonNavigationParams (See MaybeGetOverriddenURL()).
// Note that this is not calling ShouldLoadDataWithBaseURL() to preserve
// pre-existing behavior, where we would only return the data: URL with the
// DidCommitProvisionalLoadParams under this specific condition (in other
// cases we will return the DocumentLoader's URL - which will use the base URL
// if it's not empty).
// TODO(https://crbug.com/1223403, https://crbug.com/1223408): Make this
// consistent with the other LoadDataWithBaseURL checks.
bool load_data = !common_params.base_url_for_data_url.is_empty() &&
!common_params.history_url_for_data_url.is_empty() &&
common_params.url.SchemeIs(url::kDataScheme);
@@ -2625,22 +2671,50 @@ void RenderFrameImpl::CommitNavigation(
std::move(controller_service_worker_info), std::move(container_info),
std::move(prefetch_loader_factory), std::move(document_state));
// Perform a navigation to a data url if needed (for main frames).
// Note: the base URL might be invalid, so also check the data URL string.
bool should_load_data_url = !common_params->base_url_for_data_url.is_empty();
#if defined(OS_ANDROID)
should_load_data_url |= !commit_params->data_url_as_string.empty();
#endif
if (is_main_frame_ && should_load_data_url) {
// Perform a "loadDataWithBaseURL" navigation. This is different from a normal
// data: URL navigation in various ways:
// - The "document URL" will use the supplied `base_url_for_data_url` if it's
// not empty (otherwise it will fall back to the data: URL).
// - The "unreachable URL" (used for HistoryItem, etc) will use the supplied
// `history_url_for_data_url` if it's not empty (otherwise it will fall back
// to the document URL).
// - The actual data: URL will be saved in the document's DocumentState to
// later be returned as the `url` in DidCommitProvisionalLoadParams.
if (ShouldLoadDataWithBaseURL(is_main_frame_, *common_params,
*commit_params)) {
std::string mime_type, charset, data;
// `base_url` will be set to `base_url_for_data_url` from `common_params`,
// unless it's empty, in which case `url` from `common_params` will be used.
GURL base_url;
DecodeDataURL(*common_params, *commit_params, &mime_type, &charset, &data,
&base_url);
// Note that even though we use the term "base URL", `base_url` is also
// used as the "document URL" (unlike normal "base URL"s set through the
// <base> element or other means, which would only be used to resolve
// relative URLs, etc).
navigation_params->url = base_url;
WebNavigationParams::FillStaticResponse(navigation_params.get(),
WebString::FromUTF8(mime_type),
WebString::FromUTF8(charset), data);
// Needed so that history-url-only changes don't become reloads.
// Even though this is a successful navigation, we set the "unreachable URL"
// to the value of the supplied "history URL". This value will be used for:
// - Setting the HistoryItem URL in
// DocumentLoader::SetHistoryItemStateForCommit(). Note that this is *not*
// used for setting the session history entry's URL in the browser side.
// - Determining whether various states (scroll state, document.state) from
// the previous HistoryItem should be carried over.
// - Determining whether a navigation is a same-URL navigation, and thus
// should result in replacement, in FrameLoader::DetermineFrameLoadType().
// Note that the code there compares the new *document URL* against the old
// *history URL* so if the base URL and the history URL is different, even
// if the loadDataWithBaseURL() navigation is triggered with the exact same
// parameters twice, it will not be classified as "same-URL". This seems to
// be unintended, but the old comment here says this is "Needed so that
// history-url-only changes don't become reloads" so at least it works to
// prevent reloads/replacements when the history URL changes but not
// everything else.
// TODO(https://crbug.com/1223398): Figure out if these behaviors should be
// kept, or even if we should send the history URL to the renderer at all.
navigation_params->unreachable_url =
common_params->history_url_for_data_url;
std::move(commit_with_params).Run(std::move(navigation_params));
@@ -2911,6 +2985,8 @@ void RenderFrameImpl::CommitFailedNavigation(
auto navigation_params = std::make_unique<WebNavigationParams>();
FillNavigationParamsRequest(*common_params, *commit_params,
navigation_params.get());
// Use kUnreachableWebDataURL as the document URL (instead of the URL that
// failed to load, which is saved separately as the "unreachable URL" below).
navigation_params->url = GURL(kUnreachableWebDataURL);
// FillNavigationParamsRequest() sets the |navigation_params->http_method| to
// the original method of the request. In successful page loads,
@@ -2982,6 +3058,11 @@ void RenderFrameImpl::CommitFailedNavigation(
navigation_params.get());
WebNavigationParams::FillStaticResponse(navigation_params.get(), "text/html",
"UTF-8", error_html);
// Save the URL that failed to load as the "unreachable URL" so that the
// we can use that (instead of kUnreachableWebDataURL) for the HistoryItem for
// this navigation, and also to send back with the DidCommitProvisionalLoad
// message to the browser.
// TODO(https://crbug.com/1131832): Stop sending the URL back with DidCommit.
navigation_params->unreachable_url = error.url();
if (commit_params->redirects.size()) {
navigation_params->pre_redirect_url_for_failed_navigations =
@@ -4544,7 +4625,12 @@ RenderFrameImpl::MakeDidCommitProvisionalLoadParams(
params->has_potentially_trustworthy_unique_origin =
frame_origin.IsOpaque() && frame_origin.IsPotentiallyTrustworthy();
// Set the URL to be displayed in the browser UI to the user.
// Set the URL to be displayed in the browser UI to the user. Note this might
// be different than the URL actually used in the DocumentLoader (see comments
// in GetLoadingUrl() and MaybeGetOverriddenURL()). This might not be the URL
// actually shown to the user as well, since the browser has additional logic
// for virtual URLs (e.g. the "history URL" is shown for loadDataWithBaseURL
// instead of this URL).
params->url = GetLoadingUrl();
// TODO(https://crbug.com/1158101): Reconsider how we calculate
@@ -5686,13 +5772,27 @@ void RenderFrameImpl::DecodeDataURL(
DCHECK(data_tmp.empty());
}
#endif
// If `data_url_as_string` is set, the `url` in CommonNavigationParams will
// only contain the data: URL header and won't contain any actual data (see
// NavigationControllerAndroid::LoadUrl()), so we should use
// `data_url_as_string` if possible.
data_url = GURL(commit_params.data_url_as_string);
if (!data_url.is_valid() || !data_url.SchemeIs(url::kDataScheme)) {
// If the given data URL is invalid, use the data: URL header as a
// fallback.
data_url = common_params.url;
}
}
#endif
// Parse the given data, then set the `base_url`, which is used as the
// document URL.
if (net::DataURL::Parse(data_url, mime_type, charset, data)) {
// Since the base URL will also be used as the document URL, we should not
// use an empty URL. If it's empty, use the data: URL as a fallback.
// TODO(https://crbug.com/1223403): Maybe this should consider
// `data_url_as_string` too. Otherwise, the base URL might be set to the
// data: URL header with empty data, instead of the data: URL that contains
// the actual data.
*base_url = common_params.base_url_for_data_url.is_empty()
? common_params.url
: common_params.base_url_for_data_url;
@@ -5716,6 +5816,16 @@ blink::WebURL RenderFrameImpl::LastCommittedUrlForUKM() {
return GetLoadingUrl();
}
// Returns the "loading URL", which might be different than the "document URL"
// used in the DocumentLoader in some cases:
// - For error pages, it will return the URL that failed to load, instead of the
// chrome-error:// URL used as the document URL in the DocumentLoader.
// - For some loadDataWithBaseURL() navigations, it will return the data: URL
// used to commit, instead of the "base URL" used as the document URL in the
// DocumentLoader. Note that this does not cover all loadDataWithBaseURL()
// navigations, the rest will just return the document/base URL. See comments in
// BuildDocumentStateFromParams() and ShouldLoadDataWithBaseURL() for more
// details.
GURL RenderFrameImpl::GetLoadingUrl() const {
WebDocumentLoader* document_loader = frame_->GetDocumentLoader();