Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / dom / base / nsLocation.cpp
blob86510c82e875c497b4329d1fca8c4d65bf740365
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=80: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Travis Bogard <travis@netscape.com>
25 * Pierre Phaneuf <pp@ludusdesign.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsGlobalWindow.h"
42 #include "nsIScriptSecurityManager.h"
43 #include "nsIScriptContext.h"
44 #include "nsIDocShell.h"
45 #include "nsIDocShellLoadInfo.h"
46 #include "nsIWebNavigation.h"
47 #include "nsCDefaultURIFixup.h"
48 #include "nsIURIFixup.h"
49 #include "nsIURL.h"
50 #include "nsIJARURI.h"
51 #include "nsIIOService.h"
52 #include "nsIServiceManager.h"
53 #include "nsNetUtil.h"
54 #include "plstr.h"
55 #include "prprf.h"
56 #include "prmem.h"
57 #include "nsCOMPtr.h"
58 #include "nsEscape.h"
59 #include "nsJSUtils.h"
60 #include "nsIDOMWindow.h"
61 #include "nsIDOMDocument.h"
62 #include "nsIDocument.h"
63 #include "nsIPresShell.h"
64 #include "nsPresContext.h"
65 #include "nsIJSContextStack.h"
66 #include "nsXPIDLString.h"
67 #include "nsDOMError.h"
68 #include "nsDOMClassInfo.h"
69 #include "nsCRT.h"
70 #include "nsIProtocolHandler.h"
71 #include "nsReadableUtils.h"
72 #include "nsITextToSubURI.h"
73 #include "nsContentUtils.h"
74 #include "nsJSUtils.h"
76 static nsresult
77 GetContextFromStack(nsIJSContextStack *aStack, JSContext **aContext)
79 nsCOMPtr<nsIJSContextStackIterator>
80 iterator(do_CreateInstance("@mozilla.org/js/xpc/ContextStackIterator;1"));
81 NS_ENSURE_TRUE(iterator, NS_ERROR_FAILURE);
83 nsresult rv = iterator->Reset(aStack);
84 NS_ENSURE_SUCCESS(rv, rv);
86 PRBool done;
87 while (NS_SUCCEEDED(iterator->Done(&done)) && !done) {
88 rv = iterator->Prev(aContext);
89 NS_ASSERTION(NS_SUCCEEDED(rv), "Broken iterator implementation");
91 // Consider a null context the end of the line.
92 if (!*aContext) {
93 break;
96 if (nsJSUtils::GetDynamicScriptContext(*aContext)) {
97 return NS_OK;
101 *aContext = nsnull;
103 return NS_OK;
106 static nsresult
107 GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
109 aCharset.Truncate();
111 nsresult rv;
113 nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
114 NS_ENSURE_SUCCESS(rv, rv);
116 JSContext *cx;
118 rv = GetContextFromStack(stack, &cx);
119 NS_ENSURE_SUCCESS(rv, rv);
121 if (cx) {
122 nsCOMPtr<nsIDOMWindow> window =
123 do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
124 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
126 nsCOMPtr<nsIDOMDocument> domDoc;
127 rv = window->GetDocument(getter_AddRefs(domDoc));
128 NS_ENSURE_SUCCESS(rv, rv);
130 nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
132 if (doc) {
133 aCharset = doc->GetDocumentCharacterSet();
137 return NS_OK;
140 nsLocation::nsLocation(nsIDocShell *aDocShell)
142 mDocShell = do_GetWeakReference(aDocShell);
145 nsLocation::~nsLocation()
149 DOMCI_DATA(Location, nsLocation)
151 // QueryInterface implementation for nsLocation
152 NS_INTERFACE_MAP_BEGIN(nsLocation)
153 NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
154 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocation)
155 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
156 NS_INTERFACE_MAP_END
159 NS_IMPL_ADDREF(nsLocation)
160 NS_IMPL_RELEASE(nsLocation)
162 void
163 nsLocation::SetDocShell(nsIDocShell *aDocShell)
165 mDocShell = do_GetWeakReference(aDocShell);
168 nsIDocShell *
169 nsLocation::GetDocShell()
171 nsCOMPtr<nsIDocShell> docshell(do_QueryReferent(mDocShell));
172 return docshell;
175 // Try to get the the document corresponding to the given JSStackFrame.
176 static already_AddRefed<nsIDocument>
177 GetFrameDocument(JSContext *cx, JSStackFrame *fp)
179 if (!cx || !fp)
180 return nsnull;
182 JSObject* scope = JS_GetFrameScopeChain(cx, fp);
183 if (!scope)
184 return nsnull;
186 JSAutoEnterCompartment ac;
187 if (!ac.enter(cx, scope))
188 return nsnull;
190 nsCOMPtr<nsIDOMWindow> window =
191 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, scope));
192 if (!window)
193 return nsnull;
195 // If it's a window, get its document.
196 nsCOMPtr<nsIDOMDocument> domDoc;
197 window->GetDocument(getter_AddRefs(domDoc));
198 nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
199 return doc.forget();
202 nsresult
203 nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
205 *aLoadInfo = nsnull;
207 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
208 NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
210 nsresult rv;
211 // Get JSContext from stack.
212 nsCOMPtr<nsIJSContextStack>
213 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
214 NS_ENSURE_SUCCESS(rv, rv);
216 JSContext *cx;
218 NS_ENSURE_SUCCESS(GetContextFromStack(stack, &cx), NS_ERROR_FAILURE);
220 nsCOMPtr<nsISupports> owner;
221 nsCOMPtr<nsIURI> sourceURI;
223 if (cx) {
224 // No cx means that there's no JS running, or at least no JS that
225 // was run through code that properly pushed a context onto the
226 // context stack (as all code that runs JS off of web pages
227 // does). We won't bother with security checks in this case, but
228 // we need to create the loadinfo etc.
230 // Get security manager.
231 nsCOMPtr<nsIScriptSecurityManager>
232 secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
233 NS_ENSURE_SUCCESS(rv, rv);
235 // Check to see if URI is allowed.
236 rv = secMan->CheckLoadURIFromScript(cx, aURI);
237 NS_ENSURE_SUCCESS(rv, rv);
239 // Now get the principal to use when loading the URI
240 // First, get the principal and frame.
241 JSStackFrame *fp;
242 nsIPrincipal* principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp);
243 NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
245 nsCOMPtr<nsIURI> principalURI;
246 principal->GetURI(getter_AddRefs(principalURI));
248 // Make the load's referrer reflect changes to the document's URI caused by
249 // push/replaceState, if possible. First, get the document corresponding to
250 // fp. If the document's original URI (i.e. its URI before
251 // push/replaceState) matches the principal's URI, use the document's
252 // current URI as the referrer. If they don't match, use the principal's
253 // URI.
255 nsCOMPtr<nsIDocument> frameDoc = GetFrameDocument(cx, fp);
256 nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI;
257 if (frameDoc) {
258 docOriginalURI = frameDoc->GetOriginalURI();
259 docCurrentURI = frameDoc->GetDocumentURI();
262 PRBool urisEqual = PR_FALSE;
263 if (docOriginalURI && docCurrentURI && principalURI) {
264 principalURI->Equals(docOriginalURI, &urisEqual);
267 if (urisEqual) {
268 sourceURI = docCurrentURI;
270 else {
271 sourceURI = principalURI;
274 owner = do_QueryInterface(principal);
277 // Create load info
278 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
279 docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
280 NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
282 loadInfo->SetOwner(owner);
284 if (sourceURI) {
285 loadInfo->SetReferrer(sourceURI);
288 loadInfo.swap(*aLoadInfo);
290 return NS_OK;
293 nsresult
294 nsLocation::GetURI(nsIURI** aURI, PRBool aGetInnermostURI)
296 *aURI = nsnull;
298 nsresult rv;
299 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
300 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
301 if (NS_FAILED(rv)) {
302 return rv;
305 nsCOMPtr<nsIURI> uri;
306 rv = webNav->GetCurrentURI(getter_AddRefs(uri));
307 NS_ENSURE_SUCCESS(rv, rv);
309 // It is valid for docshell to return a null URI. Don't try to fixup
310 // if this happens.
311 if (!uri) {
312 return NS_OK;
315 if (aGetInnermostURI) {
316 nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
317 while (jarURI) {
318 jarURI->GetJARFile(getter_AddRefs(uri));
319 jarURI = do_QueryInterface(uri);
323 NS_ASSERTION(uri, "nsJARURI screwed up?");
325 nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
326 NS_ENSURE_SUCCESS(rv, rv);
328 return urifixup->CreateExposableURI(uri, aURI);
331 nsresult
332 nsLocation::GetWritableURI(nsIURI** aURI)
334 *aURI = nsnull;
336 nsCOMPtr<nsIURI> uri;
338 nsresult rv = GetURI(getter_AddRefs(uri));
339 if (NS_FAILED(rv) || !uri) {
340 return rv;
343 return uri->Clone(aURI);
346 nsresult
347 nsLocation::SetURI(nsIURI* aURI, PRBool aReplace)
349 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
350 if (docShell) {
351 nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
352 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
354 if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
355 return NS_ERROR_FAILURE;
357 if (aReplace) {
358 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
359 } else {
360 loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
363 return docShell->LoadURI(aURI, loadInfo,
364 nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
367 return NS_OK;
370 NS_IMETHODIMP
371 nsLocation::GetHash(nsAString& aHash)
373 aHash.SetLength(0);
375 nsCOMPtr<nsIURI> uri;
376 nsresult rv = GetURI(getter_AddRefs(uri));
378 nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
380 if (url) {
381 nsCAutoString ref;
382 nsAutoString unicodeRef;
384 rv = url->GetRef(ref);
385 if (NS_SUCCEEDED(rv)) {
386 nsCOMPtr<nsITextToSubURI> textToSubURI(
387 do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
389 if (NS_SUCCEEDED(rv)) {
390 nsCAutoString charset;
391 url->GetOriginCharset(charset);
393 rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
396 if (NS_FAILED(rv)) {
397 // Oh, well. No intl here!
398 NS_UnescapeURL(ref);
399 CopyASCIItoUTF16(ref, unicodeRef);
400 rv = NS_OK;
404 if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
405 aHash.Assign(PRUnichar('#'));
406 aHash.Append(unicodeRef);
410 return rv;
413 NS_IMETHODIMP
414 nsLocation::SetHash(const nsAString& aHash)
416 nsCOMPtr<nsIURI> uri;
417 nsresult rv = GetWritableURI(getter_AddRefs(uri));
419 nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
420 if (url) {
421 NS_ConvertUTF16toUTF8 hash(aHash);
422 if (hash.IsEmpty() || hash.First() != PRUnichar('#')) {
423 hash.Insert(PRUnichar('#'), 0);
425 rv = url->SetRef(hash);
426 if (NS_SUCCEEDED(rv)) {
427 SetURI(url);
431 return rv;
434 NS_IMETHODIMP
435 nsLocation::GetHost(nsAString& aHost)
437 aHost.Truncate();
439 nsCOMPtr<nsIURI> uri;
440 nsresult result;
442 result = GetURI(getter_AddRefs(uri), PR_TRUE);
444 if (uri) {
445 nsCAutoString hostport;
447 result = uri->GetHostPort(hostport);
449 if (NS_SUCCEEDED(result)) {
450 AppendUTF8toUTF16(hostport, aHost);
454 return NS_OK;
457 NS_IMETHODIMP
458 nsLocation::SetHost(const nsAString& aHost)
460 nsCOMPtr<nsIURI> uri;
461 nsresult rv = GetWritableURI(getter_AddRefs(uri));
463 if (uri) {
464 rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
465 if (NS_SUCCEEDED(rv)) {
466 SetURI(uri);
470 return rv;
473 NS_IMETHODIMP
474 nsLocation::GetHostname(nsAString& aHostname)
476 aHostname.Truncate();
478 nsCOMPtr<nsIURI> uri;
479 nsresult result;
481 result = GetURI(getter_AddRefs(uri), PR_TRUE);
483 if (uri) {
484 nsCAutoString host;
486 result = uri->GetHost(host);
488 if (NS_SUCCEEDED(result)) {
489 AppendUTF8toUTF16(host, aHostname);
493 return NS_OK;
496 NS_IMETHODIMP
497 nsLocation::SetHostname(const nsAString& aHostname)
499 nsCOMPtr<nsIURI> uri;
500 nsresult rv = GetWritableURI(getter_AddRefs(uri));
502 if (uri) {
503 rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
504 if (NS_SUCCEEDED(rv)) {
505 SetURI(uri);
509 return rv;
512 NS_IMETHODIMP
513 nsLocation::GetHref(nsAString& aHref)
515 aHref.Truncate();
517 nsCOMPtr<nsIURI> uri;
518 nsresult result;
520 result = GetURI(getter_AddRefs(uri));
522 if (uri) {
523 nsCAutoString uriString;
525 result = uri->GetSpec(uriString);
527 if (NS_SUCCEEDED(result)) {
528 AppendUTF8toUTF16(uriString, aHref);
532 return result;
535 NS_IMETHODIMP
536 nsLocation::SetHref(const nsAString& aHref)
538 nsAutoString oldHref;
539 nsresult rv = NS_OK;
541 // Get JSContext from stack.
542 nsCOMPtr<nsIJSContextStack>
543 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
545 if (NS_FAILED(rv))
546 return NS_ERROR_FAILURE;
548 JSContext *cx;
550 if (NS_FAILED(GetContextFromStack(stack, &cx)))
551 return NS_ERROR_FAILURE;
553 if (cx) {
554 rv = SetHrefWithContext(cx, aHref, PR_FALSE);
555 } else {
556 rv = GetHref(oldHref);
558 if (NS_SUCCEEDED(rv)) {
559 nsCOMPtr<nsIURI> oldUri;
561 rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
563 if (oldUri) {
564 rv = SetHrefWithBase(aHref, oldUri, PR_FALSE);
569 return rv;
572 nsresult
573 nsLocation::SetHrefWithContext(JSContext* cx, const nsAString& aHref,
574 PRBool aReplace)
576 nsCOMPtr<nsIURI> base;
578 // Get the source of the caller
579 nsresult result = GetSourceBaseURL(cx, getter_AddRefs(base));
581 if (NS_FAILED(result)) {
582 return result;
585 return SetHrefWithBase(aHref, base, aReplace);
588 nsresult
589 nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
590 PRBool aReplace)
592 nsresult result;
593 nsCOMPtr<nsIURI> newUri;
595 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
597 nsCAutoString docCharset;
598 if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
599 result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), aBase);
600 else
601 result = NS_NewURI(getter_AddRefs(newUri), aHref, nsnull, aBase);
603 if (newUri) {
604 /* Check with the scriptContext if it is currently processing a script tag.
605 * If so, this must be a <script> tag with a location.href in it.
606 * we want to do a replace load, in such a situation.
607 * In other cases, for example if a event handler or a JS timer
608 * had a location.href in it, we want to do a normal load,
609 * so that the new url will be appended to Session History.
610 * This solution is tricky. Hopefully it isn't going to bite
611 * anywhere else. This is part of solution for bug # 39938, 72197
614 PRBool inScriptTag=PR_FALSE;
615 // Get JSContext from stack.
616 nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
618 if (stack) {
619 JSContext *cx;
621 result = GetContextFromStack(stack, &cx);
622 if (cx) {
623 nsIScriptContext *scriptContext =
624 nsJSUtils::GetDynamicScriptContext(cx);
626 if (scriptContext) {
627 if (scriptContext->GetProcessingScriptTag()) {
628 // Now check to make sure that the script is running in our window,
629 // since we only want to replace if the location is set by a
630 // <script> tag in the same window. See bug 178729.
631 nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
632 inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
635 } //cx
636 } // stack
638 return SetURI(newUri, aReplace || inScriptTag);
641 return result;
644 NS_IMETHODIMP
645 nsLocation::GetPathname(nsAString& aPathname)
647 aPathname.Truncate();
649 nsCOMPtr<nsIURI> uri;
650 nsresult result = NS_OK;
652 result = GetURI(getter_AddRefs(uri));
654 nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
655 if (url) {
656 nsCAutoString file;
658 result = url->GetFilePath(file);
660 if (NS_SUCCEEDED(result)) {
661 AppendUTF8toUTF16(file, aPathname);
665 return result;
668 NS_IMETHODIMP
669 nsLocation::SetPathname(const nsAString& aPathname)
671 nsCOMPtr<nsIURI> uri;
672 nsresult rv = GetWritableURI(getter_AddRefs(uri));
674 if (uri) {
675 rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname));
676 if (NS_SUCCEEDED(rv)) {
677 SetURI(uri);
681 return rv;
684 NS_IMETHODIMP
685 nsLocation::GetPort(nsAString& aPort)
687 aPort.SetLength(0);
689 nsCOMPtr<nsIURI> uri;
690 nsresult result = NS_OK;
692 result = GetURI(getter_AddRefs(uri), PR_TRUE);
694 if (uri) {
695 PRInt32 port;
696 result = uri->GetPort(&port);
698 if (NS_SUCCEEDED(result) && -1 != port) {
699 nsAutoString portStr;
700 portStr.AppendInt(port);
701 aPort.Append(portStr);
704 // Don't propagate this exception to caller
705 result = NS_OK;
708 return result;
711 NS_IMETHODIMP
712 nsLocation::SetPort(const nsAString& aPort)
714 nsCOMPtr<nsIURI> uri;
715 nsresult rv = GetWritableURI(getter_AddRefs(uri));
717 if (uri) {
718 // perhaps use nsReadingIterators at some point?
719 NS_ConvertUTF16toUTF8 portStr(aPort);
720 const char *buf = portStr.get();
721 PRInt32 port = -1;
723 if (buf) {
724 if (*buf == ':') {
725 port = atol(buf+1);
727 else {
728 port = atol(buf);
732 rv = uri->SetPort(port);
733 if (NS_SUCCEEDED(rv)) {
734 SetURI(uri);
738 return rv;
741 NS_IMETHODIMP
742 nsLocation::GetProtocol(nsAString& aProtocol)
744 aProtocol.SetLength(0);
746 nsCOMPtr<nsIURI> uri;
747 nsresult result = NS_OK;
749 result = GetURI(getter_AddRefs(uri));
751 if (uri) {
752 nsCAutoString protocol;
754 result = uri->GetScheme(protocol);
756 if (NS_SUCCEEDED(result)) {
757 CopyASCIItoUTF16(protocol, aProtocol);
758 aProtocol.Append(PRUnichar(':'));
762 return result;
765 NS_IMETHODIMP
766 nsLocation::SetProtocol(const nsAString& aProtocol)
768 nsCOMPtr<nsIURI> uri;
769 nsresult rv = GetWritableURI(getter_AddRefs(uri));
771 if (uri) {
772 rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
773 if (NS_SUCCEEDED(rv)) {
774 SetURI(uri);
778 return rv;
781 NS_IMETHODIMP
782 nsLocation::GetSearch(nsAString& aSearch)
784 aSearch.SetLength(0);
786 nsCOMPtr<nsIURI> uri;
787 nsresult result = NS_OK;
789 result = GetURI(getter_AddRefs(uri));
791 nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
793 if (url) {
794 nsCAutoString search;
796 result = url->GetQuery(search);
798 if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
799 aSearch.Assign(PRUnichar('?'));
800 AppendUTF8toUTF16(search, aSearch);
804 return NS_OK;
807 NS_IMETHODIMP
808 nsLocation::SetSearch(const nsAString& aSearch)
810 nsCOMPtr<nsIURI> uri;
811 nsresult rv = GetWritableURI(getter_AddRefs(uri));
813 nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
814 if (url) {
815 rv = url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
816 if (NS_SUCCEEDED(rv)) {
817 SetURI(uri);
821 return rv;
824 NS_IMETHODIMP
825 nsLocation::Reload(PRBool aForceget)
827 nsresult rv;
828 nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
829 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
830 nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
832 if (window && window->IsHandlingResizeEvent()) {
833 // location.reload() was called on a window that is handling a
834 // resize event. Sites do this since Netscape 4.x needed it, but
835 // we don't, and it's a horrible experience for nothing. In stead
836 // of reloading the page, just clear style data and reflow the
837 // page since some sites may use this trick to work around gecko
838 // reflow bugs, and this should have the same effect.
840 nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
842 nsIPresShell *shell;
843 nsPresContext *pcx;
844 if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
845 pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
848 return NS_OK;
851 if (webNav) {
852 PRUint32 reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
854 if (aForceget) {
855 reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE |
856 nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
858 rv = webNav->Reload(reloadFlags);
859 if (rv == NS_BINDING_ABORTED) {
860 // This happens when we attempt to reload a POST result and the user says
861 // no at the "do you want to reload?" prompt. Don't propagate this one
862 // back to callers.
863 rv = NS_OK;
865 } else {
866 rv = NS_ERROR_FAILURE;
869 return rv;
872 NS_IMETHODIMP
873 nsLocation::Replace(const nsAString& aUrl)
875 nsresult rv = NS_OK;
877 // Get JSContext from stack.
878 nsCOMPtr<nsIJSContextStack>
879 stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
881 if (stack) {
882 JSContext *cx;
884 rv = GetContextFromStack(stack, &cx);
885 NS_ENSURE_SUCCESS(rv, rv);
886 if (cx) {
887 return SetHrefWithContext(cx, aUrl, PR_TRUE);
891 nsAutoString oldHref;
893 rv = GetHref(oldHref);
894 NS_ENSURE_SUCCESS(rv, rv);
896 nsCOMPtr<nsIURI> oldUri;
898 rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
899 NS_ENSURE_SUCCESS(rv, rv);
901 return SetHrefWithBase(aUrl, oldUri, PR_TRUE);
904 NS_IMETHODIMP
905 nsLocation::Assign(const nsAString& aUrl)
907 nsAutoString oldHref;
908 nsresult result = NS_OK;
910 result = GetHref(oldHref);
912 if (NS_SUCCEEDED(result)) {
913 nsCOMPtr<nsIURI> oldUri;
915 result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
917 if (oldUri) {
918 result = SetHrefWithBase(aUrl, oldUri, PR_FALSE);
922 return result;
925 NS_IMETHODIMP
926 nsLocation::ToString(nsAString& aReturn)
928 return GetHref(aReturn);
931 nsresult
932 nsLocation::GetSourceDocument(JSContext* cx, nsIDocument** aDocument)
934 // XXX Code duplicated from nsHTMLDocument
935 // XXX Tom said this reminded him of the "Six Degrees of
936 // Kevin Bacon" game. We try to get from here to there using
937 // whatever connections possible. The problem is that this
938 // could break if any of the connections along the way change.
939 // I wish there were a better way.
941 nsresult rv = NS_ERROR_FAILURE;
943 // We need to use the dynamically scoped global and assume that the
944 // current JSContext is a DOM context with a nsIScriptGlobalObject so
945 // that we can get the url of the caller.
946 // XXX This will fail on non-DOM contexts :(
948 nsCOMPtr<nsIDOMWindow> window =
949 do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx), &rv);
951 if (window) {
952 nsCOMPtr<nsIDOMDocument> domDoc;
953 rv = window->GetDocument(getter_AddRefs(domDoc));
954 if (domDoc) {
955 return CallQueryInterface(domDoc, aDocument);
957 } else {
958 *aDocument = nsnull;
961 return rv;
964 nsresult
965 nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
967 nsCOMPtr<nsIDocument> doc;
968 nsresult rv = GetSourceDocument(cx, getter_AddRefs(doc));
969 if (doc) {
970 *sourceURL = doc->GetBaseURI().get();
971 } else {
972 *sourceURL = nsnull;
975 return rv;