dom/src/jsurl/nsJSProtocolHandler.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     7 #include "nsCOMPtr.h"
     8 #include "nsAutoPtr.h"
     9 #include "jsapi.h"
    10 #include "jswrapper.h"
    11 #include "nsCRT.h"
    12 #include "nsError.h"
    13 #include "nsXPIDLString.h"
    14 #include "nsReadableUtils.h"
    15 #include "nsJSProtocolHandler.h"
    16 #include "nsStringStream.h"
    17 #include "nsNetUtil.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 "prprf.h"
    33 #include "nsEscape.h"
    34 #include "nsIWebNavigation.h"
    35 #include "nsIDocShell.h"
    36 #include "nsIContentViewer.h"
    37 #include "nsIXPConnect.h"
    38 #include "nsContentUtils.h"
    39 #include "nsCxPusher.h"
    40 #include "nsJSUtils.h"
    41 #include "nsThreadUtils.h"
    42 #include "nsIScriptChannel.h"
    43 #include "nsIDocument.h"
    44 #include "nsIObjectInputStream.h"
    45 #include "nsIObjectOutputStream.h"
    46 #include "nsIWritablePropertyBag2.h"
    47 #include "nsIContentSecurityPolicy.h"
    48 #include "nsSandboxFlags.h"
    49 #include "mozilla/dom/ScriptSettings.h"
    51 using mozilla::dom::AutoEntryScript;
    53 static NS_DEFINE_CID(kJSURICID, NS_JSURI_CID);
    55 class nsJSThunk : public nsIInputStream
    56 {
    57 public:
    58     nsJSThunk();
    60     NS_DECL_THREADSAFE_ISUPPORTS
    61     NS_FORWARD_SAFE_NSIINPUTSTREAM(mInnerStream)
    63     nsresult Init(nsIURI* uri);
    64     nsresult EvaluateScript(nsIChannel *aChannel,
    65                             PopupControlState aPopupState,
    66                             uint32_t aExecutionPolicy,
    67                             nsPIDOMWindow *aOriginalInnerWindow);
    69 protected:
    70     virtual ~nsJSThunk();
    72     nsCOMPtr<nsIInputStream>    mInnerStream;
    73     nsCString                   mScript;
    74     nsCString                   mURL;
    75 };
    77 //
    78 // nsISupports implementation...
    79 //
    80 NS_IMPL_ISUPPORTS(nsJSThunk, nsIInputStream)
    83 nsJSThunk::nsJSThunk()
    84 {
    85 }
    87 nsJSThunk::~nsJSThunk()
    88 {
    89 }
    91 nsresult nsJSThunk::Init(nsIURI* uri)
    92 {
    93     NS_ENSURE_ARG_POINTER(uri);
    95     // Get the script string to evaluate...
    96     nsresult rv = uri->GetPath(mScript);
    97     if (NS_FAILED(rv)) return rv;
    99     // Get the url.
   100     rv = uri->GetSpec(mURL);
   101     if (NS_FAILED(rv)) return rv;
   103     return NS_OK;
   104 }
   106 static bool
   107 IsISO88591(const nsString& aString)
   108 {
   109     for (nsString::const_char_iterator c = aString.BeginReading(),
   110                                    c_end = aString.EndReading();
   111          c < c_end; ++c) {
   112         if (*c > 255)
   113             return false;
   114     }
   115     return true;
   116 }
   118 static
   119 nsIScriptGlobalObject* GetGlobalObject(nsIChannel* aChannel)
   120 {
   121     // Get the global object owner from the channel
   122     nsCOMPtr<nsIDocShell> docShell;
   123     NS_QueryNotificationCallbacks(aChannel, docShell);
   124     if (!docShell) {
   125         NS_WARNING("Unable to get a docShell from the channel!");
   126         return nullptr;
   127     }
   129     // So far so good: get the script global from its docshell
   130     nsIScriptGlobalObject* global = docShell->GetScriptGlobalObject();
   132     NS_ASSERTION(global,
   133                  "Unable to get an nsIScriptGlobalObject from the "
   134                  "docShell!");
   135     return global;
   136 }
   138 nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
   139                                    PopupControlState aPopupState,
   140                                    uint32_t aExecutionPolicy,
   141                                    nsPIDOMWindow *aOriginalInnerWindow)
   142 {
   143     if (aExecutionPolicy == nsIScriptChannel::NO_EXECUTION) {
   144         // Nothing to do here.
   145         return NS_ERROR_DOM_RETVAL_UNDEFINED;
   146     }
   148     NS_ENSURE_ARG_POINTER(aChannel);
   150     // Get principal of code for execution
   151     nsCOMPtr<nsISupports> owner;
   152     aChannel->GetOwner(getter_AddRefs(owner));
   153     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(owner);
   154     if (!principal) {
   155         // No execution without a principal!
   156         NS_ASSERTION(!owner, "Non-principal owner?");
   157         NS_WARNING("No principal to execute JS with");
   158         return NS_ERROR_DOM_RETVAL_UNDEFINED;
   159     }
   161     nsresult rv;
   163     // CSP check: javascript: URIs disabled unless "inline" scripts are
   164     // allowed.
   165     nsCOMPtr<nsIContentSecurityPolicy> csp;
   166     rv = principal->GetCsp(getter_AddRefs(csp));
   167     NS_ENSURE_SUCCESS(rv, rv);
   168     if (csp) {
   169         bool allowsInline = true;
   170         bool reportViolations = false;
   171         rv = csp->GetAllowsInlineScript(&reportViolations, &allowsInline);
   172         NS_ENSURE_SUCCESS(rv, rv);
   174         if (reportViolations) {
   175             // gather information to log with violation report
   176             nsCOMPtr<nsIURI> uri;
   177             principal->GetURI(getter_AddRefs(uri));
   178             nsAutoCString asciiSpec;
   179             uri->GetAsciiSpec(asciiSpec);
   180             csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_SCRIPT,
   181                                      NS_ConvertUTF8toUTF16(asciiSpec),
   182                                      NS_ConvertUTF8toUTF16(mURL),
   183                                      0,
   184                                      EmptyString(),
   185                                      EmptyString());
   186         }
   188         //return early if inline scripts are not allowed
   189         if (!allowsInline) {
   190           return NS_ERROR_DOM_RETVAL_UNDEFINED;
   191         }
   192     }
   194     // Get the global object we should be running on.
   195     nsIScriptGlobalObject* global = GetGlobalObject(aChannel);
   196     if (!global) {
   197         return NS_ERROR_FAILURE;
   198     }
   200     // Sandboxed document check: javascript: URI's are disabled
   201     // in a sandboxed document unless 'allow-scripts' was specified.
   202     nsIDocument* doc = aOriginalInnerWindow->GetExtantDoc();
   203     if (doc && (doc->GetSandboxFlags() & SANDBOXED_SCRIPTS)) {
   204         return NS_ERROR_DOM_RETVAL_UNDEFINED;
   205     }
   207     // Push our popup control state
   208     nsAutoPopupStatePusher popupStatePusher(aPopupState);
   210     // Make sure we still have the same inner window as we used to.
   211     nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(global);
   212     nsPIDOMWindow *innerWin = win->GetCurrentInnerWindow();
   214     if (innerWin != aOriginalInnerWindow) {
   215         return NS_ERROR_UNEXPECTED;
   216     }
   218     nsCOMPtr<nsIScriptGlobalObject> innerGlobal = do_QueryInterface(innerWin);
   220     nsCOMPtr<nsIDOMWindow> domWindow(do_QueryInterface(global, &rv));
   221     if (NS_FAILED(rv)) {
   222         return NS_ERROR_FAILURE;
   223     }
   225     // So far so good: get the script context from its owner.
   226     nsCOMPtr<nsIScriptContext> scriptContext = global->GetContext();
   227     if (!scriptContext)
   228         return NS_ERROR_FAILURE;
   230     nsAutoCString script(mScript);
   231     // Unescape the script
   232     NS_UnescapeURL(script);
   235     nsCOMPtr<nsIScriptSecurityManager> securityManager;
   236     securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   237     if (NS_FAILED(rv))
   238         return rv;
   240     bool useSandbox =
   241         (aExecutionPolicy == nsIScriptChannel::EXECUTE_IN_SANDBOX);
   243     // New script entry point required, due to the "Create a script" step of
   244     // http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
   245     AutoEntryScript entryScript(innerGlobal, true,
   246                                 scriptContext->GetNativeContext());
   247     JSContext* cx = entryScript.cx();
   248     JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
   249     NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
   251     if (!useSandbox) {
   252         //-- Don't outside a sandbox unless the script principal subsumes the
   253         //   principal of the context.
   254         nsIPrincipal* objectPrincipal = nsContentUtils::GetObjectPrincipal(globalJSObject);
   256         bool subsumes;
   257         rv = principal->Subsumes(objectPrincipal, &subsumes);
   258         if (NS_FAILED(rv))
   259             return rv;
   261         useSandbox = !subsumes;
   262     }
   264     JS::Rooted<JS::Value> v (cx, JS::UndefinedValue());
   265     // Finally, we have everything needed to evaluate the expression.
   266     if (useSandbox) {
   267         // We were asked to use a sandbox, or the channel owner isn't allowed
   268         // to execute in this context.  Evaluate the javascript URL in a
   269         // sandbox to prevent it from accessing data it doesn't have
   270         // permissions to access.
   272         // First check to make sure it's OK to evaluate this script to
   273         // start with.  For example, script could be disabled.
   274         if (!securityManager->ScriptAllowed(globalJSObject)) {
   275             // Treat this as returning undefined from the script.  That's what
   276             // nsJSContext does.
   277             return NS_ERROR_DOM_RETVAL_UNDEFINED;
   278         }
   280         nsIXPConnect *xpc = nsContentUtils::XPConnect();
   282         nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
   283         // Important: Use a null principal here
   284         rv = xpc->CreateSandbox(cx, nullptr, getter_AddRefs(sandbox));
   285         NS_ENSURE_SUCCESS(rv, rv);
   287         // The nsXPConnect sandbox API gives us a wrapper to the sandbox for
   288         // our current compartment. Because our current context doesn't necessarily
   289         // subsume that of the sandbox, we want to unwrap and enter the sandbox's
   290         // compartment. It's a shame that the APIs here are so clunkly. :-(
   291         JS::Rooted<JSObject*> sandboxObj(cx, sandbox->GetJSObject());
   292         NS_ENSURE_STATE(sandboxObj);
   293         sandboxObj = js::UncheckedUnwrap(sandboxObj);
   294         JSAutoCompartment ac(cx, sandboxObj);
   296         // Push our JSContext on the context stack so the EvalInSandboxObject call (and
   297         // JS_ReportPendingException, if relevant) will use the principal of cx.
   298         nsCxPusher pusher;
   299         pusher.Push(cx);
   300         rv = xpc->EvalInSandboxObject(NS_ConvertUTF8toUTF16(script),
   301                                       /* filename = */ nullptr, cx,
   302                                       sandboxObj, true, &v);
   304         // Propagate and report exceptions that happened in the
   305         // sandbox.
   306         if (JS_IsExceptionPending(cx)) {
   307             JS_ReportPendingException(cx);
   308         }
   309     } else {
   310         // No need to use the sandbox, evaluate the script directly in
   311         // the given scope.
   312         JS::CompileOptions options(cx);
   313         options.setFileAndLine(mURL.get(), 1)
   314                .setVersion(JSVERSION_DEFAULT);
   315         nsJSUtils::EvaluateOptions evalOptions;
   316         evalOptions.setCoerceToString(true);
   317         rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script),
   318                                        globalJSObject, options, evalOptions, &v);
   320         // If there's an error on cx as a result of that call, report
   321         // it now -- either we're just running under the event loop,
   322         // so we shouldn't propagate JS exceptions out of here, or we
   323         // can't be sure that our caller is JS (and if it's not we'll
   324         // lose the error), or it might be JS that then proceeds to
   325         // cause an error of its own (which will also make us lose
   326         // this error).
   327         ::JS_ReportPendingException(cx);
   328     }
   330     // If we took the sandbox path above, v might be in the sandbox
   331     // compartment.
   332     if (!JS_WrapValue(cx, &v)) {
   333         return NS_ERROR_OUT_OF_MEMORY;
   334     }
   336     if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) {
   337         return NS_ERROR_MALFORMED_URI;
   338     } else if (v.isUndefined()) {
   339         return NS_ERROR_DOM_RETVAL_UNDEFINED;
   340     } else {
   341         nsDependentJSString result;
   342         if (!result.init(cx, v)) {
   343             return NS_ERROR_OUT_OF_MEMORY;
   344         }
   346         char *bytes;
   347         uint32_t bytesLen;
   348         NS_NAMED_LITERAL_CSTRING(isoCharset, "ISO-8859-1");
   349         NS_NAMED_LITERAL_CSTRING(utf8Charset, "UTF-8");
   350         const nsCString *charset;
   351         if (IsISO88591(result)) {
   352             // For compatibility, if the result is ISO-8859-1, we use
   353             // ISO-8859-1, so that people can compatibly create images
   354             // using javascript: URLs.
   355             bytes = ToNewCString(result);
   356             bytesLen = result.Length();
   357             charset = &isoCharset;
   358         }
   359         else {
   360             bytes = ToNewUTF8String(result, &bytesLen);
   361             charset = &utf8Charset;
   362         }
   363         aChannel->SetContentCharset(*charset);
   364         if (bytes)
   365             rv = NS_NewByteInputStream(getter_AddRefs(mInnerStream),
   366                                        bytes, bytesLen,
   367                                        NS_ASSIGNMENT_ADOPT);
   368         else
   369             rv = NS_ERROR_OUT_OF_MEMORY;
   370     }
   372     return rv;
   373 }
   375 ////////////////////////////////////////////////////////////////////////////////
   377 class nsJSChannel : public nsIChannel,
   378                     public nsIStreamListener,
   379                     public nsIScriptChannel,
   380                     public nsIPropertyBag2
   381 {
   382 public:
   383     nsJSChannel();
   385     NS_DECL_ISUPPORTS
   386     NS_DECL_NSIREQUEST
   387     NS_DECL_NSICHANNEL
   388     NS_DECL_NSIREQUESTOBSERVER
   389     NS_DECL_NSISTREAMLISTENER
   390     NS_DECL_NSISCRIPTCHANNEL
   391     NS_FORWARD_SAFE_NSIPROPERTYBAG(mPropertyBag)
   392     NS_FORWARD_SAFE_NSIPROPERTYBAG2(mPropertyBag)
   394     nsresult Init(nsIURI *aURI);
   396     // Actually evaluate the script.
   397     void EvaluateScript();
   399 protected:
   400     virtual ~nsJSChannel();
   402     nsresult StopAll();
   404     void NotifyListener();
   406     void CleanupStrongRefs();
   408 protected:
   409     nsCOMPtr<nsIChannel>    mStreamChannel;
   410     nsCOMPtr<nsIPropertyBag2> mPropertyBag;
   411     nsCOMPtr<nsIStreamListener> mListener;  // Our final listener
   412     nsCOMPtr<nsISupports> mContext; // The context passed to AsyncOpen
   413     nsCOMPtr<nsPIDOMWindow> mOriginalInnerWindow;  // The inner window our load
   414                                                    // started against.
   415     // If we blocked onload on a document in AsyncOpen, this is the document we
   416     // did it on.
   417     nsCOMPtr<nsIDocument>   mDocumentOnloadBlockedOn;
   419     nsresult mStatus; // Our status
   421     nsLoadFlags             mLoadFlags;
   422     nsLoadFlags             mActualLoadFlags; // See AsyncOpen
   424     nsRefPtr<nsJSThunk>     mIOThunk;
   425     PopupControlState       mPopupState;
   426     uint32_t                mExecutionPolicy;
   427     bool                    mIsAsync;
   428     bool                    mIsActive;
   429     bool                    mOpenedStreamChannel;
   430 };
   432 nsJSChannel::nsJSChannel() :
   433     mStatus(NS_OK),
   434     mLoadFlags(LOAD_NORMAL),
   435     mActualLoadFlags(LOAD_NORMAL),
   436     mPopupState(openOverridden),
   437     mExecutionPolicy(EXECUTE_IN_SANDBOX),
   438     mIsAsync(true),
   439     mIsActive(false),
   440     mOpenedStreamChannel(false)
   441 {
   442 }
   444 nsJSChannel::~nsJSChannel()
   445 {
   446 }
   448 nsresult nsJSChannel::StopAll()
   449 {
   450     nsresult rv = NS_ERROR_UNEXPECTED;
   451     nsCOMPtr<nsIWebNavigation> webNav;
   452     NS_QueryNotificationCallbacks(mStreamChannel, webNav);
   454     NS_ASSERTION(webNav, "Can't get nsIWebNavigation from channel!");
   455     if (webNav) {
   456         rv = webNav->Stop(nsIWebNavigation::STOP_ALL);
   457     }
   459     return rv;
   460 }
   462 nsresult nsJSChannel::Init(nsIURI *aURI)
   463 {
   464     nsRefPtr<nsJSURI> jsURI;
   465     nsresult rv = aURI->QueryInterface(kJSURICID,
   466                                        getter_AddRefs(jsURI));
   467     NS_ENSURE_SUCCESS(rv, rv);
   469     // Create the nsIStreamIO layer used by the nsIStreamIOChannel.
   470     mIOThunk = new nsJSThunk();
   471     if (!mIOThunk)
   472         return NS_ERROR_OUT_OF_MEMORY;
   474     // Create a stock input stream channel...
   475     // Remember, until AsyncOpen is called, the script will not be evaluated
   476     // and the underlying Input Stream will not be created...
   477     nsCOMPtr<nsIChannel> channel;
   479     // If the resultant script evaluation actually does return a value, we
   480     // treat it as html.
   481     rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, mIOThunk,
   482                                   NS_LITERAL_CSTRING("text/html"));
   483     if (NS_FAILED(rv)) return rv;
   485     rv = mIOThunk->Init(aURI);
   486     if (NS_SUCCEEDED(rv)) {
   487         mStreamChannel = channel;
   488         mPropertyBag = do_QueryInterface(channel);
   489         nsCOMPtr<nsIWritablePropertyBag2> writableBag =
   490             do_QueryInterface(channel);
   491         if (writableBag && jsURI->GetBaseURI()) {
   492             writableBag->SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
   493                                                 jsURI->GetBaseURI());
   494         }
   495     }
   497     return rv;
   498 }
   500 //
   501 // nsISupports implementation...
   502 //
   504 NS_IMPL_ISUPPORTS(nsJSChannel, nsIChannel, nsIRequest, nsIRequestObserver,
   505                   nsIStreamListener, nsIScriptChannel, nsIPropertyBag,
   506                   nsIPropertyBag2)
   508 //
   509 // nsIRequest implementation...
   510 //
   512 NS_IMETHODIMP
   513 nsJSChannel::GetName(nsACString &aResult)
   514 {
   515     return mStreamChannel->GetName(aResult);
   516 }
   518 NS_IMETHODIMP
   519 nsJSChannel::IsPending(bool *aResult)
   520 {
   521     *aResult = mIsActive;
   522     return NS_OK;
   523 }
   525 NS_IMETHODIMP
   526 nsJSChannel::GetStatus(nsresult *aResult)
   527 {
   528     if (NS_SUCCEEDED(mStatus) && mOpenedStreamChannel) {
   529         return mStreamChannel->GetStatus(aResult);
   530     }
   532     *aResult = mStatus;
   534     return NS_OK;
   535 }
   537 NS_IMETHODIMP
   538 nsJSChannel::Cancel(nsresult aStatus)
   539 {
   540     mStatus = aStatus;
   542     if (mOpenedStreamChannel) {
   543         mStreamChannel->Cancel(aStatus);
   544     }
   546     return NS_OK;
   547 }
   549 NS_IMETHODIMP
   550 nsJSChannel::Suspend()
   551 {
   552     return mStreamChannel->Suspend();
   553 }
   555 NS_IMETHODIMP
   556 nsJSChannel::Resume()
   557 {
   558     return mStreamChannel->Resume();
   559 }
   561 //
   562 // nsIChannel implementation
   563 //
   565 NS_IMETHODIMP
   566 nsJSChannel::GetOriginalURI(nsIURI * *aURI)
   567 {
   568     return mStreamChannel->GetOriginalURI(aURI);
   569 }
   571 NS_IMETHODIMP
   572 nsJSChannel::SetOriginalURI(nsIURI *aURI)
   573 {
   574     return mStreamChannel->SetOriginalURI(aURI);
   575 }
   577 NS_IMETHODIMP
   578 nsJSChannel::GetURI(nsIURI * *aURI)
   579 {
   580     return mStreamChannel->GetURI(aURI);
   581 }
   583 NS_IMETHODIMP
   584 nsJSChannel::Open(nsIInputStream **aResult)
   585 {
   586     nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
   587                                            mExecutionPolicy,
   588                                            mOriginalInnerWindow);
   589     NS_ENSURE_SUCCESS(rv, rv);
   591     return mStreamChannel->Open(aResult);
   592 }
   594 NS_IMETHODIMP
   595 nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
   596 {
   597     NS_ENSURE_ARG(aListener);
   599     // First make sure that we have a usable inner window; we'll want to make
   600     // sure that we execute against that inner and no other.
   601     nsIScriptGlobalObject* global = GetGlobalObject(this);
   602     if (!global) {
   603         return NS_ERROR_NOT_AVAILABLE;
   604     }
   606     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global));
   607     NS_ASSERTION(win, "Our global is not a window??");
   609     // Make sure we create a new inner window if one doesn't already exist (see
   610     // bug 306630).
   611     mOriginalInnerWindow = win->EnsureInnerWindow();
   612     if (!mOriginalInnerWindow) {
   613         return NS_ERROR_NOT_AVAILABLE;
   614     }
   616     mListener = aListener;
   617     mContext = aContext;
   619     mIsActive = true;
   621     // Temporarily set the LOAD_BACKGROUND flag to suppress load group observer
   622     // notifications (and hence nsIWebProgressListener notifications) from
   623     // being dispatched.  This is required since we suppress LOAD_DOCUMENT_URI,
   624     // which means that the DocLoader would not generate document start and
   625     // stop notifications (see bug 257875).
   626     mActualLoadFlags = mLoadFlags;
   627     mLoadFlags |= LOAD_BACKGROUND;
   629     // Add the javascript channel to its loadgroup so that we know if
   630     // network loads were canceled or not...
   631     nsCOMPtr<nsILoadGroup> loadGroup;
   632     mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
   633     if (loadGroup) {
   634         nsresult rv = loadGroup->AddRequest(this, nullptr);
   635         if (NS_FAILED(rv)) {
   636             mIsActive = false;
   637             CleanupStrongRefs();
   638             return rv;
   639         }
   640     }
   642     mDocumentOnloadBlockedOn = mOriginalInnerWindow->GetExtantDoc();
   643     if (mDocumentOnloadBlockedOn) {
   644         // If we're a document channel, we need to actually block onload on our
   645         // _parent_ document.  This is because we don't actually set our
   646         // LOAD_DOCUMENT_URI flag, so a docloader we're loading in as the
   647         // document channel will claim to not be busy, and our parent's onload
   648         // could fire too early.
   649         nsLoadFlags loadFlags;
   650         mStreamChannel->GetLoadFlags(&loadFlags);
   651         if (loadFlags & LOAD_DOCUMENT_URI) {
   652             mDocumentOnloadBlockedOn =
   653                 mDocumentOnloadBlockedOn->GetParentDocument();
   654         }
   655     }
   656     if (mDocumentOnloadBlockedOn) {
   657         mDocumentOnloadBlockedOn->BlockOnload();
   658     }
   661     mPopupState = win->GetPopupControlState();
   663     void (nsJSChannel::*method)();
   664     if (mIsAsync) {
   665         // post an event to do the rest
   666         method = &nsJSChannel::EvaluateScript;
   667     } else {
   668         EvaluateScript();
   669         if (mOpenedStreamChannel) {
   670             // That will handle notifying things
   671             return NS_OK;
   672         }
   674         NS_ASSERTION(NS_FAILED(mStatus), "We should have failed _somehow_");
   676         // mStatus is going to be NS_ERROR_DOM_RETVAL_UNDEFINED if we didn't
   677         // have any content resulting from the execution and NS_BINDING_ABORTED
   678         // if something we did causes our own load to be stopped.  Return
   679         // success in those cases, and error out in all others.
   680         if (mStatus != NS_ERROR_DOM_RETVAL_UNDEFINED &&
   681             mStatus != NS_BINDING_ABORTED) {
   682             // Note that calling EvaluateScript() handled removing us from the
   683             // loadgroup and marking us as not active anymore.
   684             CleanupStrongRefs();
   685             return mStatus;
   686         }
   688         // We're returning success from asyncOpen(), but we didn't open a
   689         // stream channel.  We'll have to notify ourselves, but make sure to do
   690         // it asynchronously.
   691         method = &nsJSChannel::NotifyListener;            
   692     }
   694     nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this, method);
   695     nsresult rv = NS_DispatchToCurrentThread(ev);
   697     if (NS_FAILED(rv)) {
   698         loadGroup->RemoveRequest(this, nullptr, rv);
   699         mIsActive = false;
   700         CleanupStrongRefs();
   701     }
   702     return rv;
   703 }
   705 void
   706 nsJSChannel::EvaluateScript()
   707 {
   708     // Synchronously execute the script...
   709     // mIsActive is used to indicate the the request is 'busy' during the
   710     // the script evaluation phase.  This means that IsPending() will 
   711     // indicate the the request is busy while the script is executing...
   713     // Note that we want to be in the loadgroup and pending while we evaluate
   714     // the script, so that we find out if the loadgroup gets canceled by the
   715     // script execution (in which case we shouldn't pump out data even if the
   716     // script returns it).
   718     if (NS_SUCCEEDED(mStatus)) {
   719         nsresult rv = mIOThunk->EvaluateScript(mStreamChannel, mPopupState,
   720                                                mExecutionPolicy,
   721                                                mOriginalInnerWindow);
   723         // Note that evaluation may have canceled us, so recheck mStatus again
   724         if (NS_FAILED(rv) && NS_SUCCEEDED(mStatus)) {
   725             mStatus = rv;
   726         }
   727     }
   729     // Remove the javascript channel from its loadgroup...
   730     nsCOMPtr<nsILoadGroup> loadGroup;
   731     mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
   732     if (loadGroup) {
   733         loadGroup->RemoveRequest(this, nullptr, mStatus);
   734     }
   736     // Reset load flags to their original value...
   737     mLoadFlags = mActualLoadFlags;
   739     // We're no longer active, it's now up to the stream channel to do
   740     // the loading, if needed.
   741     mIsActive = false;
   743     if (NS_FAILED(mStatus)) {
   744         if (mIsAsync) {
   745             NotifyListener();
   746         }
   747         return;
   748     }
   750     // EvaluateScript() succeeded, and we were not canceled, that
   751     // means there's data to parse as a result of evaluating the
   752     // script.
   754     // Get the stream channels load flags (!= mLoadFlags).
   755     nsLoadFlags loadFlags;
   756     mStreamChannel->GetLoadFlags(&loadFlags);
   758     uint32_t disposition;
   759     if (NS_FAILED(mStreamChannel->GetContentDisposition(&disposition)))
   760         disposition = nsIChannel::DISPOSITION_INLINE;
   761     if (loadFlags & LOAD_DOCUMENT_URI && disposition != nsIChannel::DISPOSITION_ATTACHMENT) {
   762         // We're loaded as the document channel and not expecting to download
   763         // the result. If we go on, we'll blow away the current document. Make
   764         // sure that's ok. If so, stop all pending network loads.
   766         nsCOMPtr<nsIDocShell> docShell;
   767         NS_QueryNotificationCallbacks(mStreamChannel, docShell);
   768         if (docShell) {
   769             nsCOMPtr<nsIContentViewer> cv;
   770             docShell->GetContentViewer(getter_AddRefs(cv));
   772             if (cv) {
   773                 bool okToUnload;
   775                 if (NS_SUCCEEDED(cv->PermitUnload(false, &okToUnload)) &&
   776                     !okToUnload) {
   777                     // The user didn't want to unload the current
   778                     // page, translate this into an undefined
   779                     // return from the javascript: URL...
   780                     mStatus = NS_ERROR_DOM_RETVAL_UNDEFINED;
   781                 }
   782             }
   783         }
   785         if (NS_SUCCEEDED(mStatus)) {
   786             mStatus = StopAll();
   787         }
   788     }
   790     if (NS_FAILED(mStatus)) {
   791         if (mIsAsync) {
   792             NotifyListener();
   793         }
   794         return;
   795     }
   797     mStatus = mStreamChannel->AsyncOpen(this, mContext);
   798     if (NS_SUCCEEDED(mStatus)) {
   799         // mStreamChannel will call OnStartRequest and OnStopRequest on
   800         // us, so we'll be sure to call them on our listener.
   801         mOpenedStreamChannel = true;
   803         // Now readd ourselves to the loadgroup so we can receive
   804         // cancellation notifications.
   805         mIsActive = true;
   806         if (loadGroup) {
   807             mStatus = loadGroup->AddRequest(this, nullptr);
   809             // If AddRequest failed, that's OK.  The key is to make sure we get
   810             // cancelled if needed, and that call just canceled us if it
   811             // failed.  We'll still get notified by the stream channel when it
   812             // finishes.
   813         }
   815     } else if (mIsAsync) {
   816         NotifyListener();
   817     }
   819     return;
   820 }
   822 void
   823 nsJSChannel::NotifyListener()
   824 {
   825     mListener->OnStartRequest(this, mContext);
   826     mListener->OnStopRequest(this, mContext, mStatus);
   828     CleanupStrongRefs();
   829 }
   831 void
   832 nsJSChannel::CleanupStrongRefs()
   833 {
   834     mListener = nullptr;
   835     mContext = nullptr;
   836     mOriginalInnerWindow = nullptr;
   837     if (mDocumentOnloadBlockedOn) {
   838         mDocumentOnloadBlockedOn->UnblockOnload(false);
   839         mDocumentOnloadBlockedOn = nullptr;
   840     }
   841 }
   843 NS_IMETHODIMP
   844 nsJSChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
   845 {
   846     *aLoadFlags = mLoadFlags;
   848     return NS_OK;
   849 }
   851 NS_IMETHODIMP
   852 nsJSChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
   853 {
   854     // Figure out whether the LOAD_BACKGROUND bit in aLoadFlags is
   855     // actually right.
   856     bool bogusLoadBackground = false;
   857     if (mIsActive && !(mActualLoadFlags & LOAD_BACKGROUND) &&
   858         (aLoadFlags & LOAD_BACKGROUND)) {
   859         // We're getting a LOAD_BACKGROUND, but it's probably just our own fake
   860         // flag being mirrored to us.  The one exception is if our loadgroup is
   861         // LOAD_BACKGROUND.
   862         bool loadGroupIsBackground = false;
   863         nsCOMPtr<nsILoadGroup> loadGroup;
   864         mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
   865         if (loadGroup) {
   866             nsLoadFlags loadGroupFlags;
   867             loadGroup->GetLoadFlags(&loadGroupFlags);
   868             loadGroupIsBackground = ((loadGroupFlags & LOAD_BACKGROUND) != 0);
   869         }
   870         bogusLoadBackground = !loadGroupIsBackground;
   871     }
   873     // Classifying a javascript: URI doesn't help us, and requires
   874     // NSS to boot, which we don't have in content processes.  See
   875     // https://bugzilla.mozilla.org/show_bug.cgi?id=617838.
   876     aLoadFlags &= ~LOAD_CLASSIFY_URI;
   878     // Since the javascript channel is never the actual channel that
   879     // any data is loaded through, don't ever set the
   880     // LOAD_DOCUMENT_URI flag on it, since that could lead to two
   881     // 'document channels' in the loadgroup if a javascript: URL is
   882     // loaded while a document is being loaded in the same window.
   884     // XXXbz this, and a whole lot of other hackery, could go away if we'd just
   885     // cancel the current document load on javascript: load start like IE does.
   887     mLoadFlags = aLoadFlags & ~LOAD_DOCUMENT_URI;
   889     if (bogusLoadBackground) {
   890         aLoadFlags = aLoadFlags & ~LOAD_BACKGROUND;
   891     }
   893     mActualLoadFlags = aLoadFlags;
   895     // ... but the underlying stream channel should get this bit, if
   896     // set, since that'll be the real document channel if the
   897     // javascript: URL generated data.
   899     return mStreamChannel->SetLoadFlags(aLoadFlags);
   900 }
   902 NS_IMETHODIMP
   903 nsJSChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
   904 {
   905     return mStreamChannel->GetLoadGroup(aLoadGroup);
   906 }
   908 NS_IMETHODIMP
   909 nsJSChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
   910 {
   911     if (aLoadGroup) {
   912         bool streamPending;
   913         nsresult rv = mStreamChannel->IsPending(&streamPending);
   914         NS_ENSURE_SUCCESS(rv, rv);
   916         if (streamPending) {
   917             nsCOMPtr<nsILoadGroup> curLoadGroup;
   918             mStreamChannel->GetLoadGroup(getter_AddRefs(curLoadGroup));
   920             if (aLoadGroup != curLoadGroup) {
   921                 // Move the stream channel to our new loadgroup.  Make sure to
   922                 // add it before removing it, so that we don't trigger onload
   923                 // by accident.
   924                 aLoadGroup->AddRequest(mStreamChannel, nullptr);
   925                 if (curLoadGroup) {
   926                     curLoadGroup->RemoveRequest(mStreamChannel, nullptr,
   927                                                 NS_BINDING_RETARGETED);
   928                 }
   929             }
   930         }
   931     }
   933     return mStreamChannel->SetLoadGroup(aLoadGroup);
   934 }
   936 NS_IMETHODIMP
   937 nsJSChannel::GetOwner(nsISupports* *aOwner)
   938 {
   939     return mStreamChannel->GetOwner(aOwner);
   940 }
   942 NS_IMETHODIMP
   943 nsJSChannel::SetOwner(nsISupports* aOwner)
   944 {
   945     return mStreamChannel->SetOwner(aOwner);
   946 }
   948 NS_IMETHODIMP
   949 nsJSChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
   950 {
   951     return mStreamChannel->GetNotificationCallbacks(aCallbacks);
   952 }
   954 NS_IMETHODIMP
   955 nsJSChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
   956 {
   957     return mStreamChannel->SetNotificationCallbacks(aCallbacks);
   958 }
   960 NS_IMETHODIMP 
   961 nsJSChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
   962 {
   963     return mStreamChannel->GetSecurityInfo(aSecurityInfo);
   964 }
   966 NS_IMETHODIMP
   967 nsJSChannel::GetContentType(nsACString &aContentType)
   968 {
   969     return mStreamChannel->GetContentType(aContentType);
   970 }
   972 NS_IMETHODIMP
   973 nsJSChannel::SetContentType(const nsACString &aContentType)
   974 {
   975     return mStreamChannel->SetContentType(aContentType);
   976 }
   978 NS_IMETHODIMP
   979 nsJSChannel::GetContentCharset(nsACString &aContentCharset)
   980 {
   981     return mStreamChannel->GetContentCharset(aContentCharset);
   982 }
   984 NS_IMETHODIMP
   985 nsJSChannel::SetContentCharset(const nsACString &aContentCharset)
   986 {
   987     return mStreamChannel->SetContentCharset(aContentCharset);
   988 }
   990 NS_IMETHODIMP
   991 nsJSChannel::GetContentDisposition(uint32_t *aContentDisposition)
   992 {
   993     return mStreamChannel->GetContentDisposition(aContentDisposition);
   994 }
   996 NS_IMETHODIMP
   997 nsJSChannel::SetContentDisposition(uint32_t aContentDisposition)
   998 {
   999     return mStreamChannel->SetContentDisposition(aContentDisposition);
  1002 NS_IMETHODIMP
  1003 nsJSChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
  1005     return mStreamChannel->GetContentDispositionFilename(aContentDispositionFilename);
  1008 NS_IMETHODIMP
  1009 nsJSChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
  1011     return mStreamChannel->SetContentDispositionFilename(aContentDispositionFilename);
  1014 NS_IMETHODIMP
  1015 nsJSChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
  1017     return mStreamChannel->GetContentDispositionHeader(aContentDispositionHeader);
  1020 NS_IMETHODIMP
  1021 nsJSChannel::GetContentLength(int64_t *aContentLength)
  1023     return mStreamChannel->GetContentLength(aContentLength);
  1026 NS_IMETHODIMP
  1027 nsJSChannel::SetContentLength(int64_t aContentLength)
  1029     return mStreamChannel->SetContentLength(aContentLength);
  1032 NS_IMETHODIMP
  1033 nsJSChannel::OnStartRequest(nsIRequest* aRequest,
  1034                             nsISupports* aContext)
  1036     NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
  1038     return mListener->OnStartRequest(this, aContext);    
  1041 NS_IMETHODIMP
  1042 nsJSChannel::OnDataAvailable(nsIRequest* aRequest,
  1043                              nsISupports* aContext, 
  1044                              nsIInputStream* aInputStream,
  1045                              uint64_t aOffset,
  1046                              uint32_t aCount)
  1048     NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
  1050     return mListener->OnDataAvailable(this, aContext, aInputStream, aOffset,
  1051                                       aCount);
  1054 NS_IMETHODIMP
  1055 nsJSChannel::OnStopRequest(nsIRequest* aRequest,
  1056                            nsISupports* aContext,
  1057                            nsresult aStatus)
  1059     NS_ENSURE_TRUE(aRequest == mStreamChannel, NS_ERROR_UNEXPECTED);
  1061     nsCOMPtr<nsIStreamListener> listener = mListener;
  1063     CleanupStrongRefs();
  1065     // Make sure aStatus matches what GetStatus() returns
  1066     if (NS_FAILED(mStatus)) {
  1067         aStatus = mStatus;
  1070     nsresult rv = listener->OnStopRequest(this, aContext, aStatus);
  1072     nsCOMPtr<nsILoadGroup> loadGroup;
  1073     mStreamChannel->GetLoadGroup(getter_AddRefs(loadGroup));
  1074     if (loadGroup) {
  1075         loadGroup->RemoveRequest(this, nullptr, mStatus);
  1078     mIsActive = false;
  1080     return rv;
  1083 NS_IMETHODIMP
  1084 nsJSChannel::SetExecutionPolicy(uint32_t aPolicy)
  1086     NS_ENSURE_ARG(aPolicy <= EXECUTE_NORMAL);
  1088     mExecutionPolicy = aPolicy;
  1089     return NS_OK;
  1092 NS_IMETHODIMP
  1093 nsJSChannel::GetExecutionPolicy(uint32_t* aPolicy)
  1095     *aPolicy = mExecutionPolicy;
  1096     return NS_OK;
  1099 NS_IMETHODIMP
  1100 nsJSChannel::SetExecuteAsync(bool aIsAsync)
  1102     if (!mIsActive) {
  1103         mIsAsync = aIsAsync;
  1105     // else ignore this call
  1106     NS_WARN_IF_FALSE(!mIsActive, "Calling SetExecuteAsync on active channel?");
  1108     return NS_OK;
  1111 NS_IMETHODIMP
  1112 nsJSChannel::GetExecuteAsync(bool* aIsAsync)
  1114     *aIsAsync = mIsAsync;
  1115     return NS_OK;
  1118 ////////////////////////////////////////////////////////////////////////////////
  1120 nsJSProtocolHandler::nsJSProtocolHandler()
  1124 nsresult
  1125 nsJSProtocolHandler::Init()
  1127     return NS_OK;
  1130 nsJSProtocolHandler::~nsJSProtocolHandler()
  1134 NS_IMPL_ISUPPORTS(nsJSProtocolHandler, nsIProtocolHandler)
  1136 nsresult
  1137 nsJSProtocolHandler::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
  1139     if (aOuter)
  1140         return NS_ERROR_NO_AGGREGATION;
  1142     nsJSProtocolHandler* ph = new nsJSProtocolHandler();
  1143     if (!ph)
  1144         return NS_ERROR_OUT_OF_MEMORY;
  1145     NS_ADDREF(ph);
  1146     nsresult rv = ph->Init();
  1147     if (NS_SUCCEEDED(rv)) {
  1148         rv = ph->QueryInterface(aIID, aResult);
  1150     NS_RELEASE(ph);
  1151     return rv;
  1154 nsresult 
  1155 nsJSProtocolHandler::EnsureUTF8Spec(const nsAFlatCString &aSpec, const char *aCharset, 
  1156                                     nsACString &aUTF8Spec)
  1158   aUTF8Spec.Truncate();
  1160   nsresult rv;
  1162   if (!mTextToSubURI) {
  1163     mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
  1164     NS_ENSURE_SUCCESS(rv, rv);
  1166   nsAutoString uStr;
  1167   rv = mTextToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec, uStr);
  1168   NS_ENSURE_SUCCESS(rv, rv);
  1170   if (!IsASCII(uStr))
  1171     NS_EscapeURL(NS_ConvertUTF16toUTF8(uStr), esc_AlwaysCopy | esc_OnlyNonASCII, aUTF8Spec);
  1173   return NS_OK;
  1176 ////////////////////////////////////////////////////////////////////////////////
  1177 // nsIProtocolHandler methods:
  1179 NS_IMETHODIMP
  1180 nsJSProtocolHandler::GetScheme(nsACString &result)
  1182     result = "javascript";
  1183     return NS_OK;
  1186 NS_IMETHODIMP
  1187 nsJSProtocolHandler::GetDefaultPort(int32_t *result)
  1189     *result = -1;        // no port for javascript: URLs
  1190     return NS_OK;
  1193 NS_IMETHODIMP
  1194 nsJSProtocolHandler::GetProtocolFlags(uint32_t *result)
  1196     *result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
  1197         URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_OPENING_EXECUTES_SCRIPT;
  1198     return NS_OK;
  1201 NS_IMETHODIMP
  1202 nsJSProtocolHandler::NewURI(const nsACString &aSpec,
  1203                             const char *aCharset,
  1204                             nsIURI *aBaseURI,
  1205                             nsIURI **result)
  1207     nsresult rv;
  1209     // javascript: URLs (currently) have no additional structure beyond that
  1210     // provided by standard URLs, so there is no "outer" object given to
  1211     // CreateInstance.
  1213     nsCOMPtr<nsIURI> url = new nsJSURI(aBaseURI);
  1215     if (!aCharset || !nsCRT::strcasecmp("UTF-8", aCharset))
  1216       rv = url->SetSpec(aSpec);
  1217     else {
  1218       nsAutoCString utf8Spec;
  1219       rv = EnsureUTF8Spec(PromiseFlatCString(aSpec), aCharset, utf8Spec);
  1220       if (NS_SUCCEEDED(rv)) {
  1221         if (utf8Spec.IsEmpty())
  1222           rv = url->SetSpec(aSpec);
  1223         else
  1224           rv = url->SetSpec(utf8Spec);
  1228     if (NS_FAILED(rv)) {
  1229         return rv;
  1232     url.forget(result);
  1233     return rv;
  1236 NS_IMETHODIMP
  1237 nsJSProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
  1239     nsresult rv;
  1240     nsJSChannel * channel;
  1242     NS_ENSURE_ARG_POINTER(uri);
  1244     channel = new nsJSChannel();
  1245     if (!channel) {
  1246         return NS_ERROR_OUT_OF_MEMORY;
  1248     NS_ADDREF(channel);
  1250     rv = channel->Init(uri);
  1251     if (NS_SUCCEEDED(rv)) {
  1252         *result = channel;
  1253         NS_ADDREF(*result);
  1255     NS_RELEASE(channel);
  1256     return rv;
  1259 NS_IMETHODIMP 
  1260 nsJSProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
  1262     // don't override anything.  
  1263     *_retval = false;
  1264     return NS_OK;
  1267 ////////////////////////////////////////////////////////////
  1268 // nsJSURI implementation
  1269 static NS_DEFINE_CID(kThisSimpleURIImplementationCID,
  1270                      NS_THIS_SIMPLEURI_IMPLEMENTATION_CID);
  1273 NS_IMPL_ADDREF_INHERITED(nsJSURI, nsSimpleURI)
  1274 NS_IMPL_RELEASE_INHERITED(nsJSURI, nsSimpleURI)
  1276 NS_INTERFACE_MAP_BEGIN(nsJSURI)
  1277   if (aIID.Equals(kJSURICID))
  1278       foundInterface = static_cast<nsIURI*>(this);
  1279   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       *aInstancePtr = nullptr;
  1284       return NS_NOINTERFACE;
  1286   else
  1287 NS_INTERFACE_MAP_END_INHERITING(nsSimpleURI)
  1289 // nsISerializable methods:
  1291 NS_IMETHODIMP
  1292 nsJSURI::Read(nsIObjectInputStream* aStream)
  1294     nsresult rv = nsSimpleURI::Read(aStream);
  1295     if (NS_FAILED(rv)) return rv;
  1297     bool haveBase;
  1298     rv = aStream->ReadBoolean(&haveBase);
  1299     if (NS_FAILED(rv)) return rv;
  1301     if (haveBase) {
  1302         nsCOMPtr<nsISupports> supports;
  1303         rv = aStream->ReadObject(true, getter_AddRefs(supports));
  1304         if (NS_FAILED(rv)) return rv;
  1305         mBaseURI = do_QueryInterface(supports);
  1308     return NS_OK;
  1311 NS_IMETHODIMP
  1312 nsJSURI::Write(nsIObjectOutputStream* aStream)
  1314     nsresult rv = nsSimpleURI::Write(aStream);
  1315     if (NS_FAILED(rv)) return rv;
  1317     rv = aStream->WriteBoolean(mBaseURI != nullptr);
  1318     if (NS_FAILED(rv)) return rv;
  1320     if (mBaseURI) {
  1321         rv = aStream->WriteObject(mBaseURI, true);
  1322         if (NS_FAILED(rv)) return rv;
  1325     return NS_OK;
  1328 // nsSimpleURI methods:
  1329 /* virtual */ nsSimpleURI*
  1330 nsJSURI::StartClone(nsSimpleURI::RefHandlingEnum /* ignored */)
  1332     nsCOMPtr<nsIURI> baseClone;
  1333     if (mBaseURI) {
  1334       // Note: We preserve ref on *base* URI, regardless of ref handling mode.
  1335       nsresult rv = mBaseURI->Clone(getter_AddRefs(baseClone));
  1336       if (NS_FAILED(rv)) {
  1337         return nullptr;
  1341     return new nsJSURI(baseClone);
  1344 /* virtual */ nsresult
  1345 nsJSURI::EqualsInternal(nsIURI* aOther,
  1346                         nsSimpleURI::RefHandlingEnum aRefHandlingMode,
  1347                         bool* aResult)
  1349     NS_ENSURE_ARG_POINTER(aOther);
  1350     NS_PRECONDITION(aResult, "null pointer for outparam");
  1352     nsRefPtr<nsJSURI> otherJSURI;
  1353     nsresult rv = aOther->QueryInterface(kJSURICID,
  1354                                          getter_AddRefs(otherJSURI));
  1355     if (NS_FAILED(rv)) {
  1356         *aResult = false; // aOther is not a nsJSURI --> not equal.
  1357         return NS_OK;
  1360     // Compare the member data that our base class knows about.
  1361     if (!nsSimpleURI::EqualsInternal(otherJSURI, aRefHandlingMode)) {
  1362         *aResult = false;
  1363         return NS_OK;
  1366     // Compare the piece of additional member data that we add to base class.
  1367     nsIURI* otherBaseURI = otherJSURI->GetBaseURI();
  1369     if (mBaseURI) {
  1370         // (As noted in StartClone, we always honor refs on mBaseURI)
  1371         return mBaseURI->Equals(otherBaseURI, aResult);
  1374     *aResult = !otherBaseURI;
  1375     return NS_OK;
  1378 NS_IMETHODIMP 
  1379 nsJSURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
  1381     *aClassIDNoAlloc = kJSURICID;
  1382     return NS_OK;

mercurial