RemoteStreamGetter.cpp (3992B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "RemoteStreamGetter.h" 8 #include "mozilla/MozPromise.h" 9 #include "mozilla/net/NeckoChild.h" 10 #include "mozilla/RefPtr.h" 11 #include "nsContentUtils.h" 12 #include "nsIInputStreamPump.h" 13 14 namespace mozilla { 15 namespace net { 16 17 NS_IMPL_ISUPPORTS(RemoteStreamGetter, nsICancelable) 18 19 RemoteStreamGetter::RemoteStreamGetter(nsIURI* aURI, nsILoadInfo* aLoadInfo) 20 : mURI(aURI), mLoadInfo(aLoadInfo) { 21 MOZ_ASSERT(aURI); 22 MOZ_ASSERT(aLoadInfo); 23 } 24 25 // Request an input stream from the parent. 26 RequestOrReason RemoteStreamGetter::GetAsync(nsIStreamListener* aListener, 27 nsIChannel* aChannel, 28 Method aMethod) { 29 MOZ_ASSERT(IsNeckoChild()); 30 MOZ_ASSERT(aMethod); 31 32 mListener = aListener; 33 mChannel = aChannel; 34 35 nsCOMPtr<nsICancelable> cancelableRequest(this); 36 37 RefPtr<RemoteStreamGetter> self = this; 38 LoadInfoArgs loadInfoArgs; 39 nsresult rv = ipc::LoadInfoToLoadInfoArgs(mLoadInfo, &loadInfoArgs); 40 if (NS_FAILED(rv)) { 41 return Err(rv); 42 } 43 44 (gNeckoChild->*aMethod)(mURI, loadInfoArgs) 45 ->Then( 46 GetMainThreadSerialEventTarget(), __func__, 47 [self](const Maybe<RemoteStreamInfo>& info) { self->OnStream(info); }, 48 [self](const mozilla::ipc::ResponseRejectReason) { 49 self->OnStream(Nothing()); 50 }); 51 return RequestOrCancelable(WrapNotNull(cancelableRequest)); 52 } 53 54 // Called to cancel the ongoing async request. 55 NS_IMETHODIMP 56 RemoteStreamGetter::Cancel(nsresult aStatus) { 57 if (mCanceled) { 58 return NS_OK; 59 } 60 61 mCanceled = true; 62 mStatus = aStatus; 63 64 if (mPump) { 65 mPump->Cancel(aStatus); 66 mPump = nullptr; 67 } 68 69 return NS_OK; 70 } 71 72 // static 73 void RemoteStreamGetter::CancelRequest(nsIStreamListener* aListener, 74 nsIChannel* aChannel, nsresult aResult) { 75 MOZ_ASSERT(aListener); 76 MOZ_ASSERT(aChannel); 77 78 aListener->OnStartRequest(aChannel); 79 aListener->OnStopRequest(aChannel, aResult); 80 aChannel->CancelWithReason(NS_BINDING_ABORTED, 81 "RemoteStreamGetter::CancelRequest"_ns); 82 } 83 84 // Handle an input stream sent from the parent. 85 void RemoteStreamGetter::OnStream(const Maybe<RemoteStreamInfo>& aStreamInfo) { 86 MOZ_ASSERT(IsNeckoChild()); 87 MOZ_ASSERT(mChannel); 88 MOZ_ASSERT(mListener); 89 90 nsCOMPtr<nsIChannel> channel = std::move(mChannel); 91 92 // We must keep an owning reference to the listener until we pass it on 93 // to AsyncRead. 94 nsCOMPtr<nsIStreamListener> listener = mListener.forget(); 95 96 if (aStreamInfo.isNothing()) { 97 // The parent didn't send us back a stream. 98 CancelRequest(listener, channel, NS_ERROR_FILE_ACCESS_DENIED); 99 return; 100 } 101 102 if (mCanceled) { 103 // The channel that has created this stream getter has been canceled. 104 CancelRequest(listener, channel, mStatus); 105 return; 106 } 107 108 nsCOMPtr<nsIInputStream> stream = std::move(aStreamInfo.ref().inputStream()); 109 if (!stream) { 110 // We somehow failed to get a stream, so just cancel the request. 111 CancelRequest(listener, channel, mStatus); 112 return; 113 } 114 115 nsCOMPtr<nsIInputStreamPump> pump; 116 nsresult rv = 117 NS_NewInputStreamPump(getter_AddRefs(pump), stream.forget(), 0, 0, false, 118 GetMainThreadSerialEventTarget()); 119 if (NS_FAILED(rv)) { 120 CancelRequest(listener, channel, rv); 121 return; 122 } 123 124 channel->SetContentType(aStreamInfo.ref().contentType()); 125 channel->SetContentLength(aStreamInfo.ref().contentLength()); 126 127 rv = pump->AsyncRead(listener); 128 if (NS_FAILED(rv)) { 129 CancelRequest(listener, channel, rv); 130 return; 131 } 132 133 mPump = pump; 134 } 135 136 } // namespace net 137 } // namespace mozilla