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-10-08 08:27:13 +04:00
|
|
|
|
2010-04-20 20:32:28 +04:00
|
|
|
#include "nsIOService.h"
|
2003-10-08 08:27:13 +04:00
|
|
|
#include "nsSyncStreamListener.h"
|
|
|
|
#include "nsIPipe.h"
|
2013-09-22 07:04:57 +04:00
|
|
|
#include "nsThreadUtils.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2003-10-08 08:27:13 +04:00
|
|
|
|
2017-04-08 00:35:48 +03:00
|
|
|
using namespace mozilla::net;
|
|
|
|
|
2003-10-08 08:27:13 +04:00
|
|
|
nsresult nsSyncStreamListener::Init() {
|
|
|
|
return NS_NewPipe(getter_AddRefs(mPipeIn), getter_AddRefs(mPipeOut),
|
2017-05-04 13:14:04 +03:00
|
|
|
mozilla::net::nsIOService::gDefaultSegmentSize,
|
2012-09-28 10:57:33 +04:00
|
|
|
UINT32_MAX, // no size limit
|
2011-10-17 18:59:28 +04:00
|
|
|
false, false);
|
2003-10-08 08:27:13 +04:00
|
|
|
}
|
|
|
|
|
2018-10-23 23:07:29 +03:00
|
|
|
// static
|
|
|
|
already_AddRefed<nsISyncStreamListener> nsSyncStreamListener::Create() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
|
|
|
RefPtr<nsSyncStreamListener> inst = new nsSyncStreamListener();
|
|
|
|
nsresult rv = inst->Init();
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
|
|
|
|
|
|
|
return inst.forget();
|
|
|
|
}
|
|
|
|
|
2003-10-08 08:27:13 +04:00
|
|
|
nsresult nsSyncStreamListener::WaitForData() {
|
2011-10-17 18:59:28 +04:00
|
|
|
mKeepWaiting = true;
|
2003-10-08 08:27:13 +04:00
|
|
|
|
2017-05-15 16:34:19 +03:00
|
|
|
if (!mozilla::SpinEventLoopUntil([&]() { return !mKeepWaiting; })) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2003-10-08 08:27:13 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsSyncStreamListener::nsISupports
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsSyncStreamListener, nsIStreamListener, nsIRequestObserver,
|
|
|
|
nsIInputStream, nsISyncStreamListener)
|
2003-10-08 08:27:13 +04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsSyncStreamListener::nsISyncStreamListener
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::GetInputStream(nsIInputStream** result) {
|
2003-10-08 08:27:13 +04:00
|
|
|
NS_ADDREF(*result = this);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsSyncStreamListener::nsIStreamListener
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::OnStartRequest(nsIRequest* request) { return NS_OK; }
|
2003-10-08 08:27:13 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::OnDataAvailable(nsIRequest* request,
|
|
|
|
nsIInputStream* stream, uint64_t offset,
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t count) {
|
|
|
|
uint32_t bytesWritten;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2003-10-08 08:27:13 +04:00
|
|
|
nsresult rv = mPipeOut->WriteFrom(stream, count, &bytesWritten);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2003-10-08 08:37:38 +04:00
|
|
|
// if we get an error, then return failure. this will cause the
|
|
|
|
// channel to be canceled, and as a result our OnStopRequest method
|
|
|
|
// will be called immediately. because of this we do not need to
|
|
|
|
// set mStatus or mKeepWaiting here.
|
2003-10-08 08:27:13 +04:00
|
|
|
if (NS_FAILED(rv)) return rv;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2003-10-08 08:37:38 +04:00
|
|
|
// we expect that all data will be written to the pipe because
|
|
|
|
// the pipe was created to have "infinite" room.
|
2017-07-06 15:00:35 +03:00
|
|
|
NS_ASSERTION(bytesWritten == count, "did not write all data");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mKeepWaiting = false; // unblock Read
|
2003-10-08 08:27:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::OnStopRequest(nsIRequest* request, nsresult status) {
|
2003-10-08 08:27:13 +04:00
|
|
|
mStatus = status;
|
2011-10-17 18:59:28 +04:00
|
|
|
mKeepWaiting = false; // unblock Read
|
|
|
|
mDone = true;
|
2003-10-08 08:27:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// nsSyncStreamListener::nsIInputStream
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSyncStreamListener::Close() {
|
|
|
|
mStatus = NS_BASE_STREAM_CLOSED;
|
2011-10-17 18:59:28 +04:00
|
|
|
mDone = true;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2006-01-02 05:30:32 +03:00
|
|
|
// It'd be nice if we could explicitly cancel the request at this point,
|
|
|
|
// but we don't have a reference to it, so the best we can do is close the
|
|
|
|
// pipe so that the next OnDataAvailable event will fail.
|
|
|
|
if (mPipeIn) {
|
|
|
|
mPipeIn->Close();
|
2012-07-30 18:20:58 +04:00
|
|
|
mPipeIn = nullptr;
|
2006-01-02 05:30:32 +03:00
|
|
|
}
|
2003-10-08 08:27:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::Available(uint64_t* result) {
|
2003-10-08 08:27:13 +04:00
|
|
|
if (NS_FAILED(mStatus)) return mStatus;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2003-10-08 08:27:13 +04:00
|
|
|
mStatus = mPipeIn->Available(result);
|
|
|
|
if (NS_SUCCEEDED(mStatus) && (*result == 0) && !mDone) {
|
|
|
|
mStatus = WaitForData();
|
|
|
|
if (NS_SUCCEEDED(mStatus)) mStatus = mPipeIn->Available(result);
|
|
|
|
}
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::Read(char* buf, uint32_t bufLen, uint32_t* result) {
|
2006-01-02 05:30:32 +03:00
|
|
|
if (mStatus == NS_BASE_STREAM_CLOSED) {
|
|
|
|
*result = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint64_t avail64;
|
2012-08-11 06:44:11 +04:00
|
|
|
if (NS_FAILED(Available(&avail64))) return mStatus;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-01-15 16:22:03 +04:00
|
|
|
uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)bufLen);
|
2003-10-08 08:27:13 +04:00
|
|
|
mStatus = mPipeIn->Read(buf, avail, result);
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::ReadSegments(nsWriteSegmentFun writer, void* closure,
|
|
|
|
uint32_t count, uint32_t* result) {
|
2006-01-02 05:30:32 +03:00
|
|
|
if (mStatus == NS_BASE_STREAM_CLOSED) {
|
|
|
|
*result = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint64_t avail64;
|
2012-08-11 06:44:11 +04:00
|
|
|
if (NS_FAILED(Available(&avail64))) return mStatus;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2013-01-15 16:22:03 +04:00
|
|
|
uint32_t avail = (uint32_t)std::min(avail64, (uint64_t)count);
|
2003-10-08 08:27:13 +04:00
|
|
|
mStatus = mPipeIn->ReadSegments(writer, closure, avail, result);
|
|
|
|
return mStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-05-01 11:47:10 +03:00
|
|
|
nsSyncStreamListener::IsNonBlocking(bool* result) {
|
2011-10-17 18:59:28 +04:00
|
|
|
*result = false;
|
2003-10-08 08:27:13 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|