11package net .tootallnate .websocket ;
22
33import java .io .IOException ;
4- import java .io .UnsupportedEncodingException ;
54import java .nio .ByteBuffer ;
65import java .nio .channels .NotYetConnectedException ;
76import java .nio .channels .SocketChannel ;
7+ import java .nio .charset .Charset ;
88import java .security .NoSuchAlgorithmException ;
9+ import java .util .HashMap ;
910import java .util .concurrent .BlockingQueue ;
1011
12+ import websync .WebSocketClientTest ;
13+
1114/**
1215 * Represents one end (client or server) of a single WebSocket connection.
1316 * Takes care of the "handshake" phase, then allows for easy sending of
@@ -30,9 +33,9 @@ public final class WebSocket {
3033 public static final int DEFAULT_PORT = 80 ;
3134 /**
3235 * The WebSocket protocol expects UTF-8 encoded bytes.
33- */
34- public static final String UTF8_CHARSET = "UTF-8" ;
35- /**
36+ */
37+ public final static Charset UTF8_CHARSET = Charset . forName ( "UTF-8" ) ;
38+ /**
3639 * The byte representing CR, or Carriage Return, or \r
3740 */
3841 public static final byte CR = (byte )0x0D ;
@@ -48,6 +51,7 @@ public final class WebSocket {
4851 * The byte representing the end of a WebSocket text frame.
4952 */
5053 public static final byte END_OF_FRAME = (byte )0xFF ;
54+
5155
5256
5357 // INSTANCE PROPERTIES /////////////////////////////////////////////////////
@@ -92,6 +96,9 @@ public final class WebSocket {
9296 private Object bufferQueueMutex = new Object ();
9397
9498 private boolean readingState = false ;
99+
100+ private WebSocketDraft draft ;
101+
95102
96103
97104 // CONSTRUCTOR /////////////////////////////////////////////////////////////
@@ -133,17 +140,28 @@ void handleRead() throws IOException, NoSuchAlgorithmException {
133140 if (bytesRead == -1 ) {
134141 close ();
135142 } else if (bytesRead > 0 ) {
136- for (int i = 0 ; i < bytesRead ; i ++) {
137- buffer .rewind ();
138- buffer .put (socketBuffer .get (i ));
139-
140- this .buffer .rewind ();
141-
142- if (!this .handshakeComplete )
143- recieveHandshake ();
144- else
145- recieveFrame ();
146- }
143+ System .out .print ( "got: {\n " + new String ( socketBuffer .array () , 0 , bytesRead ) + "\n }" );
144+ if ( !this .handshakeComplete && recieveHandshake ( bytesRead ) ) {
145+ }
146+ else {
147+ recieveFrame (bytesRead );
148+ }
149+ if (true )
150+ return ;
151+ {
152+ for ( int i = 0 ; i < bytesRead ; i ++ ) {
153+ buffer .rewind ();
154+ buffer .put ( socketBuffer .get ( i ) );
155+
156+ this .buffer .rewind ();
157+
158+ if (!this .handshakeComplete )
159+ recieveHandshake ( bytesRead );
160+ //recieveHandshake75_76( bytesRead);
161+ else
162+ recieveFrame75_76 ();
163+ }
164+ }
147165 }
148166 }
149167
@@ -164,7 +182,17 @@ public void close() throws IOException {
164182 */
165183 public boolean send (String text ) throws IOException {
166184 if (!this .handshakeComplete ) throw new NotYetConnectedException ();
167- if (text == null ) throw new NullPointerException ("Cannot send 'null' data to a WebSocket." );
185+ if ( text == null ) throw new NullPointerException ( "Cannot send 'null' data to a WebSocket." );
186+ if ( draft == WebSocketDraft .DRAFT10 ){
187+ return send10 ( text );
188+ }
189+ else
190+ return send75_76 ( text );
191+ }
192+
193+ public boolean send75_76 (String text ) throws IOException {
194+ if (!this .handshakeComplete ) throw new NotYetConnectedException ();
195+ if ( text == null ) throw new NullPointerException ( "Cannot send 'null' data to a WebSocket." );
168196
169197 // Get 'text' into a WebSocket "frame" of bytes
170198 byte [] textBytes = text .getBytes (UTF8_CHARSET );
@@ -177,7 +205,7 @@ public boolean send(String text) throws IOException {
177205 // See if we have any backlog that needs to be sent first
178206 if (handleWrite ()) {
179207 // Write the ByteBuffer to the socket
180- this . socketChannel . write ( b );
208+ channelWrite ( b );
181209 }
182210
183211 // If we didn't get it all sent, add it to the buffer of buffers
@@ -192,6 +220,31 @@ public boolean send(String text) throws IOException {
192220 return true ;
193221 }
194222
223+ private boolean send10 ( String text ) throws IOException {
224+ boolean mask =false ;
225+ byte [] mes = text .getBytes ( UTF8_CHARSET );
226+ ByteBuffer b = ByteBuffer .allocate ( 2 + mes .length +( mask ? 4 : 0 ) );
227+ ByteBuffer maskkey = ByteBuffer .allocate ( 4 );
228+ byte one = ( byte ) -127 ;
229+ //if(mask)
230+ // one |= 1;
231+ b .put ( one ); // b1 controll
232+ b .put ( ( byte ) mes .length ); // b2 length
233+ if ( mask ){
234+ maskkey .putInt ( Integer .MIN_VALUE );
235+ b .put ( maskkey .array () );
236+ for ( int i = 0 ; i < mes .length ; i ++){
237+ b .put ( ( byte ) ( mes [i ] ^ maskkey .get ( i % 4 ) ) );
238+ }
239+ }
240+ else
241+ b .put ( mes );
242+
243+ b .rewind ();
244+ channelWrite ( b );
245+ return true ;
246+ }
247+
195248 boolean hasBufferedData () {
196249 return !this .bufferQueue .isEmpty ();
197250 }
@@ -204,7 +257,7 @@ boolean handleWrite() throws IOException {
204257 synchronized (this .bufferQueueMutex ) {
205258 ByteBuffer buffer = this .bufferQueue .peek ();
206259 while (buffer != null ) {
207- this . socketChannel . write ( buffer );
260+ channelWrite ( buffer );
208261 if (buffer .remaining () > 0 ) {
209262 return false ; // Didn't finish this buffer. There's more to send.
210263 } else {
@@ -221,7 +274,7 @@ public SocketChannel socketChannel() {
221274 }
222275
223276 // PRIVATE INSTANCE METHODS ////////////////////////////////////////////////
224- private void recieveFrame () {
277+ private void recieveFrame75_76 () {
225278 byte newestByte = this .buffer .get ();
226279
227280 if (newestByte == START_OF_FRAME && !readingState ) { // Beginning of Frame
@@ -234,13 +287,7 @@ private void recieveFrame() {
234287 // currentFrame will be null if END_OF_FRAME was send directly after
235288 // START_OF_FRAME, thus we will send 'null' as the sent message.
236289 if (this .currentFrame != null ) {
237- try {
238- textFrame = new String (this .currentFrame .array (), UTF8_CHARSET );
239- } catch (UnsupportedEncodingException ex ) {
240- // TODO: Fire an 'onError' handler here
241- ex .printStackTrace ();
242- textFrame = "" ;
243- }
290+ textFrame = new String ( this .currentFrame .array () , UTF8_CHARSET );
244291 }
245292 this .wsl .onMessage (this , textFrame );
246293
@@ -254,15 +301,45 @@ private void recieveFrame() {
254301 this .currentFrame = frame ;
255302 }
256303 }
304+
305+ private void recieveFrame ( int read ) throws IOException {
306+ byte [] b = ByteBuffer .allocate ( read ).put ( socketBuffer .array () , 0 , read ).array ();//socketBuffer.array ()
307+ boolean FIN = b [0 ] >> 8 != 0 ;
308+ boolean MASK = ( b [0 ] &~1 ) != 0 ;
309+ int payloadlength = (byte )( b [1 ] & ~(byte )128 );
310+ System .out .println ( "pll: " + payloadlength );
311+ int maskskeytart = payloadlength < 125 ? 1 + 1 : payloadlength == 126 ? 1 + 2 : 1 + 8 ;
312+ int extdatastart = maskskeytart +4 ; //TODO allow extdata
313+ int payloadstart = extdatastart ;
314+ byte [] maskskey = ByteBuffer .allocate ( 4 ).put ( b , maskskeytart , 4 ).array ();
315+ //demasking the payloaddata
316+ ByteBuffer payload =ByteBuffer .allocate ( payloadlength );
317+ for ( int i = 0 ; i < payloadlength ; i ++ ){
318+ payload .put ( ( byte ) ( (byte )b [payloadstart + i ] ^ (byte )maskskey [ i %4 ] ) );
319+ }
320+
321+ /*b[1]&=~(byte)128;
322+ for( int i = 0 ; i < payloadlength ; i++ ){
323+ b[ payloadstart + i - 4 ] = ( byte ) ( (byte)b[payloadstart + i] ^ (byte)maskskey[ i%4 ] );
324+ }
325+ byte[] c = ByteBuffer.allocate ( read-4 ).put ( b , 0 , read-4 ).array ();
326+ channelWrite ( ByteBuffer.wrap ( c ) );*/
327+ this .wsl .onMessage ( this , new String ( payload .array () ,UTF8_CHARSET ) );
328+
329+ }
257330
258- private void recieveHandshake ( ) throws IOException , NoSuchAlgorithmException {
259- ByteBuffer ch = ByteBuffer .allocate (( this .remoteHandshake != null ? this .remoteHandshake .capacity () : 0 ) + this .buffer .capacity ());
260- if (this .remoteHandshake != null ) {
331+ private boolean recieveHandshake75_76 ( int bytesRead ) throws IOException {
332+ ByteBuffer ch = ByteBuffer .allocate ( ( this .remoteHandshake != null ? this .remoteHandshake .capacity () : 0 ) + this .buffer .capacity () );
333+ if ( this .remoteHandshake != null ) {
261334 this .remoteHandshake .rewind ();
262- ch .put (this .remoteHandshake );
335+ ch .put ( this .remoteHandshake );
263336 }
264337 ch .put (this .buffer );
265338 this .remoteHandshake = ch ;
339+ //byte[] h2 = ByteBuffer.wrap(socketBuffer.array(),0, bytesRead).array();
340+ ByteBuffer b =ByteBuffer .allocate ( bytesRead );
341+ b .put ( socketBuffer .array () , 0 , bytesRead );
342+ byte [] h2 = b .array ();
266343 byte [] h = this .remoteHandshake .array ();
267344 // If the ByteBuffer contains 16 random bytes, and ends with
268345 // 0x0D 0x0A 0x0D 0x0A (or two CRLFs), then the client
@@ -289,7 +366,8 @@ private void recieveHandshake() throws IOException, NoSuchAlgorithmException {
289366 h [h .length -2 ],
290367 h [h .length -1 ]
291368 });
292-
369+ draft = WebSocketDraft .DRAFT76 ;
370+ return true ;
293371 // If the ByteBuffer contains 8 random bytes,ends with
294372 // 0x0D 0x0A 0x0D 0x0A (or two CRLFs), and the response
295373 // contains Sec-WebSocket-Key1 then the client
@@ -298,6 +376,7 @@ private void recieveHandshake() throws IOException, NoSuchAlgorithmException {
298376 && h [h .length -11 ] == LF
299377 && h [h .length -10 ] == CR
300378 && h [h .length -9 ] == LF ) && new String (this .remoteHandshake .array (), UTF8_CHARSET ).contains ("Sec-WebSocket-Key1" )) {
379+ System .out .println ("------>Draft 76 Sec-WebSocket-Key1 8<------" +new String (h ));
301380 completeHandshake (new byte [] {
302381 h [h .length -8 ],
303382 h [h .length -7 ],
@@ -308,19 +387,66 @@ private void recieveHandshake() throws IOException, NoSuchAlgorithmException {
308387 h [h .length -2 ],
309388 h [h .length -1 ]
310389 });
311-
390+ draft = WebSocketDraft .DRAFT76 ;
391+ return true ;
392+
312393 // Consider Draft 75, and the Flash Security Policy
313394 // Request edge-case.
314395 } else if ((h .length >=4 && h [h .length -4 ] == CR
315396 && h [h .length -3 ] == LF
316397 && h [h .length -2 ] == CR
317398 && h [h .length -1 ] == LF ) && !(new String (this .remoteHandshake .array (), UTF8_CHARSET ).contains ("Sec" )) ||
318399 (h .length ==23 && h [h .length -1 ] == 0 ) ) {
400+ System .out .println ("------>Draft 75 / flash<------" +new String (h ));
319401 completeHandshake (null );
320- }
402+ draft = WebSocketDraft .DRAFT75 ;
403+ return true ;
404+ }
405+ else
406+ return false ;
321407 }
408+
409+ private boolean recieveHandshake ( int readcount ) throws IOException {
410+ ByteBuffer message = ByteBuffer .allocate ( readcount );
411+ message .put ( socketBuffer .array () , 0 , readcount );
412+ byte [] lines = message .array ();
413+ int previndex = 0 ;
414+ int index = findNewLine ( lines , previndex );
415+ if ( index == -1 )
416+ return false ;
417+ String line = new String ( lines , previndex , index - previndex );
418+ if ( line .startsWith ( "GET" ) == false )
419+ return false ;
420+ previndex = index + 2 ;
421+ index = findNewLine ( lines , previndex );
422+
423+ HashMap <String ,String > elements = new HashMap <String ,String > ( 10 );
424+ while ( index != -1 ) {
425+ line = new String ( lines , previndex , index - previndex );
426+ if ( index != previndex ) {
427+ String [] pair = line .split ( ":" , 2 );
428+ if ( pair .length != 2 )
429+ return false ;
430+ elements .put ( pair [ 0 ] , pair [ 1 ] );
431+ System .out .println ( "Line: " + line );
432+ }
433+ previndex = index + 2 ;
434+ index = findNewLine ( lines , previndex );
435+ }
436+ draft = WebSocketDraft .DRAFT10 ;
437+ return this .handshakeComplete = this .wsl .onHandshakeRecieved ( this , elements );
438+ }
439+
440+ private static int findNewLine ( byte [] arr , int offset ) {
441+ int len = arr .length - 1 ;
442+ for ( int i = offset ; i < len ; i ++ )
443+ if ( arr [i ] == (byte )'\r' && arr [ i + 1 ] == (byte )'\n' )
444+ return i ;
445+ return -1 ;
446+ }
447+
322448
323- private void completeHandshake (byte [] handShakeBody ) throws IOException , NoSuchAlgorithmException {
449+ private void completeHandshake (byte [] handShakeBody ) throws IOException {
324450 byte [] handshakeBytes = this .remoteHandshake .array ();
325451 String handshake = new String (handshakeBytes , UTF8_CHARSET );
326452 this .handshakeComplete = true ;
@@ -330,5 +456,16 @@ private void completeHandshake(byte[] handShakeBody) throws IOException, NoSuchA
330456 close ();
331457 }
332458 }
459+ public void channelWrite (ByteBuffer buf ) throws IOException {
460+ System .out .println ("write: {\n " +new String (buf .array ())+"}" );
461+ printBytes ( buf , buf .capacity () );
462+ socketChannel .write (buf );
463+ }
464+ public void printBytes (ByteBuffer buf , int len ){
465+ for ( int i = 0 ; i < 2 && i < len ; i ++ ){
466+ System .out .println (Integer .toBinaryString ( buf .get ( i ) ));
467+ }
468+
469+ }
333470
334471}
0 commit comments