|
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 "SerializedLoadContext.h" |
|
13 |
|
14 using namespace mozilla::ipc; |
|
15 |
|
16 namespace mozilla { |
|
17 namespace net { |
|
18 |
|
19 NS_IMPL_ISUPPORTS(WebSocketChannelParent, |
|
20 nsIWebSocketListener, |
|
21 nsIInterfaceRequestor) |
|
22 |
|
23 WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider, |
|
24 nsILoadContext* aLoadContext, |
|
25 PBOverrideStatus aOverrideStatus) |
|
26 : mAuthProvider(aAuthProvider) |
|
27 , mLoadContext(aLoadContext) |
|
28 , mIPCOpen(true) |
|
29 { |
|
30 // Websocket channels can't have a private browsing override |
|
31 MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset); |
|
32 #if defined(PR_LOGGING) |
|
33 if (!webSocketLog) |
|
34 webSocketLog = PR_NewLogModule("nsWebSocket"); |
|
35 #endif |
|
36 } |
|
37 |
|
38 //----------------------------------------------------------------------------- |
|
39 // WebSocketChannelParent::PWebSocketChannelParent |
|
40 //----------------------------------------------------------------------------- |
|
41 |
|
42 bool |
|
43 WebSocketChannelParent::RecvDeleteSelf() |
|
44 { |
|
45 LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this)); |
|
46 mChannel = nullptr; |
|
47 mAuthProvider = nullptr; |
|
48 return mIPCOpen ? Send__delete__(this) : true; |
|
49 } |
|
50 |
|
51 bool |
|
52 WebSocketChannelParent::RecvAsyncOpen(const URIParams& aURI, |
|
53 const nsCString& aOrigin, |
|
54 const nsCString& aProtocol, |
|
55 const bool& aSecure, |
|
56 const uint32_t& aPingInterval, |
|
57 const bool& aClientSetPingInterval, |
|
58 const uint32_t& aPingTimeout, |
|
59 const bool& aClientSetPingTimeout) |
|
60 { |
|
61 LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this)); |
|
62 |
|
63 nsresult rv; |
|
64 nsCOMPtr<nsIURI> uri; |
|
65 |
|
66 if (aSecure) { |
|
67 mChannel = |
|
68 do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv); |
|
69 } else { |
|
70 mChannel = |
|
71 do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv); |
|
72 } |
|
73 if (NS_FAILED(rv)) |
|
74 goto fail; |
|
75 |
|
76 rv = mChannel->SetNotificationCallbacks(this); |
|
77 if (NS_FAILED(rv)) |
|
78 goto fail; |
|
79 |
|
80 rv = mChannel->SetProtocol(aProtocol); |
|
81 if (NS_FAILED(rv)) |
|
82 goto fail; |
|
83 |
|
84 uri = DeserializeURI(aURI); |
|
85 if (!uri) { |
|
86 rv = NS_ERROR_FAILURE; |
|
87 goto fail; |
|
88 } |
|
89 |
|
90 // only use ping values from child if they were overridden by client code. |
|
91 if (aClientSetPingInterval) { |
|
92 // IDL allows setting in seconds, so must be multiple of 1000 ms |
|
93 MOZ_ASSERT(aPingInterval >= 1000 && !(aPingInterval % 1000)); |
|
94 mChannel->SetPingInterval(aPingInterval / 1000); |
|
95 } |
|
96 if (aClientSetPingTimeout) { |
|
97 MOZ_ASSERT(aPingTimeout >= 1000 && !(aPingTimeout % 1000)); |
|
98 mChannel->SetPingTimeout(aPingTimeout / 1000); |
|
99 } |
|
100 |
|
101 rv = mChannel->AsyncOpen(uri, aOrigin, this, nullptr); |
|
102 if (NS_FAILED(rv)) |
|
103 goto fail; |
|
104 |
|
105 return true; |
|
106 |
|
107 fail: |
|
108 mChannel = nullptr; |
|
109 return SendOnStop(rv); |
|
110 } |
|
111 |
|
112 bool |
|
113 WebSocketChannelParent::RecvClose(const uint16_t& code, const nsCString& reason) |
|
114 { |
|
115 LOG(("WebSocketChannelParent::RecvClose() %p\n", this)); |
|
116 if (mChannel) { |
|
117 nsresult rv = mChannel->Close(code, reason); |
|
118 NS_ENSURE_SUCCESS(rv, true); |
|
119 } |
|
120 return true; |
|
121 } |
|
122 |
|
123 bool |
|
124 WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg) |
|
125 { |
|
126 LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this)); |
|
127 if (mChannel) { |
|
128 nsresult rv = mChannel->SendMsg(aMsg); |
|
129 NS_ENSURE_SUCCESS(rv, true); |
|
130 } |
|
131 return true; |
|
132 } |
|
133 |
|
134 bool |
|
135 WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg) |
|
136 { |
|
137 LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this)); |
|
138 if (mChannel) { |
|
139 nsresult rv = mChannel->SendBinaryMsg(aMsg); |
|
140 NS_ENSURE_SUCCESS(rv, true); |
|
141 } |
|
142 return true; |
|
143 } |
|
144 |
|
145 bool |
|
146 WebSocketChannelParent::RecvSendBinaryStream(const InputStreamParams& aStream, |
|
147 const uint32_t& aLength) |
|
148 { |
|
149 LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this)); |
|
150 if (mChannel) { |
|
151 nsTArray<mozilla::ipc::FileDescriptor> fds; |
|
152 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds); |
|
153 if (!stream) { |
|
154 return false; |
|
155 } |
|
156 nsresult rv = mChannel->SendBinaryStream(stream, aLength); |
|
157 NS_ENSURE_SUCCESS(rv, true); |
|
158 } |
|
159 return true; |
|
160 } |
|
161 |
|
162 //----------------------------------------------------------------------------- |
|
163 // WebSocketChannelParent::nsIRequestObserver |
|
164 //----------------------------------------------------------------------------- |
|
165 |
|
166 NS_IMETHODIMP |
|
167 WebSocketChannelParent::OnStart(nsISupports *aContext) |
|
168 { |
|
169 LOG(("WebSocketChannelParent::OnStart() %p\n", this)); |
|
170 nsAutoCString protocol, extensions; |
|
171 if (mChannel) { |
|
172 mChannel->GetProtocol(protocol); |
|
173 mChannel->GetExtensions(extensions); |
|
174 } |
|
175 if (!mIPCOpen || !SendOnStart(protocol, extensions)) { |
|
176 return NS_ERROR_FAILURE; |
|
177 } |
|
178 return NS_OK; |
|
179 } |
|
180 |
|
181 NS_IMETHODIMP |
|
182 WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode) |
|
183 { |
|
184 LOG(("WebSocketChannelParent::OnStop() %p\n", this)); |
|
185 if (!mIPCOpen || !SendOnStop(aStatusCode)) { |
|
186 return NS_ERROR_FAILURE; |
|
187 } |
|
188 return NS_OK; |
|
189 } |
|
190 |
|
191 NS_IMETHODIMP |
|
192 WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg) |
|
193 { |
|
194 LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this)); |
|
195 if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) { |
|
196 return NS_ERROR_FAILURE; |
|
197 } |
|
198 return NS_OK; |
|
199 } |
|
200 |
|
201 NS_IMETHODIMP |
|
202 WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg) |
|
203 { |
|
204 LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this)); |
|
205 if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) { |
|
206 return NS_ERROR_FAILURE; |
|
207 } |
|
208 return NS_OK; |
|
209 } |
|
210 |
|
211 NS_IMETHODIMP |
|
212 WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, uint32_t aSize) |
|
213 { |
|
214 LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this)); |
|
215 if (!mIPCOpen || !SendOnAcknowledge(aSize)) { |
|
216 return NS_ERROR_FAILURE; |
|
217 } |
|
218 return NS_OK; |
|
219 } |
|
220 |
|
221 NS_IMETHODIMP |
|
222 WebSocketChannelParent::OnServerClose(nsISupports *aContext, |
|
223 uint16_t code, const nsACString & reason) |
|
224 { |
|
225 LOG(("WebSocketChannelParent::OnServerClose() %p\n", this)); |
|
226 if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) { |
|
227 return NS_ERROR_FAILURE; |
|
228 } |
|
229 return NS_OK; |
|
230 } |
|
231 |
|
232 void |
|
233 WebSocketChannelParent::ActorDestroy(ActorDestroyReason why) |
|
234 { |
|
235 LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this)); |
|
236 mIPCOpen = false; |
|
237 } |
|
238 |
|
239 //----------------------------------------------------------------------------- |
|
240 // WebSocketChannelParent::nsIInterfaceRequestor |
|
241 //----------------------------------------------------------------------------- |
|
242 |
|
243 NS_IMETHODIMP |
|
244 WebSocketChannelParent::GetInterface(const nsIID & iid, void **result) |
|
245 { |
|
246 LOG(("WebSocketChannelParent::GetInterface() %p\n", this)); |
|
247 if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider))) |
|
248 return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL, |
|
249 iid, result); |
|
250 |
|
251 // Only support nsILoadContext if child channel's callbacks did too |
|
252 if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { |
|
253 NS_ADDREF(mLoadContext); |
|
254 *result = static_cast<nsILoadContext*>(mLoadContext); |
|
255 return NS_OK; |
|
256 } |
|
257 |
|
258 return QueryInterface(iid, result); |
|
259 } |
|
260 |
|
261 |
|
262 } // namespace net |
|
263 } // namespace mozilla |