LCOV - code coverage report
Current view: directory - dom/src/jsurl - nsJSProtocolHandler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 528 120 22.7 %
Date: 2012-06-02 Functions: 99 35 35.4 %

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

Generated by: LCOV version 1.7