Skip to content

Commit e256ec5

Browse files
committed
resolve remaining handshake weakness ( in terms of reliability with respect to the number of bytes read from the channel)
1 parent fe10a64 commit e256ec5

5 files changed

Lines changed: 124 additions & 137 deletions

File tree

‎src/org/java_websocket/WebSocket.java‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import java.nio.ByteBuffer;
66
import java.nio.channels.NotYetConnectedException;
77

8-
import org.java_websocket.drafts.Draft.HandshakeState;
98
import org.java_websocket.exceptions.InvalidDataException;
109
import org.java_websocket.exceptions.InvalidHandshakeException;
1110
import org.java_websocket.framing.Framedata;
@@ -37,8 +36,6 @@ public enum Role {
3736
*/
3837
public abstract void close( int code, String message );
3938

40-
public abstract void closeDirect( int code, String message ) throws IOException;
41-
4239
/**
4340
* closes the socket no matter if the closing handshake completed.
4441
* Does not send any not yet written data before closing.
@@ -92,8 +89,6 @@ public enum Role {
9289
/** Returns whether the batch process all available data */
9390
public abstract boolean batch() throws IOException;
9491

95-
public abstract HandshakeState isFlashEdgeCase( ByteBuffer request );
96-
9792
public abstract void startHandshake( ClientHandshakeBuilder handshakedata ) throws InvalidHandshakeException , InterruptedException;
9893

9994
public abstract InetSocketAddress getRemoteSocketAddress();

‎src/org/java_websocket/WebSocketImpl.java‎

Lines changed: 109 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -191,111 +191,127 @@ public void decode( ByteBuffer socketBuffer ) throws IOException {
191191
* Returns whether the handshake phase has is completed.
192192
* In case of a broken handshake this will be never the case.
193193
**/
194-
private boolean decodeHandshake( ByteBuffer socketBuffer ) throws IOException {
195-
if( draft == null ) {
196-
HandshakeState isflashedgecase = isFlashEdgeCase( socketBuffer );
197-
if( isflashedgecase == HandshakeState.MATCHED ) {
198-
channelWriteDirect( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( wsl.getFlashPolicy( this ) ) ) );
199-
closeDirect( CloseFrame.FLASHPOLICY, "" );
200-
return false;
201-
} else if( isflashedgecase == HandshakeState.MATCHING ) {
202-
return false;
194+
private boolean decodeHandshake( ByteBuffer socketBufferNew ) throws IOException {
195+
ByteBuffer socketBuffer;
196+
if( tmpHandshakeBytes == null ) {
197+
socketBuffer = socketBufferNew;
198+
} else {
199+
if( tmpHandshakeBytes.remaining() < socketBufferNew.remaining() ) {
200+
ByteBuffer buf = ByteBuffer.allocate( tmpHandshakeBytes.capacity() + socketBufferNew.remaining() );
201+
tmpHandshakeBytes.flip();
202+
buf.put( tmpHandshakeBytes );
203+
tmpHandshakeBytes = buf;
203204
}
205+
206+
tmpHandshakeBytes.put( socketBufferNew );
207+
tmpHandshakeBytes.flip();
208+
socketBuffer = tmpHandshakeBytes;
204209
}
205-
HandshakeState handshakestate = null;
206-
socketBuffer.mark();
207210
try {
208-
if( role == Role.SERVER ) {
209-
if( draft == null ) {
210-
for( Draft d : known_drafts ) {
211-
try {
212-
d.setParseMode( role );
213-
socketBuffer.reset();
214-
Handshakedata tmphandshake = d.translateHandshake( socketBuffer );
215-
if( tmphandshake instanceof ClientHandshake == false ) {
216-
closeConnection( CloseFrame.PROTOCOL_ERROR, "wrong http function", false );
217-
return false;
218-
}
219-
ClientHandshake handshake = (ClientHandshake) tmphandshake;
220-
handshakestate = d.acceptHandshakeAsServer( handshake );
221-
if( handshakestate == HandshakeState.MATCHED ) {
222-
ServerHandshakeBuilder response;
223-
try {
224-
response = wsl.onWebsocketHandshakeReceivedAsServer( this, d, handshake );
225-
} catch ( InvalidDataException e ) {
226-
closeConnection( e.getCloseCode(), e.getMessage(), false );
211+
if( draft == null ) {
212+
HandshakeState isflashedgecase = isFlashEdgeCase( socketBuffer );
213+
if( isflashedgecase == HandshakeState.MATCHED ) {
214+
channelWriteDirect( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( wsl.getFlashPolicy( this ) ) ) );
215+
closeDirect( CloseFrame.FLASHPOLICY, "" );
216+
return false;
217+
}
218+
}
219+
HandshakeState handshakestate = null;
220+
socketBuffer.mark();
221+
try {
222+
if( role == Role.SERVER ) {
223+
if( draft == null ) {
224+
for( Draft d : known_drafts ) {
225+
try {
226+
d.setParseMode( role );
227+
socketBuffer.reset();
228+
Handshakedata tmphandshake = d.translateHandshake( socketBuffer );
229+
if( tmphandshake instanceof ClientHandshake == false ) {
230+
closeConnection( CloseFrame.PROTOCOL_ERROR, "wrong http function", false );
227231
return false;
228232
}
229-
writeDirect( d.createHandshake( d.postProcessHandshakeResponseAsServer( handshake, response ), role ) );
230-
draft = d;
231-
open( handshake );
232-
return true;
233-
} else if( handshakestate == HandshakeState.MATCHING ) {
234-
if( draft != null ) {
235-
throw new InvalidHandshakeException( "multible drafts matching" );
233+
ClientHandshake handshake = (ClientHandshake) tmphandshake;
234+
handshakestate = d.acceptHandshakeAsServer( handshake );
235+
if( handshakestate == HandshakeState.MATCHED ) {
236+
ServerHandshakeBuilder response;
237+
try {
238+
response = wsl.onWebsocketHandshakeReceivedAsServer( this, d, handshake );
239+
} catch ( InvalidDataException e ) {
240+
closeConnection( e.getCloseCode(), e.getMessage(), false );
241+
return false;
242+
}
243+
writeDirect( d.createHandshake( d.postProcessHandshakeResponseAsServer( handshake, response ), role ) );
244+
draft = d;
245+
open( handshake );
246+
return true;
236247
}
237-
draft = d;
248+
} catch ( InvalidHandshakeException e ) {
249+
// go on with an other draft
238250
}
239-
} catch ( InvalidHandshakeException e ) {
240-
// go on with an other draft
241-
} catch ( IncompleteHandshakeException e ) {
242-
if( socketBuffer.limit() == socketBuffer.capacity() ) {
243-
close( CloseFrame.TOOBIG, "handshake is to big" );
244-
}
245-
// read more bytes for the handshake
246-
socketBuffer.position( socketBuffer.limit() );
247-
socketBuffer.limit( socketBuffer.capacity() );
251+
}
252+
if( draft == null ) {
253+
close( CloseFrame.PROTOCOL_ERROR, "no draft matches" );
254+
}
255+
return false;
256+
} else {
257+
// special case for multiple step handshakes
258+
Handshakedata tmphandshake = draft.translateHandshake( socketBuffer );
259+
if( tmphandshake instanceof ClientHandshake == false ) {
260+
closeConnection( CloseFrame.PROTOCOL_ERROR, "wrong http function", false );
248261
return false;
249262
}
263+
ClientHandshake handshake = (ClientHandshake) tmphandshake;
264+
handshakestate = draft.acceptHandshakeAsServer( handshake );
265+
266+
if( handshakestate == HandshakeState.MATCHED ) {
267+
open( handshake );
268+
return true;
269+
} else {
270+
close( CloseFrame.PROTOCOL_ERROR, "the handshake did finaly not match" );
271+
}
272+
return false;
250273
}
251-
if( draft == null ) {
252-
close( CloseFrame.PROTOCOL_ERROR, "no draft matches" );
253-
}
254-
return false;
255-
} else {
256-
// special case for multiple step handshakes
274+
} else if( role == Role.CLIENT ) {
275+
draft.setParseMode( role );
257276
Handshakedata tmphandshake = draft.translateHandshake( socketBuffer );
258-
if( tmphandshake instanceof ClientHandshake == false ) {
259-
closeConnection( CloseFrame.PROTOCOL_ERROR, "wrong http function", false );
277+
if( tmphandshake instanceof ServerHandshake == false ) {
278+
closeConnection( CloseFrame.PROTOCOL_ERROR, "Wwrong http function", false );
260279
return false;
261280
}
262-
ClientHandshake handshake = (ClientHandshake) tmphandshake;
263-
handshakestate = draft.acceptHandshakeAsServer( handshake );
264-
281+
ServerHandshake handshake = (ServerHandshake) tmphandshake;
282+
handshakestate = draft.acceptHandshakeAsClient( handshakerequest, handshake );
265283
if( handshakestate == HandshakeState.MATCHED ) {
284+
try {
285+
wsl.onWebsocketHandshakeReceivedAsClient( this, handshakerequest, handshake );
286+
} catch ( InvalidDataException e ) {
287+
closeConnection( e.getCloseCode(), e.getMessage(), false );
288+
return false;
289+
}
266290
open( handshake );
267291
return true;
268-
} else if( handshakestate != HandshakeState.MATCHING ) {
269-
close( CloseFrame.PROTOCOL_ERROR, "the handshake did finaly not match" );
292+
} else {
293+
close( CloseFrame.PROTOCOL_ERROR, "draft " + draft + " refuses handshake" );
270294
}
271-
return false;
272-
}
273-
} else if( role == Role.CLIENT ) {
274-
draft.setParseMode( role );
275-
Handshakedata tmphandshake = draft.translateHandshake( socketBuffer );
276-
if( tmphandshake instanceof ServerHandshake == false ) {
277-
closeConnection( CloseFrame.PROTOCOL_ERROR, "Wwrong http function", false );
278-
return false;
279295
}
280-
ServerHandshake handshake = (ServerHandshake) tmphandshake;
281-
handshakestate = draft.acceptHandshakeAsClient( handshakerequest, handshake );
282-
if( handshakestate == HandshakeState.MATCHED ) {
283-
try {
284-
wsl.onWebsocketHandshakeReceivedAsClient( this, handshakerequest, handshake );
285-
} catch ( InvalidDataException e ) {
286-
closeConnection( e.getCloseCode(), e.getMessage(), false );
287-
return false;
288-
}
289-
open( handshake );
290-
return true;
291-
} else if( handshakestate == HandshakeState.MATCHING ) {
292-
return false;
296+
} catch ( InvalidHandshakeException e ) {
297+
close( e );
298+
}
299+
} catch ( IncompleteHandshakeException e ) {
300+
if( tmpHandshakeBytes == null ) {
301+
int newsize = e.getPreferedSize();
302+
if( newsize == 0 ) {
303+
newsize = socketBuffer.capacity() + 16;
293304
} else {
294-
close( CloseFrame.PROTOCOL_ERROR, "draft " + draft + " refuses handshake" );
305+
assert ( e.getPreferedSize() >= socketBuffer.remaining() );
295306
}
307+
tmpHandshakeBytes = ByteBuffer.allocate( newsize );
308+
309+
tmpHandshakeBytes.put( socketBufferNew );
310+
// tmpHandshakeBytes.flip();
311+
} else {
312+
tmpHandshakeBytes.position( tmpHandshakeBytes.limit() );
313+
tmpHandshakeBytes.limit( tmpHandshakeBytes.capacity() );
296314
}
297-
} catch ( InvalidHandshakeException e ) {
298-
close( e );
299315
}
300316
return false;
301317
}
@@ -377,7 +393,6 @@ public void close( int code, String message ) {
377393
}
378394
}
379395

380-
@Override
381396
public void closeDirect( int code, String message ) throws IOException {
382397
if( !closeHandshakeSent ) {
383398
if( handshakeComplete ) {
@@ -405,6 +420,7 @@ public void closeDirect( int code, String message ) throws IOException {
405420
if( code == CloseFrame.PROTOCOL_ERROR )// this endpoint found a PROTOCOL_ERROR
406421
closeConnection( code, false );
407422
closeHandshakeSent = true;
423+
tmpHandshakeBytes = null;
408424
return;
409425
}
410426
}
@@ -563,40 +579,21 @@ public boolean batch() throws IOException {
563579
return true;
564580
}
565581

566-
@Override
567-
public HandshakeState isFlashEdgeCase( ByteBuffer request ) {
568-
ByteBuffer buf;
569-
if( tmpHandshakeBytes == null ) {
570-
buf = request;
571-
} else {
572-
buf = tmpHandshakeBytes;
573-
tmpHandshakeBytes.position( tmpHandshakeBytes.limit() );
574-
tmpHandshakeBytes.limit( tmpHandshakeBytes.capacity() );
575-
if( request.remaining() > tmpHandshakeBytes.remaining() )
576-
return HandshakeState.NOT_MATCHED;
577-
tmpHandshakeBytes.put( request );
578-
tmpHandshakeBytes.flip();
579-
}
580-
if( buf.limit() > Draft.FLASH_POLICY_REQUEST.length ) {
581-
tmpHandshakeBytes = null;
582+
public HandshakeState isFlashEdgeCase( ByteBuffer request ) throws IncompleteHandshakeException {
583+
request.mark();
584+
if( request.limit() > Draft.FLASH_POLICY_REQUEST.length ) {
582585
return HandshakeState.NOT_MATCHED;
583586
} else if( request.limit() < Draft.FLASH_POLICY_REQUEST.length ) {
584-
if( tmpHandshakeBytes == null ) {
585-
tmpHandshakeBytes = ByteBuffer.allocate( Draft.FLASH_POLICY_REQUEST.length + 1 );
586-
tmpHandshakeBytes.put( request );
587-
tmpHandshakeBytes.flip();
588-
}
589-
return HandshakeState.MATCHING;
587+
throw new IncompleteHandshakeException( Draft.FLASH_POLICY_REQUEST.length );
590588
} else {
591-
buf.mark();
592-
for( int flash_policy_index = 0 ; buf.hasRemaining() ; flash_policy_index++ ) {
593-
if( Draft.FLASH_POLICY_REQUEST[ flash_policy_index ] != buf.get() ) {
594-
buf.reset();
589+
590+
for( int flash_policy_index = 0 ; request.hasRemaining() ; flash_policy_index++ ) {
591+
if( Draft.FLASH_POLICY_REQUEST[ flash_policy_index ] != request.get() ) {
592+
request.reset();
595593
return HandshakeState.NOT_MATCHED;
596594
}
597595
}
598596
return HandshakeState.MATCHED;
599-
// return request.remaining() >= Draft.FLASH_POLICY_REQUEST.length ? HandshakeState.MATCHED : HandshakeState.MATCHING;
600597
}
601598
}
602599

‎src/org/java_websocket/drafts/Draft.java‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.Locale;
88

99
import org.java_websocket.WebSocket.Role;
10+
import org.java_websocket.exceptions.IncompleteHandshakeException;
1011
import org.java_websocket.exceptions.InvalidDataException;
1112
import org.java_websocket.exceptions.InvalidHandshakeException;
1213
import org.java_websocket.exceptions.LimitExedeedException;
@@ -31,9 +32,7 @@ public enum HandshakeState {
3132
/** Handshake matched this Draft successfully */
3233
MATCHED,
3334
/** Handshake is does not match this Draft */
34-
NOT_MATCHED,
35-
/** Handshake matches this Draft but is not complete */
36-
MATCHING
35+
NOT_MATCHED
3736
}
3837
public enum CloseHandshakeType {
3938
NONE, ONEWAY, TWOWAY
@@ -72,12 +71,12 @@ public static String readStringLine( ByteBuffer buf ) {
7271
return b == null ? null : Charsetfunctions.stringAscii( b.array(), 0, b.limit() );
7372
}
7473

75-
public static HandshakeBuilder translateHandshakeHttp( ByteBuffer buf, Role role ) throws InvalidHandshakeException {
74+
public static HandshakeBuilder translateHandshakeHttp( ByteBuffer buf, Role role ) throws InvalidHandshakeException , IncompleteHandshakeException {
7675
HandshakeBuilder handshake;
7776

7877
String line = readStringLine( buf );
7978
if( line == null )
80-
throw new InvalidHandshakeException( "could not match http status line" );
79+
throw new IncompleteHandshakeException( buf.capacity() + 128 );
8180

8281
String[] firstLineTokens = line.split( " ", 3 );// eg. HTTP/1.1 101 Switching the Protocols
8382
if( firstLineTokens.length != 3 ) {
@@ -105,6 +104,8 @@ public static HandshakeBuilder translateHandshakeHttp( ByteBuffer buf, Role role
105104
handshake.put( pair[ 0 ], pair[ 1 ].replaceFirst( "^ +", "" ) );
106105
line = readStringLine( buf );
107106
}
107+
if( line == null )
108+
throw new IncompleteHandshakeException();
108109
return handshake;
109110
}
110111

‎src/org/java_websocket/drafts/Draft_76.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHa
116116
}
117117
byte[] content = response.getContent();
118118
if( content == null || content.length == 0 ) {
119-
return HandshakeState.MATCHING;
119+
throw new IncompleteHandshakeException();
120120
}
121121
if( Arrays.equals( content, createChallenge( request.getFieldValue( "Sec-WebSocket-Key1" ), request.getFieldValue( "Sec-WebSocket-Key2" ), request.getContent() ) ) ) {
122122
return HandshakeState.MATCHED;
@@ -182,7 +182,7 @@ public Handshakedata translateHandshake( ByteBuffer buf ) throws InvalidHandshak
182182
try {
183183
buf.get( key3 );
184184
} catch ( BufferUnderflowException e ) {
185-
throw new IncompleteHandshakeException();
185+
throw new IncompleteHandshakeException( buf.capacity() + 16 );
186186
}
187187
bui.setContent( key3 );
188188

‎src/org/java_websocket/exceptions/IncompleteHandshakeException.java‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,19 @@
22

33
public class IncompleteHandshakeException extends RuntimeException {
44

5-
/**
6-
* Serializable
7-
*/
85
private static final long serialVersionUID = 7906596804233893092L;
6+
private int newsize;
97

10-
public IncompleteHandshakeException() {
11-
super();
12-
}
13-
14-
public IncompleteHandshakeException( String message , Throwable cause ) {
15-
super( message, cause );
8+
public IncompleteHandshakeException( int newsize ) {
9+
this.newsize = newsize;
1610
}
1711

18-
public IncompleteHandshakeException( String message ) {
19-
super( message );
12+
public IncompleteHandshakeException() {
13+
this.newsize = 0;
2014
}
2115

22-
public IncompleteHandshakeException( Throwable cause ) {
23-
super( cause );
16+
public int getPreferedSize() {
17+
return newsize;
2418
}
2519

2620
}

0 commit comments

Comments
 (0)