Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=4 sw=4 et tw=78: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsCOMPtr.h"
8 : #include "jsapi.h"
9 : #include "jswrapper.h"
10 : #include "nsCRT.h"
11 : #include "nsError.h"
12 : #include "nsXPIDLString.h"
13 : #include "nsReadableUtils.h"
14 : #include "nsJSProtocolHandler.h"
15 : #include "nsStringStream.h"
16 : #include "nsNetUtil.h"
17 :
18 : #include "nsIStreamListener.h"
19 : #include "nsIComponentManager.h"
20 : #include "nsIServiceManager.h"
21 : #include "nsIURI.h"
22 : #include "nsIScriptContext.h"
23 : #include "nsIScriptGlobalObject.h"
24 : #include "nsIPrincipal.h"
25 : #include "nsIScriptSecurityManager.h"
26 : #include "nsIInterfaceRequestor.h"
27 : #include "nsIInterfaceRequestorUtils.h"
28 : #include "nsIWindowMediator.h"
29 : #include "nsPIDOMWindow.h"
30 : #include "nsIConsoleService.h"
31 : #include "nsXPIDLString.h"
32 : #include "nsEscape.h"
33 : #include "nsIWebNavigation.h"
34 : #include "nsIDocShell.h"
35 : #include "nsIContentViewer.h"
36 : #include "nsIXPConnect.h"
37 : #include "nsContentUtils.h"
38 : #include "nsJSUtils.h"
39 : #include "nsThreadUtils.h"
40 : #include "nsIScriptChannel.h"
41 : #include "nsIDocument.h"
42 : #include "nsILoadInfo.h"
43 : #include "nsIObjectInputStream.h"
44 : #include "nsIObjectOutputStream.h"
45 : #include "nsIWritablePropertyBag2.h"
46 : #include "nsIContentSecurityPolicy.h"
47 : #include "nsSandboxFlags.h"
48 : #include "mozilla/dom/ScriptSettings.h"
49 : #include "nsILoadInfo.h"
50 : #include "nsContentSecurityManager.h"
51 :
52 : #include "mozilla/ipc/URIUtils.h"
53 :
54 : using mozilla::dom::AutoEntryScript;
55 :
56 : static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID);
57 :
58 : class nsJSThunk : public nsIInputStream
59 : {
60 : public:
61 : nsJSThunk();
62 :
63 : NS_DECL_THREADSAFE_ISUPPORTS
64 0 : NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream)
65 :
66 : nsresult Init(nsIURI* uri);
67 : nsresult EvaluateScript(nsIChannel *aChannel,
68 : PopupControlState aPopupState,
69 : uint32_t aExecutionPolicy,
70 : nsPIDOMWindowInner *aOriginalInnerWindow);
71 :
72 : protected:
73 : virtual ~nsJSThunk();
74 :
75 : nsCOMPtr<nsIInputStream> mInnerStream;
76 : nsCString mScript;
77 : nsCString mURL;
78 : };
79 :
80 : //
81 : // nsISupports implementation...
82 : //
83 0 : NS_IMPL_ISUPPORTS(nsJSThunk, nsIInputStream)
84 :
85 :
86 0 : nsJSThunk::nsJSThunk()
87 : {
88 0 : }
89 :
90 0 : nsJSThunk::~nsJSThunk()
91 : {
92 0 : }
93 :
94 0 : nsresult nsJSThunk::Init(nsIURI* uri)
95 : {
96 0 : NS_ENSURE_ARG_POINTER(uri);
97 :
98 : // Get the script string to evaluate...
99 0 : nsresult rv = uri->GetPath(mScript);
100 0 : if (NS_FAILED(rv)) return rv;
101 :
102 : // Get the url.
103 0 : rv = uri->GetSpec(mURL);
104 0 : if (NS_FAILED(rv)) return rv;
105 :
106 0 : return NS_OK;
107 : }
108 :
109 : static bool
110 0 : IsISO88591(const nsString& aString)
111 : {
112 0 : for (nsString::const_char_iterator c = aString.BeginReading(),
113 0 : c_end = aString.EndReading();
114 0 : c < c_end; ++c) {
115 0 : if (*c > 255)
116 0 : return false;
117 : }
118 0 : return true;
119 : }
120 :
121 : static
122 0 : nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel)
123 : {
124 : // Get the global object owner from the channel
125 0 : nsCOMPtr<nsIDocShell> docShell;
126 0 : NS_QueryNotificationCallbacks(aChannel, docShell);
127 0 : if (!docShell) {
128 0 : NS_WARNING("Unable to get a docShell from the channel!");
129 0 : return nullptr;
130 : }
131 :
132 : // So far so good: get the script global from its docshell
133 0 : nsIScriptGlobalObject* global = docShell->GetScriptGlobalObject();
134 :
135 0 : NS_ASSERTION(global,
136 : "Unable to get an nsIScriptGlobalObject from the "
137 : "docShell!");
138 0 : return global;
139 : }
140 :
141 0 : nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
142 : PopupControlState aPopupState,
143 : uint32_t aExecutionPolicy,
144 : nsPIDOMWindowInner *aOriginalInnerWindow)
145 : {
146 0 : if (aExecutionPolicy == nsIScriptChannel::NO_EXECUTION) {
147 : // Nothing to do here.
148 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
149 : }
150 :
151 0 : NS_ENSURE_ARG_POINTER(aChannel);
152 :
153 : // Get principal of code for execution
154 0 : nsCOMPtr<nsISupports> owner;
155 0 : aChannel->GetOwner(getter_AddRefs(owner));
156 0 : nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
157 0 : if (!principal) {
158 0 : nsCOMPtr<nsILoadInfo> loadInfo;
159 0 : aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
160 0 : if (loadInfo && loadInfo->GetForceInheritPrincipal()) {
161 0 : principal = loadInfo->PrincipalToInherit();
162 0 : if (!principal) {
163 0 : principal = loadInfo->TriggeringPrincipal();
164 : }
165 : } else {
166 : // No execution without a principal!
167 0 : NS_ASSERTION(!owner, "Non-principal owner?");
168 0 : NS_WARNING("No principal to execute JS with");
169 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
170 : }
171 : }
172 :
173 : nsresult rv;
174 :
175 : // CSP check: javascript: URIs disabled unless "inline" scripts are
176 : // allowed.
177 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
178 0 : rv = principal->GetCsp(getter_AddRefs(csp));
179 0 : NS_ENSURE_SUCCESS(rv, rv);
180 0 : if (csp) {
181 0 : bool allowsInlineScript = true;
182 0 : rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
183 0 : EmptyString(), // aNonce
184 : true, // aParserCreated
185 0 : EmptyString(), // aContent
186 : 0, // aLineNumber
187 0 : &allowsInlineScript);
188 :
189 : //return early if inline scripts are not allowed
190 0 : if (!allowsInlineScript) {
191 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
192 : }
193 : }
194 :
195 : // Get the global object we should be running on.
196 0 : nsIScriptGlobalObject* global = GetGlobalObject(aChannel);
197 0 : if (!global) {
198 0 : return NS_ERROR_FAILURE;
199 : }
200 :
201 : // Sandboxed document check: javascript: URI's are disabled
202 : // in a sandboxed document unless 'allow-scripts' was specified.
203 0 : nsIDocument* doc = aOriginalInnerWindow->GetExtantDoc();
204 0 : if (doc && doc->HasScriptsBlockedBySandbox()) {
205 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
206 : }
207 :
208 : // Push our popup control state
209 0 : nsAutoPopupStatePusher popupStatePusher(aPopupState);
210 :
211 : // Make sure we still have the same inner window as we used to.
212 0 : nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(global);
213 0 : nsPIDOMWindowInner *innerWin = win->GetCurrentInnerWindow();
214 :
215 0 : if (innerWin != aOriginalInnerWindow) {
216 0 : return NS_ERROR_UNEXPECTED;
217 : }
218 :
219 0 : nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin);
220 :
221 0 : mozilla::DebugOnly<nsCOMPtr<nsIDOMWindow>> domWindow(do_QueryInterface(global, &rv));
222 0 : if (NS_FAILED(rv)) {
223 0 : return NS_ERROR_FAILURE;
224 : }
225 :
226 : // So far so good: get the script context from its owner.
227 0 : nsCOMPtr<nsIScriptContext> scriptContext = global->GetContext();
228 0 : if (!scriptContext)
229 0 : return NS_ERROR_FAILURE;
230 :
231 0 : nsAutoCString script(mScript);
232 : // Unescape the script
233 0 : NS_UnescapeURL(script);
234 :
235 :
236 0 : nsCOMPtr<nsIScriptSecurityManager> securityManager;
237 0 : securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
238 0 : if (NS_FAILED(rv))
239 0 : return rv;
240 :
241 : // New script entry point required, due to the "Create a script" step of
242 : // http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
243 0 : nsAutoMicroTask mt;
244 0 : AutoEntryScript aes(innerGlobal, "javascript: URI", true);
245 0 : JSContext* cx = aes.cx();
246 0 : JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
247 0 : NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
248 :
249 : //-- Don't execute unless the script principal subsumes the
250 : // principal of the context.
251 0 : nsIPrincipal* objectPrincipal = nsContentUtils::ObjectPrincipal(globalJSObject);
252 :
253 : bool subsumes;
254 0 : rv = principal->Subsumes(objectPrincipal, &subsumes);
255 0 : if (NS_FAILED(rv))
256 0 : return rv;
257 :
258 0 : if (!subsumes) {
259 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
260 : }
261 :
262 : // Fail if someone tries to execute in a global with system principal.
263 0 : if (nsContentUtils::IsSystemPrincipal(objectPrincipal)) {
264 0 : return NS_ERROR_DOM_SECURITY_ERR;
265 : }
266 :
267 0 : JS::Rooted<JS::Value> v (cx, JS::UndefinedValue());
268 : // Finally, we have everything needed to evaluate the expression.
269 0 : JS::CompileOptions options(cx);
270 0 : options.setFileAndLine(mURL.get(), 1)
271 0 : .setVersion(JSVERSION_DEFAULT);
272 : {
273 0 : nsJSUtils::ExecutionContext exec(cx, globalJSObject);
274 0 : exec.SetCoerceToString(true);
275 0 : exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script));
276 0 : rv = exec.ExtractReturnValue(&v);
277 : }
278 :
279 0 : js::AssertSameCompartment(cx, v);
280 :
281 0 : if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
282 0 : return NS_ERROR_MALFORMED_URI;
283 0 : } else if (v.isUndefined()) {
284 0 : return NS_ERROR_DOM_RETVAL_UNDEFINED;
285 : } else {
286 0 : MOZ_ASSERT(rv != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW,
287 : "How did we get a non-undefined return value?");
288 0 : nsAutoJSString result;
289 0 : if (!result.init(cx, v)) {
290 0 : return NS_ERROR_OUT_OF_MEMORY;
291 : }
292 :
293 : char *bytes;
294 : uint32_t bytesLen;
295 0 : NS_NAMED_LITERAL_CSTRING(isoCharset, "windows-1252");
296 0 : NS_NAMED_LITERAL_CSTRING(utf8Charset, "UTF-8");
297 : const nsLiteralCString *charset;
298 0 : if (IsISO88591(result)) {
299 : // For compatibility, if the result is ISO-8859-1, we use
300 : // windows-1252, so that people can compatibly create images
301 : // using javascript: URLs.
302 0 : bytes = ToNewCString(result);
303 0 : bytesLen = result.Length();
304 0 : charset = &isoCharset;
305 : }
306 : else {
307 0 : bytes = ToNewUTF8String(result, &bytesLen);
308 0 : charset = &utf8Charset;
309 : }
310 0 : aChannel->SetContentCharset(*charset);
311 0 : if (bytes)
312 0 : rv = NS_NewByteInputStream(getter_AddRefs(mInnerStream),
313 : bytes, bytesLen,
314 : NS_ASSIGNMENT_ADOPT);
315 : else
316 0 : rv = NS_ERROR_OUT_OF_MEMORY;
317 : }
318 :
319 0 : return rv;
320 : }
321 :
322 : ////////////////////////////////////////////////////////////////////////////////
323 :
324 : class nsJSChannel : public nsIChannel,
325 : public nsIStreamListener,
326 : public nsIScriptChannel,
327 : public nsIPropertyBag2
328 : {
329 : public:
330 : nsJSChannel();
331 :
332 : NS_DECL_ISUPPORTS
333 : NS_DECL_NSIREQUEST
334 : NS_DECL_NSICHANNEL
335 : NS_DECL_NSIREQUESTOBSERVER
336 : NS_DECL_NSISTREAMLISTENER
337 : NS_DECL_NSISCRIPTCHANNEL
338 0 : NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag)
339 0 : NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag)
340 :
341 : nsresult Init(nsIURI *aURI, nsILoadInfo* aLoadInfo);
342 :
343 : // Actually evaluate the script.
344 : void EvaluateScript();
345 :
346 : protected:
347 : virtual ~nsJSChannel();
348 :
349 : nsresult StopAll();
350 :
351 : void NotifyListener();
352 :
353 : void CleanupStrongRefs();
354 :
355 : protected:
356 : nsCOMPtr<nsIChannel> mStreamChannel;
357 : nsCOMPtr<nsIPropertyBag2> mPropertyBag;
358 : nsCOMPtr<nsIStreamListener> mListener; // Our final listener
359 : nsCOMPtr<nsPIDOMWindowInner> mOriginalInnerWindow; // The inner window our load
360 : // started against.
361 : // If we blocked onload on a document in AsyncOpen2, this is the document we
362 : // did it on.
363 : nsCOMPtr<nsIDocument> mDocumentOnloadBlockedOn;
364 :
365 : nsresult mStatus; // Our status
366 :
367 : nsLoadFlags mLoadFlags;
368 : nsLoadFlags mActualLoadFlags; // See AsyncOpen2
369 :
370 : RefPtr<nsJSThunk> mIOThunk;
371 : PopupControlState mPopupState;
372 : uint32_t mExecutionPolicy;
373 : bool mIsAsync;
374 : bool mIsActive;
375 : bool mOpenedStreamChannel;
376 : };
377 :
378 0 : nsJSChannel::nsJSChannel() :
379 : mStatus(NS_OK),
380 : mLoadFlags(LOAD_NORMAL),
381 : mActualLoadFlags(LOAD_NORMAL),
382 : mPopupState(openOverridden),
383 : mExecutionPolicy(NO_EXECUTION),
384 : mIsAsync(true),
385 : mIsActive(false),
386 0 : mOpenedStreamChannel(false)
387 : {
388 0 : }
389 :
390 0 : nsJSChannel::~nsJSChannel()
391 : {
392 0 : }
393 :
394 0 : nsresult nsJSChannel::StopAll()
395 : {
396 0 : nsresult rv = NS_ERROR_UNEXPECTED;
397 0 : nsCOMPtr<nsIWebNavigation> webNav;
398 0 : NS_QueryNotificationCallbacks(mStreamChannel, webNav);
399 :
400 0 : NS_ASSERTION(webNav, "Can't get nsIWebNavigation from channel!");
401 0 : if (webNav) {
402 0 : rv = webNav->Stop(nsIWebNavigation::STOP_ALL);
403 : }
404 :
405 0 : return rv;
406 : }
407 :
408 0 : nsresult nsJSChannel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo)
409 : {
410 0 : RefPtr<nsJSURI> jsURI;
411 0 : nsresult rv = aURI->QueryInterface(kJSURICID,
412 0 : getter_AddRefs(jsURI));
413 0 : NS_ENSURE_SUCCESS(rv, rv);
414 :
415 : // Create the nsIStreamIO layer used by the nsIStreamIOChannel.
416 0 : mIOThunk = new nsJSThunk();
417 :
418 : // Create a stock input stream channel...
419 : // Remember, until AsyncOpen is called, the script will not be evaluated
420 : // and the underlying Input Stream will not be created...
421 0 : nsCOMPtr<nsIChannel> channel;
422 0 : rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
423 : aURI,
424 : mIOThunk,
425 0 : NS_LITERAL_CSTRING("text/html"),
426 0 : EmptyCString(),
427 0 : aLoadInfo);
428 0 : NS_ENSURE_SUCCESS(rv, rv);
429 :
430 0 : rv = mIOThunk->Init(aURI);
431 0 : if (NS_SUCCEEDED(rv)) {
432 0 : mStreamChannel = channel;
433 0 : mPropertyBag = do_QueryInterface(channel);
434 : nsCOMPtr<nsIWritablePropertyBag2> writableBag =
435 0 : do_QueryInterface(channel);
436 0 : if (writableBag && jsURI->GetBaseURI()) {
437 0 : writableBag->SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
438 0 : jsURI->GetBaseURI());
439 : }
440 : }
441 :
442 0 : return rv;
443 : }
444 :
445 : NS_IMETHODIMP
446 0 : nsJSChannel::GetIsDocument(bool *aIsDocument)
447 : {
448 0 : return NS_GetIsDocumentChannel(this, aIsDocument);
449 : }
450 :
451 : //
452 : // nsISupports implementation...
453 : //
454 :
455 0 : NS_IMPL_ISUPPORTS(nsJSChannel, nsIChannel, nsIRequest, nsIRequestObserver,
456 : nsIStreamListener, nsIScriptChannel, nsIPropertyBag,
457 : nsIPropertyBag2)
458 :
459 : //
460 : // nsIRequest implementation...
461 : //
462 :
463 : NS_IMETHODIMP
464 0 : nsJSChannel::GetName(nsACString &aResult)
465 : {
466 0 : return mStreamChannel->GetName(aResult);
467 : }
468 :
469 : NS_IMETHODIMP
470 0 : nsJSChannel::IsPending(bool *aResult)
471 : {
472 0 : *aResult = mIsActive;
473 0 : return NS_OK;
474 : }
475 :
476 : NS_IMETHODIMP
477 0 : nsJSChannel::GetStatus(nsresult *aResult)
478 : {
479 0 : if (NS_SUCCEEDED(mStatus) && mOpenedStreamChannel) {
480 0 : return mStreamChannel->GetStatus(aResult);
481 : }
482 :
483 0 : *aResult = mStatus;
484 :
485 0 : return NS_OK;
486 : }
487 :
488 : NS_IMETHODIMP
489 0 : nsJSChannel::Cancel(nsresult aStatus)
490 : {
491 0 : mStatus = aStatus;
492 :
493 0 : if (mOpenedStreamChannel) {
494 0 : mStreamChannel->Cancel(aStatus);
495 : }
496 :
497 0 : return NS_OK;
498 : }
499 :
500 : NS_IMETHODIMP
501 0 : nsJSChannel::Suspend()
502 : {
503 0 : return mStreamChannel->Suspend();
504 : }
505 :
506 : NS_IMETHODIMP
507 0 : nsJSChannel::Resume()
508 : {
509 0 : return mStreamChannel->Resume();
510 : }
511 :
512 : //
513 : // nsIChannel implementation
514 : //
515 :
516 : NS_IMETHODIMP
517 0 : nsJSChannel::GetOriginalURI(nsIURI * *aURI)
518 : {
519 0 : return mStreamChannel->GetOriginalURI(aURI);
520 : }
521 :
522 : NS_IMETHODIMP
523 0 : nsJSChannel::SetOriginalURI(nsIURI *aURI)
524 : {
525 0 : return mStreamChannel->SetOriginalURI(aURI);
526 : }
527 :
528 : NS_IMETHODIMP
529 0 : nsJSChannel::GetURI(nsIURI * *aURI)
530 : {
531 0 : return mStreamChannel->GetURI(aURI);
532 : }
533 :
534 : NS_IMETHODIMP
535 0 : nsJSChannel::Open(nsIInputStream **aResult)
536 : {
537 0 : nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
538 : mExecutionPolicy,
539 0 : mOriginalInnerWindow);
540 0 : NS_ENSURE_SUCCESS(rv, rv);
541 :
542 0 : return mStreamChannel->Open(aResult);
543 : }
544 :
545 : NS_IMETHODIMP
546 0 : nsJSChannel::Open2(nsIInputStream** aStream)
547 : {
548 0 : nsCOMPtr<nsIStreamListener> listener;
549 0 : nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
550 0 : NS_ENSURE_SUCCESS(rv, rv);
551 0 : return Open(aStream);
552 : }
553 :
554 : NS_IMETHODIMP
555 0 : nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
556 : {
557 : #ifdef DEBUG
558 : {
559 0 : nsCOMPtr<nsILoadInfo> loadInfo = nsIChannel::GetLoadInfo();
560 0 : MOZ_ASSERT(!loadInfo || loadInfo->GetSecurityMode() == 0 ||
561 : loadInfo->GetInitialSecurityCheckDone(),
562 : "security flags in loadInfo but asyncOpen2() not called");
563 : }
564 : #endif
565 0 : MOZ_RELEASE_ASSERT(!aContext, "please call AsyncOpen2()");
566 :
567 0 : NS_ENSURE_ARG(aListener);
568 :
569 : // First make sure that we have a usable inner window; we'll want to make
570 : // sure that we execute against that inner and no other.
571 0 : nsIScriptGlobalObject* global = GetGlobalObject(this);
572 0 : if (!global) {
573 0 : return NS_ERROR_NOT_AVAILABLE;
574 : }
575 :
576 0 : nsCOMPtr<nsPIDOMWindowOuter> win(do_QueryInterface(global));
577 0 : NS_ASSERTION(win, "Our global is not a window??");
578 :
579 : // Make sure we create a new inner window if one doesn't already exist (see
580 : // bug 306630).
581 0 : mOriginalInnerWindow = win->EnsureInnerWindow();
582 0 : if (!mOriginalInnerWindow) {
583 0 : return NS_ERROR_NOT_AVAILABLE;
584 : }
585 :
586 0 : mListener = aListener;
587 :
588 0 : mIsActive = true;
589 :
590 : // Temporarily set the LOAD_BACKGROUND flag to suppress load group observer
591 : // notifications (and hence nsIWebProgressListener notifications) from
592 : // being dispatched. This is required since we suppress LOAD_DOCUMENT_URI,
593 : // which means that the DocLoader would not generate document start and
594 : // stop notifications (see bug 257875).
595 0 : mActualLoadFlags = mLoadFlags;
596 0 : mLoadFlags |= LOAD_BACKGROUND;
597 :
598 : // Add the javascript channel to its loadgroup so that we know if
599 : // network loads were canceled or not...
600 0 : nsCOMPtr<nsILoadGroup> loadGroup;
601 0 : mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
602 0 : if (loadGroup) {
603 0 : nsresult rv = loadGroup->AddRequest(this, nullptr);
604 0 : if (NS_FAILED(rv)) {
605 0 : mIsActive = false;
606 0 : CleanupStrongRefs();
607 0 : return rv;
608 : }
609 : }
610 :
611 0 : mDocumentOnloadBlockedOn = mOriginalInnerWindow->GetExtantDoc();
612 0 : if (mDocumentOnloadBlockedOn) {
613 : // If we're a document channel, we need to actually block onload on our
614 : // _parent_ document. This is because we don't actually set our
615 : // LOAD_DOCUMENT_URI flag, so a docloader we're loading in as the
616 : // document channel will claim to not be busy, and our parent's onload
617 : // could fire too early.
618 : nsLoadFlags loadFlags;
619 0 : mStreamChannel->GetLoadFlags(&loadFlags);
620 0 : if (loadFlags & LOAD_DOCUMENT_URI) {
621 : mDocumentOnloadBlockedOn =
622 0 : mDocumentOnloadBlockedOn->GetParentDocument();
623 : }
624 : }
625 0 : if (mDocumentOnloadBlockedOn) {
626 0 : mDocumentOnloadBlockedOn->BlockOnload();
627 : }
628 :
629 :
630 0 : mPopupState = win->GetPopupControlState();
631 :
632 : void (nsJSChannel::*method)();
633 : const char* name;
634 0 : if (mIsAsync) {
635 : // post an event to do the rest
636 0 : method = &nsJSChannel::EvaluateScript;
637 0 : name = "nsJSChannel::EvaluateScript";
638 : } else {
639 0 : EvaluateScript();
640 0 : if (mOpenedStreamChannel) {
641 : // That will handle notifying things
642 0 : return NS_OK;
643 : }
644 :
645 0 : NS_ASSERTION(NS_FAILED(mStatus), "We should have failed _somehow_");
646 :
647 : // mStatus is going to be NS_ERROR_DOM_RETVAL_UNDEFINED if we didn't
648 : // have any content resulting from the execution and NS_BINDING_ABORTED
649 : // if something we did causes our own load to be stopped. Return
650 : // success in those cases, and error out in all others.
651 0 : if (mStatus != NS_ERROR_DOM_RETVAL_UNDEFINED &&
652 0 : mStatus != NS_BINDING_ABORTED) {
653 : // Note that calling EvaluateScript() handled removing us from the
654 : // loadgroup and marking us as not active anymore.
655 0 : CleanupStrongRefs();
656 0 : return mStatus;
657 : }
658 :
659 : // We're returning success from asyncOpen2(), but we didn't open a
660 : // stream channel. We'll have to notify ourselves, but make sure to do
661 : // it asynchronously.
662 0 : method = &nsJSChannel::NotifyListener;
663 0 : name = "nsJSChannel::NotifyListener";
664 : }
665 :
666 0 : nsresult rv = NS_DispatchToCurrentThread(
667 0 : mozilla::NewRunnableMethod(name, this, method));
668 :
669 0 : if (NS_FAILED(rv)) {
670 0 : loadGroup->RemoveRequest(this, nullptr, rv);
671 0 : mIsActive = false;
672 0 : CleanupStrongRefs();
673 : }
674 0 : return rv;
675 : }
676 :
677 : NS_IMETHODIMP
678 0 : nsJSChannel::AsyncOpen2(nsIStreamListener *aListener)
679 : {
680 0 : nsCOMPtr<nsIStreamListener> listener = aListener;
681 0 : nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
682 0 : NS_ENSURE_SUCCESS(rv, rv);
683 0 : return AsyncOpen(listener, nullptr);
684 : }
685 :
686 : void
687 0 : nsJSChannel::EvaluateScript()
688 : {
689 : // Synchronously execute the script...
690 : // mIsActive is used to indicate the the request is 'busy' during the
691 : // the script evaluation phase. This means that IsPending() will
692 : // indicate the the request is busy while the script is executing...
693 :
694 : // Note that we want to be in the loadgroup and pending while we evaluate
695 : // the script, so that we find out if the loadgroup gets canceled by the
696 : // script execution (in which case we shouldn't pump out data even if the
697 : // script returns it).
698 :
699 0 : if (NS_SUCCEEDED(mStatus)) {
700 0 : nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
701 : mExecutionPolicy,
702 0 : mOriginalInnerWindow);
703 :
704 : // Note that evaluation may have canceled us, so recheck mStatus again
705 0 : if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus)) {
706 0 : mStatus = rv;
707 : }
708 : }
709 :
710 : // Remove the javascript channel from its loadgroup...
711 0 : nsCOMPtr<nsILoadGroup> loadGroup;
712 0 : mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
713 0 : if (loadGroup) {
714 0 : loadGroup->RemoveRequest(this, nullptr, mStatus);
715 : }
716 :
717 : // Reset load flags to their original value...
718 0 : mLoadFlags = mActualLoadFlags;
719 :
720 : // We're no longer active, it's now up to the stream channel to do
721 : // the loading, if needed.
722 0 : mIsActive = false;
723 :
724 0 : if (NS_FAILED(mStatus)) {
725 0 : if (mIsAsync) {
726 0 : NotifyListener();
727 : }
728 0 : return;
729 : }
730 :
731 : // EvaluateScript() succeeded, and we were not canceled, that
732 : // means there's data to parse as a result of evaluating the
733 : // script.
734 :
735 : // Get the stream channels load flags (!= mLoadFlags).
736 : nsLoadFlags loadFlags;
737 0 : mStreamChannel->GetLoadFlags(&loadFlags);
738 :
739 : uint32_t disposition;
740 0 : if (NS_FAILED(mStreamChannel->GetContentDisposition(&disposition)))
741 0 : disposition = nsIChannel::DISPOSITION_INLINE;
742 0 : if (loadFlags & LOAD_DOCUMENT_URI && disposition != nsIChannel::DISPOSITION_ATTACHMENT) {
743 : // We're loaded as the document channel and not expecting to download
744 : // the result. If we go on, we'll blow away the current document. Make
745 : // sure that's ok. If so, stop all pending network loads.
746 :
747 0 : nsCOMPtr<nsIDocShell> docShell;
748 0 : NS_QueryNotificationCallbacks(mStreamChannel, docShell);
749 0 : if (docShell) {
750 0 : nsCOMPtr<nsIContentViewer> cv;
751 0 : docShell->GetContentViewer(getter_AddRefs(cv));
752 :
753 0 : if (cv) {
754 : bool okToUnload;
755 :
756 0 : if (NS_SUCCEEDED(cv->PermitUnload(&okToUnload)) &&
757 0 : !okToUnload) {
758 : // The user didn't want to unload the current
759 : // page, translate this into an undefined
760 : // return from the javascript: URL...
761 0 : mStatus = NS_ERROR_DOM_RETVAL_UNDEFINED;
762 : }
763 : }
764 : }
765 :
766 0 : if (NS_SUCCEEDED(mStatus)) {
767 0 : mStatus = StopAll();
768 : }
769 : }
770 :
771 0 : if (NS_FAILED(mStatus)) {
772 0 : if (mIsAsync) {
773 0 : NotifyListener();
774 : }
775 0 : return;
776 : }
777 :
778 0 : mStatus = mStreamChannel->AsyncOpen2(this);
779 0 : if (NS_SUCCEEDED(mStatus)) {
780 : // mStreamChannel will call OnStartRequest and OnStopRequest on
781 : // us, so we'll be sure to call them on our listener.
782 0 : mOpenedStreamChannel = true;
783 :
784 : // Now readd ourselves to the loadgroup so we can receive
785 : // cancellation notifications.
786 0 : mIsActive = true;
787 0 : if (loadGroup) {
788 0 : mStatus = loadGroup->AddRequest(this, nullptr);
789 :
790 : // If AddRequest failed, that's OK. The key is to make sure we get
791 : // cancelled if needed, and that call just canceled us if it
792 : // failed. We'll still get notified by the stream channel when it
793 : // finishes.
794 : }
795 :
796 0 : } else if (mIsAsync) {
797 0 : NotifyListener();
798 : }
799 :
800 0 : return;
801 : }
802 :
803 : void
804 0 : nsJSChannel::NotifyListener()
805 : {
806 0 : mListener->OnStartRequest(this, nullptr);
807 0 : mListener->OnStopRequest(this, nullptr, mStatus);
808 :
809 0 : CleanupStrongRefs();
810 0 : }
811 :
812 : void
813 0 : nsJSChannel::CleanupStrongRefs()
814 : {
815 0 : mListener = nullptr;
816 0 : mOriginalInnerWindow = nullptr;
817 0 : if (mDocumentOnloadBlockedOn) {
818 0 : mDocumentOnloadBlockedOn->UnblockOnload(false);
819 0 : mDocumentOnloadBlockedOn = nullptr;
820 : }
821 0 : }
822 :
823 : NS_IMETHODIMP
824 0 : nsJSChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
825 : {
826 0 : *aLoadFlags = mLoadFlags;
827 :
828 0 : return NS_OK;
829 : }
830 :
831 : NS_IMETHODIMP
832 0 : nsJSChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
833 : {
834 : // Figure out whether the LOAD_BACKGROUND bit in aLoadFlags is
835 : // actually right.
836 0 : bool bogusLoadBackground = false;
837 0 : if (mIsActive && !(mActualLoadFlags & LOAD_BACKGROUND) &&
838 0 : (aLoadFlags & LOAD_BACKGROUND)) {
839 : // We're getting a LOAD_BACKGROUND, but it's probably just our own fake
840 : // flag being mirrored to us. The one exception is if our loadgroup is
841 : // LOAD_BACKGROUND.
842 0 : bool loadGroupIsBackground = false;
843 0 : nsCOMPtr<nsILoadGroup> loadGroup;
844 0 : mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
845 0 : if (loadGroup) {
846 : nsLoadFlags loadGroupFlags;
847 0 : loadGroup->GetLoadFlags(&loadGroupFlags);
848 0 : loadGroupIsBackground = ((loadGroupFlags & LOAD_BACKGROUND) != 0);
849 : }
850 0 : bogusLoadBackground = !loadGroupIsBackground;
851 : }
852 :
853 : // Classifying a javascript: URI doesn't help us, and requires
854 : // NSS to boot, which we don't have in content processes. See
855 : // https://bugzilla.mozilla.org/show_bug.cgi?id=617838.
856 0 : aLoadFlags &= ~LOAD_CLASSIFY_URI;
857 :
858 : // Since the javascript channel is never the actual channel that
859 : // any data is loaded through, don't ever set the
860 : // LOAD_DOCUMENT_URI flag on it, since that could lead to two
861 : // 'document channels' in the loadgroup if a javascript: URL is
862 : // loaded while a document is being loaded in the same window.
863 :
864 : // XXXbz this, and a whole lot of other hackery, could go away if we'd just
865 : // cancel the current document load on javascript: load start like IE does.
866 :
867 0 : mLoadFlags = aLoadFlags & ~LOAD_DOCUMENT_URI;
868 :
869 0 : if (bogusLoadBackground) {
870 0 : aLoadFlags = aLoadFlags & ~LOAD_BACKGROUND;
871 : }
872 :
873 0 : mActualLoadFlags = aLoadFlags;
874 :
875 : // ... but the underlying stream channel should get this bit, if
876 : // set, since that'll be the real document channel if the
877 : // javascript: URL generated data.
878 :
879 0 : return mStreamChannel->SetLoadFlags(aLoadFlags);
880 : }
881 :
882 : NS_IMETHODIMP
883 0 : nsJSChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
884 : {
885 0 : return mStreamChannel->GetLoadGroup(aLoadGroup);
886 : }
887 :
888 : NS_IMETHODIMP
889 0 : nsJSChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
890 : {
891 0 : if (aLoadGroup) {
892 : bool streamPending;
893 0 : nsresult rv = mStreamChannel->IsPending(&streamPending);
894 0 : NS_ENSURE_SUCCESS(rv, rv);
895 :
896 0 : if (streamPending) {
897 0 : nsCOMPtr<nsILoadGroup> curLoadGroup;
898 0 : mStreamChannel->GetLoadGroup(getter_AddRefs(curLoadGroup));
899 :
900 0 : if (aLoadGroup != curLoadGroup) {
901 : // Move the stream channel to our new loadgroup. Make sure to
902 : // add it before removing it, so that we don't trigger onload
903 : // by accident.
904 0 : aLoadGroup->AddRequest(mStreamChannel, nullptr);
905 0 : if (curLoadGroup) {
906 0 : curLoadGroup->RemoveRequest(mStreamChannel, nullptr,
907 0 : NS_BINDING_RETARGETED);
908 : }
909 : }
910 : }
911 : }
912 :
913 0 : return mStreamChannel->SetLoadGroup(aLoadGroup);
914 : }
915 :
916 : NS_IMETHODIMP
917 0 : nsJSChannel::GetOwner(nsISupports* *aOwner)
918 : {
919 0 : return mStreamChannel->GetOwner(aOwner);
920 : }
921 :
922 : NS_IMETHODIMP
923 0 : nsJSChannel::SetOwner(nsISupports* aOwner)
924 : {
925 0 : return mStreamChannel->SetOwner(aOwner);
926 : }
927 :
928 : NS_IMETHODIMP
929 0 : nsJSChannel::GetLoadInfo(nsILoadInfo* *aLoadInfo)
930 : {
931 0 : return mStreamChannel->GetLoadInfo(aLoadInfo);
932 : }
933 :
934 : NS_IMETHODIMP
935 0 : nsJSChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
936 : {
937 0 : return mStreamChannel->SetLoadInfo(aLoadInfo);
938 : }
939 :
940 : NS_IMETHODIMP
941 0 : nsJSChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
942 : {
943 0 : return mStreamChannel->GetNotificationCallbacks(aCallbacks);
944 : }
945 :
946 : NS_IMETHODIMP
947 0 : nsJSChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
948 : {
949 0 : return mStreamChannel->SetNotificationCallbacks(aCallbacks);
950 : }
951 :
952 : NS_IMETHODIMP
953 0 : nsJSChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
954 : {
955 0 : return mStreamChannel->GetSecurityInfo(aSecurityInfo);
956 : }
957 :
958 : NS_IMETHODIMP
959 0 : nsJSChannel::GetContentType(nsACString &aContentType)
960 : {
961 0 : return mStreamChannel->GetContentType(aContentType);
962 : }
963 :
964 : NS_IMETHODIMP
965 0 : nsJSChannel::SetContentType(const nsACString &aContentType)
966 : {
967 0 : return mStreamChannel->SetContentType(aContentType);
968 : }
969 :
970 : NS_IMETHODIMP
971 0 : nsJSChannel::GetContentCharset(nsACString &aContentCharset)
972 : {
973 0 : return mStreamChannel->GetContentCharset(aContentCharset);
974 : }
975 :
976 : NS_IMETHODIMP
977 0 : nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
978 : {
979 0 : return mStreamChannel->SetContentCharset(aContentCharset);
980 : }
981 :
982 : NS_IMETHODIMP
983 0 : nsJSChannel::GetContentDisposition(uint32_t *aContentDisposition)
984 : {
985 0 : return mStreamChannel->GetContentDisposition(aContentDisposition);
986 : }
987 :
988 : NS_IMETHODIMP
989 0 : nsJSChannel::SetContentDisposition(uint32_t aContentDisposition)
990 : {
991 0 : return mStreamChannel->SetContentDisposition(aContentDisposition);
992 : }
993 :
994 : NS_IMETHODIMP
995 0 : nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
996 : {
997 0 : return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename);
998 : }
999 :
1000 : NS_IMETHODIMP
1001 0 : nsJSChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
1002 : {
1003 0 : return mStreamChannel->SetContentDispositionFilename(aContentDispositionFilename);
1004 : }
1005 :
1006 : NS_IMETHODIMP
1007 0 : nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
1008 : {
1009 0 : return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader);
1010 : }
1011 :
1012 : NS_IMETHODIMP
1013 0 : nsJSChannel::GetContentLength(int64_t *aContentLength)
1014 : {
1015 0 : return mStreamChannel->GetContentLength(aContentLength);
1016 : }
1017 :
1018 : NS_IMETHODIMP
1019 0 : nsJSChannel::SetContentLength(int64_t aContentLength)
1020 : {
1021 0 : return mStreamChannel->SetContentLength(aContentLength);
1022 : }
1023 :
1024 : NS_IMETHODIMP
1025 0 : nsJSChannel::OnStartRequest(nsIRequest* aRequest,
1026 : nsISupports* aContext)
1027 : {
1028 0 : NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1029 :
1030 0 : return mListener->OnStartRequest(this, aContext);
1031 : }
1032 :
1033 : NS_IMETHODIMP
1034 0 : nsJSChannel::OnDataAvailable(nsIRequest* aRequest,
1035 : nsISupports* aContext,
1036 : nsIInputStream* aInputStream,
1037 : uint64_t aOffset,
1038 : uint32_t aCount)
1039 : {
1040 0 : NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1041 :
1042 0 : return mListener->OnDataAvailable(this, aContext, aInputStream, aOffset,
1043 0 : aCount);
1044 : }
1045 :
1046 : NS_IMETHODIMP
1047 0 : nsJSChannel::OnStopRequest(nsIRequest* aRequest,
1048 : nsISupports* aContext,
1049 : nsresult aStatus)
1050 : {
1051 0 : NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
1052 :
1053 0 : nsCOMPtr<nsIStreamListener> listener = mListener;
1054 :
1055 0 : CleanupStrongRefs();
1056 :
1057 : // Make sure aStatus matches what GetStatus() returns
1058 0 : if (NS_FAILED(mStatus)) {
1059 0 : aStatus = mStatus;
1060 : }
1061 :
1062 0 : nsresult rv = listener->OnStopRequest(this, aContext, aStatus);
1063 :
1064 0 : nsCOMPtr<nsILoadGroup> loadGroup;
1065 0 : mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
1066 0 : if (loadGroup) {
1067 0 : loadGroup->RemoveRequest(this, nullptr, mStatus);
1068 : }
1069 :
1070 0 : mIsActive = false;
1071 :
1072 0 : return rv;
1073 : }
1074 :
1075 : NS_IMETHODIMP
1076 0 : nsJSChannel::SetExecutionPolicy(uint32_t aPolicy)
1077 : {
1078 0 : NS_ENSURE_ARG(aPolicy <= EXECUTE_NORMAL);
1079 :
1080 0 : mExecutionPolicy = aPolicy;
1081 0 : return NS_OK;
1082 : }
1083 :
1084 : NS_IMETHODIMP
1085 0 : nsJSChannel::GetExecutionPolicy(uint32_t* aPolicy)
1086 : {
1087 0 : *aPolicy = mExecutionPolicy;
1088 0 : return NS_OK;
1089 : }
1090 :
1091 : NS_IMETHODIMP
1092 0 : nsJSChannel::SetExecuteAsync(bool aIsAsync)
1093 : {
1094 0 : if (!mIsActive) {
1095 0 : mIsAsync = aIsAsync;
1096 : }
1097 : // else ignore this call
1098 0 : NS_WARNING_ASSERTION(!mIsActive,
1099 : "Calling SetExecuteAsync on active channel?");
1100 :
1101 0 : return NS_OK;
1102 : }
1103 :
1104 : NS_IMETHODIMP
1105 0 : nsJSChannel::GetExecuteAsync(bool* aIsAsync)
1106 : {
1107 0 : *aIsAsync = mIsAsync;
1108 0 : return NS_OK;
1109 : }
1110 :
1111 : ////////////////////////////////////////////////////////////////////////////////
1112 :
1113 0 : nsJSProtocolHandler::nsJSProtocolHandler()
1114 : {
1115 0 : }
1116 :
1117 : nsresult
1118 0 : nsJSProtocolHandler::Init()
1119 : {
1120 0 : return NS_OK;
1121 : }
1122 :
1123 0 : nsJSProtocolHandler::~nsJSProtocolHandler()
1124 : {
1125 0 : }
1126 :
1127 0 : NS_IMPL_ISUPPORTS(nsJSProtocolHandler, nsIProtocolHandler)
1128 :
1129 : nsresult
1130 0 : nsJSProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
1131 : {
1132 0 : if (aOuter)
1133 0 : return NS_ERROR_NO_AGGREGATION;
1134 :
1135 0 : nsJSProtocolHandler* ph = new nsJSProtocolHandler();
1136 0 : NS_ADDREF(ph);
1137 0 : nsresult rv = ph->Init();
1138 0 : if (NS_SUCCEEDED(rv)) {
1139 0 : rv = ph->QueryInterface(aIID, aResult);
1140 : }
1141 0 : NS_RELEASE(ph);
1142 0 : return rv;
1143 : }
1144 :
1145 : nsresult
1146 0 : nsJSProtocolHandler::EnsureUTF8Spec(const nsCString& aSpec, const char *aCharset,
1147 : nsACString &aUTF8Spec)
1148 : {
1149 0 : aUTF8Spec.Truncate();
1150 :
1151 : nsresult rv;
1152 :
1153 0 : if (!mTextToSubURI) {
1154 0 : mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
1155 0 : NS_ENSURE_SUCCESS(rv, rv);
1156 : }
1157 0 : nsAutoString uStr;
1158 0 : rv = mTextToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec, uStr);
1159 0 : NS_ENSURE_SUCCESS(rv, rv);
1160 :
1161 0 : if (!IsASCII(uStr)) {
1162 0 : rv = NS_EscapeURL(NS_ConvertUTF16toUTF8(uStr),
1163 : esc_AlwaysCopy | esc_OnlyNonASCII, aUTF8Spec,
1164 : mozilla::fallible);
1165 0 : NS_ENSURE_SUCCESS(rv, rv);
1166 : }
1167 :
1168 0 : return NS_OK;
1169 : }
1170 :
1171 : ////////////////////////////////////////////////////////////////////////////////
1172 : // nsIProtocolHandler methods:
1173 :
1174 : NS_IMETHODIMP
1175 0 : nsJSProtocolHandler::GetScheme(nsACString &result)
1176 : {
1177 0 : result = "javascript";
1178 0 : return NS_OK;
1179 : }
1180 :
1181 : NS_IMETHODIMP
1182 0 : nsJSProtocolHandler::GetDefaultPort(int32_t *result)
1183 : {
1184 0 : *result = -1; // no port for javascript: URLs
1185 0 : return NS_OK;
1186 : }
1187 :
1188 : NS_IMETHODIMP
1189 0 : nsJSProtocolHandler::GetProtocolFlags(uint32_t *result)
1190 : {
1191 0 : *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
1192 : URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_OPENING_EXECUTES_SCRIPT;
1193 0 : return NS_OK;
1194 : }
1195 :
1196 : NS_IMETHODIMP
1197 0 : nsJSProtocolHandler::NewURI(const nsACString &aSpec,
1198 : const char *aCharset,
1199 : nsIURI *aBaseURI,
1200 : nsIURI **result)
1201 : {
1202 : nsresult rv;
1203 :
1204 : // javascript: URLs (currently) have no additional structure beyond that
1205 : // provided by standard URLs, so there is no "outer" object given to
1206 : // CreateInstance.
1207 :
1208 0 : nsCOMPtr<nsIURI> url = new nsJSURI(aBaseURI);
1209 :
1210 0 : if (!aCharset || !nsCRT::strcasecmp("UTF-8", aCharset))
1211 0 : rv = url->SetSpec(aSpec);
1212 : else {
1213 0 : nsAutoCString utf8Spec;
1214 0 : rv = EnsureUTF8Spec(PromiseFlatCString(aSpec), aCharset, utf8Spec);
1215 0 : if (NS_SUCCEEDED(rv)) {
1216 0 : if (utf8Spec.IsEmpty())
1217 0 : rv = url->SetSpec(aSpec);
1218 : else
1219 0 : rv = url->SetSpec(utf8Spec);
1220 : }
1221 : }
1222 :
1223 0 : if (NS_FAILED(rv)) {
1224 0 : return rv;
1225 : }
1226 :
1227 0 : url.forget(result);
1228 0 : return rv;
1229 : }
1230 :
1231 : NS_IMETHODIMP
1232 0 : nsJSProtocolHandler::NewChannel2(nsIURI* uri,
1233 : nsILoadInfo* aLoadInfo,
1234 : nsIChannel** result)
1235 : {
1236 : nsresult rv;
1237 :
1238 0 : NS_ENSURE_ARG_POINTER(uri);
1239 0 : RefPtr<nsJSChannel> channel = new nsJSChannel();
1240 0 : if (!channel) {
1241 0 : return NS_ERROR_OUT_OF_MEMORY;
1242 : }
1243 :
1244 0 : rv = channel->Init(uri, aLoadInfo);
1245 0 : NS_ENSURE_SUCCESS(rv, rv);
1246 :
1247 0 : if (NS_SUCCEEDED(rv)) {
1248 0 : channel.forget(result);
1249 : }
1250 0 : return rv;
1251 : }
1252 :
1253 : NS_IMETHODIMP
1254 0 : nsJSProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
1255 : {
1256 0 : return NewChannel2(uri, nullptr, result);
1257 : }
1258 :
1259 : NS_IMETHODIMP
1260 0 : nsJSProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
1261 : {
1262 : // don't override anything.
1263 0 : *_retval = false;
1264 0 : return NS_OK;
1265 : }
1266 :
1267 : ////////////////////////////////////////////////////////////
1268 : // nsJSURI implementation
1269 : static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
1270 : NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
1271 :
1272 :
1273 0 : NS_IMPL_ADDREF_INHERITED(nsJSURI, mozilla::net::nsSimpleURI)
1274 0 : NS_IMPL_RELEASE_INHERITED(nsJSURI, mozilla::net::nsSimpleURI)
1275 :
1276 0 : NS_INTERFACE_MAP_BEGIN(nsJSURI)
1277 0 : if (aIID.Equals(kJSURICID))
1278 0 : foundInterface = static_cast<nsIURI*>(this);
1279 0 : else if (aIID.Equals(kThisSimpleURIImplementationCID)) {
1280 : // Need to return explicitly here, because if we just set foundInterface
1281 : // to null the NS_INTERFACE_MAP_END_INHERITING will end up calling into
1282 : // nsSimplURI::QueryInterface and finding something for this CID.
1283 0 : *aInstancePtr = nullptr;
1284 0 : return NS_NOINTERFACE;
1285 : }
1286 : else
1287 0 : NS_INTERFACE_MAP_END_INHERITING(mozilla::net::nsSimpleURI)
1288 :
1289 : // nsISerializable methods:
1290 :
1291 : NS_IMETHODIMP
1292 0 : nsJSURI::Read(nsIObjectInputStream* aStream)
1293 : {
1294 0 : nsresult rv = mozilla::net::nsSimpleURI::Read(aStream);
1295 0 : if (NS_FAILED(rv)) return rv;
1296 :
1297 : bool haveBase;
1298 0 : rv = aStream->ReadBoolean(&haveBase);
1299 0 : if (NS_FAILED(rv)) return rv;
1300 :
1301 0 : if (haveBase) {
1302 0 : nsCOMPtr<nsISupports> supports;
1303 0 : rv = aStream->ReadObject(true, getter_AddRefs(supports));
1304 0 : if (NS_FAILED(rv)) return rv;
1305 0 : mBaseURI = do_QueryInterface(supports);
1306 : }
1307 :
1308 0 : return NS_OK;
1309 : }
1310 :
1311 : NS_IMETHODIMP
1312 0 : nsJSURI::Write(nsIObjectOutputStream* aStream)
1313 : {
1314 0 : nsresult rv = mozilla::net::nsSimpleURI::Write(aStream);
1315 0 : if (NS_FAILED(rv)) return rv;
1316 :
1317 0 : rv = aStream->WriteBoolean(mBaseURI != nullptr);
1318 0 : if (NS_FAILED(rv)) return rv;
1319 :
1320 0 : if (mBaseURI) {
1321 0 : rv = aStream->WriteObject(mBaseURI, true);
1322 0 : if (NS_FAILED(rv)) return rv;
1323 : }
1324 :
1325 0 : return NS_OK;
1326 : }
1327 :
1328 : // nsIIPCSerializableURI
1329 : void
1330 0 : nsJSURI::Serialize(mozilla::ipc::URIParams& aParams)
1331 : {
1332 : using namespace mozilla::ipc;
1333 :
1334 0 : JSURIParams jsParams;
1335 0 : URIParams simpleParams;
1336 :
1337 0 : mozilla::net::nsSimpleURI::Serialize(simpleParams);
1338 :
1339 0 : jsParams.simpleParams() = simpleParams;
1340 0 : if (mBaseURI) {
1341 0 : SerializeURI(mBaseURI, jsParams.baseURI());
1342 : } else {
1343 0 : jsParams.baseURI() = mozilla::void_t();
1344 : }
1345 :
1346 0 : aParams = jsParams;
1347 0 : }
1348 :
1349 : bool
1350 0 : nsJSURI::Deserialize(const mozilla::ipc::URIParams& aParams)
1351 : {
1352 : using namespace mozilla::ipc;
1353 :
1354 0 : if (aParams.type() != URIParams::TJSURIParams) {
1355 0 : NS_ERROR("Received unknown parameters from the other process!");
1356 0 : return false;
1357 : }
1358 :
1359 0 : const JSURIParams& jsParams = aParams.get_JSURIParams();
1360 0 : mozilla::net::nsSimpleURI::Deserialize(jsParams.simpleParams());
1361 :
1362 0 : if (jsParams.baseURI().type() != OptionalURIParams::Tvoid_t) {
1363 0 : mBaseURI = DeserializeURI(jsParams.baseURI().get_URIParams());
1364 : } else {
1365 0 : mBaseURI = nullptr;
1366 : }
1367 0 : return true;
1368 : }
1369 :
1370 : // nsSimpleURI methods:
1371 : /* virtual */ mozilla::net::nsSimpleURI*
1372 0 : nsJSURI::StartClone(mozilla::net::nsSimpleURI::RefHandlingEnum refHandlingMode,
1373 : const nsACString& newRef)
1374 : {
1375 0 : nsCOMPtr<nsIURI> baseClone;
1376 0 : if (mBaseURI) {
1377 : // Note: We preserve ref on *base* URI, regardless of ref handling mode.
1378 0 : nsresult rv = mBaseURI->Clone(getter_AddRefs(baseClone));
1379 0 : if (NS_FAILED(rv)) {
1380 0 : return nullptr;
1381 : }
1382 : }
1383 :
1384 0 : nsJSURI* url = new nsJSURI(baseClone);
1385 0 : SetRefOnClone(url, refHandlingMode, newRef);
1386 0 : return url;
1387 : }
1388 :
1389 : /* virtual */ nsresult
1390 0 : nsJSURI::EqualsInternal(nsIURI* aOther,
1391 : mozilla::net::nsSimpleURI::RefHandlingEnum aRefHandlingMode,
1392 : bool* aResult)
1393 : {
1394 0 : NS_ENSURE_ARG_POINTER(aOther);
1395 0 : NS_PRECONDITION(aResult, "null pointer for outparam");
1396 :
1397 0 : RefPtr<nsJSURI> otherJSURI;
1398 0 : nsresult rv = aOther->QueryInterface(kJSURICID,
1399 0 : getter_AddRefs(otherJSURI));
1400 0 : if (NS_FAILED(rv)) {
1401 0 : *aResult = false; // aOther is not a nsJSURI --> not equal.
1402 0 : return NS_OK;
1403 : }
1404 :
1405 : // Compare the member data that our base class knows about.
1406 0 : if (!mozilla::net::nsSimpleURI::EqualsInternal(otherJSURI, aRefHandlingMode)) {
1407 0 : *aResult = false;
1408 0 : return NS_OK;
1409 : }
1410 :
1411 : // Compare the piece of additional member data that we add to base class.
1412 0 : nsIURI* otherBaseURI = otherJSURI->GetBaseURI();
1413 :
1414 0 : if (mBaseURI) {
1415 : // (As noted in StartClone, we always honor refs on mBaseURI)
1416 0 : return mBaseURI->Equals(otherBaseURI, aResult);
1417 : }
1418 :
1419 0 : *aResult = !otherBaseURI;
1420 0 : return NS_OK;
1421 : }
1422 :
1423 : NS_IMETHODIMP
1424 0 : nsJSURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
1425 : {
1426 0 : *aClassIDNoAlloc = kJSURICID;
1427 0 : return NS_OK;
1428 : }
1429 :
|