2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
#include "nsStreamTransportService.h"
|
2006-05-10 21:30:15 +04:00
|
|
|
#include "nsXPCOMCIDInternal.h"
|
2003-01-18 04:27:53 +03:00
|
|
|
#include "nsNetSegmentUtils.h"
|
2003-10-06 05:46:31 +04:00
|
|
|
#include "nsTransportUtils.h"
|
|
|
|
#include "nsStreamUtils.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2003-10-06 05:46:31 +04:00
|
|
|
#include "nsNetCID.h"
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
#include "nsIAsyncInputStream.h"
|
|
|
|
#include "nsIAsyncOutputStream.h"
|
|
|
|
#include "nsISeekableStream.h"
|
|
|
|
#include "nsIPipe.h"
|
|
|
|
#include "nsITransport.h"
|
2006-05-10 21:30:15 +04:00
|
|
|
#include "nsIObserverService.h"
|
2013-09-22 07:04:57 +04:00
|
|
|
#include "nsIThreadPool.h"
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
#include "mozilla/Services.h"
|
2003-01-18 04:27:53 +03:00
|
|
|
|
2016-05-19 05:02:57 +03:00
|
|
|
namespace mozilla {
|
|
|
|
namespace net {
|
|
|
|
|
2003-01-18 04:27:53 +03:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsInputStreamTransport
|
2003-10-06 05:46:31 +04:00
|
|
|
//
|
|
|
|
// Implements nsIInputStream as a wrapper around the real input stream. This
|
|
|
|
// allows the transport to support seeking, range-limiting, progress reporting,
|
|
|
|
// and close-when-done semantics while utilizing NS_AsyncCopy.
|
2003-01-18 04:27:53 +03:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
class nsInputStreamTransport : public nsITransport
|
|
|
|
, public nsIInputStream
|
2003-01-18 04:27:53 +03:00
|
|
|
{
|
|
|
|
public:
|
2013-07-19 06:24:13 +04:00
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
2003-01-18 04:27:53 +03:00
|
|
|
NS_DECL_NSITRANSPORT
|
2003-10-06 05:46:31 +04:00
|
|
|
NS_DECL_NSIINPUTSTREAM
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
nsInputStreamTransport(nsIInputStream *source,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool closeWhenDone)
|
2003-01-18 04:27:53 +03:00
|
|
|
: mSource(source)
|
2017-09-26 08:21:27 +03:00
|
|
|
, mOffset(0)
|
2003-01-18 04:27:53 +03:00
|
|
|
, mCloseWhenDone(closeWhenDone)
|
2011-10-17 18:59:28 +04:00
|
|
|
, mInProgress(false)
|
2003-01-18 04:27:53 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-06-24 20:36:44 +04:00
|
|
|
private:
|
2003-01-18 04:27:53 +03:00
|
|
|
virtual ~nsInputStreamTransport()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAsyncInputStream> mPipeIn;
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
// while the copy is active, these members may only be accessed from the
|
|
|
|
// nsIInputStream implementation.
|
2003-01-18 04:27:53 +03:00
|
|
|
nsCOMPtr<nsITransportEventSink> mEventSink;
|
|
|
|
nsCOMPtr<nsIInputStream> mSource;
|
2015-01-08 22:48:52 +03:00
|
|
|
int64_t mOffset;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mCloseWhenDone;
|
2003-10-06 05:46:31 +04:00
|
|
|
|
|
|
|
// this variable serves as a lock to prevent the state of the transport
|
|
|
|
// from being modified once the copy is in progress.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool mInProgress;
|
2003-01-18 04:27:53 +03:00
|
|
|
};
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsInputStreamTransport,
|
|
|
|
nsITransport,
|
|
|
|
nsIInputStream)
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
/** nsITransport **/
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
nsInputStreamTransport::OpenInputStream(uint32_t flags,
|
|
|
|
uint32_t segsize,
|
|
|
|
uint32_t segcount,
|
2003-01-18 04:27:53 +03:00
|
|
|
nsIInputStream **result)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIEventTarget> target =
|
2006-05-10 21:30:15 +04:00
|
|
|
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
|
2003-10-06 05:46:31 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2003-01-18 04:27:53 +03:00
|
|
|
// XXX if the caller requests an unbuffered stream, then perhaps
|
|
|
|
// we'd want to simply return mSource; however, then we would
|
|
|
|
// not be reading mSource on a background thread. is this ok?
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool nonblocking = !(flags & OPEN_BLOCKING);
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
net_ResolveSegmentParams(segsize, segcount);
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
nsCOMPtr<nsIAsyncOutputStream> pipeOut;
|
|
|
|
rv = NS_NewPipe2(getter_AddRefs(mPipeIn),
|
|
|
|
getter_AddRefs(pipeOut),
|
2011-10-17 18:59:28 +04:00
|
|
|
nonblocking, true,
|
2012-01-10 07:43:52 +04:00
|
|
|
segsize, segcount);
|
2003-01-18 04:27:53 +03:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mInProgress = true;
|
2003-01-18 04:27:53 +03:00
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
// startup async copy process...
|
|
|
|
rv = NS_AsyncCopy(this, pipeOut, target,
|
|
|
|
NS_ASYNCCOPY_VIA_WRITESEGMENTS, segsize);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
NS_ADDREF(*result = mPipeIn);
|
2003-01-18 04:27:53 +03:00
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
return rv;
|
2003-01-18 04:27:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
nsInputStreamTransport::OpenOutputStream(uint32_t flags,
|
|
|
|
uint32_t segsize,
|
|
|
|
uint32_t segcount,
|
2003-01-18 04:27:53 +03:00
|
|
|
nsIOutputStream **result)
|
|
|
|
{
|
|
|
|
// this transport only supports reading!
|
|
|
|
NS_NOTREACHED("nsInputStreamTransport::OpenOutputStream");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsInputStreamTransport::Close(nsresult reason)
|
|
|
|
{
|
|
|
|
if (NS_SUCCEEDED(reason))
|
|
|
|
reason = NS_BASE_STREAM_CLOSED;
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
return mPipeIn->CloseWithStatus(reason);
|
2003-01-18 04:27:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsInputStreamTransport::SetEventSink(nsITransportEventSink *sink,
|
2003-10-06 05:46:31 +04:00
|
|
|
nsIEventTarget *target)
|
2003-01-18 04:27:53 +03:00
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(!mInProgress, NS_ERROR_IN_PROGRESS);
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
if (target)
|
|
|
|
return net_NewTransportEventSinkProxy(getter_AddRefs(mEventSink),
|
|
|
|
sink, target);
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
mEventSink = sink;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-10-06 05:46:31 +04:00
|
|
|
/** nsIInputStream **/
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsInputStreamTransport::Close()
|
|
|
|
{
|
|
|
|
if (mCloseWhenDone)
|
|
|
|
mSource->Close();
|
|
|
|
|
|
|
|
// make additional reads return early...
|
2017-09-26 08:21:27 +03:00
|
|
|
mOffset = 0;
|
2003-10-06 05:46:31 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
nsInputStreamTransport::Available(uint64_t *result)
|
2003-10-06 05:46:31 +04:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
nsInputStreamTransport::Read(char *buf, uint32_t count, uint32_t *result)
|
2003-10-06 05:46:31 +04:00
|
|
|
{
|
|
|
|
nsresult rv = mSource->Read(buf, count, result);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mOffset += *result;
|
|
|
|
if (mEventSink)
|
2012-08-01 12:17:09 +04:00
|
|
|
mEventSink->OnTransportStatus(this, NS_NET_STATUS_READING, mOffset,
|
2017-09-26 08:21:27 +03:00
|
|
|
-1);
|
2003-10-06 05:46:31 +04:00
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsInputStreamTransport::ReadSegments(nsWriteSegmentFun writer, void *closure,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t count, uint32_t *result)
|
2003-10-06 05:46:31 +04:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
nsInputStreamTransport::IsNonBlocking(bool *result)
|
2003-10-06 05:46:31 +04:00
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
*result = false;
|
2003-10-06 05:46:31 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsStreamTransportService
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2006-05-10 21:30:15 +04:00
|
|
|
nsStreamTransportService::~nsStreamTransportService()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsStreamTransportService::Init()
|
|
|
|
{
|
|
|
|
mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
|
|
|
|
NS_ENSURE_STATE(mPool);
|
|
|
|
|
|
|
|
// Configure the pool
|
2012-06-12 21:06:20 +04:00
|
|
|
mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
|
2013-01-23 09:26:00 +04:00
|
|
|
mPool->SetThreadLimit(25);
|
|
|
|
mPool->SetIdleThreadLimit(1);
|
|
|
|
mPool->SetIdleThreadTimeout(PR_SecondsToInterval(30));
|
2006-05-10 21:30:15 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
mozilla::services::GetObserverService();
|
2006-05-10 21:30:15 +04:00
|
|
|
if (obsSvc)
|
2011-10-17 18:59:28 +04:00
|
|
|
obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
|
2006-05-10 21:30:15 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsStreamTransportService,
|
|
|
|
nsIStreamTransportService,
|
|
|
|
nsIEventTarget,
|
|
|
|
nsIObserver)
|
2006-05-10 21:30:15 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2015-07-10 06:21:46 +03:00
|
|
|
nsStreamTransportService::DispatchFromScript(nsIRunnable *task, uint32_t flags)
|
2006-05-10 21:30:15 +04:00
|
|
|
{
|
2015-07-10 06:21:46 +03:00
|
|
|
nsCOMPtr<nsIRunnable> event(task);
|
|
|
|
return Dispatch(event.forget(), flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2016-06-01 03:04:54 +03:00
|
|
|
nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable> task, uint32_t flags)
|
2015-07-10 06:21:46 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRunnable> event(task); // so it gets released on failure paths
|
2014-06-21 14:26:43 +04:00
|
|
|
nsCOMPtr<nsIThreadPool> pool;
|
|
|
|
{
|
|
|
|
mozilla::MutexAutoLock lock(mShutdownLock);
|
|
|
|
if (mIsShutdown) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
pool = mPool;
|
|
|
|
}
|
|
|
|
NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
|
2015-07-10 06:21:46 +03:00
|
|
|
return pool->Dispatch(event.forget(), flags);
|
2006-05-10 21:30:15 +04:00
|
|
|
}
|
|
|
|
|
2016-05-13 01:15:43 +03:00
|
|
|
NS_IMETHODIMP
|
2016-06-01 03:04:54 +03:00
|
|
|
nsStreamTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
|
2016-05-13 01:15:43 +03:00
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2017-05-22 21:26:39 +03:00
|
|
|
NS_IMETHODIMP_(bool)
|
|
|
|
nsStreamTransportService::IsOnCurrentThreadInfallible()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIThreadPool> pool;
|
|
|
|
{
|
|
|
|
mozilla::MutexAutoLock lock(mShutdownLock);
|
|
|
|
pool = mPool;
|
|
|
|
}
|
|
|
|
if (!pool) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return pool->IsOnCurrentThread();
|
|
|
|
}
|
|
|
|
|
2006-05-10 21:30:15 +04:00
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
nsStreamTransportService::IsOnCurrentThread(bool *result)
|
2006-05-10 21:30:15 +04:00
|
|
|
{
|
2014-06-21 14:26:43 +04:00
|
|
|
nsCOMPtr<nsIThreadPool> pool;
|
|
|
|
{
|
|
|
|
mozilla::MutexAutoLock lock(mShutdownLock);
|
|
|
|
if (mIsShutdown) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
pool = mPool;
|
|
|
|
}
|
|
|
|
NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
return pool->IsOnCurrentThread(result);
|
2006-05-10 21:30:15 +04:00
|
|
|
}
|
2003-01-18 04:27:53 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsStreamTransportService::CreateInputTransport(nsIInputStream *stream,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool closeWhenDone,
|
2003-01-18 04:27:53 +03:00
|
|
|
nsITransport **result)
|
|
|
|
{
|
|
|
|
nsInputStreamTransport *trans =
|
2017-09-26 08:21:27 +03:00
|
|
|
new nsInputStreamTransport(stream, closeWhenDone);
|
2003-01-18 04:27:53 +03:00
|
|
|
if (!trans)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(*result = trans);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-05-10 21:30:15 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsStreamTransportService::Observe(nsISupports *subject, const char *topic,
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t *data)
|
2006-05-10 21:30:15 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(strcmp(topic, "xpcom-shutdown-threads") == 0, "oops");
|
2013-06-11 16:12:06 +04:00
|
|
|
|
2014-06-21 14:26:43 +04:00
|
|
|
{
|
|
|
|
mozilla::MutexAutoLock lock(mShutdownLock);
|
|
|
|
mIsShutdown = true;
|
|
|
|
}
|
|
|
|
|
2006-05-10 21:30:15 +04:00
|
|
|
if (mPool) {
|
|
|
|
mPool->Shutdown();
|
2012-07-30 18:20:58 +04:00
|
|
|
mPool = nullptr;
|
2006-05-10 21:30:15 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-05-19 05:02:57 +03:00
|
|
|
|
2017-05-06 00:51:13 +03:00
|
|
|
class AvailableEvent final : public Runnable
|
|
|
|
{
|
2017-06-12 22:34:10 +03:00
|
|
|
public:
|
|
|
|
AvailableEvent(nsIInputStream* stream,
|
|
|
|
nsIInputAvailableCallback* callback)
|
|
|
|
: Runnable("net::AvailableEvent")
|
|
|
|
, mStream(stream)
|
|
|
|
, mCallback(callback)
|
|
|
|
, mDoingCallback(false)
|
|
|
|
, mSize(0)
|
|
|
|
, mResultForCallback(NS_OK)
|
|
|
|
{
|
|
|
|
mCallbackTarget = GetCurrentThreadEventTarget();
|
|
|
|
}
|
2017-05-06 00:51:13 +03:00
|
|
|
|
|
|
|
NS_IMETHOD Run() override
|
|
|
|
{
|
|
|
|
if (mDoingCallback) {
|
|
|
|
// pong
|
|
|
|
mCallback->OnInputAvailableComplete(mSize, mResultForCallback);
|
|
|
|
mCallback = nullptr;
|
|
|
|
} else {
|
|
|
|
// ping
|
|
|
|
mResultForCallback = mStream->Available(&mSize);
|
|
|
|
mStream = nullptr;
|
|
|
|
mDoingCallback = true;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRunnable> event(this); // overly cute
|
|
|
|
mCallbackTarget->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
|
|
|
|
mCallbackTarget = nullptr;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual ~AvailableEvent() { }
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInputStream> mStream;
|
|
|
|
nsCOMPtr<nsIInputAvailableCallback> mCallback;
|
|
|
|
nsCOMPtr<nsIEventTarget> mCallbackTarget;
|
|
|
|
bool mDoingCallback;
|
|
|
|
uint64_t mSize;
|
|
|
|
nsresult mResultForCallback;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsStreamTransportService::InputAvailable(nsIInputStream *stream,
|
|
|
|
nsIInputAvailableCallback *callback)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIThreadPool> pool;
|
|
|
|
{
|
|
|
|
mozilla::MutexAutoLock lock(mShutdownLock);
|
|
|
|
if (mIsShutdown) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
pool = mPool;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIRunnable> event = new AvailableEvent(stream, callback);
|
|
|
|
return pool->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
2016-05-19 05:02:57 +03:00
|
|
|
} // namespace net
|
|
|
|
} // namespace mozilla
|