Back to index

lightning-sunbird  0.9+nobinonly
nsLocation.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set ts=2 sw=2 et tw=80: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Travis Bogard <travis@netscape.com>
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsGlobalWindow.h"
00042 #include "nsIScriptSecurityManager.h"
00043 #include "nsIScriptContext.h"
00044 #include "nsIDocShell.h"
00045 #include "nsIDocShellLoadInfo.h"
00046 #include "nsIWebNavigation.h"
00047 #include "nsCDefaultURIFixup.h"
00048 #include "nsIURIFixup.h"
00049 #include "nsIURL.h"
00050 #include "nsIJARURI.h"
00051 #include "nsIIOService.h"
00052 #include "nsIServiceManager.h"
00053 #include "nsNetUtil.h"
00054 #include "plstr.h"
00055 #include "prprf.h"
00056 #include "prmem.h"
00057 #include "nsCOMPtr.h"
00058 #include "nsEscape.h"
00059 #include "nsJSUtils.h"
00060 #include "nsIScriptSecurityManager.h"
00061 #include "nsIDOMWindow.h"
00062 #include "nsIDOMDocument.h"
00063 #include "nsIDocument.h"
00064 #include "nsIPresShell.h"
00065 #include "nsPresContext.h"
00066 #include "nsIJSContextStack.h"
00067 #include "nsXPIDLString.h"
00068 #include "nsDOMError.h"
00069 #include "nsDOMClassInfo.h"
00070 #include "nsCRT.h"
00071 #include "nsIProtocolHandler.h"
00072 #include "nsReadableUtils.h"
00073 #include "nsITextToSubURI.h"
00074 #include "nsContentUtils.h"
00075 
00076 static nsresult
00077 GetContextFromStack(nsIJSContextStack *aStack, JSContext **aContext)
00078 {
00079   nsCOMPtr<nsIJSContextStackIterator>
00080     iterator(do_CreateInstance("@mozilla.org/js/xpc/ContextStackIterator;1"));
00081   NS_ENSURE_TRUE(iterator, NS_ERROR_FAILURE);
00082 
00083   nsresult rv = iterator->Reset(aStack);
00084   NS_ENSURE_SUCCESS(rv, rv);
00085   
00086   PRBool done;
00087   while (NS_SUCCEEDED(iterator->Done(&done)) && !done) {
00088     rv = iterator->Prev(aContext);
00089     NS_ASSERTION(NS_SUCCEEDED(rv), "Broken iterator implementation");
00090 
00091     if (nsJSUtils::GetDynamicScriptContext(*aContext)) {
00092       return NS_OK;
00093     }
00094   }
00095 
00096   *aContext = nsnull;
00097 
00098   return NS_OK;
00099 }
00100 
00101 static nsresult
00102 GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
00103 {
00104   aCharset.Truncate();
00105 
00106   nsresult rv;
00107 
00108   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
00109   NS_ENSURE_SUCCESS(rv, rv);
00110 
00111   JSContext *cx;
00112 
00113   rv = GetContextFromStack(stack, &cx);
00114   NS_ENSURE_SUCCESS(rv, rv);
00115 
00116   if (cx) {
00117     nsCOMPtr<nsIDOMWindow> window =
00118       do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
00119     NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
00120 
00121     nsCOMPtr<nsIDOMDocument> domDoc;
00122     rv = window->GetDocument(getter_AddRefs(domDoc));
00123     NS_ENSURE_SUCCESS(rv, rv);
00124 
00125     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
00126 
00127     if (doc) {
00128       aCharset = doc->GetDocumentCharacterSet();
00129     }
00130   }
00131 
00132   return NS_OK;
00133 }
00134 
00135 nsLocation::nsLocation(nsIDocShell *aDocShell)
00136 {
00137   mDocShell = do_GetWeakReference(aDocShell);
00138 }
00139 
00140 nsLocation::~nsLocation()
00141 {
00142 }
00143 
00144 
00145 // QueryInterface implementation for nsLocation
00146 NS_INTERFACE_MAP_BEGIN(nsLocation)
00147   NS_INTERFACE_MAP_ENTRY(nsIDOMNSLocation)
00148   NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
00149   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocation)
00150   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
00151 NS_INTERFACE_MAP_END
00152 
00153 
00154 NS_IMPL_ADDREF(nsLocation)
00155 NS_IMPL_RELEASE(nsLocation)
00156 
00157 void
00158 nsLocation::SetDocShell(nsIDocShell *aDocShell)
00159 {
00160    mDocShell = do_GetWeakReference(aDocShell);
00161 }
00162 
00163 nsIDocShell *
00164 nsLocation::GetDocShell()
00165 {
00166   nsCOMPtr<nsIDocShell> docshell(do_QueryReferent(mDocShell));
00167   return docshell;
00168 }
00169 
00170 nsresult
00171 nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
00172 {
00173   *aLoadInfo = nsnull;
00174 
00175   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00176   if (!docShell) {
00177     return NS_ERROR_NOT_AVAILABLE;
00178   }
00179 
00180   nsresult result;
00181   // Get JSContext from stack.
00182   nsCOMPtr<nsIJSContextStack>
00183     stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
00184 
00185   if (NS_FAILED(result))
00186     return NS_ERROR_FAILURE;
00187 
00188   JSContext *cx;
00189 
00190   if (NS_FAILED(GetContextFromStack(stack, &cx)))
00191     return NS_ERROR_FAILURE;
00192 
00193   nsCOMPtr<nsISupports> owner;
00194   nsCOMPtr<nsIURI> sourceURI;
00195 
00196   if (cx) {
00197     // No cx means that there's no JS running, or at least no JS that
00198     // was run through code that properly pushed a context onto the
00199     // context stack (as all code that runs JS off of web pages
00200     // does). We won't bother with security checks in this case, but
00201     // we need to create the loadinfo etc.
00202 
00203     // Get security manager.
00204     nsCOMPtr<nsIScriptSecurityManager>
00205       secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &result));
00206 
00207     if (NS_FAILED(result))
00208       return NS_ERROR_FAILURE;
00209 
00210     // Check to see if URI is allowed.
00211     result = secMan->CheckLoadURIFromScript(cx, aURI);
00212 
00213     if (NS_FAILED(result))
00214       return result;
00215 
00216     // Now get the principal to use when loading the URI
00217     nsCOMPtr<nsIPrincipal> principal;
00218     if (NS_FAILED(secMan->GetSubjectPrincipal(getter_AddRefs(principal))) ||
00219         !principal)
00220       return NS_ERROR_FAILURE;
00221     owner = do_QueryInterface(principal);
00222 
00223     principal->GetURI(getter_AddRefs(sourceURI));
00224   }
00225 
00226   // Create load info
00227   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
00228   docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
00229   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
00230 
00231   loadInfo->SetOwner(owner);
00232 
00233   // now set the referrer on the loadinfo
00234   if (sourceURI) {
00235     loadInfo->SetReferrer(sourceURI);
00236   }
00237 
00238   loadInfo.swap(*aLoadInfo);
00239 
00240   return NS_OK;
00241 }
00242 
00243 // Walk up the docshell hierarchy and find a usable base URI. Basically 
00244 // anything that would allow a relative uri.
00245 
00246 nsresult
00247 nsLocation::FindUsableBaseURI(nsIURI * aBaseURI, nsIDocShell * aParent,
00248                               nsIURI ** aUsableURI)
00249 {
00250   if (!aBaseURI || !aParent)
00251     return NS_ERROR_FAILURE;
00252   NS_ENSURE_ARG_POINTER(aUsableURI);
00253 
00254   *aUsableURI = nsnull;
00255   nsresult rv = NS_OK;    
00256   nsCOMPtr<nsIDocShell> parentDS = aParent;
00257   nsCOMPtr<nsIURI> baseURI = aBaseURI;
00258   nsCOMPtr<nsIIOService> ioService =
00259     do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
00260 
00261   while(NS_SUCCEEDED(rv) && baseURI) {
00262     // Check if the current base uri supports relative uris.
00263     // We make this check by looking at the protocol flags of
00264     // the protocol handler. If the protocol flags has URI_NORELATIVE,
00265     // it means that the base uri does not support relative uris.
00266     nsCAutoString scheme;
00267     baseURI->GetScheme(scheme);
00268     nsCOMPtr<nsIProtocolHandler> protocolHandler;
00269     // Get the protocol handler for the base uri.
00270     ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(protocolHandler));
00271     if (!protocolHandler)
00272       return NS_ERROR_FAILURE;
00273     PRUint32 pFlags; // Is there a default value for the protocol flags?
00274     protocolHandler->GetProtocolFlags(&pFlags);
00275     if (!(pFlags & nsIProtocolHandler::URI_NORELATIVE)) {
00276       *aUsableURI = baseURI;
00277       NS_ADDREF(*aUsableURI);
00278       return NS_OK;
00279     }
00280 
00281     // Get the same type parent docshell
00282     nsCOMPtr<nsIDocShellTreeItem> docShellAsTreeItem(do_QueryInterface(parentDS));
00283     if (!docShellAsTreeItem)
00284       return NS_ERROR_FAILURE;
00285     nsCOMPtr<nsIDocShellTreeItem> parentDSTreeItem;
00286     docShellAsTreeItem->GetSameTypeParent(getter_AddRefs(parentDSTreeItem));      
00287     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(parentDSTreeItem));
00288 
00289     // Get the parent docshell's uri
00290     if (webNav) {
00291       rv = webNav->GetCurrentURI(getter_AddRefs(baseURI));
00292       parentDS = do_QueryInterface(parentDSTreeItem);
00293     }
00294     else
00295       return NS_ERROR_FAILURE;
00296   }  // while 
00297 
00298   return rv;
00299 }
00300 
00301 
00302 nsresult
00303 nsLocation::GetURI(nsIURI** aURI, PRBool aGetInnermostURI)
00304 {
00305   *aURI = nsnull;
00306 
00307   nsresult rv;
00308   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00309   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
00310   if (NS_FAILED(rv)) {
00311     return rv;
00312   }
00313 
00314   nsCOMPtr<nsIURI> uri;
00315   rv = webNav->GetCurrentURI(getter_AddRefs(uri));
00316   NS_ENSURE_SUCCESS(rv, rv);
00317 
00318   // It is valid for docshell to return a null URI. Don't try to fixup
00319   // if this happens.
00320   if (!uri) {
00321     return NS_OK;
00322   }
00323 
00324   if (aGetInnermostURI) {
00325     nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
00326     while (jarURI) {
00327       jarURI->GetJARFile(getter_AddRefs(uri));
00328       jarURI = do_QueryInterface(uri);
00329     }
00330   }
00331 
00332   NS_ASSERTION(uri, "nsJARURI screwed up?");
00333 
00334   nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
00335   NS_ENSURE_SUCCESS(rv, rv);
00336 
00337   return urifixup->CreateExposableURI(uri, aURI);
00338 }
00339 
00340 nsresult
00341 nsLocation::GetWritableURI(nsIURI** aURI)
00342 {
00343   *aURI = nsnull;
00344 
00345   nsCOMPtr<nsIURI> uri;
00346 
00347   nsresult rv = GetURI(getter_AddRefs(uri));
00348   if (NS_FAILED(rv) || !uri) {
00349     return rv;
00350   }
00351 
00352   return uri->Clone(aURI);
00353 }
00354 
00355 nsresult
00356 nsLocation::SetURI(nsIURI* aURI, PRBool aReplace)
00357 {
00358   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00359   if (docShell) {
00360     nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
00361     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
00362 
00363     if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
00364       return NS_ERROR_FAILURE;
00365 
00366     if (aReplace) {
00367       loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
00368     } else {
00369       loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
00370     }
00371 
00372     return docShell->LoadURI(aURI, loadInfo,
00373                              nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
00374   }
00375 
00376   return NS_OK;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsLocation::GetHash(nsAString& aHash)
00381 {
00382   aHash.SetLength(0);
00383 
00384   nsCOMPtr<nsIURI> uri;
00385   nsresult rv = GetURI(getter_AddRefs(uri));
00386 
00387   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
00388 
00389   if (url) {
00390     nsCAutoString ref;
00391     nsAutoString unicodeRef;
00392 
00393     rv = url->GetRef(ref);
00394     if (NS_SUCCEEDED(rv)) {
00395       nsCOMPtr<nsITextToSubURI> textToSubURI(
00396           do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
00397 
00398       if (NS_SUCCEEDED(rv)) {
00399         nsCAutoString charset;
00400         url->GetOriginCharset(charset);
00401         
00402         rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
00403       }
00404       
00405       if (NS_FAILED(rv)) {
00406         // Oh, well.  No intl here!
00407         NS_UnescapeURL(ref);
00408         CopyASCIItoUTF16(ref, unicodeRef);
00409         rv = NS_OK;
00410       }
00411     }
00412 
00413     if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
00414       aHash.Assign(PRUnichar('#'));
00415       aHash.Append(unicodeRef);
00416     }
00417   }
00418 
00419   return rv;
00420 }
00421 
00422 NS_IMETHODIMP
00423 nsLocation::SetHash(const nsAString& aHash)
00424 {
00425   nsCOMPtr<nsIURI> uri;
00426   nsresult result = NS_OK;
00427 
00428   result = GetWritableURI(getter_AddRefs(uri));
00429 
00430   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
00431 
00432   if (url) {
00433     url->SetRef(NS_ConvertUCS2toUTF8(aHash));
00434     SetURI(url);
00435   }
00436 
00437   return result;
00438 }
00439 
00440 NS_IMETHODIMP
00441 nsLocation::GetHost(nsAString& aHost)
00442 {
00443   aHost.Truncate();
00444 
00445   nsCOMPtr<nsIURI> uri;
00446   nsresult result;
00447 
00448   result = GetURI(getter_AddRefs(uri), PR_TRUE);
00449 
00450   if (uri) {
00451     nsCAutoString hostport;
00452 
00453     result = uri->GetHostPort(hostport);
00454 
00455     if (NS_SUCCEEDED(result)) {
00456       AppendUTF8toUTF16(hostport, aHost);
00457     }
00458   }
00459 
00460   return result;
00461 }
00462 
00463 NS_IMETHODIMP
00464 nsLocation::SetHost(const nsAString& aHost)
00465 {
00466   nsCOMPtr<nsIURI> uri;
00467   nsresult result;
00468 
00469   result = GetWritableURI(getter_AddRefs(uri));
00470 
00471   if (uri) {
00472     uri->SetHostPort(NS_ConvertUCS2toUTF8(aHost));
00473     SetURI(uri);
00474   }
00475 
00476   return result;
00477 }
00478 
00479 NS_IMETHODIMP
00480 nsLocation::GetHostname(nsAString& aHostname)
00481 {
00482   aHostname.Truncate();
00483 
00484   nsCOMPtr<nsIURI> uri;
00485   nsresult result;
00486 
00487   result = GetURI(getter_AddRefs(uri), PR_TRUE);
00488 
00489   if (uri) {
00490     nsCAutoString host;
00491 
00492     result = uri->GetHost(host);
00493 
00494     if (NS_SUCCEEDED(result)) {
00495       AppendUTF8toUTF16(host, aHostname);
00496     }
00497   }
00498 
00499   return result;
00500 }
00501 
00502 NS_IMETHODIMP
00503 nsLocation::SetHostname(const nsAString& aHostname)
00504 {
00505   nsCOMPtr<nsIURI> uri;
00506   nsresult result;
00507 
00508   result = GetWritableURI(getter_AddRefs(uri));
00509 
00510   if (uri) {
00511     uri->SetHost(NS_ConvertUCS2toUTF8(aHostname));
00512     SetURI(uri);
00513   }
00514 
00515   return result;
00516 }
00517 
00518 NS_IMETHODIMP
00519 nsLocation::GetHref(nsAString& aHref)
00520 {
00521   aHref.Truncate();
00522 
00523   nsCOMPtr<nsIURI> uri;
00524   nsresult result;
00525 
00526   result = GetURI(getter_AddRefs(uri));
00527 
00528   if (uri) {
00529     nsCAutoString uriString;
00530 
00531     result = uri->GetSpec(uriString);
00532 
00533     if (NS_SUCCEEDED(result)) {
00534       AppendUTF8toUTF16(uriString, aHref);
00535     }
00536   }
00537 
00538   return result;
00539 }
00540 
00541 NS_IMETHODIMP
00542 nsLocation::SetHref(const nsAString& aHref)
00543 {
00544   nsAutoString oldHref;
00545   nsresult rv = NS_OK;
00546 
00547   // Get JSContext from stack.
00548   nsCOMPtr<nsIJSContextStack>
00549     stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
00550 
00551   if (NS_FAILED(rv))
00552     return NS_ERROR_FAILURE;
00553 
00554   JSContext *cx;
00555 
00556   if (NS_FAILED(GetContextFromStack(stack, &cx)))
00557     return NS_ERROR_FAILURE;
00558 
00559   if (cx) {
00560     rv = SetHrefWithContext(cx, aHref, PR_FALSE);
00561   } else {
00562     rv = GetHref(oldHref);
00563 
00564     if (NS_SUCCEEDED(rv)) {
00565       nsCOMPtr<nsIURI> oldUri;
00566 
00567       rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
00568 
00569       if (oldUri) {
00570         rv = SetHrefWithBase(aHref, oldUri, PR_FALSE);
00571       }
00572     }
00573   }
00574 
00575   return rv;
00576 }
00577 
00578 nsresult
00579 nsLocation::SetHrefWithContext(JSContext* cx, const nsAString& aHref,
00580                                PRBool aReplace)
00581 {
00582   nsCOMPtr<nsIURI> base;
00583 
00584   // Get the source of the caller
00585   nsresult result = GetSourceBaseURL(cx, getter_AddRefs(base));
00586 
00587   if (NS_FAILED(result)) {
00588     return result;
00589   }
00590 
00591   return SetHrefWithBase(aHref, base, aReplace);
00592 }
00593 
00594 nsresult
00595 nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
00596                             PRBool aReplace)
00597 {
00598   nsresult result;
00599   nsCOMPtr<nsIURI> newUri, baseURI;
00600 
00601   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00602 
00603   // Try to make sure the base url is something that will be useful. 
00604   result = FindUsableBaseURI(aBase,  docShell, getter_AddRefs(baseURI));
00605   if (!baseURI)  {
00606     // If nothing useful was found, just use what you have.
00607     baseURI = aBase;
00608   }
00609 
00610   nsCAutoString docCharset;
00611   if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
00612     result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), baseURI);
00613   else
00614     result = NS_NewURI(getter_AddRefs(newUri), aHref, nsnull, baseURI);
00615 
00616   if (newUri) {
00617     /* Check with the scriptContext if it is currently processing a script tag.
00618      * If so, this must be a <script> tag with a location.href in it.
00619      * we want to do a replace load, in such a situation. 
00620      * In other cases, for example if a event handler or a JS timer
00621      * had a location.href in it, we want to do a normal load,
00622      * so that the new url will be appended to Session History.
00623      * This solution is tricky. Hopefully it isn't going to bite
00624      * anywhere else. This is part of solution for bug # 39938, 72197
00625      * 
00626      */
00627     PRBool inScriptTag=PR_FALSE;
00628     // Get JSContext from stack.
00629     nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
00630 
00631     if (stack) {
00632       JSContext *cx;
00633 
00634       result = GetContextFromStack(stack, &cx);
00635       if (cx) {
00636         nsIScriptContext *scriptContext =
00637           nsJSUtils::GetDynamicScriptContext(cx);
00638 
00639         if (scriptContext) {
00640           if (scriptContext->GetProcessingScriptTag()) {
00641             // Now check to make sure that the script is running in our window,
00642             // since we only want to replace if the location is set by a
00643             // <script> tag in the same window.  See bug 178729.
00644             nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
00645             inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
00646           }
00647         }  
00648       } //cx
00649     }  // stack
00650 
00651     return SetURI(newUri, aReplace || inScriptTag);
00652   }
00653 
00654   return result;
00655 }
00656 
00657 NS_IMETHODIMP
00658 nsLocation::GetPathname(nsAString& aPathname)
00659 {
00660   aPathname.Truncate();
00661 
00662   nsCOMPtr<nsIURI> uri;
00663   nsresult result = NS_OK;
00664 
00665   result = GetURI(getter_AddRefs(uri));
00666 
00667   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
00668   if (url) {
00669     nsCAutoString file;
00670 
00671     result = url->GetFilePath(file);
00672 
00673     if (NS_SUCCEEDED(result)) {
00674       AppendUTF8toUTF16(file, aPathname);
00675     }
00676   }
00677 
00678   return result;
00679 }
00680 
00681 NS_IMETHODIMP
00682 nsLocation::SetPathname(const nsAString& aPathname)
00683 {
00684   nsCOMPtr<nsIURI> uri;
00685   nsresult result = NS_OK;
00686 
00687   result = GetWritableURI(getter_AddRefs(uri));
00688 
00689   if (uri) {
00690     uri->SetPath(NS_ConvertUCS2toUTF8(aPathname));
00691     SetURI(uri);
00692   }
00693 
00694   return result;
00695 }
00696 
00697 NS_IMETHODIMP
00698 nsLocation::GetPort(nsAString& aPort)
00699 {
00700   aPort.SetLength(0);
00701 
00702   nsCOMPtr<nsIURI> uri;
00703   nsresult result = NS_OK;
00704 
00705   result = GetURI(getter_AddRefs(uri), PR_TRUE);
00706 
00707   if (uri) {
00708     PRInt32 port;
00709     result = uri->GetPort(&port);
00710 
00711     if (NS_SUCCEEDED(result) && -1 != port) {
00712       nsAutoString portStr;
00713       portStr.AppendInt(port);
00714       aPort.Append(portStr);
00715     }
00716 
00717     // Don't propagate this exception to caller
00718     result = NS_OK;
00719   }
00720 
00721   return result;
00722 }
00723 
00724 NS_IMETHODIMP
00725 nsLocation::SetPort(const nsAString& aPort)
00726 {
00727   nsCOMPtr<nsIURI> uri;
00728   nsresult result = NS_OK;
00729 
00730   result = GetWritableURI(getter_AddRefs(uri));
00731 
00732   if (uri) {
00733     // perhaps use nsReadingIterators at some point?
00734     NS_ConvertUCS2toUTF8 portStr(aPort);
00735     const char *buf = portStr.get();
00736     PRInt32 port = -1;
00737 
00738     if (buf) {
00739       if (*buf == ':') {
00740         port = atol(buf+1);
00741       }
00742       else {
00743         port = atol(buf);
00744       }
00745     }
00746 
00747     uri->SetPort(port);
00748     SetURI(uri);
00749   }
00750 
00751   return result;
00752 }
00753 
00754 NS_IMETHODIMP
00755 nsLocation::GetProtocol(nsAString& aProtocol)
00756 {
00757   aProtocol.SetLength(0);
00758 
00759   nsCOMPtr<nsIURI> uri;
00760   nsresult result = NS_OK;
00761 
00762   result = GetURI(getter_AddRefs(uri));
00763 
00764   if (uri) {
00765     nsCAutoString protocol;
00766 
00767     result = uri->GetScheme(protocol);
00768 
00769     if (NS_SUCCEEDED(result)) {
00770       CopyASCIItoUTF16(protocol, aProtocol);
00771       aProtocol.Append(PRUnichar(':'));
00772     }
00773   }
00774 
00775   return result;
00776 }
00777 
00778 NS_IMETHODIMP
00779 nsLocation::SetProtocol(const nsAString& aProtocol)
00780 {
00781   nsCOMPtr<nsIURI> uri;
00782   nsresult result = NS_OK;
00783 
00784   result = GetWritableURI(getter_AddRefs(uri));
00785 
00786   if (uri) {
00787     uri->SetScheme(NS_ConvertUCS2toUTF8(aProtocol));
00788     SetURI(uri);
00789   }
00790 
00791   return result;
00792 }
00793 
00794 NS_IMETHODIMP
00795 nsLocation::GetSearch(nsAString& aSearch)
00796 {
00797   aSearch.SetLength(0);
00798 
00799   nsCOMPtr<nsIURI> uri;
00800   nsresult result = NS_OK;
00801 
00802   result = GetURI(getter_AddRefs(uri));
00803 
00804   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
00805 
00806   if (url) {
00807     nsCAutoString search;
00808 
00809     result = url->GetQuery(search);
00810 
00811     if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
00812       aSearch.Assign(PRUnichar('?'));
00813       AppendUTF8toUTF16(search, aSearch);
00814     }
00815   }
00816 
00817   return NS_OK;
00818 }
00819 
00820 NS_IMETHODIMP
00821 nsLocation::SetSearch(const nsAString& aSearch)
00822 {
00823   nsCOMPtr<nsIURI> uri;
00824   nsresult result = NS_OK;
00825 
00826   result = GetWritableURI(getter_AddRefs(uri));
00827 
00828   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
00829   if (url) {
00830     result = url->SetQuery(NS_ConvertUCS2toUTF8(aSearch));
00831     SetURI(uri);
00832   }
00833 
00834   return result;
00835 }
00836 
00837 NS_IMETHODIMP
00838 nsLocation::Reload(PRBool aForceget)
00839 {
00840   nsresult rv;
00841   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00842   nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
00843 
00844   if (webNav) {
00845     PRUint32 reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
00846 
00847     if (aForceget) {
00848       reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE | 
00849                     nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
00850     }
00851     rv = webNav->Reload(reloadFlags);
00852     if (rv == NS_BINDING_ABORTED) {
00853       // This happens when we attempt to reload a POST result and the user says
00854       // no at the "do you want to reload?" prompt.  Don't propagate this one
00855       // back to callers.
00856       rv = NS_OK;
00857     }
00858   } else {
00859     rv = NS_ERROR_FAILURE;
00860   }
00861 
00862   return rv;
00863 }
00864 
00865 NS_IMETHODIMP
00866 nsLocation::Reload()
00867 {
00868   nsCOMPtr<nsIXPCNativeCallContext> ncc;
00869   nsresult rv = nsContentUtils::XPConnect()->
00870     GetCurrentNativeCallContext(getter_AddRefs(ncc));
00871   NS_ENSURE_SUCCESS(rv, rv);
00872 
00873   if (!ncc)
00874     return NS_ERROR_NOT_AVAILABLE;
00875 
00876   nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
00877   nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
00878 
00879   if (window && window->IsHandlingResizeEvent()) {
00880     // location.reload() was called on a window that is handling a
00881     // resize event. Sites do this since Netscape 4.x needed it, but
00882     // we don't, and it's a horrible experience for nothing. In stead
00883     // of reloading the page, just clear style data and reflow the
00884     // page since some sites may use this trick to work around gecko
00885     // reflow bugs, and this should have the same effect.
00886 
00887     nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
00888 
00889     nsIPresShell *shell;
00890     nsPresContext *pcx;
00891     if (doc && (shell = doc->GetShellAt(0)) &&
00892         (pcx = shell->GetPresContext())) {
00893       pcx->ClearStyleDataAndReflow();
00894     }
00895 
00896     return NS_OK;
00897   }
00898 
00899   PRBool force_get = PR_FALSE;
00900 
00901   PRUint32 argc;
00902 
00903   ncc->GetArgc(&argc);
00904 
00905   if (argc > 0) {
00906     jsval *argv = nsnull;
00907 
00908     ncc->GetArgvPtr(&argv);
00909     NS_ENSURE_TRUE(argv, NS_ERROR_UNEXPECTED);
00910 
00911     JSContext *cx = nsnull;
00912 
00913     rv = ncc->GetJSContext(&cx);
00914     NS_ENSURE_SUCCESS(rv, rv);
00915 
00916     JS_ValueToBoolean(cx, argv[0], &force_get);
00917   }
00918 
00919   return Reload(force_get);
00920 }
00921 
00922 NS_IMETHODIMP
00923 nsLocation::Replace(const nsAString& aUrl)
00924 {
00925   nsresult rv = NS_OK;
00926 
00927   // Get JSContext from stack.
00928   nsCOMPtr<nsIJSContextStack>
00929   stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
00930 
00931   if (stack) {
00932     JSContext *cx;
00933 
00934     rv = GetContextFromStack(stack, &cx);
00935     NS_ENSURE_SUCCESS(rv, rv);
00936     if (cx) {
00937       return SetHrefWithContext(cx, aUrl, PR_TRUE);
00938     }
00939   }
00940 
00941   nsAutoString oldHref;
00942 
00943   rv = GetHref(oldHref);
00944   NS_ENSURE_SUCCESS(rv, rv);
00945 
00946   nsCOMPtr<nsIURI> oldUri;
00947 
00948   rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
00949   NS_ENSURE_SUCCESS(rv, rv);
00950 
00951   return SetHrefWithBase(aUrl, oldUri, PR_TRUE);
00952 }
00953 
00954 NS_IMETHODIMP
00955 nsLocation::Assign(const nsAString& aUrl)
00956 {
00957   nsAutoString oldHref;
00958   nsresult result = NS_OK;
00959 
00960   result = GetHref(oldHref);
00961 
00962   if (NS_SUCCEEDED(result)) {
00963     nsCOMPtr<nsIURI> oldUri;
00964 
00965     result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
00966 
00967     if (oldUri) {
00968       result = SetHrefWithBase(aUrl, oldUri, PR_FALSE);
00969     }
00970   }
00971 
00972   return result;
00973 }
00974 
00975 NS_IMETHODIMP
00976 nsLocation::ToString(nsAString& aReturn)
00977 {
00978   return GetHref(aReturn);
00979 }
00980 
00981 nsresult
00982 nsLocation::GetSourceDocument(JSContext* cx, nsIDocument** aDocument)
00983 {
00984   // XXX Code duplicated from nsHTMLDocument
00985   // XXX Tom said this reminded him of the "Six Degrees of
00986   // Kevin Bacon" game. We try to get from here to there using
00987   // whatever connections possible. The problem is that this
00988   // could break if any of the connections along the way change.
00989   // I wish there were a better way.
00990 
00991   nsresult rv = NS_ERROR_FAILURE;
00992 
00993   // We need to use the dynamically scoped global and assume that the
00994   // current JSContext is a DOM context with a nsIScriptGlobalObject so
00995   // that we can get the url of the caller.
00996   // XXX This will fail on non-DOM contexts :(
00997 
00998   nsCOMPtr<nsIDOMWindow> window =
00999     do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx), &rv);
01000 
01001   if (window) {
01002     nsCOMPtr<nsIDOMDocument> domDoc;
01003     rv = window->GetDocument(getter_AddRefs(domDoc));
01004     if (domDoc) {
01005       return CallQueryInterface(domDoc, aDocument);
01006     }
01007   } else {
01008     *aDocument = nsnull;
01009   }
01010 
01011   return rv;
01012 }
01013 
01014 nsresult
01015 nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
01016 {
01017   nsCOMPtr<nsIDocument> doc;
01018   nsresult rv = GetSourceDocument(cx, getter_AddRefs(doc));
01019   if (doc) {
01020     NS_IF_ADDREF(*sourceURL = doc->GetBaseURI());
01021   } else {
01022     *sourceURL = nsnull;
01023   }
01024 
01025   return rv;
01026 }