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 "BaseWebSocketChannel.h"
9 : #include "MainThreadUtils.h"
10 : #include "nsILoadGroup.h"
11 : #include "nsINode.h"
12 : #include "nsIInterfaceRequestor.h"
13 : #include "nsAutoPtr.h"
14 : #include "nsProxyRelease.h"
15 : #include "nsStandardURL.h"
16 : #include "LoadInfo.h"
17 : #include "nsIDOMNode.h"
18 : #include "mozilla/dom/ContentChild.h"
19 : #include "nsITransportProvider.h"
20 :
21 : using mozilla::dom::ContentChild;
22 :
23 : namespace mozilla {
24 : namespace net {
25 :
26 : LazyLogModule webSocketLog("nsWebSocket");
27 : static uint64_t gNextWebSocketID = 0;
28 :
29 : // We use only 53 bits for the WebSocket serial ID so that it can be converted
30 : // to and from a JS value without loss of precision. The upper bits of the
31 : // WebSocket serial ID hold the process ID. The lower bits identify the
32 : // WebSocket.
33 : static const uint64_t kWebSocketIDTotalBits = 53;
34 : static const uint64_t kWebSocketIDProcessBits = 22;
35 : static const uint64_t kWebSocketIDWebSocketBits = kWebSocketIDTotalBits - kWebSocketIDProcessBits;
36 :
37 0 : BaseWebSocketChannel::BaseWebSocketChannel()
38 : : mWasOpened(0)
39 : , mClientSetPingInterval(0)
40 : , mClientSetPingTimeout(0)
41 : , mEncrypted(0)
42 : , mPingForced(0)
43 : , mIsServerSide(false)
44 : , mPingInterval(0)
45 0 : , mPingResponseTimeout(10000)
46 : {
47 : // Generation of a unique serial ID.
48 0 : uint64_t processID = 0;
49 0 : if (XRE_IsContentProcess()) {
50 0 : ContentChild* cc = ContentChild::GetSingleton();
51 0 : processID = cc->GetID();
52 : }
53 :
54 0 : uint64_t processBits = processID & ((uint64_t(1) << kWebSocketIDProcessBits) - 1);
55 :
56 : // Make sure no actual webSocket ends up with mWebSocketID == 0 but less then
57 : // what the kWebSocketIDProcessBits allows.
58 0 : if (++gNextWebSocketID >= (uint64_t(1) << kWebSocketIDWebSocketBits)) {
59 0 : gNextWebSocketID = 1;
60 : }
61 :
62 0 : uint64_t webSocketBits = gNextWebSocketID & ((uint64_t(1) << kWebSocketIDWebSocketBits) - 1);
63 0 : mSerial = (processBits << kWebSocketIDWebSocketBits) | webSocketBits;
64 0 : }
65 :
66 : //-----------------------------------------------------------------------------
67 : // BaseWebSocketChannel::nsIWebSocketChannel
68 : //-----------------------------------------------------------------------------
69 :
70 : NS_IMETHODIMP
71 0 : BaseWebSocketChannel::GetOriginalURI(nsIURI **aOriginalURI)
72 : {
73 0 : LOG(("BaseWebSocketChannel::GetOriginalURI() %p\n", this));
74 :
75 0 : if (!mOriginalURI)
76 0 : return NS_ERROR_NOT_INITIALIZED;
77 0 : NS_ADDREF(*aOriginalURI = mOriginalURI);
78 0 : return NS_OK;
79 : }
80 :
81 : NS_IMETHODIMP
82 0 : BaseWebSocketChannel::GetURI(nsIURI **aURI)
83 : {
84 0 : LOG(("BaseWebSocketChannel::GetURI() %p\n", this));
85 :
86 0 : if (!mOriginalURI)
87 0 : return NS_ERROR_NOT_INITIALIZED;
88 0 : if (mURI)
89 0 : NS_ADDREF(*aURI = mURI);
90 : else
91 0 : NS_ADDREF(*aURI = mOriginalURI);
92 0 : return NS_OK;
93 : }
94 :
95 : NS_IMETHODIMP
96 0 : BaseWebSocketChannel::
97 : GetNotificationCallbacks(nsIInterfaceRequestor **aNotificationCallbacks)
98 : {
99 0 : LOG(("BaseWebSocketChannel::GetNotificationCallbacks() %p\n", this));
100 0 : NS_IF_ADDREF(*aNotificationCallbacks = mCallbacks);
101 0 : return NS_OK;
102 : }
103 :
104 : NS_IMETHODIMP
105 0 : BaseWebSocketChannel::
106 : SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks)
107 : {
108 0 : LOG(("BaseWebSocketChannel::SetNotificationCallbacks() %p\n", this));
109 0 : mCallbacks = aNotificationCallbacks;
110 0 : return NS_OK;
111 : }
112 :
113 : NS_IMETHODIMP
114 0 : BaseWebSocketChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
115 : {
116 0 : LOG(("BaseWebSocketChannel::GetLoadGroup() %p\n", this));
117 0 : NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
118 0 : return NS_OK;
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : BaseWebSocketChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
123 : {
124 0 : LOG(("BaseWebSocketChannel::SetLoadGroup() %p\n", this));
125 0 : mLoadGroup = aLoadGroup;
126 0 : return NS_OK;
127 : }
128 :
129 : NS_IMETHODIMP
130 0 : BaseWebSocketChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
131 : {
132 0 : mLoadInfo = aLoadInfo;
133 0 : return NS_OK;
134 : }
135 :
136 : NS_IMETHODIMP
137 0 : BaseWebSocketChannel::GetLoadInfo(nsILoadInfo** aLoadInfo)
138 : {
139 0 : NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
140 0 : return NS_OK;
141 : }
142 :
143 : NS_IMETHODIMP
144 0 : BaseWebSocketChannel::GetExtensions(nsACString &aExtensions)
145 : {
146 0 : LOG(("BaseWebSocketChannel::GetExtensions() %p\n", this));
147 0 : aExtensions = mNegotiatedExtensions;
148 0 : return NS_OK;
149 : }
150 :
151 : NS_IMETHODIMP
152 0 : BaseWebSocketChannel::GetProtocol(nsACString &aProtocol)
153 : {
154 0 : LOG(("BaseWebSocketChannel::GetProtocol() %p\n", this));
155 0 : aProtocol = mProtocol;
156 0 : return NS_OK;
157 : }
158 :
159 : NS_IMETHODIMP
160 0 : BaseWebSocketChannel::SetProtocol(const nsACString &aProtocol)
161 : {
162 0 : LOG(("BaseWebSocketChannel::SetProtocol() %p\n", this));
163 0 : mProtocol = aProtocol; /* the sub protocol */
164 0 : return NS_OK;
165 : }
166 :
167 : NS_IMETHODIMP
168 0 : BaseWebSocketChannel::GetPingInterval(uint32_t *aSeconds)
169 : {
170 : // stored in ms but should only have second resolution
171 0 : MOZ_ASSERT(!(mPingInterval % 1000));
172 :
173 0 : *aSeconds = mPingInterval / 1000;
174 0 : return NS_OK;
175 : }
176 :
177 : NS_IMETHODIMP
178 0 : BaseWebSocketChannel::SetPingInterval(uint32_t aSeconds)
179 : {
180 0 : MOZ_ASSERT(NS_IsMainThread());
181 :
182 0 : if (mWasOpened) {
183 0 : return NS_ERROR_IN_PROGRESS;
184 : }
185 :
186 0 : mPingInterval = aSeconds * 1000;
187 0 : mClientSetPingInterval = 1;
188 :
189 0 : return NS_OK;
190 : }
191 :
192 : NS_IMETHODIMP
193 0 : BaseWebSocketChannel::GetPingTimeout(uint32_t *aSeconds)
194 : {
195 : // stored in ms but should only have second resolution
196 0 : MOZ_ASSERT(!(mPingResponseTimeout % 1000));
197 :
198 0 : *aSeconds = mPingResponseTimeout / 1000;
199 0 : return NS_OK;
200 : }
201 :
202 : NS_IMETHODIMP
203 0 : BaseWebSocketChannel::SetPingTimeout(uint32_t aSeconds)
204 : {
205 0 : MOZ_ASSERT(NS_IsMainThread());
206 :
207 0 : if (mWasOpened) {
208 0 : return NS_ERROR_IN_PROGRESS;
209 : }
210 :
211 0 : mPingResponseTimeout = aSeconds * 1000;
212 0 : mClientSetPingTimeout = 1;
213 :
214 0 : return NS_OK;
215 : }
216 :
217 : NS_IMETHODIMP
218 0 : BaseWebSocketChannel::InitLoadInfo(nsIDOMNode* aLoadingNode,
219 : nsIPrincipal* aLoadingPrincipal,
220 : nsIPrincipal* aTriggeringPrincipal,
221 : uint32_t aSecurityFlags,
222 : uint32_t aContentPolicyType)
223 : {
224 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aLoadingNode);
225 : mLoadInfo = new LoadInfo(aLoadingPrincipal, aTriggeringPrincipal,
226 0 : node, aSecurityFlags, aContentPolicyType);
227 0 : return NS_OK;
228 : }
229 :
230 : NS_IMETHODIMP
231 0 : BaseWebSocketChannel::GetSerial(uint32_t* aSerial)
232 : {
233 0 : if (!aSerial) {
234 0 : return NS_ERROR_FAILURE;
235 : }
236 :
237 0 : *aSerial = mSerial;
238 0 : return NS_OK;
239 : }
240 :
241 : NS_IMETHODIMP
242 0 : BaseWebSocketChannel::SetSerial(uint32_t aSerial)
243 : {
244 0 : mSerial = aSerial;
245 0 : return NS_OK;
246 : }
247 :
248 : NS_IMETHODIMP
249 0 : BaseWebSocketChannel::SetServerParameters(nsITransportProvider* aProvider,
250 : const nsACString& aNegotiatedExtensions)
251 : {
252 0 : MOZ_ASSERT(aProvider);
253 0 : mServerTransportProvider = aProvider;
254 0 : mNegotiatedExtensions = aNegotiatedExtensions;
255 0 : mIsServerSide = true;
256 0 : return NS_OK;
257 : }
258 :
259 : //-----------------------------------------------------------------------------
260 : // BaseWebSocketChannel::nsIProtocolHandler
261 : //-----------------------------------------------------------------------------
262 :
263 :
264 : NS_IMETHODIMP
265 0 : BaseWebSocketChannel::GetScheme(nsACString &aScheme)
266 : {
267 0 : LOG(("BaseWebSocketChannel::GetScheme() %p\n", this));
268 :
269 0 : if (mEncrypted)
270 0 : aScheme.AssignLiteral("wss");
271 : else
272 0 : aScheme.AssignLiteral("ws");
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : BaseWebSocketChannel::GetDefaultPort(int32_t *aDefaultPort)
278 : {
279 0 : LOG(("BaseWebSocketChannel::GetDefaultPort() %p\n", this));
280 :
281 0 : if (mEncrypted)
282 0 : *aDefaultPort = kDefaultWSSPort;
283 : else
284 0 : *aDefaultPort = kDefaultWSPort;
285 0 : return NS_OK;
286 : }
287 :
288 : NS_IMETHODIMP
289 0 : BaseWebSocketChannel::GetProtocolFlags(uint32_t *aProtocolFlags)
290 : {
291 0 : LOG(("BaseWebSocketChannel::GetProtocolFlags() %p\n", this));
292 :
293 0 : *aProtocolFlags = URI_NORELATIVE | URI_NON_PERSISTABLE | ALLOWS_PROXY |
294 : ALLOWS_PROXY_HTTP | URI_DOES_NOT_RETURN_DATA | URI_DANGEROUS_TO_LOAD;
295 0 : return NS_OK;
296 : }
297 :
298 : NS_IMETHODIMP
299 0 : BaseWebSocketChannel::NewURI(const nsACString & aSpec, const char *aOriginCharset,
300 : nsIURI *aBaseURI, nsIURI **_retval)
301 : {
302 0 : LOG(("BaseWebSocketChannel::NewURI() %p\n", this));
303 :
304 : int32_t port;
305 0 : nsresult rv = GetDefaultPort(&port);
306 0 : if (NS_FAILED(rv))
307 0 : return rv;
308 :
309 0 : RefPtr<nsStandardURL> url = new nsStandardURL();
310 0 : rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, port, aSpec,
311 0 : aOriginCharset, aBaseURI);
312 0 : if (NS_FAILED(rv))
313 0 : return rv;
314 0 : url.forget(_retval);
315 0 : return NS_OK;
316 : }
317 :
318 : NS_IMETHODIMP
319 0 : BaseWebSocketChannel::NewChannel2(nsIURI* aURI,
320 : nsILoadInfo* aLoadInfo,
321 : nsIChannel** outChannel)
322 : {
323 0 : LOG(("BaseWebSocketChannel::NewChannel2() %p\n", this));
324 0 : return NS_ERROR_NOT_IMPLEMENTED;
325 : }
326 :
327 : NS_IMETHODIMP
328 0 : BaseWebSocketChannel::NewChannel(nsIURI *aURI, nsIChannel **_retval)
329 : {
330 0 : LOG(("BaseWebSocketChannel::NewChannel() %p\n", this));
331 0 : return NS_ERROR_NOT_IMPLEMENTED;
332 : }
333 :
334 : NS_IMETHODIMP
335 0 : BaseWebSocketChannel::AllowPort(int32_t port, const char *scheme,
336 : bool *_retval)
337 : {
338 0 : LOG(("BaseWebSocketChannel::AllowPort() %p\n", this));
339 :
340 : // do not override any blacklisted ports
341 0 : *_retval = false;
342 0 : return NS_OK;
343 : }
344 :
345 : //-----------------------------------------------------------------------------
346 : // BaseWebSocketChannel::nsIThreadRetargetableRequest
347 : //-----------------------------------------------------------------------------
348 :
349 : NS_IMETHODIMP
350 0 : BaseWebSocketChannel::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
351 : {
352 0 : MOZ_ASSERT(NS_IsMainThread());
353 0 : MOZ_ASSERT(aTargetThread);
354 0 : MOZ_ASSERT(!mTargetThread, "Delivery target should be set once, before AsyncOpen");
355 0 : MOZ_ASSERT(!mWasOpened, "Should not be called after AsyncOpen!");
356 :
357 0 : mTargetThread = do_QueryInterface(aTargetThread);
358 0 : MOZ_ASSERT(mTargetThread);
359 0 : return NS_OK;
360 : }
361 :
362 0 : BaseWebSocketChannel::ListenerAndContextContainer::ListenerAndContextContainer(
363 : nsIWebSocketListener* aListener,
364 0 : nsISupports* aContext)
365 : : mListener(aListener)
366 0 : , mContext(aContext)
367 : {
368 0 : MOZ_ASSERT(NS_IsMainThread());
369 0 : MOZ_ASSERT(mListener);
370 0 : }
371 :
372 0 : BaseWebSocketChannel::ListenerAndContextContainer::~ListenerAndContextContainer()
373 : {
374 0 : MOZ_ASSERT(mListener);
375 :
376 : NS_ReleaseOnMainThread(
377 : "BaseWebSocketChannel::ListenerAndContextContainer::mListener",
378 0 : mListener.forget());
379 : NS_ReleaseOnMainThread(
380 : "BaseWebSocketChannel::ListenerAndContextContainer::mContext",
381 0 : mContext.forget());
382 0 : }
383 :
384 : } // namespace net
385 : } // namespace mozilla
|