Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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/. */
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
10 #include "HttpChannelParentListener.h"
11 #include "mozilla/net/HttpChannelParent.h"
12 #include "mozilla/unused.h"
13 #include "nsIRedirectChannelRegistrar.h"
14 #include "nsIHttpEventSink.h"
16 using mozilla::unused;
18 namespace mozilla {
19 namespace net {
21 HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel)
22 : mNextListener(aInitialChannel)
23 , mRedirectChannelId(0)
24 , mSuspendedForDiversion(false)
25 {
26 }
28 HttpChannelParentListener::~HttpChannelParentListener()
29 {
30 }
32 //-----------------------------------------------------------------------------
33 // HttpChannelParentListener::nsISupports
34 //-----------------------------------------------------------------------------
36 NS_IMPL_ISUPPORTS(HttpChannelParentListener,
37 nsIInterfaceRequestor,
38 nsIStreamListener,
39 nsIRequestObserver,
40 nsIChannelEventSink,
41 nsIRedirectResultListener)
43 //-----------------------------------------------------------------------------
44 // HttpChannelParentListener::nsIRequestObserver
45 //-----------------------------------------------------------------------------
47 NS_IMETHODIMP
48 HttpChannelParentListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
49 {
50 MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
51 "Cannot call OnStartRequest if suspended for diversion!");
53 if (!mNextListener)
54 return NS_ERROR_UNEXPECTED;
56 LOG(("HttpChannelParentListener::OnStartRequest [this=%p]\n", this));
57 return mNextListener->OnStartRequest(aRequest, aContext);
58 }
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!");
68 if (!mNextListener)
69 return NS_ERROR_UNEXPECTED;
71 LOG(("HttpChannelParentListener::OnStopRequest: [this=%p status=%ul]\n",
72 this, aStatusCode));
73 nsresult rv = mNextListener->OnStopRequest(aRequest, aContext, aStatusCode);
75 mNextListener = nullptr;
76 return rv;
77 }
79 //-----------------------------------------------------------------------------
80 // HttpChannelParentListener::nsIStreamListener
81 //-----------------------------------------------------------------------------
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!");
93 if (!mNextListener)
94 return NS_ERROR_UNEXPECTED;
96 LOG(("HttpChannelParentListener::OnDataAvailable [this=%p]\n", this));
97 return mNextListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
98 }
100 //-----------------------------------------------------------------------------
101 // HttpChannelParentListener::nsIInterfaceRequestor
102 //-----------------------------------------------------------------------------
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 }
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 }
122 return NS_NOINTERFACE;
123 }
125 //-----------------------------------------------------------------------------
126 // HttpChannelParentListener::nsIChannelEventSink
127 //-----------------------------------------------------------------------------
129 NS_IMETHODIMP
130 HttpChannelParentListener::AsyncOnChannelRedirect(
131 nsIChannel *oldChannel,
132 nsIChannel *newChannel,
133 uint32_t redirectFlags,
134 nsIAsyncVerifyRedirectCallback* callback)
135 {
136 nsresult rv;
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);
143 rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId);
144 NS_ENSURE_SUCCESS(rv, rv);
146 LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId));
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 }
155 return activeRedirectingChannel->StartRedirect(mRedirectChannelId,
156 newChannel,
157 redirectFlags,
158 callback);
159 }
161 //-----------------------------------------------------------------------------
162 // HttpChannelParentListener::nsIRedirectResultListener
163 //-----------------------------------------------------------------------------
165 NS_IMETHODIMP
166 HttpChannelParentListener::OnRedirectResult(bool succeeded)
167 {
168 nsresult rv;
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);
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));
182 nsCOMPtr<nsIChannel> newChannel;
183 rv = registrar->GetRegisteredChannel(mRedirectChannelId,
184 getter_AddRefs(newChannel));
185 MOZ_ASSERT(newChannel, "Already registered channel not found");
187 if (NS_SUCCEEDED(rv))
188 newChannel->Cancel(NS_BINDING_ABORTED);
189 }
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);
195 mRedirectChannelId = 0;
196 }
198 if (!redirectChannel) {
199 succeeded = false;
200 }
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.");
208 if (activeRedirectingChannel) {
209 activeRedirectingChannel->CompleteRedirect(succeeded);
210 } else {
211 succeeded = false;
212 }
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 }
228 return NS_OK;
229 }
231 //-----------------------------------------------------------------------------
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 }
241 // While this is set, no OnStart/OnData/OnStop callbacks should be forwarded
242 // to mNextListener.
243 mSuspendedForDiversion = true;
245 return NS_OK;
246 }
248 nsresult
249 HttpChannelParentListener::ResumeForDiversion()
250 {
251 MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
253 // Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener.
254 mSuspendedForDiversion = false;
256 return NS_OK;
257 }
259 nsresult
260 HttpChannelParentListener::DivertTo(nsIStreamListener* aListener)
261 {
262 MOZ_ASSERT(aListener);
263 MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
265 mNextListener = aListener;
267 return ResumeForDiversion();
268 }
270 }} // mozilla::net