1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/* -*- 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 "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
|