GeckoViewContentChannelChild.cpp (9262B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=4 sw=2 sts=2 et 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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "GeckoViewContentChannelChild.h" 8 9 #include "mozilla/dom/BrowserChild.h" 10 #include "mozilla/dom/ContentChild.h" 11 #include "mozilla/ipc/URIUtils.h" 12 #include "mozilla/net/NeckoChild.h" 13 #include "nsContentSecurityManager.h" 14 #include "nsGkAtoms.h" 15 #include "nsIBrowserChild.h" 16 #include "nsIURIMutator.h" 17 #include "nsStringStream.h" 18 #include "SerializedLoadContext.h" 19 20 namespace mozilla::net { 21 22 NS_IMPL_ISUPPORTS_INHERITED(GeckoViewContentChannelChild, nsBaseChannel, 23 nsIChildChannel) 24 25 GeckoViewContentChannelChild::GeckoViewContentChannelChild(nsIURI* aURI) 26 : mEventQ(new ChannelEventQueue(static_cast<nsIChildChannel*>(this))) { 27 SetURI(aURI); 28 SetOriginalURI(aURI); 29 } 30 31 NS_IMETHODIMP 32 GeckoViewContentChannelChild::ConnectParent(uint32_t aId) { 33 mozilla::dom::BrowserChild* browserChild = nullptr; 34 nsCOMPtr<nsIBrowserChild> iBrowserChild; 35 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, 36 NS_GET_IID(nsIBrowserChild), 37 getter_AddRefs(iBrowserChild)); 38 GetCallback(iBrowserChild); 39 if (iBrowserChild) { 40 browserChild = 41 static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get()); 42 } 43 44 GeckoViewContentChannelConnectArgs connectArgs(aId); 45 if (!gNeckoChild->SendPGeckoViewContentChannelConstructor( 46 this, browserChild, IPC::SerializedLoadContext(this), connectArgs)) { 47 return NS_ERROR_FAILURE; 48 } 49 50 return NS_OK; 51 } 52 53 NS_IMETHODIMP 54 GeckoViewContentChannelChild::CompleteRedirectSetup( 55 nsIStreamListener* aListener) { 56 mListener = aListener; 57 58 if (mLoadGroup) { 59 mLoadGroup->AddRequest(this, nullptr); 60 } 61 62 return NS_OK; 63 } 64 65 void GeckoViewContentChannelChild::ActorDestroy(ActorDestroyReason why) {} 66 67 NS_IMETHODIMP 68 GeckoViewContentChannelChild::AsyncOpen(nsIStreamListener* aListener) { 69 nsCOMPtr<nsIStreamListener> listener = aListener; 70 71 nsresult rv = 72 nsContentSecurityManager::doContentSecurityCheck(this, listener); 73 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 74 return rv; 75 } 76 77 NS_ENSURE_TRUE(!!gNeckoChild, NS_ERROR_FAILURE); 78 NS_ENSURE_TRUE(!dom::ContentChild::GetSingleton()->IsShuttingDown(), 79 NS_ERROR_FAILURE); 80 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED); 81 NS_ENSURE_ARG(listener); 82 83 // Ensure that this is an allowed port before proceeding. 84 rv = NS_CheckPortSafety(nsBaseChannel::URI()); 85 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 86 return rv; 87 } 88 89 if (mLoadGroup) { 90 mLoadGroup->AddRequest(this, nullptr); 91 } 92 93 uint32_t loadFlags = 0; 94 GetLoadFlags(&loadFlags); 95 96 GeckoViewContentChannelOpenArgs openArgs; 97 ipc::SerializeURI(nsBaseChannel::URI(), openArgs.uri()); 98 openArgs.loadFlags() = loadFlags; 99 100 nsCOMPtr<nsILoadInfo> loadInfo = nsBaseChannel::LoadInfo(); 101 rv = mozilla::ipc::LoadInfoToLoadInfoArgs(loadInfo, &openArgs.loadInfo()); 102 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 103 return rv; 104 } 105 106 mozilla::dom::BrowserChild* browserChild = nullptr; 107 nsCOMPtr<nsIBrowserChild> iBrowserChild; 108 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, 109 NS_GET_IID(nsIBrowserChild), 110 getter_AddRefs(iBrowserChild)); 111 GetCallback(iBrowserChild); 112 if (iBrowserChild) { 113 browserChild = 114 static_cast<mozilla::dom::BrowserChild*>(iBrowserChild.get()); 115 } 116 117 if (!gNeckoChild->SendPGeckoViewContentChannelConstructor( 118 this, browserChild, IPC::SerializedLoadContext(this), openArgs)) { 119 return NS_ERROR_FAILURE; 120 } 121 122 return NS_OK; 123 } 124 125 NS_IMETHODIMP 126 GeckoViewContentChannelChild::Cancel(nsresult aStatus) { 127 if (mCanceled) { 128 return NS_OK; 129 } 130 131 mCanceled = true; 132 mStatus = aStatus; 133 134 if (CanSend()) { 135 SendCancel(aStatus); 136 } 137 138 return NS_OK; 139 } 140 141 NS_IMETHODIMP 142 GeckoViewContentChannelChild::Suspend() { 143 if (!mSuspendCount++) { 144 SendSuspend(); 145 mSuspendSent = true; 146 } 147 mEventQ->Suspend(); 148 149 return NS_OK; 150 } 151 152 NS_IMETHODIMP 153 GeckoViewContentChannelChild::Resume() { 154 if (!mSuspendCount) { 155 return NS_ERROR_UNEXPECTED; 156 } 157 158 if (!--mSuspendCount && mSuspendSent) { 159 SendResume(); 160 } 161 mEventQ->Resume(); 162 163 return NS_OK; 164 } 165 166 nsresult GeckoViewContentChannelChild::OpenContentStream( 167 bool aAsync, nsIInputStream** aStream, nsIChannel** aChannel) { 168 MOZ_ASSERT_UNREACHABLE( 169 "GeckoViewContentChannel*Child* should never have OpenContentStream " 170 "called!"); 171 return NS_OK; 172 } 173 174 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnStartRequest( 175 const nsresult& aChannelStatus, const nsACString& aContentType, 176 const nsACString& aEntityID, mozilla::NotNull<nsIURI*> aURI) { 177 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 178 this, [self = UnsafePtr<GeckoViewContentChannelChild>(this), 179 aChannelStatus, aContentType = nsCString(aContentType), 180 aEntityID = nsCString(aEntityID), aURI = RefPtr{aURI.get()}]() { 181 self->DoOnStartRequest(aChannelStatus, aContentType, aEntityID, aURI); 182 })); 183 return IPC_OK(); 184 } 185 186 void GeckoViewContentChannelChild::DoOnStartRequest( 187 const nsresult& aChannelStatus, const nsCString& aContentType, 188 const nsCString& aEntityID, nsIURI* aURI) { 189 // content:// doesn't know data length at this time. 190 mContentLength = -1; 191 SetContentType(aContentType); 192 193 nsCString spec; 194 nsresult rv = aURI->GetSpec(spec); 195 if (NS_SUCCEEDED(rv)) { 196 // Changes nsBaseChannel::URI() 197 rv = NS_MutateURI(mURI).SetSpec(spec).Finalize(mURI); 198 } 199 200 if (NS_FAILED(rv)) { 201 Cancel(rv); 202 } 203 204 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 205 rv = mListener->OnStartRequest(reinterpret_cast<nsBaseChannel*>(this)); 206 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 207 Cancel(rv); 208 } 209 } 210 211 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnDataAvailable( 212 const nsresult& aChannelStatus, const nsACString& aData, 213 const uint64_t& aOffset, const uint32_t& aCount) { 214 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 215 this, [self = UnsafePtr<GeckoViewContentChannelChild>(this), 216 aChannelStatus, aData = nsCString(aData), aOffset, aCount]() { 217 self->DoOnDataAvailable(aChannelStatus, aData, aOffset, aCount); 218 })); 219 return IPC_OK(); 220 } 221 222 void GeckoViewContentChannelChild::DoOnDataAvailable( 223 const nsresult& aChannelStatus, const nsCString& aData, 224 const uint64_t& aOffset, const uint32_t& aCount) { 225 nsCOMPtr<nsIInputStream> stringStream; 226 nsresult rv = 227 NS_NewByteInputStream(getter_AddRefs(stringStream), 228 Span(aData).To(aCount), NS_ASSIGNMENT_DEPEND); 229 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 230 Cancel(rv); 231 return; 232 } 233 234 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 235 rv = mListener->OnDataAvailable(reinterpret_cast<nsBaseChannel*>(this), 236 stringStream, aOffset, aCount); 237 stringStream->Close(); 238 if (MOZ_UNLIKELY(NS_FAILED(rv))) { 239 Cancel(rv); 240 } 241 } 242 243 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnStopRequest( 244 const nsresult& aChannelStatus) { 245 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 246 this, [self = UnsafePtr<GeckoViewContentChannelChild>(this), 247 aChannelStatus]() { self->DoOnStopRequest(aChannelStatus); })); 248 return IPC_OK(); 249 } 250 251 void GeckoViewContentChannelChild::DoOnStopRequest( 252 const nsresult& aChannelStatus) { 253 if (!mCanceled) { 254 mStatus = aChannelStatus; 255 } 256 257 { 258 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 259 mListener->OnStopRequest(reinterpret_cast<nsBaseChannel*>(this), 260 aChannelStatus); 261 mListener = nullptr; 262 263 if (mLoadGroup) { 264 mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus); 265 } 266 } 267 268 Send__delete__(this); 269 } 270 271 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvOnAsyncOpenFailed( 272 const nsresult& aChannelStatus) { 273 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 274 this, [self = UnsafePtr<GeckoViewContentChannelChild>(this), 275 aChannelStatus]() { self->DoOnAsyncOpenFailed(aChannelStatus); })); 276 return IPC_OK(); 277 } 278 279 void GeckoViewContentChannelChild::DoOnAsyncOpenFailed( 280 const nsresult& aChannelStatus) { 281 mStatus = aChannelStatus; 282 283 if (mLoadGroup) { 284 mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus); 285 } 286 287 if (mListener) { 288 mListener->OnStartRequest(reinterpret_cast<nsBaseChannel*>(this)); 289 mListener->OnStopRequest(reinterpret_cast<nsBaseChannel*>(this), 290 aChannelStatus); 291 } 292 293 mListener = nullptr; 294 295 if (CanSend()) { 296 Send__delete__(this); 297 } 298 } 299 300 mozilla::ipc::IPCResult GeckoViewContentChannelChild::RecvDeleteSelf() { 301 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 302 this, [self = UnsafePtr<GeckoViewContentChannelChild>(this)]() { 303 self->DoDeleteSelf(); 304 })); 305 return IPC_OK(); 306 } 307 308 void GeckoViewContentChannelChild::DoDeleteSelf() { 309 if (CanSend()) { 310 Send__delete__(this); 311 } 312 } 313 314 } // namespace mozilla::net