netwerk/base/src/nsTransportUtils.cpp
author Patrick McManus <mcmanus@ducksong.com>
Thu, 08 Jan 2015 14:48:52 -0500
changeset 224688 91e1a0afee555a045c8e283934456556b1d4a43d
parent 190501 ef6cb0f76224810fdaf44cd4c5164ff552e0ade0
permissions -rw-r--r--
bug 1116867 - make nsIProgressEventSink and nsITransportEventSink safely scriptable r=mayhemer r=bz These scriptable interfaces use uint_64 arguments with sentinel values of UINT64_MAX. However, UINT64_MAX exceeds MAX_SAFE_INTEGER and cannot be gatewayed to/from javascript - so they cannot be used correctly. Change them to use signed 64 bit numbers and -1 as the sentinnel. C++ implementations ought to be enough to audit as the special value could never be used correctly in JS anyhow - also audited OnProgressChange() uses for downstream use of this data. --- dom/base/nsXMLHttpRequest.cpp | 19 +++++++---- dom/base/nsXMLHttpRequest.h | 10 +++--- dom/plugins/base/nsPluginStreamListenerPeer.cpp | 4 +-- .../webbrowserpersist/nsWebBrowserPersist.cpp | 14 ++++---- image/src/imgLoader.cpp | 4 +-- modules/libjar/nsJARChannel.cpp | 3 +- netwerk/base/public/nsIProgressEventSink.idl | 8 ++--- netwerk/base/public/nsITransport.idl | 8 ++--- netwerk/base/public/nsNetUtil.h | 24 ++++++++++++++ netwerk/base/src/Dashboard.cpp | 2 +- netwerk/base/src/nsBaseChannel.cpp | 12 +++---- netwerk/base/src/nsIncrementalDownload.cpp | 4 +-- netwerk/base/src/nsSocketTransport2.cpp | 5 +-- netwerk/base/src/nsStreamTransportService.cpp | 38 +++++++++++++--------- netwerk/base/src/nsTransportUtils.cpp | 12 +++---- netwerk/protocol/file/nsFileChannel.cpp | 8 +++-- netwerk/protocol/ftp/nsFtpConnectionThread.cpp | 4 +-- netwerk/protocol/http/Http2Push.cpp | 2 +- netwerk/protocol/http/Http2Session.cpp | 2 +- netwerk/protocol/http/HttpChannelChild.cpp | 31 +++++++++--------- netwerk/protocol/http/HttpChannelChild.h | 6 ++-- netwerk/protocol/http/HttpChannelParent.cpp | 4 +-- netwerk/protocol/http/HttpChannelParent.h | 4 +-- netwerk/protocol/http/NullHttpTransaction.cpp | 2 +- netwerk/protocol/http/PHttpChannel.ipdl | 2 +- netwerk/protocol/http/SpdyPush31.cpp | 2 +- netwerk/protocol/http/SpdySession31.cpp | 2 +- netwerk/protocol/http/TunnelUtils.cpp | 2 +- netwerk/protocol/http/nsAHttpTransaction.h | 4 +-- netwerk/protocol/http/nsHttpChannel.cpp | 30 +++++++++++------ netwerk/protocol/http/nsHttpConnection.cpp | 4 +-- netwerk/protocol/http/nsHttpConnectionMgr.cpp | 4 +-- netwerk/protocol/http/nsHttpPipeline.cpp | 4 +-- netwerk/protocol/http/nsHttpPipeline.h | 6 ++-- netwerk/protocol/http/nsHttpResponseHead.cpp | 2 +- netwerk/protocol/http/nsHttpResponseHead.h | 2 +- netwerk/protocol/http/nsHttpTransaction.cpp | 32 +++++++++--------- netwerk/protocol/http/nsHttpTransaction.h | 2 +- netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp | 2 +- netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp | 3 +- netwerk/test/TestIncrementalDownload.cpp | 7 ++-- uriloader/base/nsDocLoader.cpp | 14 ++++---- 42 files changed, 203 insertions(+), 151 deletions(-)

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/Mutex.h"
#include "nsTransportUtils.h"
#include "nsITransport.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"

using namespace mozilla;

//-----------------------------------------------------------------------------

class nsTransportStatusEvent;

class nsTransportEventSinkProxy : public nsITransportEventSink
{
public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSITRANSPORTEVENTSINK

    nsTransportEventSinkProxy(nsITransportEventSink *sink,
                              nsIEventTarget *target,
                              bool coalesceAll)
        : mSink(sink)
        , mTarget(target)
        , mLock("nsTransportEventSinkProxy.mLock")
        , mLastEvent(nullptr)
        , mCoalesceAll(coalesceAll)
    {
        NS_ADDREF(mSink);
    }

private:
    virtual ~nsTransportEventSinkProxy()
    {
        // our reference to mSink could be the last, so be sure to release
        // it on the target thread.  otherwise, we could get into trouble.
        NS_ProxyRelease(mTarget, mSink);
    }

public:
    nsITransportEventSink           *mSink;
    nsCOMPtr<nsIEventTarget>         mTarget;
    Mutex                            mLock;
    nsTransportStatusEvent          *mLastEvent;
    bool                             mCoalesceAll;
};

class nsTransportStatusEvent : public nsRunnable
{
public:
    nsTransportStatusEvent(nsTransportEventSinkProxy *proxy,
                           nsITransport *transport,
                           nsresult status,
                           int64_t progress,
                           int64_t progressMax)
        : mProxy(proxy)
        , mTransport(transport)
        , mStatus(status)
        , mProgress(progress)
        , mProgressMax(progressMax)
    {}

    ~nsTransportStatusEvent() {}

    NS_IMETHOD Run()
    {
        // since this event is being handled, we need to clear the proxy's ref.
        // if not coalescing all, then last event may not equal self!
        {
            MutexAutoLock lock(mProxy->mLock);
            if (mProxy->mLastEvent == this)
                mProxy->mLastEvent = nullptr;
        }

        mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress,
                                         mProgressMax);
        return NS_OK;
    }

    nsRefPtr<nsTransportEventSinkProxy> mProxy;

    // parameters to OnTransportStatus
    nsCOMPtr<nsITransport> mTransport;
    nsresult               mStatus;
    int64_t                mProgress;
    int64_t                mProgressMax;
};

NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink)

NS_IMETHODIMP
nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport,
                                             nsresult status,
                                             int64_t progress,
                                             int64_t progressMax)
{
    nsresult rv = NS_OK;
    nsRefPtr<nsTransportStatusEvent> event;
    {
        MutexAutoLock lock(mLock);

        // try to coalesce events! ;-)
        if (mLastEvent && (mCoalesceAll || mLastEvent->mStatus == status)) {
            mLastEvent->mStatus = status;
            mLastEvent->mProgress = progress;
            mLastEvent->mProgressMax = progressMax;
        }
        else {
            event = new nsTransportStatusEvent(this, transport, status,
                                               progress, progressMax);
            if (!event)
                rv = NS_ERROR_OUT_OF_MEMORY;
            mLastEvent = event;  // weak ref
        }
    }
    if (event) {
        rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
        if (NS_FAILED(rv)) {
            NS_WARNING("unable to post transport status event");

            MutexAutoLock lock(mLock); // cleanup.. don't reference anymore!
            mLastEvent = nullptr;
        }
    }
    return rv;
}

//-----------------------------------------------------------------------------

nsresult
net_NewTransportEventSinkProxy(nsITransportEventSink **result,
                               nsITransportEventSink *sink,
                               nsIEventTarget *target,
                               bool coalesceAll)
{
    *result = new nsTransportEventSinkProxy(sink, target, coalesceAll);
    if (!*result)
        return NS_ERROR_OUT_OF_MEMORY;
    NS_ADDREF(*result);
    return NS_OK;
}