Commit 2f2e06d1 authored by bzbarsky@mit.edu's avatar bzbarsky@mit.edu
Browse files

Make plug-in loads of javascript: URIs execute synchronously. Bug 364028,r=biesi, sr=jst

parent 9ba62529
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@
 *   principal of the environment in which the program is to be executed the
 *   execution will be forced to happen in a sandbox.
 */
[scriptable, uuid(6dec981b-6fce-4f57-bf97-d518c6079c77)]
[scriptable, uuid(33234b99-9588-4c7d-9da6-86b8b7cba565)]
interface nsIScriptChannel : nsISupports
{
  /**
@@ -85,4 +85,18 @@ interface nsIScriptChannel : nsISupports
   * @throws NS_ERROR_INVALID_ARG when set to an unrecognized value.
   */
  attribute unsigned long executionPolicy;

  /**
   * Control whether the program should be executed synchronosly when
   * the channel's AsyncOpen method is called or whether it should be
   * executed asynchronously.  In both cases, any data that the
   * channel returns will be returned asynchronously; the only thing
   * this property affects is when the program executes.
   *
   * The default value of this property is TRUE.
   *
   * Setting this property after asyncOpen has been called on the
   * channel has no effect.
   */
  attribute boolean executeAsync;   
};
+66 −11
Original line number Diff line number Diff line
@@ -429,6 +429,7 @@ protected:
    nsRefPtr<nsJSThunk>     mIOThunk;
    PopupControlState       mPopupState;
    PRUint32                mExecutionPolicy;
    PRPackedBool            mIsAsync;
    PRPackedBool            mIsActive;
    PRPackedBool            mOpenedStreamChannel;
};
@@ -439,6 +440,7 @@ nsJSChannel::nsJSChannel() :
    mActualLoadFlags(LOAD_NORMAL),
    mPopupState(openOverridden),
    mExecutionPolicy(EXECUTE_IN_SANDBOX),
    mIsAsync(PR_TRUE),
    mIsActive(PR_FALSE),
    mOpenedStreamChannel(PR_FALSE)
{
@@ -630,9 +632,42 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
        loadGroup->AddRequest(this, nsnull);
    }

    mPopupState = win->GetPopupControlState();

    nsRunnableMethod<nsJSChannel>::Method method;
    if (mIsAsync) {
        // post an event to do the rest
    nsCOMPtr<nsIRunnable> ev =
        new nsRunnableMethod<nsJSChannel>(this, &nsJSChannel::EvaluateScript);
        method = &nsJSChannel::EvaluateScript;
    } else {   
        EvaluateScript();
        if (mOpenedStreamChannel) {
            // That will handle notifying things
            return NS_OK;
        }

        NS_ASSERTION(NS_FAILED(mStatus), "We should have failed _somehow_");

        // mStatus is going to be NS_ERROR_DOM_RETVAL_UNDEFINED if we didn't
        // have any content resulting from the execution and NS_BINDING_ABORTED
        // if something we did causes our own load to be stopped.  Return
        // success in those cases, and error out in all others.
        if (mStatus != NS_ERROR_DOM_RETVAL_UNDEFINED &&
            mStatus != NS_BINDING_ABORTED) {
            // Note that calling EvaluateScript() handled removing us from the
            // loadgroup and marking us as not active anymore.
            mListener = nsnull;
            mContext = nsnull;
            mOriginalInnerWindow = nsnull;
            return mStatus;
        }

        // We're returning success from asyncOpen(), but we didn't open a
        // stream channel.  We'll have to notify ourselves, but make sure to do
        // it asynchronously.
        method = &nsJSChannel::NotifyListener;            
    }

    nsCOMPtr<nsIRunnable> ev = new nsRunnableMethod<nsJSChannel>(this, method);
    nsresult rv = NS_DispatchToCurrentThread(ev);

    if (NS_FAILED(rv)) {
@@ -642,9 +677,6 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
        mContext = nsnull;
        mOriginalInnerWindow = nsnull;
    }

    mPopupState = win->GetPopupControlState();

    return rv;
}

@@ -687,7 +719,9 @@ nsJSChannel::EvaluateScript()
    mIsActive = PR_FALSE;

    if (NS_FAILED(mStatus)) {
        if (mIsAsync) {
            NotifyListener();
        }
        return;
    }
    
@@ -729,17 +763,19 @@ nsJSChannel::EvaluateScript()
    }

    if (NS_FAILED(mStatus)) {
        if (mIsAsync) {
            NotifyListener();
        }
        return;
    }
    
    mStatus = mStreamChannel->AsyncOpen(this, mContext);
    if (NS_FAILED(mStatus)) {
        NotifyListener();
    } else {
    if (NS_SUCCEEDED(mStatus)) {
        // mStreamChannel will call OnStartRequest and OnStopRequest on
        // us, so we'll be sure to call them on our listener.
        mOpenedStreamChannel = PR_TRUE;
    } else if (mIsAsync) {
        NotifyListener();
    }

    return;
@@ -920,6 +956,25 @@ nsJSChannel::GetExecutionPolicy(PRUint32* aPolicy)
    return NS_OK;
}

NS_IMETHODIMP
nsJSChannel::SetExecuteAsync(PRBool aIsAsync)
{
    if (!mIsActive) {
        mIsAsync = aIsAsync;
    }
    // else ignore this call
    NS_WARN_IF_FALSE(!mIsActive, "Calling SetExecuteAsync on active channel?");

    return NS_OK;
}

NS_IMETHODIMP
nsJSChannel::GetExecuteAsync(PRBool* aIsAsync)
{
    *aIsAsync = mIsAsync;
    return NS_OK;
}

////////////////////////////////////////////////////////////////////////////////

nsJSProtocolHandler::nsJSProtocolHandler()
+2 −0
Original line number Diff line number Diff line
@@ -5809,6 +5809,8 @@ NS_IMETHODIMP nsPluginHostImpl::NewPluginURLStream(const nsString& aURL,
        nsCOMPtr<nsIScriptChannel> scriptChannel(do_QueryInterface(channel));
        if (scriptChannel) {
          scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
          // Plug-ins seem to depend on javascript: URIs running synchronously
          scriptChannel->SetExecuteAsync(PR_FALSE);
        }
      }