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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2010 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Wellington Fernando de Macedo <wfernandom2004@gmail.com> (original author)
25 : * Patrick McManus <mcmanus@ducksong.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef mozilla_net_WebSocketChannel_h
42 : #define mozilla_net_WebSocketChannel_h
43 :
44 : #include "nsIURI.h"
45 : #include "nsISupports.h"
46 : #include "nsIInterfaceRequestor.h"
47 : #include "nsIEventTarget.h"
48 : #include "nsIStreamListener.h"
49 : #include "nsIProtocolHandler.h"
50 : #include "nsISocketTransport.h"
51 : #include "nsIAsyncInputStream.h"
52 : #include "nsIAsyncOutputStream.h"
53 : #include "nsILoadGroup.h"
54 : #include "nsITimer.h"
55 : #include "nsIDNSListener.h"
56 : #include "nsIHttpChannel.h"
57 : #include "nsIChannelEventSink.h"
58 : #include "nsIAsyncVerifyRedirectCallback.h"
59 : #include "nsIStringStream.h"
60 : #include "nsIHttpChannelInternal.h"
61 : #include "nsIRandomGenerator.h"
62 : #include "BaseWebSocketChannel.h"
63 :
64 : #include "nsCOMPtr.h"
65 : #include "nsString.h"
66 : #include "nsDeque.h"
67 :
68 : namespace mozilla { namespace net {
69 :
70 : class OutboundMessage;
71 : class OutboundEnqueuer;
72 : class nsWSAdmissionManager;
73 : class nsWSCompression;
74 : class CallOnMessageAvailable;
75 : class CallOnStop;
76 : class CallOnServerClose;
77 : class CallAcknowledge;
78 :
79 : class WebSocketChannel : public BaseWebSocketChannel,
80 : public nsIHttpUpgradeListener,
81 : public nsIStreamListener,
82 : public nsIInputStreamCallback,
83 : public nsIOutputStreamCallback,
84 : public nsITimerCallback,
85 : public nsIDNSListener,
86 : public nsIInterfaceRequestor,
87 : public nsIChannelEventSink
88 : {
89 : public:
90 : NS_DECL_ISUPPORTS
91 : NS_DECL_NSIHTTPUPGRADELISTENER
92 : NS_DECL_NSIREQUESTOBSERVER
93 : NS_DECL_NSISTREAMLISTENER
94 : NS_DECL_NSIINPUTSTREAMCALLBACK
95 : NS_DECL_NSIOUTPUTSTREAMCALLBACK
96 : NS_DECL_NSITIMERCALLBACK
97 : NS_DECL_NSIDNSLISTENER
98 : NS_DECL_NSIINTERFACEREQUESTOR
99 : NS_DECL_NSICHANNELEVENTSINK
100 :
101 : // nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us
102 : //
103 : NS_IMETHOD AsyncOpen(nsIURI *aURI,
104 : const nsACString &aOrigin,
105 : nsIWebSocketListener *aListener,
106 : nsISupports *aContext);
107 : NS_IMETHOD Close(PRUint16 aCode, const nsACString & aReason);
108 : NS_IMETHOD SendMsg(const nsACString &aMsg);
109 : NS_IMETHOD SendBinaryMsg(const nsACString &aMsg);
110 : NS_IMETHOD SendBinaryStream(nsIInputStream *aStream, PRUint32 length);
111 : NS_IMETHOD GetSecurityInfo(nsISupports **aSecurityInfo);
112 :
113 : WebSocketChannel();
114 : static void Shutdown();
115 :
116 : enum {
117 : // Non Control Frames
118 : kContinuation = 0x0,
119 : kText = 0x1,
120 : kBinary = 0x2,
121 :
122 : // Control Frames
123 : kClose = 0x8,
124 : kPing = 0x9,
125 : kPong = 0xA
126 : };
127 :
128 : const static PRUint32 kControlFrameMask = 0x8;
129 : const static PRUint8 kMaskBit = 0x80;
130 : const static PRUint8 kFinalFragBit = 0x80;
131 :
132 : protected:
133 : virtual ~WebSocketChannel();
134 :
135 : private:
136 : friend class OutboundEnqueuer;
137 : friend class nsWSAdmissionManager;
138 : friend class CallOnMessageAvailable;
139 : friend class CallOnStop;
140 : friend class CallOnServerClose;
141 : friend class CallAcknowledge;
142 :
143 : // Common send code for binary + text msgs
144 : nsresult SendMsgCommon(const nsACString *aMsg, bool isBinary,
145 : PRUint32 length, nsIInputStream *aStream = NULL);
146 :
147 : void EnqueueOutgoingMessage(nsDeque &aQueue, OutboundMessage *aMsg);
148 :
149 : void PrimeNewOutgoingMessage();
150 : void DeleteCurrentOutGoingMessage();
151 : void GeneratePong(PRUint8 *payload, PRUint32 len);
152 : void GeneratePing();
153 :
154 : nsresult BeginOpen();
155 : nsresult HandleExtensions();
156 : nsresult SetupRequest();
157 : nsresult ApplyForAdmission();
158 : nsresult StartWebsocketData();
159 : PRUint16 ResultToCloseCode(nsresult resultCode);
160 :
161 : void StopSession(nsresult reason);
162 : void AbortSession(nsresult reason);
163 : void ReleaseSession();
164 : void CleanupConnection();
165 :
166 : void EnsureHdrOut(PRUint32 size);
167 : void ApplyMask(PRUint32 mask, PRUint8 *data, PRUint64 len);
168 :
169 : bool IsPersistentFramePtr();
170 : nsresult ProcessInput(PRUint8 *buffer, PRUint32 count);
171 : bool UpdateReadBuffer(PRUint8 *buffer, PRUint32 count,
172 : PRUint32 accumulatedFragments,
173 : PRUint32 *available);
174 :
175 :
176 : nsCOMPtr<nsIEventTarget> mSocketThread;
177 : nsCOMPtr<nsIHttpChannelInternal> mChannel;
178 : nsCOMPtr<nsIHttpChannel> mHttpChannel;
179 : nsCOMPtr<nsICancelable> mDNSRequest;
180 : nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
181 : nsCOMPtr<nsIRandomGenerator> mRandomGenerator;
182 :
183 : nsCString mHashedSecret;
184 : nsCString mAddress;
185 :
186 : nsCOMPtr<nsISocketTransport> mTransport;
187 : nsCOMPtr<nsIAsyncInputStream> mSocketIn;
188 : nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
189 :
190 : nsCOMPtr<nsITimer> mCloseTimer;
191 : PRUint32 mCloseTimeout; /* milliseconds */
192 :
193 : nsCOMPtr<nsITimer> mOpenTimer;
194 : PRUint32 mOpenTimeout; /* milliseconds */
195 :
196 : nsCOMPtr<nsITimer> mPingTimer;
197 : PRUint32 mPingTimeout; /* milliseconds */
198 : PRUint32 mPingResponseTimeout; /* milliseconds */
199 :
200 : nsCOMPtr<nsITimer> mLingeringCloseTimer;
201 : const static PRInt32 kLingeringCloseTimeout = 1000;
202 : const static PRInt32 kLingeringCloseThreshold = 50;
203 :
204 : PRInt32 mMaxConcurrentConnections;
205 :
206 : PRUint32 mRecvdHttpOnStartRequest : 1;
207 : PRUint32 mRecvdHttpUpgradeTransport : 1;
208 : PRUint32 mRequestedClose : 1;
209 : PRUint32 mClientClosed : 1;
210 : PRUint32 mServerClosed : 1;
211 : PRUint32 mStopped : 1;
212 : PRUint32 mCalledOnStop : 1;
213 : PRUint32 mPingOutstanding : 1;
214 : PRUint32 mAllowCompression : 1;
215 : PRUint32 mAutoFollowRedirects : 1;
216 : PRUint32 mReleaseOnTransmit : 1;
217 : PRUint32 mTCPClosed : 1;
218 : PRUint32 mOpenBlocked : 1;
219 : PRUint32 mOpenRunning : 1;
220 : PRUint32 mChannelWasOpened : 1;
221 :
222 : PRInt32 mMaxMessageSize;
223 : nsresult mStopOnClose;
224 : PRUint16 mServerCloseCode;
225 : nsCString mServerCloseReason;
226 : PRUint16 mScriptCloseCode;
227 : nsCString mScriptCloseReason;
228 :
229 : // These are for the read buffers
230 : const static PRUint32 kIncomingBufferInitialSize = 16 * 1024;
231 : // We're ok with keeping a buffer this size or smaller around for the life of
232 : // the websocket. If a particular message needs bigger than this we'll
233 : // increase the buffer temporarily, then drop back down to this size.
234 : const static PRUint32 kIncomingBufferStableSize = 128 * 1024;
235 :
236 : PRUint8 *mFramePtr;
237 : PRUint8 *mBuffer;
238 : PRUint8 mFragmentOpcode;
239 : PRUint32 mFragmentAccumulator;
240 : PRUint32 mBuffered;
241 : PRUint32 mBufferSize;
242 : nsCOMPtr<nsIStreamListener> mInflateReader;
243 : nsCOMPtr<nsIStringInputStream> mInflateStream;
244 :
245 : // These are for the send buffers
246 : const static PRInt32 kCopyBreak = 1000;
247 :
248 : OutboundMessage *mCurrentOut;
249 : PRUint32 mCurrentOutSent;
250 : nsDeque mOutgoingMessages;
251 : nsDeque mOutgoingPingMessages;
252 : nsDeque mOutgoingPongMessages;
253 : PRUint32 mHdrOutToSend;
254 : PRUint8 *mHdrOut;
255 : PRUint8 mOutHeader[kCopyBreak + 16];
256 : nsWSCompression *mCompressor;
257 : PRUint32 mDynamicOutputSize;
258 : PRUint8 *mDynamicOutput;
259 : };
260 :
261 : class WebSocketSSLChannel : public WebSocketChannel
262 : {
263 : public:
264 0 : WebSocketSSLChannel() { BaseWebSocketChannel::mEncrypted = true; }
265 : protected:
266 0 : virtual ~WebSocketSSLChannel() {}
267 : };
268 :
269 : }} // namespace mozilla::net
270 :
271 : #endif // mozilla_net_WebSocketChannel_h
|