diff options
Diffstat (limited to 'netwerk/protocol/http/AltDataOutputStreamChild.cpp')
-rw-r--r-- | netwerk/protocol/http/AltDataOutputStreamChild.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/netwerk/protocol/http/AltDataOutputStreamChild.cpp b/netwerk/protocol/http/AltDataOutputStreamChild.cpp new file mode 100644 index 0000000000..f1f562255b --- /dev/null +++ b/netwerk/protocol/http/AltDataOutputStreamChild.cpp @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/net/AltDataOutputStreamChild.h" +#include "mozilla/Unused.h" +#include "nsIInputStream.h" +#include "nsStreamUtils.h" + +namespace mozilla { +namespace net { + +NS_IMPL_ADDREF(AltDataOutputStreamChild) + +NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release() { + MOZ_ASSERT(0 != mRefCnt, "dup release"); + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild"); + + if (mRefCnt == 1 && mIPCOpen) { + // The only reference left is the IPDL one. After the parent replies back + // with a DeleteSelf message, the child will call Send__delete__(this), + // decrementing the ref count and triggering the destructor. + SendDeleteSelf(); + return 1; + } + + if (mRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + delete this; + return 0; + } + return mRefCnt; +} + +NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild) + NS_INTERFACE_MAP_ENTRY(nsIAsyncOutputStream) + NS_INTERFACE_MAP_ENTRY(nsIOutputStream) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +AltDataOutputStreamChild::AltDataOutputStreamChild() + : mIPCOpen(false), mError(NS_OK), mCallbackFlags(0) { + MOZ_ASSERT(NS_IsMainThread(), "Main thread only"); +} + +void AltDataOutputStreamChild::AddIPDLReference() { + MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference"); + mIPCOpen = true; + AddRef(); +} + +void AltDataOutputStreamChild::ReleaseIPDLReference() { + MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference"); + mIPCOpen = false; + + if (mCallback) { + NotifyListener(); + } + + Release(); +} + +bool AltDataOutputStreamChild::WriteDataInChunks( + const nsDependentCSubstring& data) { + const size_t kChunkSize = 128 * 1024; + size_t next = std::min(data.Length(), kChunkSize); + for (size_t i = 0; i < data.Length(); + i = next, next = std::min(data.Length(), next + kChunkSize)) { + nsCString chunk(Substring(data, i, kChunkSize)); + if (mIPCOpen && !SendWriteData(chunk)) { + mIPCOpen = false; + return false; + } + } + return true; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::Close() { return CloseWithStatus(NS_OK); } + +NS_IMETHODIMP +AltDataOutputStreamChild::Flush() { + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + + // This is a no-op + return NS_OK; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::Write(const char* aBuf, uint32_t aCount, + uint32_t* _retval) { + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + if (WriteDataInChunks(nsDependentCSubstring(aBuf, aCount))) { + *_retval = aCount; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::WriteFrom(nsIInputStream* aFromStream, + uint32_t aCount, uint32_t* _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, + void* aClosure, uint32_t aCount, + uint32_t* _retval) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::IsNonBlocking(bool* _retval) { + *_retval = false; + return NS_OK; +} + +mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvError( + const nsresult& err) { + mError = err; + return IPC_OK(); +} + +mozilla::ipc::IPCResult AltDataOutputStreamChild::RecvDeleteSelf() { + PAltDataOutputStreamChild::Send__delete__(this); + return IPC_OK(); +} + +// nsIAsyncOutputStream + +NS_IMETHODIMP +AltDataOutputStreamChild::CloseWithStatus(nsresult aStatus) { + if (!mIPCOpen) { + return NS_ERROR_NOT_AVAILABLE; + } + if (NS_FAILED(mError)) { + return mError; + } + Unused << SendClose(aStatus); + + return NS_OK; +} + +NS_IMETHODIMP +AltDataOutputStreamChild::AsyncWait(nsIOutputStreamCallback* aCallback, + uint32_t aFlags, uint32_t aRequestedCount, + nsIEventTarget* aEventTarget) { + mCallback = aCallback; + mCallbackFlags = aFlags; + mCallbackTarget = aEventTarget; + + if (!mCallback) { + return NS_OK; + } + + // The stream is blocking so it is writable at any time + if (!mIPCOpen || !(aFlags & WAIT_CLOSURE_ONLY)) { + NotifyListener(); + } + + return NS_OK; +} + +void AltDataOutputStreamChild::NotifyListener() { + MOZ_ASSERT(mCallback); + + if (!mCallbackTarget) { + mCallbackTarget = GetMainThreadEventTarget(); + } + + nsCOMPtr<nsIOutputStreamCallback> asyncCallback = + NS_NewOutputStreamReadyEvent(mCallback, mCallbackTarget); + + mCallback = nullptr; + mCallbackTarget = nullptr; + + asyncCallback->OnOutputStreamReady(this); +} + +} // namespace net +} // namespace mozilla |