summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/res/RemoteStreamGetter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/res/RemoteStreamGetter.cpp')
-rw-r--r--netwerk/protocol/res/RemoteStreamGetter.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/netwerk/protocol/res/RemoteStreamGetter.cpp b/netwerk/protocol/res/RemoteStreamGetter.cpp
new file mode 100644
index 0000000000..8bad84ef5e
--- /dev/null
+++ b/netwerk/protocol/res/RemoteStreamGetter.cpp
@@ -0,0 +1,138 @@
+/* -*- 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 "RemoteStreamGetter.h"
+#include "mozilla/MozPromise.h"
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/ResultExtensions.h"
+#include "nsContentUtils.h"
+#include "nsIInputStreamPump.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(RemoteStreamGetter, nsICancelable)
+
+RemoteStreamGetter::RemoteStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo)
+ : mURI(aURI), mLoadInfo(aLoadInfo) {
+ MOZ_ASSERT(aURI);
+ MOZ_ASSERT(aLoadInfo);
+}
+
+// Request an input stream from the parent.
+RequestOrReason RemoteStreamGetter::GetAsync(nsIStreamListener* aListener,
+ nsIChannel* aChannel,
+ Method aMethod) {
+ MOZ_ASSERT(IsNeckoChild());
+ MOZ_ASSERT(aMethod);
+
+ mListener = aListener;
+ mChannel = aChannel;
+
+ nsCOMPtr<nsICancelable> cancelableRequest(this);
+
+ RefPtr<RemoteStreamGetter> self = this;
+ LoadInfoArgs loadInfoArgs;
+ nsresult rv = ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs);
+ if (NS_FAILED(rv)) {
+ return Err(rv);
+ }
+
+ (gNeckoChild->*aMethod)(mURI, loadInfoArgs)
+ ->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ [self](const Maybe<RemoteStreamInfo>& info) { self->OnStream(info); },
+ [self](const mozilla::ipc::ResponseRejectReason) {
+ self->OnStream(Nothing());
+ });
+ return RequestOrCancelable(WrapNotNull(cancelableRequest));
+}
+
+// Called to cancel the ongoing async request.
+NS_IMETHODIMP
+RemoteStreamGetter::Cancel(nsresult aStatus) {
+ if (mCanceled) {
+ return NS_OK;
+ }
+
+ mCanceled = true;
+ mStatus = aStatus;
+
+ if (mPump) {
+ mPump->Cancel(aStatus);
+ mPump = nullptr;
+ }
+
+ return NS_OK;
+}
+
+// static
+void RemoteStreamGetter::CancelRequest(nsIStreamListener* aListener,
+ nsIChannel* aChannel, nsresult aResult) {
+ MOZ_ASSERT(aListener);
+ MOZ_ASSERT(aChannel);
+
+ aListener->OnStartRequest(aChannel);
+ aListener->OnStopRequest(aChannel, aResult);
+ aChannel->CancelWithReason(NS_BINDING_ABORTED,
+ "RemoteStreamGetter::CancelRequest"_ns);
+}
+
+// Handle an input stream sent from the parent.
+void RemoteStreamGetter::OnStream(const Maybe<RemoteStreamInfo>& aStreamInfo) {
+ MOZ_ASSERT(IsNeckoChild());
+ MOZ_ASSERT(mChannel);
+ MOZ_ASSERT(mListener);
+
+ nsCOMPtr<nsIChannel> channel = std::move(mChannel);
+
+ // We must keep an owning reference to the listener until we pass it on
+ // to AsyncRead.
+ nsCOMPtr<nsIStreamListener> listener = mListener.forget();
+
+ if (aStreamInfo.isNothing()) {
+ // The parent didn't send us back a stream.
+ CancelRequest(listener, channel, NS_ERROR_FILE_ACCESS_DENIED);
+ return;
+ }
+
+ if (mCanceled) {
+ // The channel that has created this stream getter has been canceled.
+ CancelRequest(listener, channel, mStatus);
+ return;
+ }
+
+ nsCOMPtr<nsIInputStream> stream = std::move(aStreamInfo.ref().inputStream());
+ if (!stream) {
+ // We somehow failed to get a stream, so just cancel the request.
+ CancelRequest(listener, channel, mStatus);
+ return;
+ }
+
+ nsCOMPtr<nsIInputStreamPump> pump;
+ nsresult rv =
+ NS_NewInputStreamPump(getter_AddRefs(pump), stream.forget(), 0, 0, false,
+ GetMainThreadSerialEventTarget());
+ if (NS_FAILED(rv)) {
+ CancelRequest(listener, channel, rv);
+ return;
+ }
+
+ channel->SetContentType(aStreamInfo.ref().contentType());
+ channel->SetContentLength(aStreamInfo.ref().contentLength());
+
+ rv = pump->AsyncRead(listener);
+ if (NS_FAILED(rv)) {
+ CancelRequest(listener, channel, rv);
+ return;
+ }
+
+ mPump = pump;
+}
+
+} // namespace net
+} // namespace mozilla