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
5 : *
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/
10 : *
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.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
23 : * Contributor(s):
24 : * Travis Bogard <travis@netscape.com>
25 : * Pierre Phaneuf <pp@ludusdesign.com>
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "nsLocation.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 "nsIDOMWindow.h"
60 : #include "nsIDOMDocument.h"
61 : #include "nsIDocument.h"
62 : #include "nsIPresShell.h"
63 : #include "nsPresContext.h"
64 : #include "nsIJSContextStack.h"
65 : #include "nsXPIDLString.h"
66 : #include "nsDOMError.h"
67 : #include "nsDOMClassInfoID.h"
68 : #include "nsCRT.h"
69 : #include "nsIProtocolHandler.h"
70 : #include "nsReadableUtils.h"
71 : #include "nsITextToSubURI.h"
72 : #include "nsContentUtils.h"
73 : #include "nsJSUtils.h"
74 : #include "jsfriendapi.h"
75 :
76 : static nsresult
77 0 : GetContextFromStack(nsIJSContextStack *aStack, JSContext **aContext)
78 : {
79 : nsCOMPtr<nsIJSContextStackIterator>
80 0 : iterator(do_CreateInstance("@mozilla.org/js/xpc/ContextStackIterator;1"));
81 0 : NS_ENSURE_TRUE(iterator, NS_ERROR_FAILURE);
82 :
83 0 : nsresult rv = iterator->Reset(aStack);
84 0 : NS_ENSURE_SUCCESS(rv, rv);
85 :
86 : bool done;
87 0 : while (NS_SUCCEEDED(iterator->Done(&done)) && !done) {
88 0 : rv = iterator->Prev(aContext);
89 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "Broken iterator implementation");
90 :
91 : // Consider a null context the end of the line.
92 0 : if (!*aContext) {
93 0 : break;
94 : }
95 :
96 0 : if (nsJSUtils::GetDynamicScriptContext(*aContext)) {
97 0 : return NS_OK;
98 : }
99 : }
100 :
101 0 : *aContext = nsnull;
102 :
103 0 : return NS_OK;
104 : }
105 :
106 : static nsresult
107 0 : GetDocumentCharacterSetForURI(const nsAString& aHref, nsACString& aCharset)
108 : {
109 0 : aCharset.Truncate();
110 :
111 : nsresult rv;
112 :
113 0 : nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
114 0 : NS_ENSURE_SUCCESS(rv, rv);
115 :
116 : JSContext *cx;
117 :
118 0 : rv = GetContextFromStack(stack, &cx);
119 0 : NS_ENSURE_SUCCESS(rv, rv);
120 :
121 0 : if (cx) {
122 : nsCOMPtr<nsIDOMWindow> window =
123 0 : do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
124 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
125 :
126 0 : nsCOMPtr<nsIDOMDocument> domDoc;
127 0 : rv = window->GetDocument(getter_AddRefs(domDoc));
128 0 : NS_ENSURE_SUCCESS(rv, rv);
129 :
130 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
131 :
132 0 : if (doc) {
133 0 : aCharset = doc->GetDocumentCharacterSet();
134 : }
135 : }
136 :
137 0 : return NS_OK;
138 : }
139 :
140 0 : nsLocation::nsLocation(nsIDocShell *aDocShell)
141 : {
142 0 : mDocShell = do_GetWeakReference(aDocShell);
143 0 : }
144 :
145 0 : nsLocation::~nsLocation()
146 : {
147 0 : }
148 :
149 : DOMCI_DATA(Location, nsLocation)
150 :
151 : // QueryInterface implementation for nsLocation
152 0 : NS_INTERFACE_MAP_BEGIN(nsLocation)
153 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMLocation)
154 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocation)
155 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Location)
156 0 : NS_INTERFACE_MAP_END
157 :
158 :
159 0 : NS_IMPL_ADDREF(nsLocation)
160 0 : NS_IMPL_RELEASE(nsLocation)
161 :
162 : void
163 0 : nsLocation::SetDocShell(nsIDocShell *aDocShell)
164 : {
165 0 : mDocShell = do_GetWeakReference(aDocShell);
166 0 : }
167 :
168 : nsIDocShell *
169 0 : nsLocation::GetDocShell()
170 : {
171 0 : nsCOMPtr<nsIDocShell> docshell(do_QueryReferent(mDocShell));
172 0 : return docshell;
173 : }
174 :
175 : // Try to get the the document corresponding to the given JSStackFrame.
176 : static already_AddRefed<nsIDocument>
177 0 : GetFrameDocument(JSContext *cx, JSStackFrame *fp)
178 : {
179 0 : if (!cx || !fp)
180 0 : return nsnull;
181 :
182 0 : JSObject* scope = JS_GetGlobalForFrame(fp);
183 0 : if (!scope)
184 0 : return nsnull;
185 :
186 0 : JSAutoEnterCompartment ac;
187 0 : if (!ac.enter(cx, scope))
188 0 : return nsnull;
189 :
190 : nsCOMPtr<nsIDOMWindow> window =
191 0 : do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, scope));
192 0 : if (!window)
193 0 : return nsnull;
194 :
195 : // If it's a window, get its document.
196 0 : nsCOMPtr<nsIDOMDocument> domDoc;
197 0 : window->GetDocument(getter_AddRefs(domDoc));
198 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
199 0 : return doc.forget();
200 : }
201 :
202 : nsresult
203 0 : nsLocation::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo)
204 : {
205 0 : *aLoadInfo = nsnull;
206 :
207 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
208 0 : NS_ENSURE_TRUE(docShell, NS_ERROR_NOT_AVAILABLE);
209 :
210 : nsresult rv;
211 : // Get JSContext from stack.
212 : nsCOMPtr<nsIJSContextStack>
213 0 : stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
214 0 : NS_ENSURE_SUCCESS(rv, rv);
215 :
216 : JSContext *cx;
217 :
218 0 : NS_ENSURE_SUCCESS(GetContextFromStack(stack, &cx), NS_ERROR_FAILURE);
219 :
220 0 : nsCOMPtr<nsISupports> owner;
221 0 : nsCOMPtr<nsIURI> sourceURI;
222 :
223 0 : 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.
229 :
230 : // Get security manager.
231 : nsCOMPtr<nsIScriptSecurityManager>
232 0 : secMan(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
233 0 : NS_ENSURE_SUCCESS(rv, rv);
234 :
235 : // Check to see if URI is allowed.
236 0 : rv = secMan->CheckLoadURIFromScript(cx, aURI);
237 0 : NS_ENSURE_SUCCESS(rv, rv);
238 :
239 : // Now get the principal to use when loading the URI
240 : // First, get the principal and frame.
241 : JSStackFrame *fp;
242 0 : nsIPrincipal* principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp);
243 0 : NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
244 :
245 0 : nsCOMPtr<nsIURI> principalURI;
246 0 : principal->GetURI(getter_AddRefs(principalURI));
247 :
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.
254 :
255 0 : nsCOMPtr<nsIDocument> frameDoc = GetFrameDocument(cx, fp);
256 0 : nsCOMPtr<nsIURI> docOriginalURI, docCurrentURI;
257 0 : if (frameDoc) {
258 0 : docOriginalURI = frameDoc->GetOriginalURI();
259 0 : docCurrentURI = frameDoc->GetDocumentURI();
260 : }
261 :
262 0 : bool urisEqual = false;
263 0 : if (docOriginalURI && docCurrentURI && principalURI) {
264 0 : principalURI->Equals(docOriginalURI, &urisEqual);
265 : }
266 :
267 0 : if (urisEqual) {
268 0 : sourceURI = docCurrentURI;
269 : }
270 : else {
271 0 : sourceURI = principalURI;
272 : }
273 :
274 0 : owner = do_QueryInterface(principal);
275 : }
276 :
277 : // Create load info
278 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
279 0 : docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
280 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
281 :
282 0 : loadInfo->SetOwner(owner);
283 :
284 0 : if (sourceURI) {
285 0 : loadInfo->SetReferrer(sourceURI);
286 : }
287 :
288 0 : loadInfo.swap(*aLoadInfo);
289 :
290 0 : return NS_OK;
291 : }
292 :
293 : nsresult
294 0 : nsLocation::GetURI(nsIURI** aURI, bool aGetInnermostURI)
295 : {
296 0 : *aURI = nsnull;
297 :
298 : nsresult rv;
299 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
300 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell, &rv));
301 0 : if (NS_FAILED(rv)) {
302 0 : return rv;
303 : }
304 :
305 0 : nsCOMPtr<nsIURI> uri;
306 0 : rv = webNav->GetCurrentURI(getter_AddRefs(uri));
307 0 : NS_ENSURE_SUCCESS(rv, rv);
308 :
309 : // It is valid for docshell to return a null URI. Don't try to fixup
310 : // if this happens.
311 0 : if (!uri) {
312 0 : return NS_OK;
313 : }
314 :
315 0 : if (aGetInnermostURI) {
316 0 : nsCOMPtr<nsIJARURI> jarURI(do_QueryInterface(uri));
317 0 : while (jarURI) {
318 0 : jarURI->GetJARFile(getter_AddRefs(uri));
319 0 : jarURI = do_QueryInterface(uri);
320 : }
321 : }
322 :
323 0 : NS_ASSERTION(uri, "nsJARURI screwed up?");
324 :
325 0 : nsCOMPtr<nsIURIFixup> urifixup(do_GetService(NS_URIFIXUP_CONTRACTID, &rv));
326 0 : NS_ENSURE_SUCCESS(rv, rv);
327 :
328 0 : return urifixup->CreateExposableURI(uri, aURI);
329 : }
330 :
331 : nsresult
332 0 : nsLocation::GetWritableURI(nsIURI** aURI)
333 : {
334 0 : *aURI = nsnull;
335 :
336 0 : nsCOMPtr<nsIURI> uri;
337 :
338 0 : nsresult rv = GetURI(getter_AddRefs(uri));
339 0 : if (NS_FAILED(rv) || !uri) {
340 0 : return rv;
341 : }
342 :
343 0 : return uri->Clone(aURI);
344 : }
345 :
346 : nsresult
347 0 : nsLocation::SetURI(nsIURI* aURI, bool aReplace)
348 : {
349 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
350 0 : if (docShell) {
351 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
352 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
353 :
354 0 : if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
355 0 : return NS_ERROR_FAILURE;
356 :
357 0 : if (aReplace) {
358 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace);
359 : } else {
360 0 : loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
361 : }
362 :
363 0 : return docShell->LoadURI(aURI, loadInfo,
364 0 : nsIWebNavigation::LOAD_FLAGS_NONE, true);
365 : }
366 :
367 0 : return NS_OK;
368 : }
369 :
370 : NS_IMETHODIMP
371 0 : nsLocation::GetHash(nsAString& aHash)
372 : {
373 0 : aHash.SetLength(0);
374 :
375 0 : nsCOMPtr<nsIURI> uri;
376 0 : nsresult rv = GetURI(getter_AddRefs(uri));
377 0 : if (NS_FAILED(rv) || !uri) {
378 0 : return rv;
379 : }
380 :
381 0 : nsCAutoString ref;
382 0 : nsAutoString unicodeRef;
383 :
384 0 : rv = uri->GetRef(ref);
385 0 : if (NS_SUCCEEDED(rv)) {
386 : nsCOMPtr<nsITextToSubURI> textToSubURI(
387 0 : do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
388 :
389 0 : if (NS_SUCCEEDED(rv)) {
390 0 : nsCAutoString charset;
391 0 : uri->GetOriginCharset(charset);
392 :
393 0 : rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef);
394 : }
395 :
396 0 : if (NS_FAILED(rv)) {
397 : // Oh, well. No intl here!
398 0 : NS_UnescapeURL(ref);
399 0 : CopyASCIItoUTF16(ref, unicodeRef);
400 0 : rv = NS_OK;
401 : }
402 : }
403 :
404 0 : if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) {
405 0 : aHash.Assign(PRUnichar('#'));
406 0 : aHash.Append(unicodeRef);
407 : }
408 :
409 0 : if (aHash == mCachedHash) {
410 : // Work around ShareThis stupidly polling location.hash every
411 : // 5ms all the time by handing out the same exact string buffer
412 : // we handed out last time.
413 0 : aHash = mCachedHash;
414 : } else {
415 0 : mCachedHash = aHash;
416 : }
417 :
418 0 : return rv;
419 : }
420 :
421 : NS_IMETHODIMP
422 0 : nsLocation::SetHash(const nsAString& aHash)
423 : {
424 0 : nsCOMPtr<nsIURI> uri;
425 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
426 0 : if (NS_FAILED(rv) || !uri) {
427 0 : return rv;
428 : }
429 :
430 0 : NS_ConvertUTF16toUTF8 hash(aHash);
431 0 : if (hash.IsEmpty() || hash.First() != PRUnichar('#')) {
432 0 : hash.Insert(PRUnichar('#'), 0);
433 : }
434 0 : rv = uri->SetRef(hash);
435 0 : if (NS_SUCCEEDED(rv)) {
436 0 : SetURI(uri);
437 : }
438 :
439 0 : return rv;
440 : }
441 :
442 : NS_IMETHODIMP
443 0 : nsLocation::GetHost(nsAString& aHost)
444 : {
445 0 : aHost.Truncate();
446 :
447 0 : nsCOMPtr<nsIURI> uri;
448 : nsresult result;
449 :
450 0 : result = GetURI(getter_AddRefs(uri), true);
451 :
452 0 : if (uri) {
453 0 : nsCAutoString hostport;
454 :
455 0 : result = uri->GetHostPort(hostport);
456 :
457 0 : if (NS_SUCCEEDED(result)) {
458 0 : AppendUTF8toUTF16(hostport, aHost);
459 : }
460 : }
461 :
462 0 : return NS_OK;
463 : }
464 :
465 : NS_IMETHODIMP
466 0 : nsLocation::SetHost(const nsAString& aHost)
467 : {
468 0 : nsCOMPtr<nsIURI> uri;
469 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
470 :
471 0 : if (uri) {
472 0 : rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
473 0 : if (NS_SUCCEEDED(rv)) {
474 0 : SetURI(uri);
475 : }
476 : }
477 :
478 0 : return rv;
479 : }
480 :
481 : NS_IMETHODIMP
482 0 : nsLocation::GetHostname(nsAString& aHostname)
483 : {
484 0 : aHostname.Truncate();
485 :
486 0 : nsCOMPtr<nsIURI> uri;
487 : nsresult result;
488 :
489 0 : result = GetURI(getter_AddRefs(uri), true);
490 :
491 0 : if (uri) {
492 0 : nsCAutoString host;
493 :
494 0 : result = uri->GetHost(host);
495 :
496 0 : if (NS_SUCCEEDED(result)) {
497 0 : AppendUTF8toUTF16(host, aHostname);
498 : }
499 : }
500 :
501 0 : return NS_OK;
502 : }
503 :
504 : NS_IMETHODIMP
505 0 : nsLocation::SetHostname(const nsAString& aHostname)
506 : {
507 0 : nsCOMPtr<nsIURI> uri;
508 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
509 :
510 0 : if (uri) {
511 0 : rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
512 0 : if (NS_SUCCEEDED(rv)) {
513 0 : SetURI(uri);
514 : }
515 : }
516 :
517 0 : return rv;
518 : }
519 :
520 : NS_IMETHODIMP
521 0 : nsLocation::GetHref(nsAString& aHref)
522 : {
523 0 : aHref.Truncate();
524 :
525 0 : nsCOMPtr<nsIURI> uri;
526 : nsresult result;
527 :
528 0 : result = GetURI(getter_AddRefs(uri));
529 :
530 0 : if (uri) {
531 0 : nsCAutoString uriString;
532 :
533 0 : result = uri->GetSpec(uriString);
534 :
535 0 : if (NS_SUCCEEDED(result)) {
536 0 : AppendUTF8toUTF16(uriString, aHref);
537 : }
538 : }
539 :
540 0 : return result;
541 : }
542 :
543 : NS_IMETHODIMP
544 0 : nsLocation::SetHref(const nsAString& aHref)
545 : {
546 0 : nsAutoString oldHref;
547 0 : nsresult rv = NS_OK;
548 :
549 : // Get JSContext from stack.
550 : nsCOMPtr<nsIJSContextStack>
551 0 : stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv));
552 :
553 0 : if (NS_FAILED(rv))
554 0 : return NS_ERROR_FAILURE;
555 :
556 : JSContext *cx;
557 :
558 0 : if (NS_FAILED(GetContextFromStack(stack, &cx)))
559 0 : return NS_ERROR_FAILURE;
560 :
561 0 : if (cx) {
562 0 : rv = SetHrefWithContext(cx, aHref, false);
563 : } else {
564 0 : rv = GetHref(oldHref);
565 :
566 0 : if (NS_SUCCEEDED(rv)) {
567 0 : nsCOMPtr<nsIURI> oldUri;
568 :
569 0 : rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
570 :
571 0 : if (oldUri) {
572 0 : rv = SetHrefWithBase(aHref, oldUri, false);
573 : }
574 : }
575 : }
576 :
577 0 : return rv;
578 : }
579 :
580 : nsresult
581 0 : nsLocation::SetHrefWithContext(JSContext* cx, const nsAString& aHref,
582 : bool aReplace)
583 : {
584 0 : nsCOMPtr<nsIURI> base;
585 :
586 : // Get the source of the caller
587 0 : nsresult result = GetSourceBaseURL(cx, getter_AddRefs(base));
588 :
589 0 : if (NS_FAILED(result)) {
590 0 : return result;
591 : }
592 :
593 0 : return SetHrefWithBase(aHref, base, aReplace);
594 : }
595 :
596 : nsresult
597 0 : nsLocation::SetHrefWithBase(const nsAString& aHref, nsIURI* aBase,
598 : bool aReplace)
599 : {
600 : nsresult result;
601 0 : nsCOMPtr<nsIURI> newUri;
602 :
603 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
604 :
605 0 : nsCAutoString docCharset;
606 0 : if (NS_SUCCEEDED(GetDocumentCharacterSetForURI(aHref, docCharset)))
607 0 : result = NS_NewURI(getter_AddRefs(newUri), aHref, docCharset.get(), aBase);
608 : else
609 0 : result = NS_NewURI(getter_AddRefs(newUri), aHref, nsnull, aBase);
610 :
611 0 : if (newUri) {
612 : /* Check with the scriptContext if it is currently processing a script tag.
613 : * If so, this must be a <script> tag with a location.href in it.
614 : * we want to do a replace load, in such a situation.
615 : * In other cases, for example if a event handler or a JS timer
616 : * had a location.href in it, we want to do a normal load,
617 : * so that the new url will be appended to Session History.
618 : * This solution is tricky. Hopefully it isn't going to bite
619 : * anywhere else. This is part of solution for bug # 39938, 72197
620 : *
621 : */
622 0 : bool inScriptTag=false;
623 : // Get JSContext from stack.
624 0 : nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1", &result));
625 :
626 0 : if (stack) {
627 : JSContext *cx;
628 :
629 0 : result = GetContextFromStack(stack, &cx);
630 0 : if (cx) {
631 : nsIScriptContext *scriptContext =
632 0 : nsJSUtils::GetDynamicScriptContext(cx);
633 :
634 0 : if (scriptContext) {
635 0 : if (scriptContext->GetProcessingScriptTag()) {
636 : // Now check to make sure that the script is running in our window,
637 : // since we only want to replace if the location is set by a
638 : // <script> tag in the same window. See bug 178729.
639 0 : nsCOMPtr<nsIScriptGlobalObject> ourGlobal(do_GetInterface(docShell));
640 0 : inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
641 : }
642 : }
643 : } //cx
644 : } // stack
645 :
646 0 : return SetURI(newUri, aReplace || inScriptTag);
647 : }
648 :
649 0 : return result;
650 : }
651 :
652 : NS_IMETHODIMP
653 0 : nsLocation::GetPathname(nsAString& aPathname)
654 : {
655 0 : aPathname.Truncate();
656 :
657 0 : nsCOMPtr<nsIURI> uri;
658 0 : nsresult result = NS_OK;
659 :
660 0 : result = GetURI(getter_AddRefs(uri));
661 :
662 0 : nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
663 0 : if (url) {
664 0 : nsCAutoString file;
665 :
666 0 : result = url->GetFilePath(file);
667 :
668 0 : if (NS_SUCCEEDED(result)) {
669 0 : AppendUTF8toUTF16(file, aPathname);
670 : }
671 : }
672 :
673 0 : return result;
674 : }
675 :
676 : NS_IMETHODIMP
677 0 : nsLocation::SetPathname(const nsAString& aPathname)
678 : {
679 0 : nsCOMPtr<nsIURI> uri;
680 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
681 :
682 0 : if (uri) {
683 0 : rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname));
684 0 : if (NS_SUCCEEDED(rv)) {
685 0 : SetURI(uri);
686 : }
687 : }
688 :
689 0 : return rv;
690 : }
691 :
692 : NS_IMETHODIMP
693 0 : nsLocation::GetPort(nsAString& aPort)
694 : {
695 0 : aPort.SetLength(0);
696 :
697 0 : nsCOMPtr<nsIURI> uri;
698 0 : nsresult result = NS_OK;
699 :
700 0 : result = GetURI(getter_AddRefs(uri), true);
701 :
702 0 : if (uri) {
703 : PRInt32 port;
704 0 : result = uri->GetPort(&port);
705 :
706 0 : if (NS_SUCCEEDED(result) && -1 != port) {
707 0 : nsAutoString portStr;
708 0 : portStr.AppendInt(port);
709 0 : aPort.Append(portStr);
710 : }
711 :
712 : // Don't propagate this exception to caller
713 0 : result = NS_OK;
714 : }
715 :
716 0 : return result;
717 : }
718 :
719 : NS_IMETHODIMP
720 0 : nsLocation::SetPort(const nsAString& aPort)
721 : {
722 0 : nsCOMPtr<nsIURI> uri;
723 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
724 :
725 0 : if (uri) {
726 : // perhaps use nsReadingIterators at some point?
727 0 : NS_ConvertUTF16toUTF8 portStr(aPort);
728 0 : const char *buf = portStr.get();
729 0 : PRInt32 port = -1;
730 :
731 0 : if (buf) {
732 0 : if (*buf == ':') {
733 0 : port = atol(buf+1);
734 : }
735 : else {
736 0 : port = atol(buf);
737 : }
738 : }
739 :
740 0 : rv = uri->SetPort(port);
741 0 : if (NS_SUCCEEDED(rv)) {
742 0 : SetURI(uri);
743 : }
744 : }
745 :
746 0 : return rv;
747 : }
748 :
749 : NS_IMETHODIMP
750 0 : nsLocation::GetProtocol(nsAString& aProtocol)
751 : {
752 0 : aProtocol.SetLength(0);
753 :
754 0 : nsCOMPtr<nsIURI> uri;
755 0 : nsresult result = NS_OK;
756 :
757 0 : result = GetURI(getter_AddRefs(uri));
758 :
759 0 : if (uri) {
760 0 : nsCAutoString protocol;
761 :
762 0 : result = uri->GetScheme(protocol);
763 :
764 0 : if (NS_SUCCEEDED(result)) {
765 0 : CopyASCIItoUTF16(protocol, aProtocol);
766 0 : aProtocol.Append(PRUnichar(':'));
767 : }
768 : }
769 :
770 0 : return result;
771 : }
772 :
773 : NS_IMETHODIMP
774 0 : nsLocation::SetProtocol(const nsAString& aProtocol)
775 : {
776 0 : nsCOMPtr<nsIURI> uri;
777 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
778 :
779 0 : if (uri) {
780 0 : rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol));
781 0 : if (NS_SUCCEEDED(rv)) {
782 0 : SetURI(uri);
783 : }
784 : }
785 :
786 0 : return rv;
787 : }
788 :
789 : NS_IMETHODIMP
790 0 : nsLocation::GetSearch(nsAString& aSearch)
791 : {
792 0 : aSearch.SetLength(0);
793 :
794 0 : nsCOMPtr<nsIURI> uri;
795 0 : nsresult result = NS_OK;
796 :
797 0 : result = GetURI(getter_AddRefs(uri));
798 :
799 0 : nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
800 :
801 0 : if (url) {
802 0 : nsCAutoString search;
803 :
804 0 : result = url->GetQuery(search);
805 :
806 0 : if (NS_SUCCEEDED(result) && !search.IsEmpty()) {
807 0 : aSearch.Assign(PRUnichar('?'));
808 0 : AppendUTF8toUTF16(search, aSearch);
809 : }
810 : }
811 :
812 0 : return NS_OK;
813 : }
814 :
815 : NS_IMETHODIMP
816 0 : nsLocation::SetSearch(const nsAString& aSearch)
817 : {
818 0 : nsCOMPtr<nsIURI> uri;
819 0 : nsresult rv = GetWritableURI(getter_AddRefs(uri));
820 :
821 0 : nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
822 0 : if (url) {
823 0 : rv = url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
824 0 : if (NS_SUCCEEDED(rv)) {
825 0 : SetURI(uri);
826 : }
827 : }
828 :
829 0 : return rv;
830 : }
831 :
832 : NS_IMETHODIMP
833 0 : nsLocation::Reload(bool aForceget)
834 : {
835 : nsresult rv;
836 0 : nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
837 0 : nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
838 0 : nsCOMPtr<nsPIDOMWindow> window(do_GetInterface(docShell));
839 :
840 0 : if (window && window->IsHandlingResizeEvent()) {
841 : // location.reload() was called on a window that is handling a
842 : // resize event. Sites do this since Netscape 4.x needed it, but
843 : // we don't, and it's a horrible experience for nothing. In stead
844 : // of reloading the page, just clear style data and reflow the
845 : // page since some sites may use this trick to work around gecko
846 : // reflow bugs, and this should have the same effect.
847 :
848 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
849 :
850 : nsIPresShell *shell;
851 : nsPresContext *pcx;
852 0 : if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
853 0 : pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
854 : }
855 :
856 0 : return NS_OK;
857 : }
858 :
859 0 : if (webNav) {
860 0 : PRUint32 reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
861 :
862 0 : if (aForceget) {
863 : reloadFlags = nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE |
864 0 : nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY;
865 : }
866 0 : rv = webNav->Reload(reloadFlags);
867 0 : if (rv == NS_BINDING_ABORTED) {
868 : // This happens when we attempt to reload a POST result and the user says
869 : // no at the "do you want to reload?" prompt. Don't propagate this one
870 : // back to callers.
871 0 : rv = NS_OK;
872 : }
873 : } else {
874 0 : rv = NS_ERROR_FAILURE;
875 : }
876 :
877 0 : return rv;
878 : }
879 :
880 : NS_IMETHODIMP
881 0 : nsLocation::Replace(const nsAString& aUrl)
882 : {
883 0 : nsresult rv = NS_OK;
884 :
885 : // Get JSContext from stack.
886 : nsCOMPtr<nsIJSContextStack>
887 0 : stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
888 :
889 0 : if (stack) {
890 : JSContext *cx;
891 :
892 0 : rv = GetContextFromStack(stack, &cx);
893 0 : NS_ENSURE_SUCCESS(rv, rv);
894 0 : if (cx) {
895 0 : return SetHrefWithContext(cx, aUrl, true);
896 : }
897 : }
898 :
899 0 : nsAutoString oldHref;
900 :
901 0 : rv = GetHref(oldHref);
902 0 : NS_ENSURE_SUCCESS(rv, rv);
903 :
904 0 : nsCOMPtr<nsIURI> oldUri;
905 :
906 0 : rv = NS_NewURI(getter_AddRefs(oldUri), oldHref);
907 0 : NS_ENSURE_SUCCESS(rv, rv);
908 :
909 0 : return SetHrefWithBase(aUrl, oldUri, true);
910 : }
911 :
912 : NS_IMETHODIMP
913 0 : nsLocation::Assign(const nsAString& aUrl)
914 : {
915 0 : nsAutoString oldHref;
916 0 : nsresult result = NS_OK;
917 :
918 0 : result = GetHref(oldHref);
919 :
920 0 : if (NS_SUCCEEDED(result)) {
921 0 : nsCOMPtr<nsIURI> oldUri;
922 :
923 0 : result = NS_NewURI(getter_AddRefs(oldUri), oldHref);
924 :
925 0 : if (oldUri) {
926 0 : result = SetHrefWithBase(aUrl, oldUri, false);
927 : }
928 : }
929 :
930 0 : return result;
931 : }
932 :
933 : NS_IMETHODIMP
934 0 : nsLocation::ToString(nsAString& aReturn)
935 : {
936 0 : return GetHref(aReturn);
937 : }
938 :
939 : nsresult
940 0 : nsLocation::GetSourceDocument(JSContext* cx, nsIDocument** aDocument)
941 : {
942 : // XXX Code duplicated from nsHTMLDocument
943 : // XXX Tom said this reminded him of the "Six Degrees of
944 : // Kevin Bacon" game. We try to get from here to there using
945 : // whatever connections possible. The problem is that this
946 : // could break if any of the connections along the way change.
947 : // I wish there were a better way.
948 :
949 0 : nsresult rv = NS_ERROR_FAILURE;
950 :
951 : // We need to use the dynamically scoped global and assume that the
952 : // current JSContext is a DOM context with a nsIScriptGlobalObject so
953 : // that we can get the url of the caller.
954 : // XXX This will fail on non-DOM contexts :(
955 :
956 : nsCOMPtr<nsIDOMWindow> window =
957 0 : do_QueryInterface(nsJSUtils::GetDynamicScriptGlobal(cx), &rv);
958 :
959 0 : if (window) {
960 0 : nsCOMPtr<nsIDOMDocument> domDoc;
961 0 : rv = window->GetDocument(getter_AddRefs(domDoc));
962 0 : if (domDoc) {
963 0 : return CallQueryInterface(domDoc, aDocument);
964 : }
965 : } else {
966 0 : *aDocument = nsnull;
967 : }
968 :
969 0 : return rv;
970 : }
971 :
972 : nsresult
973 0 : nsLocation::GetSourceBaseURL(JSContext* cx, nsIURI** sourceURL)
974 : {
975 0 : nsCOMPtr<nsIDocument> doc;
976 0 : nsresult rv = GetSourceDocument(cx, getter_AddRefs(doc));
977 0 : if (doc) {
978 0 : *sourceURL = doc->GetBaseURI().get();
979 : } else {
980 0 : *sourceURL = nsnull;
981 : }
982 :
983 0 : return rv;
984 : }
|