Line data Source code
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 : #include "WebSocketLog.h"
8 : #include "WebSocketChannelParent.h"
9 : #include "nsIAuthPromptProvider.h"
10 : #include "mozilla/ipc/InputStreamUtils.h"
11 : #include "mozilla/ipc/URIUtils.h"
12 : #include "mozilla/ipc/BackgroundUtils.h"
13 : #include "SerializedLoadContext.h"
14 : #include "mozilla/net/NeckoCommon.h"
15 : #include "mozilla/net/WebSocketChannel.h"
16 :
17 : using namespace mozilla::ipc;
18 :
19 : namespace mozilla {
20 : namespace net {
21 :
22 0 : NS_IMPL_ISUPPORTS(WebSocketChannelParent,
23 : nsIWebSocketListener,
24 : nsIInterfaceRequestor)
25 :
26 0 : WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider,
27 : nsILoadContext* aLoadContext,
28 : PBOverrideStatus aOverrideStatus,
29 0 : uint32_t aSerial)
30 : : mAuthProvider(aAuthProvider)
31 : , mLoadContext(aLoadContext)
32 : , mIPCOpen(true)
33 0 : , mSerial(aSerial)
34 : {
35 : // Websocket channels can't have a private browsing override
36 0 : MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset);
37 0 : }
38 :
39 0 : WebSocketChannelParent::~WebSocketChannelParent()
40 : {
41 0 : }
42 : //-----------------------------------------------------------------------------
43 : // WebSocketChannelParent::PWebSocketChannelParent
44 : //-----------------------------------------------------------------------------
45 :
46 : mozilla::ipc::IPCResult
47 0 : WebSocketChannelParent::RecvDeleteSelf()
48 : {
49 0 : LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
50 0 : mChannel = nullptr;
51 0 : mAuthProvider = nullptr;
52 0 : IProtocol* mgr = Manager();
53 0 : if (mIPCOpen && !Send__delete__(this)) {
54 0 : return IPC_FAIL_NO_REASON(mgr);
55 : }
56 0 : return IPC_OK();
57 : }
58 :
59 : mozilla::ipc::IPCResult
60 0 : WebSocketChannelParent::RecvAsyncOpen(const OptionalURIParams& aURI,
61 : const nsCString& aOrigin,
62 : const uint64_t& aInnerWindowID,
63 : const nsCString& aProtocol,
64 : const bool& aSecure,
65 : const uint32_t& aPingInterval,
66 : const bool& aClientSetPingInterval,
67 : const uint32_t& aPingTimeout,
68 : const bool& aClientSetPingTimeout,
69 : const OptionalLoadInfoArgs& aLoadInfoArgs,
70 : const OptionalTransportProvider& aTransportProvider,
71 : const nsCString& aNegotiatedExtensions)
72 : {
73 0 : LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this));
74 :
75 : nsresult rv;
76 0 : nsCOMPtr<nsIURI> uri;
77 0 : nsCOMPtr<nsILoadInfo> loadInfo;
78 :
79 0 : rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo));
80 0 : if (NS_FAILED(rv)) {
81 0 : goto fail;
82 : }
83 :
84 0 : if (aSecure) {
85 : mChannel =
86 0 : do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
87 : } else {
88 : mChannel =
89 0 : do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
90 : }
91 0 : if (NS_FAILED(rv))
92 0 : goto fail;
93 :
94 0 : rv = mChannel->SetSerial(mSerial);
95 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
96 0 : goto fail;
97 : }
98 :
99 0 : rv = mChannel->SetLoadInfo(loadInfo);
100 0 : if (NS_FAILED(rv)) {
101 0 : goto fail;
102 : }
103 :
104 0 : rv = mChannel->SetNotificationCallbacks(this);
105 0 : if (NS_FAILED(rv))
106 0 : goto fail;
107 :
108 0 : rv = mChannel->SetProtocol(aProtocol);
109 0 : if (NS_FAILED(rv))
110 0 : goto fail;
111 :
112 0 : if (aTransportProvider.type() != OptionalTransportProvider::Tvoid_t) {
113 : RefPtr<TransportProviderParent> provider =
114 : static_cast<TransportProviderParent*>(
115 0 : aTransportProvider.get_PTransportProviderParent());
116 0 : rv = mChannel->SetServerParameters(provider, aNegotiatedExtensions);
117 0 : if (NS_FAILED(rv)) {
118 0 : goto fail;
119 : }
120 : } else {
121 0 : uri = DeserializeURI(aURI);
122 0 : if (!uri) {
123 0 : rv = NS_ERROR_FAILURE;
124 0 : goto fail;
125 : }
126 : }
127 :
128 : // only use ping values from child if they were overridden by client code.
129 0 : if (aClientSetPingInterval) {
130 : // IDL allows setting in seconds, so must be multiple of 1000 ms
131 0 : MOZ_ASSERT(aPingInterval >= 1000 && !(aPingInterval % 1000));
132 0 : DebugOnly<nsresult> rv = mChannel->SetPingInterval(aPingInterval / 1000);
133 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
134 : }
135 0 : if (aClientSetPingTimeout) {
136 0 : MOZ_ASSERT(aPingTimeout >= 1000 && !(aPingTimeout % 1000));
137 0 : DebugOnly<nsresult> rv = mChannel->SetPingTimeout(aPingTimeout / 1000);
138 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
139 : }
140 :
141 0 : rv = mChannel->AsyncOpen(uri, aOrigin, aInnerWindowID, this, nullptr);
142 0 : if (NS_FAILED(rv))
143 0 : goto fail;
144 :
145 0 : return IPC_OK();
146 :
147 : fail:
148 0 : mChannel = nullptr;
149 0 : if (!SendOnStop(rv)) {
150 0 : return IPC_FAIL_NO_REASON(this);
151 : }
152 0 : return IPC_OK();
153 : }
154 :
155 : mozilla::ipc::IPCResult
156 0 : WebSocketChannelParent::RecvClose(const uint16_t& code, const nsCString& reason)
157 : {
158 0 : LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
159 0 : if (mChannel) {
160 0 : nsresult rv = mChannel->Close(code, reason);
161 0 : NS_ENSURE_SUCCESS(rv, IPC_OK());
162 : }
163 :
164 0 : return IPC_OK();
165 : }
166 :
167 : mozilla::ipc::IPCResult
168 0 : WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg)
169 : {
170 0 : LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this));
171 0 : if (mChannel) {
172 0 : nsresult rv = mChannel->SendMsg(aMsg);
173 0 : NS_ENSURE_SUCCESS(rv, IPC_OK());
174 : }
175 0 : return IPC_OK();
176 : }
177 :
178 : mozilla::ipc::IPCResult
179 0 : WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg)
180 : {
181 0 : LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this));
182 0 : if (mChannel) {
183 0 : nsresult rv = mChannel->SendBinaryMsg(aMsg);
184 0 : NS_ENSURE_SUCCESS(rv, IPC_OK());
185 : }
186 0 : return IPC_OK();
187 : }
188 :
189 : mozilla::ipc::IPCResult
190 0 : WebSocketChannelParent::RecvSendBinaryStream(const IPCStream& aStream,
191 : const uint32_t& aLength)
192 : {
193 0 : LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this));
194 0 : if (mChannel) {
195 0 : nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStream);
196 0 : if (!stream) {
197 0 : return IPC_FAIL_NO_REASON(this);
198 : }
199 0 : nsresult rv = mChannel->SendBinaryStream(stream, aLength);
200 0 : NS_ENSURE_SUCCESS(rv, IPC_OK());
201 : }
202 0 : return IPC_OK();
203 : }
204 :
205 : //-----------------------------------------------------------------------------
206 : // WebSocketChannelParent::nsIRequestObserver
207 : //-----------------------------------------------------------------------------
208 :
209 : NS_IMETHODIMP
210 0 : WebSocketChannelParent::OnStart(nsISupports *aContext)
211 : {
212 0 : LOG(("WebSocketChannelParent::OnStart() %p\n", this));
213 0 : nsAutoCString protocol, extensions;
214 0 : nsString effectiveURL;
215 0 : bool encrypted = false;
216 0 : if (mChannel) {
217 0 : DebugOnly<nsresult> rv = mChannel->GetProtocol(protocol);
218 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
219 0 : rv = mChannel->GetExtensions(extensions);
220 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
221 :
222 0 : RefPtr<WebSocketChannel> channel;
223 0 : channel = static_cast<WebSocketChannel*>(mChannel.get());
224 0 : MOZ_ASSERT(channel);
225 :
226 0 : channel->GetEffectiveURL(effectiveURL);
227 0 : encrypted = channel->IsEncrypted();
228 : }
229 0 : if (!mIPCOpen || !SendOnStart(protocol, extensions, effectiveURL, encrypted)) {
230 0 : return NS_ERROR_FAILURE;
231 : }
232 0 : return NS_OK;
233 : }
234 :
235 : NS_IMETHODIMP
236 0 : WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode)
237 : {
238 0 : LOG(("WebSocketChannelParent::OnStop() %p\n", this));
239 0 : if (!mIPCOpen || !SendOnStop(aStatusCode)) {
240 0 : return NS_ERROR_FAILURE;
241 : }
242 0 : return NS_OK;
243 : }
244 :
245 : NS_IMETHODIMP
246 0 : WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
247 : {
248 0 : LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this));
249 0 : if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) {
250 0 : return NS_ERROR_FAILURE;
251 : }
252 0 : return NS_OK;
253 : }
254 :
255 : NS_IMETHODIMP
256 0 : WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
257 : {
258 0 : LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this));
259 0 : if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) {
260 0 : return NS_ERROR_FAILURE;
261 : }
262 0 : return NS_OK;
263 : }
264 :
265 : NS_IMETHODIMP
266 0 : WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
267 : {
268 0 : LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this));
269 0 : if (!mIPCOpen || !SendOnAcknowledge(aSize)) {
270 0 : return NS_ERROR_FAILURE;
271 : }
272 0 : return NS_OK;
273 : }
274 :
275 : NS_IMETHODIMP
276 0 : WebSocketChannelParent::OnServerClose(nsISupports *aContext,
277 : uint16_t code, const nsACString & reason)
278 : {
279 0 : LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
280 0 : if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) {
281 0 : return NS_ERROR_FAILURE;
282 : }
283 0 : return NS_OK;
284 : }
285 :
286 : void
287 0 : WebSocketChannelParent::ActorDestroy(ActorDestroyReason why)
288 : {
289 0 : LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this));
290 0 : mIPCOpen = false;
291 0 : }
292 :
293 : //-----------------------------------------------------------------------------
294 : // WebSocketChannelParent::nsIInterfaceRequestor
295 : //-----------------------------------------------------------------------------
296 :
297 : NS_IMETHODIMP
298 0 : WebSocketChannelParent::GetInterface(const nsIID & iid, void **result)
299 : {
300 0 : LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
301 0 : if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
302 0 : return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
303 0 : iid, result);
304 :
305 : // Only support nsILoadContext if child channel's callbacks did too
306 0 : if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
307 0 : nsCOMPtr<nsILoadContext> copy = mLoadContext;
308 0 : copy.forget(result);
309 0 : return NS_OK;
310 : }
311 :
312 0 : return QueryInterface(iid, result);
313 : }
314 :
315 : } // namespace net
316 : } // namespace mozilla
|