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 "GIOChannelParent.h"
8 #include "nsGIOProtocolHandler.h"
9 #include "mozilla/Assertions.h"
10 #include "mozilla/dom/ContentParent.h"
11 #include "mozilla/dom/BrowserParent.h"
12 #include "mozilla/net/NeckoParent.h"
13 #include "nsNetUtil.h"
14 #include "nsIChannel.h"
15 #include "mozilla/net/NeckoChannelParams.h"
16 #include "nsIAuthPrompt.h"
17 #include "nsIAuthPromptProvider.h"
18 #include "nsISecureBrowserUI.h"
19 #include "nsQueryObject.h"
20 #include "mozilla/Logging.h"
21 
22 using namespace mozilla::dom;
23 using namespace mozilla::ipc;
24 
25 namespace mozilla {
26 #undef LOG
27 #define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args)
28 namespace net {
29 
GIOChannelParent(dom::BrowserParent * aIframeEmbedding,nsILoadContext * aLoadContext,PBOverrideStatus aOverrideStatus)30 GIOChannelParent::GIOChannelParent(dom::BrowserParent* aIframeEmbedding,
31                                    nsILoadContext* aLoadContext,
32                                    PBOverrideStatus aOverrideStatus)
33     : mLoadContext(aLoadContext),
34       mPBOverride(aOverrideStatus),
35       mBrowserParent(aIframeEmbedding) {
36   mEventQ = new ChannelEventQueue(static_cast<nsIParentChannel*>(this));
37 }
38 
ActorDestroy(ActorDestroyReason why)39 void GIOChannelParent::ActorDestroy(ActorDestroyReason why) {
40   // We may still have refcount>0 if the channel hasn't called OnStopRequest
41   // yet, but we must not send any more msgs to child.
42   mIPCClosed = true;
43 }
44 
45 //-----------------------------------------------------------------------------
46 // GIOChannelParent::nsISupports
47 //-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS(GIOChannelParent,nsIStreamListener,nsIParentChannel,nsIInterfaceRequestor,nsIRequestObserver)48 NS_IMPL_ISUPPORTS(GIOChannelParent, nsIStreamListener, nsIParentChannel,
49                   nsIInterfaceRequestor, nsIRequestObserver)
50 
51 //-----------------------------------------------------------------------------
52 // GIOChannelParent methods
53 //-----------------------------------------------------------------------------
54 
55 bool GIOChannelParent::Init(const GIOChannelCreationArgs& aOpenArgs) {
56   switch (aOpenArgs.type()) {
57     case GIOChannelCreationArgs::TGIOChannelOpenArgs: {
58       const GIOChannelOpenArgs& a = aOpenArgs.get_GIOChannelOpenArgs();
59       return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream(),
60                          a.loadInfo(), a.loadFlags());
61     }
62     case GIOChannelCreationArgs::TGIOChannelConnectArgs: {
63       const GIOChannelConnectArgs& cArgs =
64           aOpenArgs.get_GIOChannelConnectArgs();
65       return ConnectChannel(cArgs.channelId());
66     }
67     default:
68       MOZ_ASSERT_UNREACHABLE("unknown open type");
69       return false;
70   }
71 }
72 
DoAsyncOpen(const URIParams & aURI,const uint64_t & aStartPos,const nsCString & aEntityID,const Maybe<IPCStream> & aUploadStream,const Maybe<LoadInfoArgs> & aLoadInfoArgs,const uint32_t & aLoadFlags)73 bool GIOChannelParent::DoAsyncOpen(const URIParams& aURI,
74                                    const uint64_t& aStartPos,
75                                    const nsCString& aEntityID,
76                                    const Maybe<IPCStream>& aUploadStream,
77                                    const Maybe<LoadInfoArgs>& aLoadInfoArgs,
78                                    const uint32_t& aLoadFlags) {
79   nsresult rv;
80 
81   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
82   if (!uri) {
83     return false;
84   }
85 
86 #ifdef DEBUG
87   LOG(("GIOChannelParent DoAsyncOpen [this=%p uri=%s]\n", this,
88        uri->GetSpecOrDefault().get()));
89 #endif
90 
91   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
92   if (NS_FAILED(rv)) {
93     return SendFailedAsyncOpen(rv);
94   }
95 
96   nsCOMPtr<nsILoadInfo> loadInfo;
97   rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs,
98                                             getter_AddRefs(loadInfo));
99   if (NS_FAILED(rv)) {
100     return SendFailedAsyncOpen(rv);
101   }
102 
103   OriginAttributes attrs;
104   rv = loadInfo->GetOriginAttributes(&attrs);
105   if (NS_FAILED(rv)) {
106     return SendFailedAsyncOpen(rv);
107   }
108 
109   nsCOMPtr<nsIChannel> chan;
110   rv = NS_NewChannelInternal(getter_AddRefs(chan), uri, loadInfo, nullptr,
111                              nullptr, nullptr, aLoadFlags, ios);
112 
113   if (NS_FAILED(rv)) {
114     return SendFailedAsyncOpen(rv);
115   }
116 
117   mChannel = chan;
118 
119   nsIChannel* gioChan = static_cast<nsIChannel*>(mChannel.get());
120 
121   rv = gioChan->AsyncOpen(this);
122   if (NS_FAILED(rv)) {
123     return SendFailedAsyncOpen(rv);
124   }
125 
126   return true;
127 }
128 
ConnectChannel(const uint64_t & channelId)129 bool GIOChannelParent::ConnectChannel(const uint64_t& channelId) {
130   nsresult rv;
131 
132   LOG(("Looking for a registered channel [this=%p, id=%" PRIx64 "]", this,
133        channelId));
134 
135   nsCOMPtr<nsIChannel> channel;
136   rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
137   if (NS_SUCCEEDED(rv)) {
138     mChannel = channel;
139   }
140 
141   LOG(("  found channel %p, rv=%08" PRIx32, mChannel.get(),
142        static_cast<uint32_t>(rv)));
143 
144   return true;
145 }
146 
RecvCancel(const nsresult & status)147 mozilla::ipc::IPCResult GIOChannelParent::RecvCancel(const nsresult& status) {
148   if (mChannel) {
149     mChannel->Cancel(status);
150   }
151 
152   return IPC_OK();
153 }
154 
RecvSuspend()155 mozilla::ipc::IPCResult GIOChannelParent::RecvSuspend() {
156   if (mChannel) {
157     mChannel->Suspend();
158   }
159   return IPC_OK();
160 }
161 
RecvResume()162 mozilla::ipc::IPCResult GIOChannelParent::RecvResume() {
163   if (mChannel) {
164     mChannel->Resume();
165   }
166   return IPC_OK();
167 }
168 
169 //-----------------------------------------------------------------------------
170 // GIOChannelParent::nsIRequestObserver
171 //-----------------------------------------------------------------------------
172 
173 NS_IMETHODIMP
OnStartRequest(nsIRequest * aRequest)174 GIOChannelParent::OnStartRequest(nsIRequest* aRequest) {
175   LOG(("GIOChannelParent::OnStartRequest [this=%p]\n", this));
176   nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
177   MOZ_ASSERT(chan);
178   NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
179 
180   int64_t contentLength;
181   chan->GetContentLength(&contentLength);
182   nsCString contentType;
183   chan->GetContentType(contentType);
184   nsresult channelStatus = NS_OK;
185   chan->GetStatus(&channelStatus);
186 
187   nsCString entityID;
188   URIParams uriparam;
189   nsCOMPtr<nsIURI> uri;
190   chan->GetURI(getter_AddRefs(uri));
191   SerializeURI(uri, uriparam);
192 
193   if (mIPCClosed || !SendOnStartRequest(channelStatus, contentLength,
194                                         contentType, entityID, uriparam)) {
195     return NS_ERROR_UNEXPECTED;
196   }
197 
198   return NS_OK;
199 }
200 
201 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsresult aStatusCode)202 GIOChannelParent::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
203   LOG(("GIOChannelParent::OnStopRequest: [this=%p status=%" PRIu32 "]\n", this,
204        static_cast<uint32_t>(aStatusCode)));
205 
206   if (mIPCClosed || !SendOnStopRequest(aStatusCode)) {
207     return NS_ERROR_UNEXPECTED;
208   }
209 
210   return NS_OK;
211 }
212 
213 //-----------------------------------------------------------------------------
214 // GIOChannelParent::nsIStreamListener
215 //-----------------------------------------------------------------------------
216 
217 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)218 GIOChannelParent::OnDataAvailable(nsIRequest* aRequest,
219                                   nsIInputStream* aInputStream,
220                                   uint64_t aOffset, uint32_t aCount) {
221   LOG(("GIOChannelParent::OnDataAvailable [this=%p]\n", this));
222 
223   nsCString data;
224   nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
225   if (NS_FAILED(rv)) {
226     return rv;
227   }
228 
229   nsresult channelStatus = NS_OK;
230   mChannel->GetStatus(&channelStatus);
231 
232   if (mIPCClosed ||
233       !SendOnDataAvailable(channelStatus, data, aOffset, aCount)) {
234     return NS_ERROR_UNEXPECTED;
235   }
236   return NS_OK;
237 }
238 
239 //-----------------------------------------------------------------------------
240 // GIOChannelParent::nsIParentChannel
241 //-----------------------------------------------------------------------------
242 
243 NS_IMETHODIMP
SetParentListener(ParentChannelListener * aListener)244 GIOChannelParent::SetParentListener(ParentChannelListener* aListener) {
245   // Do not need ptr to ParentChannelListener.
246   return NS_OK;
247 }
248 
249 NS_IMETHODIMP
NotifyClassificationFlags(uint32_t aClassificationFlags,bool aIsThirdParty)250 GIOChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags,
251                                             bool aIsThirdParty) {
252   // Nothing to do.
253   return NS_OK;
254 }
255 
256 NS_IMETHODIMP
NotifyFlashPluginStateChanged(nsIHttpChannel::FlashPluginState aState)257 GIOChannelParent::NotifyFlashPluginStateChanged(
258     nsIHttpChannel::FlashPluginState aState) {
259   // Nothing to do.
260   return NS_OK;
261 }
262 
263 NS_IMETHODIMP
SetClassifierMatchedInfo(const nsACString & aList,const nsACString & aProvider,const nsACString & aFullHash)264 GIOChannelParent::SetClassifierMatchedInfo(const nsACString& aList,
265                                            const nsACString& aProvider,
266                                            const nsACString& aFullHash) {
267   // nothing to do
268   return NS_OK;
269 }
270 
271 NS_IMETHODIMP
SetClassifierMatchedTrackingInfo(const nsACString & aLists,const nsACString & aFullHashes)272 GIOChannelParent::SetClassifierMatchedTrackingInfo(
273     const nsACString& aLists, const nsACString& aFullHashes) {
274   // nothing to do
275   return NS_OK;
276 }
277 
278 NS_IMETHODIMP
Delete()279 GIOChannelParent::Delete() {
280   if (mIPCClosed || !SendDeleteSelf()) {
281     return NS_ERROR_UNEXPECTED;
282   }
283 
284   return NS_OK;
285 }
286 
287 NS_IMETHODIMP
GetRemoteType(nsACString & aRemoteType)288 GIOChannelParent::GetRemoteType(nsACString& aRemoteType) {
289   if (!CanSend()) {
290     return NS_ERROR_UNEXPECTED;
291   }
292 
293   dom::PContentParent* pcp = Manager()->Manager();
294   aRemoteType = static_cast<dom::ContentParent*>(pcp)->GetRemoteType();
295   return NS_OK;
296 }
297 
298 //-----------------------------------------------------------------------------
299 // GIOChannelParent::nsIInterfaceRequestor
300 //-----------------------------------------------------------------------------
301 
302 NS_IMETHODIMP
GetInterface(const nsIID & uuid,void ** result)303 GIOChannelParent::GetInterface(const nsIID& uuid, void** result) {
304   if (uuid.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
305       uuid.Equals(NS_GET_IID(nsISecureBrowserUI))) {
306     if (mBrowserParent) {
307       return mBrowserParent->QueryInterface(uuid, result);
308     }
309   }
310 
311   // Only support nsILoadContext if child channel's callbacks did too
312   if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
313     nsCOMPtr<nsILoadContext> copy = mLoadContext;
314     copy.forget(result);
315     return NS_OK;
316   }
317 
318   return QueryInterface(uuid, result);
319 }
320 
321 //---------------------
322 }  // namespace net
323 }  // namespace mozilla
324