blob: aed9884a40657f657bf403dc6ad182f56469760a [file] [log] [blame]
/*
* Copyright (C) 2008, 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "core/frame/Location.h"
#include "bindings/core/v8/BindingSecurity.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/usv_string_or_trusted_url.h"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/trustedtypes/TrustedURL.h"
#include "core/frame/DOMWindow.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h"
#include "core/loader/FrameLoader.h"
#include "core/url/DOMURLUtilsReadOnly.h"
#include "platform/bindings/V8DOMActivityLogger.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SecurityOrigin.h"
namespace blink {
Location::Location(DOMWindow* dom_window) : dom_window_(dom_window) {}
void Location::Trace(blink::Visitor* visitor) {
visitor->Trace(dom_window_);
ScriptWrappable::Trace(visitor);
}
inline const KURL& Location::Url() const {
const KURL& url = GetDocument()->Url();
if (!url.IsValid()) {
// Use "about:blank" while the page is still loading (before we have a
// frame).
return BlankURL();
}
return url;
}
void Location::href(USVStringOrTrustedURL& result) const {
result.SetUSVString(Url().StrippedForUseAsHref());
}
String Location::protocol() const {
return DOMURLUtilsReadOnly::protocol(Url());
}
String Location::host() const {
return DOMURLUtilsReadOnly::host(Url());
}
String Location::hostname() const {
return DOMURLUtilsReadOnly::hostname(Url());
}
String Location::port() const {
return DOMURLUtilsReadOnly::port(Url());
}
String Location::pathname() const {
return DOMURLUtilsReadOnly::pathname(Url());
}
String Location::search() const {
return DOMURLUtilsReadOnly::search(Url());
}
String Location::origin() const {
return DOMURLUtilsReadOnly::origin(Url());
}
DOMStringList* Location::ancestorOrigins() const {
DOMStringList* origins = DOMStringList::Create();
if (!IsAttached())
return origins;
for (Frame* frame = dom_window_->GetFrame()->Tree().Parent(); frame;
frame = frame->Tree().Parent()) {
origins->Append(
frame->GetSecurityContext()->GetSecurityOrigin()->ToString());
}
return origins;
}
String Location::toString() const {
USVStringOrTrustedURL result;
href(result);
DCHECK(result.IsUSVString());
return result.GetAsUSVString();
}
String Location::hash() const {
return DOMURLUtilsReadOnly::hash(Url());
}
void Location::setHref(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const USVStringOrTrustedURL& stringOrUrl,
ExceptionState& exception_state) {
DCHECK(stringOrUrl.IsUSVString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
if (stringOrUrl.IsUSVString() &&
current_window->document()->RequireTrustedTypes()) {
exception_state.ThrowTypeError(
"This document requires `TrustedURL` assignment.");
return;
}
String url = stringOrUrl.IsUSVString()
? stringOrUrl.GetAsUSVString()
: stringOrUrl.GetAsTrustedURL()->toString();
SetLocation(url, current_window, entered_window, &exception_state);
}
void Location::setProtocol(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& protocol,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
if (!url.SetProtocol(protocol)) {
exception_state.ThrowDOMException(
kSyntaxError, "'" + protocol + "' is an invalid protocol.");
return;
}
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setHost(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& host,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetHostAndPort(host);
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setHostname(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& hostname,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetHost(hostname);
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setPort(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& port_string,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetPort(port_string);
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setPathname(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& pathname,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetPath(pathname);
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setSearch(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& search,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
url.SetQuery(search);
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::setHash(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& hash,
ExceptionState& exception_state) {
KURL url = GetDocument()->Url();
String old_fragment_identifier = url.FragmentIdentifier();
String new_fragment_identifier = hash;
if (hash[0] == '#')
new_fragment_identifier = hash.Substring(1);
url.SetFragmentIdentifier(new_fragment_identifier);
// Note that by parsing the URL and *then* comparing fragments, we are
// comparing fragments post-canonicalization, and so this handles the
// cases where fragment identifiers are ignored or invalid.
if (EqualIgnoringNullity(old_fragment_identifier, url.FragmentIdentifier()))
return;
SetLocation(url.GetString(), current_window, entered_window,
&exception_state);
}
void Location::assign(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& url,
ExceptionState& exception_state) {
// TODO(yukishiino): Remove this check once we remove [CrossOrigin] from
// the |assign| DOM operation's definition in Location.idl. See the comment
// in Location.idl for details.
if (!BindingSecurity::ShouldAllowAccessTo(current_window, this,
exception_state)) {
return;
}
SetLocation(url, current_window, entered_window, &exception_state);
}
void Location::replace(LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
const String& url,
ExceptionState& exception_state) {
SetLocation(url, current_window, entered_window, &exception_state,
SetLocationPolicy::kReplaceThisFrame);
}
void Location::reload(LocalDOMWindow* current_window) {
if (!IsAttached())
return;
if (GetDocument()->Url().ProtocolIsJavaScript())
return;
dom_window_->GetFrame()->Reload(kFrameLoadTypeReload,
ClientRedirectPolicy::kClientRedirect);
}
void Location::SetLocation(const String& url,
LocalDOMWindow* current_window,
LocalDOMWindow* entered_window,
ExceptionState* exception_state,
SetLocationPolicy set_location_policy) {
if (!IsAttached())
return;
if (!current_window->GetFrame())
return;
Document* entered_document = entered_window->document();
if (!entered_document)
return;
KURL completed_url = entered_document->CompleteURL(url);
if (completed_url.IsNull())
return;
if (!current_window->GetFrame()->CanNavigate(*dom_window_->GetFrame(),
completed_url)) {
if (exception_state) {
exception_state->ThrowSecurityError(
"The current window does not have permission to navigate the target "
"frame to '" +
url + "'.");
}
return;
}
if (exception_state && !completed_url.IsValid()) {
exception_state->ThrowDOMException(kSyntaxError,
"'" + url + "' is not a valid URL.");
return;
}
if (dom_window_->IsInsecureScriptAccess(*current_window, completed_url))
return;
V8DOMActivityLogger* activity_logger =
V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld();
if (activity_logger) {
Vector<String> argv;
argv.push_back("LocalDOMWindow");
argv.push_back("url");
argv.push_back(entered_document->Url());
argv.push_back(completed_url);
activity_logger->LogEvent("blinkSetAttribute", argv.size(), argv.data());
}
dom_window_->GetFrame()->Navigate(
*current_window->document(), completed_url,
set_location_policy == SetLocationPolicy::kReplaceThisFrame,
UserGestureStatus::kNone);
}
Document* Location::GetDocument() const {
return ToLocalDOMWindow(dom_window_)->document();
}
bool Location::IsAttached() const {
return dom_window_->GetFrame();
}
} // namespace blink