|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set sw=2 ts=8 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 // HttpLog.h should generally be included first |
|
8 #include "HttpLog.h" |
|
9 |
|
10 #include "HttpChannelParentListener.h" |
|
11 #include "mozilla/net/HttpChannelParent.h" |
|
12 #include "mozilla/unused.h" |
|
13 #include "nsIRedirectChannelRegistrar.h" |
|
14 #include "nsIHttpEventSink.h" |
|
15 |
|
16 using mozilla::unused; |
|
17 |
|
18 namespace mozilla { |
|
19 namespace net { |
|
20 |
|
21 HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel) |
|
22 : mNextListener(aInitialChannel) |
|
23 , mRedirectChannelId(0) |
|
24 , mSuspendedForDiversion(false) |
|
25 { |
|
26 } |
|
27 |
|
28 HttpChannelParentListener::~HttpChannelParentListener() |
|
29 { |
|
30 } |
|
31 |
|
32 //----------------------------------------------------------------------------- |
|
33 // HttpChannelParentListener::nsISupports |
|
34 //----------------------------------------------------------------------------- |
|
35 |
|
36 NS_IMPL_ISUPPORTS(HttpChannelParentListener, |
|
37 nsIInterfaceRequestor, |
|
38 nsIStreamListener, |
|
39 nsIRequestObserver, |
|
40 nsIChannelEventSink, |
|
41 nsIRedirectResultListener) |
|
42 |
|
43 //----------------------------------------------------------------------------- |
|
44 // HttpChannelParentListener::nsIRequestObserver |
|
45 //----------------------------------------------------------------------------- |
|
46 |
|
47 NS_IMETHODIMP |
|
48 HttpChannelParentListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) |
|
49 { |
|
50 MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, |
|
51 "Cannot call OnStartRequest if suspended for diversion!"); |
|
52 |
|
53 if (!mNextListener) |
|
54 return NS_ERROR_UNEXPECTED; |
|
55 |
|
56 LOG(("HttpChannelParentListener::OnStartRequest [this=%p]\n", this)); |
|
57 return mNextListener->OnStartRequest(aRequest, aContext); |
|
58 } |
|
59 |
|
60 NS_IMETHODIMP |
|
61 HttpChannelParentListener::OnStopRequest(nsIRequest *aRequest, |
|
62 nsISupports *aContext, |
|
63 nsresult aStatusCode) |
|
64 { |
|
65 MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, |
|
66 "Cannot call OnStopRequest if suspended for diversion!"); |
|
67 |
|
68 if (!mNextListener) |
|
69 return NS_ERROR_UNEXPECTED; |
|
70 |
|
71 LOG(("HttpChannelParentListener::OnStopRequest: [this=%p status=%ul]\n", |
|
72 this, aStatusCode)); |
|
73 nsresult rv = mNextListener->OnStopRequest(aRequest, aContext, aStatusCode); |
|
74 |
|
75 mNextListener = nullptr; |
|
76 return rv; |
|
77 } |
|
78 |
|
79 //----------------------------------------------------------------------------- |
|
80 // HttpChannelParentListener::nsIStreamListener |
|
81 //----------------------------------------------------------------------------- |
|
82 |
|
83 NS_IMETHODIMP |
|
84 HttpChannelParentListener::OnDataAvailable(nsIRequest *aRequest, |
|
85 nsISupports *aContext, |
|
86 nsIInputStream *aInputStream, |
|
87 uint64_t aOffset, |
|
88 uint32_t aCount) |
|
89 { |
|
90 MOZ_RELEASE_ASSERT(!mSuspendedForDiversion, |
|
91 "Cannot call OnDataAvailable if suspended for diversion!"); |
|
92 |
|
93 if (!mNextListener) |
|
94 return NS_ERROR_UNEXPECTED; |
|
95 |
|
96 LOG(("HttpChannelParentListener::OnDataAvailable [this=%p]\n", this)); |
|
97 return mNextListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount); |
|
98 } |
|
99 |
|
100 //----------------------------------------------------------------------------- |
|
101 // HttpChannelParentListener::nsIInterfaceRequestor |
|
102 //----------------------------------------------------------------------------- |
|
103 |
|
104 NS_IMETHODIMP |
|
105 HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result) |
|
106 { |
|
107 if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) || |
|
108 aIID.Equals(NS_GET_IID(nsIHttpEventSink)) || |
|
109 aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) |
|
110 { |
|
111 return QueryInterface(aIID, result); |
|
112 } |
|
113 |
|
114 nsCOMPtr<nsIInterfaceRequestor> ir; |
|
115 if (mNextListener && |
|
116 NS_SUCCEEDED(CallQueryInterface(mNextListener.get(), |
|
117 getter_AddRefs(ir)))) |
|
118 { |
|
119 return ir->GetInterface(aIID, result); |
|
120 } |
|
121 |
|
122 return NS_NOINTERFACE; |
|
123 } |
|
124 |
|
125 //----------------------------------------------------------------------------- |
|
126 // HttpChannelParentListener::nsIChannelEventSink |
|
127 //----------------------------------------------------------------------------- |
|
128 |
|
129 NS_IMETHODIMP |
|
130 HttpChannelParentListener::AsyncOnChannelRedirect( |
|
131 nsIChannel *oldChannel, |
|
132 nsIChannel *newChannel, |
|
133 uint32_t redirectFlags, |
|
134 nsIAsyncVerifyRedirectCallback* callback) |
|
135 { |
|
136 nsresult rv; |
|
137 |
|
138 // Register the new channel and obtain id for it |
|
139 nsCOMPtr<nsIRedirectChannelRegistrar> registrar = |
|
140 do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); |
|
141 NS_ENSURE_SUCCESS(rv, rv); |
|
142 |
|
143 rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId); |
|
144 NS_ENSURE_SUCCESS(rv, rv); |
|
145 |
|
146 LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId)); |
|
147 |
|
148 nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel = |
|
149 do_QueryInterface(mNextListener); |
|
150 if (!activeRedirectingChannel) { |
|
151 NS_RUNTIMEABORT("Channel got a redirect response, but doesn't implement " |
|
152 "nsIParentRedirectingChannel to handle it."); |
|
153 } |
|
154 |
|
155 return activeRedirectingChannel->StartRedirect(mRedirectChannelId, |
|
156 newChannel, |
|
157 redirectFlags, |
|
158 callback); |
|
159 } |
|
160 |
|
161 //----------------------------------------------------------------------------- |
|
162 // HttpChannelParentListener::nsIRedirectResultListener |
|
163 //----------------------------------------------------------------------------- |
|
164 |
|
165 NS_IMETHODIMP |
|
166 HttpChannelParentListener::OnRedirectResult(bool succeeded) |
|
167 { |
|
168 nsresult rv; |
|
169 |
|
170 nsCOMPtr<nsIParentChannel> redirectChannel; |
|
171 if (mRedirectChannelId) { |
|
172 nsCOMPtr<nsIRedirectChannelRegistrar> registrar = |
|
173 do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); |
|
174 NS_ENSURE_SUCCESS(rv, rv); |
|
175 |
|
176 rv = registrar->GetParentChannel(mRedirectChannelId, |
|
177 getter_AddRefs(redirectChannel)); |
|
178 if (NS_FAILED(rv) || !redirectChannel) { |
|
179 // Redirect might get canceled before we got AsyncOnChannelRedirect |
|
180 LOG(("Registered parent channel not found under id=%d", mRedirectChannelId)); |
|
181 |
|
182 nsCOMPtr<nsIChannel> newChannel; |
|
183 rv = registrar->GetRegisteredChannel(mRedirectChannelId, |
|
184 getter_AddRefs(newChannel)); |
|
185 MOZ_ASSERT(newChannel, "Already registered channel not found"); |
|
186 |
|
187 if (NS_SUCCEEDED(rv)) |
|
188 newChannel->Cancel(NS_BINDING_ABORTED); |
|
189 } |
|
190 |
|
191 // Release all previously registered channels, they are no longer need to be |
|
192 // kept in the registrar from this moment. |
|
193 registrar->DeregisterChannels(mRedirectChannelId); |
|
194 |
|
195 mRedirectChannelId = 0; |
|
196 } |
|
197 |
|
198 if (!redirectChannel) { |
|
199 succeeded = false; |
|
200 } |
|
201 |
|
202 nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel = |
|
203 do_QueryInterface(mNextListener); |
|
204 MOZ_ASSERT(activeRedirectingChannel, |
|
205 "Channel finished a redirect response, but doesn't implement " |
|
206 "nsIParentRedirectingChannel to complete it."); |
|
207 |
|
208 if (activeRedirectingChannel) { |
|
209 activeRedirectingChannel->CompleteRedirect(succeeded); |
|
210 } else { |
|
211 succeeded = false; |
|
212 } |
|
213 |
|
214 if (succeeded) { |
|
215 // Switch to redirect channel and delete the old one. |
|
216 nsCOMPtr<nsIParentChannel> parent; |
|
217 parent = do_QueryInterface(mNextListener); |
|
218 MOZ_ASSERT(parent); |
|
219 parent->Delete(); |
|
220 mNextListener = do_QueryInterface(redirectChannel); |
|
221 MOZ_ASSERT(mNextListener); |
|
222 redirectChannel->SetParentListener(this); |
|
223 } else if (redirectChannel) { |
|
224 // Delete the redirect target channel: continue using old channel |
|
225 redirectChannel->Delete(); |
|
226 } |
|
227 |
|
228 return NS_OK; |
|
229 } |
|
230 |
|
231 //----------------------------------------------------------------------------- |
|
232 |
|
233 nsresult |
|
234 HttpChannelParentListener::SuspendForDiversion() |
|
235 { |
|
236 if (NS_WARN_IF(mSuspendedForDiversion)) { |
|
237 MOZ_ASSERT(!mSuspendedForDiversion, "Cannot SuspendForDiversion twice!"); |
|
238 return NS_ERROR_UNEXPECTED; |
|
239 } |
|
240 |
|
241 // While this is set, no OnStart/OnData/OnStop callbacks should be forwarded |
|
242 // to mNextListener. |
|
243 mSuspendedForDiversion = true; |
|
244 |
|
245 return NS_OK; |
|
246 } |
|
247 |
|
248 nsresult |
|
249 HttpChannelParentListener::ResumeForDiversion() |
|
250 { |
|
251 MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); |
|
252 |
|
253 // Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener. |
|
254 mSuspendedForDiversion = false; |
|
255 |
|
256 return NS_OK; |
|
257 } |
|
258 |
|
259 nsresult |
|
260 HttpChannelParentListener::DivertTo(nsIStreamListener* aListener) |
|
261 { |
|
262 MOZ_ASSERT(aListener); |
|
263 MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!"); |
|
264 |
|
265 mNextListener = aListener; |
|
266 |
|
267 return ResumeForDiversion(); |
|
268 } |
|
269 |
|
270 }} // mozilla::net |