gecko-dev/dom/src/base/nsLocation.cpp

820 lines
17 KiB
C++
Raw Normal View History

1998-08-13 04:34:53 +00:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
1998-08-13 04:34:53 +00:00
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
1998-08-13 04:34:53 +00:00
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
1998-08-13 04:34:53 +00:00
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Travis Bogard <travis@netscape.com>
* Pierre Phaneuf <pp@ludusdesign.com>
1998-08-13 04:34:53 +00:00
*/
#include "nsGlobalWindow.h"
#include "nsIWebShell.h"
#include "nsIDocShell.h"
#include "nsIDocShellLoadInfo.h"
#include "nsIWebNavigation.h"
1998-08-13 04:34:53 +00:00
#include "nsIURL.h"
#include "nsIIOService.h"
#include "nsIServiceManager.h"
#include "nsNetUtil.h"
1998-08-13 04:34:53 +00:00
#include "plstr.h"
#include "prprf.h"
1998-08-13 04:34:53 +00:00
#include "prmem.h"
#include "nsCOMPtr.h"
#include "nsJSUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsICodebasePrincipal.h"
#include "nsIDOMWindow.h"
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
#include "nsIJSContextStack.h"
#include "nsXPIDLString.h"
#include "nsDOMError.h"
#include "nsDOMClassInfo.h"
1998-08-13 04:34:53 +00:00
LocationImpl::LocationImpl(nsIDocShell *aDocShell)
1998-08-13 04:34:53 +00:00
{
1999-02-04 19:06:11 +00:00
NS_INIT_REFCNT();
mDocShell = aDocShell; // Weak Reference
1998-08-13 04:34:53 +00:00
}
1998-08-13 04:34:53 +00:00
LocationImpl::~LocationImpl()
{
}
// XPConnect interface list for LocationImpl
NS_CLASSINFO_MAP_BEGIN(Location)
NS_CLASSINFO_MAP_ENTRY(nsIDOMLocation)
NS_CLASSINFO_MAP_ENTRY(nsIDOMNSLocation)
NS_CLASSINFO_MAP_END
1998-08-13 04:34:53 +00:00
// QueryInterface implementation for LocationImpl
NS_INTERFACE_MAP_BEGIN(LocationImpl)
NS_INTERFACE_MAP_ENTRY(nsIDOMNSLocation)
NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocation)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(LocationImpl)
NS_IMPL_RELEASE(LocationImpl)
1998-08-13 04:34:53 +00:00
NS_IMETHODIMP_(void) LocationImpl::SetDocShell(nsIDocShell *aDocShell)
1998-08-13 04:34:53 +00:00
{
mDocShell = aDocShell; // Weak Reference
1998-08-13 04:34:53 +00:00
}
nsresult
LocationImpl::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
{
nsresult result;
// Get JSContext from stack.
nsCOMPtr<nsIJSContextStack>
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
if (NS_FAILED(result))
return NS_ERROR_FAILURE;
JSContext *cx;
if (NS_FAILED(stack->Peek(&cx)))
return NS_ERROR_FAILURE;
// Get security manager.
nsCOMPtr<nsIScriptSecurityManager>
secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &result));
if (NS_FAILED(result))
return NS_ERROR_FAILURE;
// Check to see if URI is allowed.
result = secMan->CheckLoadURIFromScript(cx, aURI);
if (NS_FAILED(result))
return result;
2000-08-11 04:31:08 +00:00
// Create load info
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
// Now get the principal to use when loading the URI
nsCOMPtr<nsIPrincipal> principal;
2000-08-11 04:31:08 +00:00
if (NS_FAILED(secMan->GetSubjectPrincipal(getter_AddRefs(principal))) ||
!principal)
return NS_ERROR_FAILURE;
2000-08-11 04:31:08 +00:00
nsCOMPtr<nsISupports> owner = do_QueryInterface(principal);
loadInfo->SetOwner(owner);
*aLoadInfo = loadInfo.get();
NS_ADDREF(*aLoadInfo);
return NS_OK;
}
nsresult
LocationImpl::SetURL(nsIURI* aURI)
1998-08-13 04:34:53 +00:00
{
if (mDocShell) {
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
return NS_ERROR_FAILURE;
loadInfo->SetStopActiveDocument(PR_TRUE);
return mDocShell->LoadURI(aURI, loadInfo,
nsIWebNavigation::LOAD_FLAGS_NONE);
}
return NS_OK;
1998-08-13 04:34:53 +00:00
}
NS_IMETHODIMP
LocationImpl::GetHash(nsAWritableString& aHash)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
nsXPIDLCString ref;
if (url) {
result = url->GetRef(getter_Copies(ref));
1999-06-23 06:12:02 +00:00
}
if (NS_SUCCEEDED(result) && ref && *ref) {
aHash.Assign(NS_LITERAL_STRING("#"));
aHash.Append(NS_ConvertASCIItoUCS2(ref));
1998-08-13 04:34:53 +00:00
}
else {
aHash.SetLength(0);
}
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetHash(const nsAReadableString& aHash)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (NS_FAILED(result))
return result;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri, &result));
if (url) {
url->SetRef(NS_ConvertUCS2toUTF8(aHash).get());
SetURL(url);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetHost(nsAWritableString& aHost)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsXPIDLCString host;
result = uri->GetHost(getter_Copies(host));
if (NS_SUCCEEDED(result)) {
PRInt32 port;
CopyASCIItoUCS2(nsLiteralCString(host), aHost);
uri->GetPort(&port);
if (port != -1) {
aHost.Append(PRUnichar(':'));
nsAutoString tmpHost;
tmpHost.AppendInt(port);
aHost.Append(tmpHost);
}
1998-08-13 04:34:53 +00:00
}
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetHost(const nsAReadableString& aHost)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
uri->SetHost(NS_ConvertUCS2toUTF8(aHost).get());
SetURL(uri);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetHostname(nsAWritableString& aHostname)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsXPIDLCString host;
result = uri->GetHost(getter_Copies(host));
if (NS_SUCCEEDED(result)) {
CopyASCIItoUCS2(nsLiteralCString(host), aHostname);
}
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetHostname(const nsAReadableString& aHostname)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
uri->SetHost(NS_ConvertUCS2toUTF8(aHostname).get());
SetURL(uri);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetHref(nsAWritableString& aHref)
1998-08-13 04:34:53 +00:00
{
nsresult result = NS_OK;
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
if (webNav) {
nsCOMPtr<nsIURI> uri;
result = webNav->GetCurrentURI(getter_AddRefs(uri));
2000-04-28 06:17:47 +00:00
if (NS_SUCCEEDED(result) && uri) {
nsXPIDLCString uriString;
result = uri->GetSpec(getter_Copies(uriString));
if (NS_SUCCEEDED(result))
CopyASCIItoUCS2(nsLiteralCString(uriString), aHref);
}
1998-08-13 04:34:53 +00:00
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetHref(const nsAReadableString& aHref)
1998-08-13 04:34:53 +00:00
{
nsAutoString oldHref;
nsresult rv = NS_OK;
// Get JSContext from stack.
nsCOMPtr<nsIJSContextStack>
stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
JSContext *cx;
if (NS_FAILED(stack->Peek(&cx)))
return NS_ERROR_FAILURE;
if (cx) {
rv = SetHrefWithContext(cx, aHref);
} else {
rv = GetHref(oldHref);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIURI> oldUri;
rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
if (oldUri) {
rv = SetHrefWithBase(aHref, oldUri, PR_FALSE);
}
}
}
return rv;
}
nsresult
LocationImpl::SetHrefWithContext(JSContext* cx,
const nsAReadableString& aHref)
{
nsCOMPtr<nsIURI> base;
// Get the source of the caller
nsresult result = GetSourceURL(cx, getter_AddRefs(base));
if (NS_FAILED(result)) {
return result;
}
return SetHrefWithBase(aHref, base, PR_FALSE);
}
nsresult
LocationImpl::SetHrefWithBase(const nsAReadableString& aHref,
nsIURI* aBase, PRBool aReplace)
{
nsresult result;
nsCOMPtr<nsIURI> newUri;
1998-08-13 04:34:53 +00:00
result = NS_NewURI(getter_AddRefs(newUri), aHref, aBase);
if (newUri && mDocShell) {
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
nsresult rv = CheckURL(newUri, getter_AddRefs(loadInfo));
if(NS_FAILED(rv))
return rv;
// Check if docshell is currently loading a document.
// If so, this request from JS is probably part of a onload
// handler or a simple script tag with a
// location.href="new location" for redirection.
// In such a case, request a replace load, so that
// the new url will replace the existing url in SH.
// NOTE: this will not be the case if a event handler had a
// location.href in it or a JS timer went off well after
// the current document is loaded. In such cases, we will
// append the new url to SH.
// This solution is tricky. Hopefully it isn't going to bite
// anywhere else. This is part of solution for bug # 39938
PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
mDocShell->GetBusyFlags(&busyFlags);
if (aReplace || (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY)) {
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
}
loadInfo->SetStopActiveDocument(PR_TRUE);
return mDocShell->LoadURI(newUri, loadInfo,
nsIWebNavigation::LOAD_FLAGS_NONE);
}
return result;
1998-08-13 04:34:53 +00:00
}
NS_IMETHODIMP
LocationImpl::GetPathname(nsAWritableString& aPathname)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
aPathname.Truncate();
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if (url) {
nsXPIDLCString file;
result = url->GetFilePath(getter_Copies(file));
if (NS_SUCCEEDED(result)) {
CopyASCIItoUCS2(nsLiteralCString(file), aPathname);
}
}
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetPathname(const nsAReadableString& aPathname)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
uri->SetPath(NS_ConvertUCS2toUTF8(aPathname).get());
SetURL(uri);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetPort(nsAWritableString& aPort)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
1998-08-13 04:34:53 +00:00
aPort.SetLength(0);
PRInt32 port;
uri->GetPort(&port);
1998-08-13 04:34:53 +00:00
if (-1 != port) {
nsAutoString portStr;
portStr.AppendInt(port);
aPort.Append(portStr);
1998-08-13 04:34:53 +00:00
}
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetPort(const nsAReadableString& aPort)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
// perhaps use nsReadingIterators at some point?
NS_ConvertUCS2toUTF8 portStr(aPort);
const char *buf = portStr.get();
1998-08-13 04:34:53 +00:00
PRInt32 port = -1;
if (buf) {
if (*buf == ':') {
port = atol(buf+1);
}
else {
port = atol(buf);
}
}
uri->SetPort(port);
SetURL(uri);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetProtocol(nsAWritableString& aProtocol)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
1998-08-13 04:34:53 +00:00
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsXPIDLCString protocol;
result = uri->GetScheme(getter_Copies(protocol));
if (NS_SUCCEEDED(result)) {
aProtocol.Assign(NS_ConvertASCIItoUCS2(protocol));
aProtocol.Append(PRUnichar(':'));
}
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::SetProtocol(const nsAReadableString& aProtocol)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
uri->SetScheme(NS_ConvertUCS2toUTF8(aProtocol).get());
SetURL(uri);
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::GetSearch(nsAWritableString& aSearch)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsXPIDLCString search;
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
if (url) {
result = url->GetEscapedQuery(getter_Copies(search));
1999-06-23 06:12:02 +00:00
}
if (NS_SUCCEEDED(result) && search && *search) {
aSearch.Assign(NS_LITERAL_STRING("?"));
aSearch.Append(NS_ConvertASCIItoUCS2(search));
1998-08-13 04:34:53 +00:00
}
else {
aSearch.SetLength(0);
}
}
}
return NS_OK;
1998-08-13 04:34:53 +00:00
}
NS_IMETHODIMP
LocationImpl::SetSearch(const nsAReadableString& aSearch)
1998-08-13 04:34:53 +00:00
{
nsAutoString href;
nsresult result = NS_OK;
result = GetHref(href);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> uri;
result = NS_NewURI(getter_AddRefs(uri), href);
if (uri) {
nsCOMPtr<nsIURL> url(do_QueryInterface(uri, &result));
if (url) {
result = url->SetQuery(NS_ConvertUCS2toUTF8(aSearch).get());
SetURL(uri);
1999-06-23 06:12:02 +00:00
}
1998-08-13 04:34:53 +00:00
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::Reload(PRBool aForceget)
1998-08-13 04:34:53 +00:00
{
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell));
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
1998-08-13 04:34:53 +00:00
NS_ENSURE_SUCCESS(webNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE),
NS_ERROR_FAILURE);
1998-08-13 04:34:53 +00:00
return NS_OK;
1998-08-13 04:34:53 +00:00
}
NS_IMETHODIMP
LocationImpl::Reload()
1998-08-13 04:34:53 +00:00
{
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPCNativeCallContext> ncc;
rv = xpc->GetCurrentNativeCallContext(getter_AddRefs(ncc));
NS_ENSURE_SUCCESS(rv, rv);
if (!ncc)
return NS_ERROR_NOT_AVAILABLE;
PRBool force_get = PR_FALSE;
PRUint32 argc;
ncc->GetArgc(&argc);
if (argc > 0) {
jsval *argv = nsnull;
ncc->GetArgvPtr(&argv);
NS_ENSURE_TRUE(argv, NS_ERROR_UNEXPECTED);
JSContext *cx = nsnull;
rv = ncc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JS_ValueToBoolean(cx, argv[0], &force_get);
1998-08-13 04:34:53 +00:00
}
return Reload(force_get);
}
NS_IMETHODIMP
LocationImpl::Replace(const nsAReadableString& aUrl)
{
nsAutoString oldHref;
nsresult result = NS_OK;
result = GetHref(oldHref);
// XXX: Get current context and base URL!!!
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> oldUri;
result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
if (oldUri) {
result = SetHrefWithBase(aUrl, oldUri, PR_TRUE);
}
}
return result;
}
NS_IMETHODIMP
LocationImpl::Assign(const nsAReadableString& aUrl)
{
nsAutoString oldHref;
nsresult result = NS_OK;
result = GetHref(oldHref);
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIURI> oldUri;
result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
if (oldUri) {
result = SetHrefWithBase(aUrl, oldUri, PR_FALSE);
}
}
return result;
1998-08-13 04:34:53 +00:00
}
NS_IMETHODIMP
LocationImpl::ToString(nsAWritableString& aReturn)
{
return GetHref(aReturn);
}
nsresult
LocationImpl::GetSourceURL(JSContext* cx, nsIURI** sourceURI)
{
// XXX Code duplicated from nsHTMLDocument
// XXX Tom said this reminded him of the "Six Degrees of
// Kevin Bacon" game. We try to get from here to there using
// whatever connections possible. The problem is that this
// could break if any of the connections along the way change.
// I wish there were a better way.
nsresult result = NS_ERROR_FAILURE;
// We need to use the dynamically scoped global and assume that the
// current JSContext is a DOM context with a nsIScriptGlobalObject so
// that we can get the url of the caller.
// XXX This will fail on non-DOM contexts :(
nsCOMPtr<nsIScriptGlobalObject> nativeGlob;
nsJSUtils::GetDynamicScriptGlobal(cx, getter_AddRefs(nativeGlob));
if (nativeGlob) {
nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(nativeGlob);
if (window) {
nsCOMPtr<nsIDOMDocument> domDoc;
result = window->GetDocument(getter_AddRefs(domDoc));
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
if (doc) {
result = doc->GetBaseURL(*sourceURI);
if (!*sourceURI) {
*sourceURI = doc->GetDocumentURL();
}
}
}
}
}
return result;
}