From 3bd0f5125fb4edf9f07128d0eb1a80e08886cc03 Mon Sep 17 00:00:00 2001 From: marci4 Date: Fri, 8 Sep 2017 19:49:22 +0200 Subject: [PATCH] Removal of deprecated drafts Removed Draft_10, Draft_17, Draft_75, Draft_76 --- .../java/org/java_websocket/WebSocket.java | 46 +- .../org/java_websocket/WebSocketImpl.java | 86 ++-- .../java/org/java_websocket/drafts/Draft.java | 14 + .../org/java_websocket/drafts/Draft_10.java | 423 ------------------ .../org/java_websocket/drafts/Draft_6455.java | 209 +++++++-- .../org/java_websocket/drafts/Draft_75.java | 227 ---------- .../org/java_websocket/drafts/Draft_76.java | 270 ----------- .../IncompleteException.java} | 50 +-- 8 files changed, 295 insertions(+), 1030 deletions(-) delete mode 100644 src/main/java/org/java_websocket/drafts/Draft_10.java delete mode 100644 src/main/java/org/java_websocket/drafts/Draft_75.java delete mode 100644 src/main/java/org/java_websocket/drafts/Draft_76.java rename src/main/java/org/java_websocket/{drafts/Draft_17.java => exceptions/IncompleteException.java} (55%) diff --git a/src/main/java/org/java_websocket/WebSocket.java b/src/main/java/org/java_websocket/WebSocket.java index 23271bfc1..514d8d884 100644 --- a/src/main/java/org/java_websocket/WebSocket.java +++ b/src/main/java/org/java_websocket/WebSocket.java @@ -38,14 +38,14 @@ public interface WebSocket { /** * Enum which represents the states a websocket may be in */ - public enum Role { + enum Role { CLIENT, SERVER } /** * Enum which represents the state a websocket may be in */ - public enum READYSTATE { + enum READYSTATE { NOT_YET_CONNECTED, CONNECTING, OPEN, CLOSING, CLOSED } @@ -54,14 +54,14 @@ public enum READYSTATE { * constructor is used, DEFAULT_PORT will be the port the WebSocketServer * is binded to. Note that ports under 1024 usually require root permissions. */ - public static final int DEFAULT_PORT = 80; + int DEFAULT_PORT = 80; /** * The default wss port of WebSockets, as defined in the spec. If the nullary * constructor is used, DEFAULT_WSS_PORT will be the port the WebSocketServer * is binded to. Note that ports under 1024 usually require root permissions. */ - public static final int DEFAULT_WSS_PORT = 443; + int DEFAULT_WSS_PORT = 443; /** * sends the closing handshake. @@ -69,17 +69,17 @@ public enum READYSTATE { * @param code the closing code * @param message the closing message */ - public void close( int code, String message ); + void close( int code, String message ); /** * sends the closing handshake. * may be send in response to an other handshake. * @param code the closing code */ - public void close( int code ); + void close( int code ); /** Convenience function which behaves like close(CloseFrame.NORMAL) */ - public void close(); + void close(); /** * This will close the connection immediately without a proper close handshake. @@ -87,7 +87,7 @@ public enum READYSTATE { * @param code the closing code * @param message the closing message **/ - public abstract void closeConnection( int code, String message ); + void closeConnection( int code, String message ); /** * Send Text data to the other end. @@ -95,7 +95,7 @@ public enum READYSTATE { * @param text the text data to send * @throws NotYetConnectedException websocket is not yet connected */ - public abstract void send( String text ) throws NotYetConnectedException; + void send( String text ) throws NotYetConnectedException; /** * Send Binary data (plain bytes) to the other end. @@ -104,7 +104,7 @@ public enum READYSTATE { * @throws IllegalArgumentException the data is null * @throws NotYetConnectedException websocket is not yet connected */ - public abstract void send( ByteBuffer bytes ) throws IllegalArgumentException , NotYetConnectedException; + void send( ByteBuffer bytes ) throws IllegalArgumentException , NotYetConnectedException; /** * Send Binary data (plain bytes) to the other end. @@ -113,7 +113,7 @@ public enum READYSTATE { * @throws IllegalArgumentException the data is null * @throws NotYetConnectedException websocket is not yet connected */ - public abstract void send( byte[] bytes ) throws IllegalArgumentException , NotYetConnectedException; + void send( byte[] bytes ) throws IllegalArgumentException , NotYetConnectedException; /** * Send a frame to the other end @@ -146,64 +146,64 @@ public enum READYSTATE { * @param fin * true means the current frame is the last in the sequence. **/ - public abstract void sendFragmentedFrame( Opcode op, ByteBuffer buffer, boolean fin ); + void sendFragmentedFrame( Opcode op, ByteBuffer buffer, boolean fin ); /** * Checks if the websocket has buffered data * @return has the websocket buffered data */ - public abstract boolean hasBufferedData(); + boolean hasBufferedData(); /** * Returns the address of the endpoint this socket is connected to, or{@code null} if it is unconnected. * * @return never returns null */ - public abstract InetSocketAddress getRemoteSocketAddress(); + InetSocketAddress getRemoteSocketAddress(); /** * Returns the address of the endpoint this socket is bound to. * * @return never returns null */ - public abstract InetSocketAddress getLocalSocketAddress(); + InetSocketAddress getLocalSocketAddress(); /** * Is the websocket in the state CONNECTING * @return state equals READYSTATE.CONNECTING */ - public abstract boolean isConnecting(); + boolean isConnecting(); /** * Is the websocket in the state OPEN * @return state equals READYSTATE.OPEN */ - public abstract boolean isOpen(); + boolean isOpen(); /** * Is the websocket in the state CLOSING * @return state equals READYSTATE.CLOSING */ - public abstract boolean isClosing(); + boolean isClosing(); /** * Returns true when no further frames may be submitted
* This happens before the socket connection is closed. * @return true when no further frames may be submitted */ - public abstract boolean isFlushAndClose(); + boolean isFlushAndClose(); /** * Is the websocket in the state CLOSED * @return state equals READYSTATE.CLOSED */ - public abstract boolean isClosed(); + boolean isClosed(); /** * Getter for the draft * @return the used draft */ - public abstract Draft getDraft(); + Draft getDraft(); /** * Retrieve the WebSocket 'readyState'. @@ -212,12 +212,12 @@ public enum READYSTATE { * * @return Returns '0 = CONNECTING', '1 = OPEN', '2 = CLOSING' or '3 = CLOSED' */ - public abstract READYSTATE getReadyState(); + READYSTATE getReadyState(); /** * Returns the HTTP Request-URI as defined by http://tools.ietf.org/html/rfc2616#section-5.1.2
* If the opening handshake has not yet happened it will return null. * @return Returns the decoded path component of this URI. **/ - public abstract String getResourceDescriptor(); + String getResourceDescriptor(); } \ No newline at end of file diff --git a/src/main/java/org/java_websocket/WebSocketImpl.java b/src/main/java/org/java_websocket/WebSocketImpl.java index 0ec8f408d..74aca199d 100644 --- a/src/main/java/org/java_websocket/WebSocketImpl.java +++ b/src/main/java/org/java_websocket/WebSocketImpl.java @@ -25,9 +25,10 @@ package org.java_websocket; -import org.java_websocket.drafts.*; +import org.java_websocket.drafts.Draft; import org.java_websocket.drafts.Draft.CloseHandshakeType; import org.java_websocket.drafts.Draft.HandshakeState; +import org.java_websocket.drafts.Draft_6455; import org.java_websocket.exceptions.IncompleteHandshakeException; import org.java_websocket.exceptions.InvalidDataException; import org.java_websocket.exceptions.InvalidHandshakeException; @@ -47,7 +48,10 @@ import java.nio.channels.ByteChannel; import java.nio.channels.NotYetConnectedException; import java.nio.channels.SelectionKey; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -141,7 +145,7 @@ public class WebSocketImpl implements WebSocket { * Creates a websocket with server role * * @param listener The listener for this instance - * @param drafts The drafts which should be used + * @param drafts The drafts which should be used */ public WebSocketImpl( WebSocketListener listener, List drafts ) { this( listener, ( Draft ) null ); @@ -149,7 +153,7 @@ public WebSocketImpl( WebSocketListener listener, List drafts ) { // draft.copyInstance will be called when the draft is first needed if( drafts == null || drafts.isEmpty() ) { knownDrafts = new ArrayList(); - knownDrafts.add(new Draft_6455()); + knownDrafts.add( new Draft_6455() ); } else { knownDrafts = drafts; } @@ -159,7 +163,7 @@ public WebSocketImpl( WebSocketListener listener, List drafts ) { * creates a websocket with client role * * @param listener The listener for this instance - * @param draft The draft which should be used + * @param draft The draft which should be used */ public WebSocketImpl( WebSocketListener listener, Draft draft ) { if( listener == null || ( draft == null && role == Role.SERVER ) )// socket can be null because we want do be able to create the object without already having a bound channel @@ -184,6 +188,7 @@ public WebSocketImpl( WebSocketListener listener, List drafts, Socket soc /** * Method to decode the provided ByteBuffer + * * @param socketBuffer the ByteBuffer to decode */ public void decode( ByteBuffer socketBuffer ) { @@ -193,7 +198,7 @@ public void decode( ByteBuffer socketBuffer ) { System.out.println( "process(" + socketBuffer.remaining() + "): {" + ( socketBuffer.remaining() > 1000 ? "too big to display" : new String( socketBuffer.array(), socketBuffer.position(), socketBuffer.remaining() ) ) + "}" ); if( readystate != READYSTATE.NOT_YET_CONNECTED ) { - if ( readystate == READYSTATE.OPEN ) { + if( readystate == READYSTATE.OPEN ) { decodeFrames( socketBuffer ); } } else { @@ -236,8 +241,8 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) { HandshakeState isflashedgecase = isFlashEdgeCase( socketBuffer ); if( isflashedgecase == HandshakeState.MATCHED ) { try { - write( Collections.singletonList( ByteBuffer.wrap(Charsetfunctions.utf8Bytes(wsl.getFlashPolicy(this))))); - close(CloseFrame.FLASHPOLICY, ""); + write( Collections.singletonList( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( wsl.getFlashPolicy( this ) ) ) ) ); + close( CloseFrame.FLASHPOLICY, "" ); } catch ( InvalidDataException e ) { close( CloseFrame.ABNORMAL_CLOSE, "remote peer closed connection before flashpolicy could be transmitted", true ); } @@ -256,7 +261,7 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) { socketBuffer.reset(); Handshakedata tmphandshake = d.translateHandshake( socketBuffer ); if( !( tmphandshake instanceof ClientHandshake ) ) { - closeConnectionDueToWrongHandshake( new InvalidDataException( CloseFrame.PROTOCOL_ERROR, "wrong http function" )); + closeConnectionDueToWrongHandshake( new InvalidDataException( CloseFrame.PROTOCOL_ERROR, "wrong http function" ) ); return false; } ClientHandshake handshake = ( ClientHandshake ) tmphandshake; @@ -284,7 +289,7 @@ private boolean decodeHandshake( ByteBuffer socketBufferNew ) { } } if( draft == null ) { - closeConnectionDueToWrongHandshake( new InvalidDataException( CloseFrame.PROTOCOL_ERROR, "no draft matches")); + closeConnectionDueToWrongHandshake( new InvalidDataException( CloseFrame.PROTOCOL_ERROR, "no draft matches" ) ); } return false; } else { @@ -373,38 +378,41 @@ private void decodeFrames( ByteBuffer socketBuffer ) { /** * Close the connection if the received handshake was not correct + * * @param exception the InvalidDataException causing this problem */ private void closeConnectionDueToWrongHandshake( InvalidDataException exception ) { - write(generateHttpResponseDueToError( 404 )); + write( generateHttpResponseDueToError( 404 ) ); flushAndClose( exception.getCloseCode(), exception.getMessage(), false ); } /** * Close the connection if there was a server error by a RuntimeException + * * @param exception the RuntimeException causing this problem */ - private void closeConnectionDueToInternalServerError(RuntimeException exception) { - write(generateHttpResponseDueToError( 500 )); + private void closeConnectionDueToInternalServerError( RuntimeException exception ) { + write( generateHttpResponseDueToError( 500 ) ); flushAndClose( CloseFrame.NEVER_CONNECTED, exception.getMessage(), false ); } /** * Generate a simple response for the corresponding endpoint to indicate some error + * * @param errorCode the http error code * @return the complete response as ByteBuffer */ - private ByteBuffer generateHttpResponseDueToError(int errorCode) { + private ByteBuffer generateHttpResponseDueToError( int errorCode ) { String errorCodeDescription; - switch (errorCode) { + switch(errorCode) { case 404: errorCodeDescription = "404 WebSocket Upgrade Failure"; break; case 500: default: - errorCodeDescription = "500 Internal Server Error"; + errorCodeDescription = "500 Internal Server Error"; } - return ByteBuffer.wrap( Charsetfunctions.asciiBytes( "HTTP/1.1 "+ errorCodeDescription +"\r\nContent-Type: text/html\nServer: TooTallNate Java-WebSocket\r\nContent-Length: " + (48 + errorCodeDescription.length()) +"\r\n\r\n

" + errorCodeDescription + "

" )); + return ByteBuffer.wrap( Charsetfunctions.asciiBytes( "HTTP/1.1 " + errorCodeDescription + "\r\nContent-Type: text/html\nServer: TooTallNate Java-WebSocket\r\nContent-Length: " + ( 48 + errorCodeDescription.length() ) + "\r\n\r\n

" + errorCodeDescription + "

" ) ); } public void close( int code, String message, boolean remote ) { @@ -426,10 +434,10 @@ public void close( int code, String message, boolean remote ) { } } CloseFrame closeFrame = new CloseFrame(); - closeFrame.setReason(message); - closeFrame.setCode(code); + closeFrame.setReason( message ); + closeFrame.setCode( code ); closeFrame.isValid(); - sendFrame(closeFrame); + sendFrame( closeFrame ); } catch ( InvalidDataException e ) { wsl.onWebsocketError( this, e ); flushAndClose( CloseFrame.ABNORMAL_CLOSE, "generated frame is invalid", false ); @@ -458,12 +466,13 @@ public void close( int code, String message ) { /** * This will close the connection immediately without a proper close handshake. * The code and the message therefore won't be transfered over the wire also they will be forwarded to onClose/onWebsocketClose. - * @param code the closing code + * + * @param code the closing code * @param message the closing message - * @param remote Indicates who "generated" code.
- * true means that this endpoint received the code from the other endpoint.
- * false means this endpoint decided to send the given code,
- * remote may also be true if this endpoint started the closing handshake since the other endpoint may not simply echo the code but close the connection the same time this endpoint does do but with an other code.
+ * @param remote Indicates who "generated" code.
+ * true means that this endpoint received the code from the other endpoint.
+ * false means this endpoint decided to send the given code,
+ * remote may also be true if this endpoint started the closing handshake since the other endpoint may not simply echo the code but close the connection the same time this endpoint does do but with an other code.
**/ public synchronized void closeConnection( int code, String message, boolean remote ) { if( readystate == READYSTATE.CLOSED ) { @@ -478,9 +487,9 @@ public synchronized void closeConnection( int code, String message, boolean remo try { channel.close(); } catch ( IOException e ) { - if (e.getMessage().equals( "Broken pipe" )) { - if (WebSocketImpl.DEBUG) { - System.out.println("Caught IOException: Broken pipe during closeConnection()"); + if( e.getMessage().equals( "Broken pipe" ) ) { + if( WebSocketImpl.DEBUG ) { + System.out.println( "Caught IOException: Broken pipe during closeConnection()" ); } } else { wsl.onWebsocketError( this, e ); @@ -596,11 +605,11 @@ private void send( Collection frames ) { if( !isOpen() ) { throw new WebsocketNotConnectedException(); } - if ( frames == null || frames.isEmpty() ) { + if( frames == null || frames.isEmpty() ) { throw new IllegalArgumentException(); } ArrayList outgoingFrames = new ArrayList(); - for (Framedata f : frames) { + for( Framedata f : frames ) { if( DEBUG ) System.out.println( "send frame: " + f ); outgoingFrames.add( draft.createBinaryFrame( f ) ); @@ -614,20 +623,20 @@ public void sendFragmentedFrame( Opcode op, ByteBuffer buffer, boolean fin ) { } @Override - public void sendFrame(Collection frames) { + public void sendFrame( Collection frames ) { send( frames ); } @Override public void sendFrame( Framedata framedata ) { - send ( Collections.singletonList( framedata ) ); + send( Collections.singletonList( framedata ) ); } public void sendPing() throws NotYetConnectedException { - if (pingFrame == null) { + if( pingFrame == null ) { pingFrame = new PingFrame(); } - sendFrame(pingFrame); + sendFrame( pingFrame ); } @Override @@ -694,12 +703,13 @@ private void write( ByteBuffer buf ) { /** * Write a list of bytebuffer (frames in binary form) into the outgoing queue + * * @param bufs the list of bytebuffer */ private void write( List bufs ) { - synchronized ( synchronizeWriteObject ) { - for (ByteBuffer b : bufs) { - write(b); + synchronized(synchronizeWriteObject) { + for( ByteBuffer b : bufs ) { + write( b ); } } } @@ -784,6 +794,7 @@ public String getResourceDescriptor() { /** * Getter for the last pong recieved + * * @return the timestamp for the last recieved pong */ long getLastPong() { @@ -799,6 +810,7 @@ public void updateLastPong() { /** * Getter for the websocket listener + * * @return the websocket listener associated with this instance */ public WebSocketListener getWebSocketListener() { diff --git a/src/main/java/org/java_websocket/drafts/Draft.java b/src/main/java/org/java_websocket/drafts/Draft.java index a0218d854..a3648381b 100644 --- a/src/main/java/org/java_websocket/drafts/Draft.java +++ b/src/main/java/org/java_websocket/drafts/Draft.java @@ -265,6 +265,20 @@ public int checkAlloc( int bytecount ) throws LimitExedeedException , InvalidDat return bytecount; } + int readVersion( Handshakedata handshakedata ) { + String vers = handshakedata.getFieldValue( "Sec-WebSocket-Version" ); + if( vers.length() > 0 ) { + int v; + try { + v = new Integer( vers.trim() ); + return v; + } catch ( NumberFormatException e ) { + return -1; + } + } + return -1; + } + public void setParseMode( Role role ) { this.role = role; } diff --git a/src/main/java/org/java_websocket/drafts/Draft_10.java b/src/main/java/org/java_websocket/drafts/Draft_10.java deleted file mode 100644 index 0aafa85c1..000000000 --- a/src/main/java/org/java_websocket/drafts/Draft_10.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2010-2017 Nathan Rajlich - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -package org.java_websocket.drafts; - -import org.java_websocket.WebSocket.Role; -import org.java_websocket.WebSocketImpl; -import org.java_websocket.exceptions.*; -import org.java_websocket.framing.*; -import org.java_websocket.framing.Framedata.Opcode; -import org.java_websocket.handshake.*; -import org.java_websocket.util.Base64; -import org.java_websocket.util.Charsetfunctions; - -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -@Deprecated -public class Draft_10 extends Draft { - - class IncompleteException extends Throwable { - - /** - * It's Serializable. - */ - private static final long serialVersionUID = 7330519489840500997L; - - private int preferedsize; - - public IncompleteException( int preferedsize ) { - this.preferedsize = preferedsize; - } - - public int getPreferedSize() { - return preferedsize; - } - } - - public static int readVersion( Handshakedata handshakedata ) { - String vers = handshakedata.getFieldValue( "Sec-WebSocket-Version" ); - if( vers.length() > 0 ) { - int v; - try { - v = new Integer( vers.trim() ); - return v; - } catch ( NumberFormatException e ) { - return -1; - } - } - return -1; - } - - ByteBuffer incompleteframe; - - private final Random reuseableRandom = new Random(); - - @Override - public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) throws InvalidHandshakeException { - if( !request.hasFieldValue( "Sec-WebSocket-Key" ) || !response.hasFieldValue( "Sec-WebSocket-Accept" ) ) - return HandshakeState.NOT_MATCHED; - - String seckey_answere = response.getFieldValue( "Sec-WebSocket-Accept" ); - String seckey_challenge = request.getFieldValue( "Sec-WebSocket-Key" ); - seckey_challenge = generateFinalKey( seckey_challenge ); - - if( seckey_challenge.equals( seckey_answere ) ) - return HandshakeState.MATCHED; - return HandshakeState.NOT_MATCHED; - } - - @Override - public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) throws InvalidHandshakeException { - // Sec-WebSocket-Origin is only required for browser clients - int v = readVersion( handshakedata ); - if( v == 7 || v == 8 )// g - return basicAccept( handshakedata ) ? HandshakeState.MATCHED : HandshakeState.NOT_MATCHED; - return HandshakeState.NOT_MATCHED; - } - - @Override - public ByteBuffer createBinaryFrame( Framedata framedata ) { - ByteBuffer mes = framedata.getPayloadData(); - boolean mask = role == Role.CLIENT; // framedata.getTransfereMasked(); - int sizebytes = mes.remaining() <= 125 ? 1 : mes.remaining() <= 65535 ? 2 : 8; - ByteBuffer buf = ByteBuffer.allocate( 1 + ( sizebytes > 1 ? sizebytes + 1 : sizebytes ) + ( mask ? 4 : 0 ) + mes.remaining() ); - byte optcode = fromOpcode( framedata.getOpcode() ); - byte one = ( byte ) ( framedata.isFin() ? -128 : 0 ); - one |= optcode; - buf.put( one ); - byte[] payloadlengthbytes = toByteArray( mes.remaining(), sizebytes ); - assert ( payloadlengthbytes.length == sizebytes ); - - if( sizebytes == 1 ) { - buf.put( ( byte ) ( payloadlengthbytes[0] | ( mask ? ( byte ) -128 : 0 ) ) ); - } else if( sizebytes == 2 ) { - buf.put( ( byte ) ( ( byte ) 126 | ( mask ? ( byte ) -128 : 0 ) ) ); - buf.put( payloadlengthbytes ); - } else if( sizebytes == 8 ) { - buf.put( ( byte ) ( ( byte ) 127 | ( mask ? ( byte ) -128 : 0 ) ) ); - buf.put( payloadlengthbytes ); - } else - throw new RuntimeException( "Size representation not supported/specified" ); - - if( mask ) { - ByteBuffer maskkey = ByteBuffer.allocate( 4 ); - maskkey.putInt( reuseableRandom.nextInt() ); - buf.put( maskkey.array() ); - for( int i = 0; mes.hasRemaining(); i++ ) { - buf.put( ( byte ) ( mes.get() ^ maskkey.get( i % 4 ) ) ); - } - } else { - buf.put( mes ); - //Reset the position of the bytebuffer e.g. for additional use - mes.flip(); - } - assert ( buf.remaining() == 0 ) : buf.remaining(); - buf.flip(); - return buf; - } - - @Override - public List createFrames( ByteBuffer binary, boolean mask ) { - BinaryFrame curframe = new BinaryFrame(); - curframe.setPayload( binary ); - curframe.setTransferemasked( mask ); - try { - curframe.isValid(); - } catch ( InvalidDataException e ) { - throw new NotSendableException( e ); - } - return Collections.singletonList( ( Framedata ) curframe ); - } - - @Override - public List createFrames( String text, boolean mask ) { - TextFrame curframe = new TextFrame(); - curframe.setPayload( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( text ) ) ); - curframe.setTransferemasked( mask ); - try { - curframe.isValid(); - } catch ( InvalidDataException e ) { - throw new NotSendableException( e ); - } - return Collections.singletonList( ( Framedata ) curframe ); - } - - public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws InvalidDataException { - throw new UnsupportedOperationException( "This draft is not supported any more. Please use Draft_6455." ); - } - - private byte fromOpcode( Opcode opcode ) { - if( opcode == Opcode.CONTINUOUS ) - return 0; - else if( opcode == Opcode.TEXT ) - return 1; - else if( opcode == Opcode.BINARY ) - return 2; - else if( opcode == Opcode.CLOSING ) - return 8; - else if( opcode == Opcode.PING ) - return 9; - else if( opcode == Opcode.PONG ) - return 10; - throw new RuntimeException( "Don't know how to handle " + opcode.toString() ); - } - - private String generateFinalKey( String in ) { - String seckey = in.trim(); - String acc = seckey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; - MessageDigest sh1; - try { - sh1 = MessageDigest.getInstance( "SHA1" ); - } catch ( NoSuchAlgorithmException e ) { - throw new RuntimeException( e ); - } - return Base64.encodeBytes( sh1.digest( acc.getBytes() ) ); - } - - @Override - public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) { - request.put( "Upgrade", "websocket" ); - request.put( "Connection", "Upgrade" ); // to respond to a Connection keep alives - request.put( "Sec-WebSocket-Version", "8" ); - - byte[] random = new byte[16]; - reuseableRandom.nextBytes( random ); - request.put( "Sec-WebSocket-Key", Base64.encodeBytes( random ) ); - - return request; - } - - @Override - public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder response ) throws InvalidHandshakeException { - response.put( "Upgrade", "websocket" ); - response.put( "Connection", request.getFieldValue( "Connection" ) ); // to respond to a Connection keep alives - response.setHttpStatusMessage( "Switching Protocols" ); - String seckey = request.getFieldValue( "Sec-WebSocket-Key" ); - if( seckey == null ) - throw new InvalidHandshakeException( "missing Sec-WebSocket-Key" ); - response.put( "Sec-WebSocket-Accept", generateFinalKey( seckey ) ); - return response; - } - - private byte[] toByteArray( long val, int bytecount ) { - byte[] buffer = new byte[bytecount]; - int highest = 8 * bytecount - 8; - for( int i = 0; i < bytecount; i++ ) { - buffer[i] = ( byte ) ( val >>> ( highest - 8 * i ) ); - } - return buffer; - } - - Opcode toOpcode( byte opcode ) throws InvalidFrameException { - switch(opcode) { - case 0: - return Opcode.CONTINUOUS; - case 1: - return Opcode.TEXT; - case 2: - return Opcode.BINARY; - // 3-7 are not yet defined - case 8: - return Opcode.CLOSING; - case 9: - return Opcode.PING; - case 10: - return Opcode.PONG; - // 11-15 are not yet defined - default: - throw new InvalidFrameException( "Unknown opcode " + ( short ) opcode ); - } - } - - @Override - public List translateFrame( ByteBuffer buffer ) throws LimitExedeedException, InvalidDataException { - while( true ) { - List frames = new LinkedList(); - Framedata cur; - - if( incompleteframe != null ) { - // complete an incomplete frame - try { - buffer.mark(); - int available_next_byte_count = buffer.remaining();// The number of bytes received - int expected_next_byte_count = incompleteframe.remaining();// The number of bytes to complete the incomplete frame - - if( expected_next_byte_count > available_next_byte_count ) { - // did not receive enough bytes to complete the frame - incompleteframe.put( buffer.array(), buffer.position(), available_next_byte_count ); - buffer.position( buffer.position() + available_next_byte_count ); - return Collections.emptyList(); - } - incompleteframe.put( buffer.array(), buffer.position(), expected_next_byte_count ); - buffer.position( buffer.position() + expected_next_byte_count ); - - cur = translateSingleFrame( ( ByteBuffer ) incompleteframe.duplicate().position( 0 ) ); - frames.add( cur ); - incompleteframe = null; - } catch ( IncompleteException e ) { - // extending as much as suggested - int oldsize = incompleteframe.limit(); - ByteBuffer extendedframe = ByteBuffer.allocate( checkAlloc( e.getPreferedSize() ) ); - assert ( extendedframe.limit() > incompleteframe.limit() ); - incompleteframe.rewind(); - extendedframe.put( incompleteframe ); - incompleteframe = extendedframe; - continue; - } - } - - while( buffer.hasRemaining() ) {// Read as much as possible full frames - buffer.mark(); - try { - cur = translateSingleFrame( buffer ); - frames.add( cur ); - } catch ( IncompleteException e ) { - // remember the incomplete data - buffer.reset(); - int pref = e.getPreferedSize(); - incompleteframe = ByteBuffer.allocate( checkAlloc( pref ) ); - incompleteframe.put( buffer ); - break; - } - } - return frames; - } - } - - public Framedata translateSingleFrame( ByteBuffer buffer ) throws IncompleteException, InvalidDataException { - int maxpacketsize = buffer.remaining(); - int realpacketsize = 2; - if( maxpacketsize < realpacketsize ) - throw new IncompleteException( realpacketsize ); - byte b1 = buffer.get( /*0*/ ); - boolean FIN = b1 >> 8 != 0; - boolean rsv1 = false, rsv2 = false, rsv3 = false; - if( ( b1 & 0x40 ) != 0 ) { - rsv1 = true; - } - if( ( b1 & 0x20 ) != 0 ) { - rsv2 = true; - } - if( ( b1 & 0x10 ) != 0 ) { - rsv3 = true; - } - if( rsv1 || rsv2 || rsv3 ) - throw new InvalidFrameException( "bad rsv rsv1: " + rsv1 + " rsv2: " + rsv2 + " rsv3: " + rsv3 ); - byte b2 = buffer.get( /*1*/ ); - boolean MASK = ( b2 & -128 ) != 0; - int payloadlength = ( byte ) ( b2 & ~( byte ) 128 ); - Opcode optcode = toOpcode( ( byte ) ( b1 & 15 ) ); - - if( !FIN ) { - if( optcode == Opcode.PING || optcode == Opcode.PONG || optcode == Opcode.CLOSING ) { - throw new InvalidFrameException( "control frames may no be fragmented" ); - } - } - - if( !( payloadlength >= 0 && payloadlength <= 125 ) ) { - if( optcode == Opcode.PING || optcode == Opcode.PONG || optcode == Opcode.CLOSING ) { - throw new InvalidFrameException( "more than 125 octets" ); - } - if( payloadlength == 126 ) { - realpacketsize += 2; // additional length bytes - if( maxpacketsize < realpacketsize ) - throw new IncompleteException( realpacketsize ); - byte[] sizebytes = new byte[3]; - sizebytes[1] = buffer.get( /*1 + 1*/ ); - sizebytes[2] = buffer.get( /*1 + 2*/ ); - payloadlength = new BigInteger( sizebytes ).intValue(); - } else { - realpacketsize += 8; // additional length bytes - if( maxpacketsize < realpacketsize ) - throw new IncompleteException( realpacketsize ); - byte[] bytes = new byte[8]; - for( int i = 0; i < 8; i++ ) { - bytes[i] = buffer.get( /*1 + i*/ ); - } - long length = new BigInteger( bytes ).longValue(); - if( length > Integer.MAX_VALUE ) { - throw new LimitExedeedException( "Payloadsize is to big..." ); - } else { - payloadlength = ( int ) length; - } - } - } - - // int maskskeystart = foff + realpacketsize; - realpacketsize += ( MASK ? 4 : 0 ); - // int payloadstart = foff + realpacketsize; - realpacketsize += payloadlength; - - if( maxpacketsize < realpacketsize ) - throw new IncompleteException( realpacketsize ); - - ByteBuffer payload = ByteBuffer.allocate( checkAlloc( payloadlength ) ); - if( MASK ) { - byte[] maskskey = new byte[4]; - buffer.get( maskskey ); - for( int i = 0; i < payloadlength; i++ ) { - payload.put( ( byte ) ( buffer.get( /*payloadstart + i*/ ) ^ maskskey[i % 4] ) ); - } - } else { - payload.put( buffer.array(), buffer.position(), payload.limit() ); - buffer.position( buffer.position() + payload.limit() ); - } - - FramedataImpl1 frame; - if( optcode == Opcode.CLOSING ) { - frame = new CloseFrame(); - } else { - frame = FramedataImpl1.get( optcode ); - frame.setFin( FIN ); - } - payload.flip(); - frame.setPayload( payload ); - frame.isValid(); - return frame; - } - - @Override - public void reset() { - incompleteframe = null; - } - - @Override - public Draft copyInstance() { - return new Draft_10(); - } - - @Override - public CloseHandshakeType getCloseHandshakeType() { - return CloseHandshakeType.TWOWAY; - } -} diff --git a/src/main/java/org/java_websocket/drafts/Draft_6455.java b/src/main/java/org/java_websocket/drafts/Draft_6455.java index 7bde1c8f0..519359d50 100644 --- a/src/main/java/org/java_websocket/drafts/Draft_6455.java +++ b/src/main/java/org/java_websocket/drafts/Draft_6455.java @@ -27,20 +27,17 @@ import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; -import org.java_websocket.exceptions.InvalidDataException; -import org.java_websocket.exceptions.InvalidFrameException; -import org.java_websocket.exceptions.InvalidHandshakeException; -import org.java_websocket.exceptions.LimitExedeedException; -import org.java_websocket.extensions.DefaultExtension; -import org.java_websocket.extensions.IExtension; -import org.java_websocket.framing.CloseFrame; -import org.java_websocket.framing.Framedata; -import org.java_websocket.framing.FramedataImpl1; +import org.java_websocket.exceptions.*; +import org.java_websocket.extensions.*; +import org.java_websocket.framing.*; import org.java_websocket.handshake.*; -import org.java_websocket.util.Charsetfunctions; +import org.java_websocket.util.*; +import org.java_websocket.util.Base64; import java.math.BigInteger; import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.*; @@ -48,8 +45,7 @@ * Implementation for the RFC 6455 websocket protocol * This is the recommended class for your websocket connection */ -@SuppressWarnings("deprecation") -public class Draft_6455 extends Draft_17 { +public class Draft_6455 extends Draft { /** * Attribute for the used extension in this draft @@ -66,6 +62,16 @@ public class Draft_6455 extends Draft_17 { */ private Framedata current_continuous_frame; + /** + * Attribute for the current incomplete frame + */ + private ByteBuffer incompleteframe; + + /** + * Attribute for the reusable random instance + */ + private final Random reuseableRandom = new Random(); + /** * Constructor for the websocket protocol specified by RFC 6455 with default extensions */ @@ -105,9 +111,9 @@ public Draft_6455( List inputExtensions ) { @Override public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) throws InvalidHandshakeException { - if( super.acceptHandshakeAsServer( handshakedata ) == HandshakeState.NOT_MATCHED ) { + int v = readVersion( handshakedata ); + if( v != 13 ) return HandshakeState.NOT_MATCHED; - } String requestedExtension = handshakedata.getFieldValue( "Sec-WebSocket-Extensions" ); for( IExtension knownExtension : knownExtensions ) { if( knownExtension.acceptProvidedExtensionAsServer( requestedExtension ) ) { @@ -121,9 +127,19 @@ public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) t @Override public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) throws InvalidHandshakeException { - if( super.acceptHandshakeAsClient( request, response ) == HandshakeState.NOT_MATCHED ) { + if (! basicAccept( response )) { return HandshakeState.NOT_MATCHED; } + if( !request.hasFieldValue( "Sec-WebSocket-Key" ) || !response.hasFieldValue( "Sec-WebSocket-Accept" ) ) + return HandshakeState.NOT_MATCHED; + + String seckey_answere = response.getFieldValue( "Sec-WebSocket-Accept" ); + String seckey_challenge = request.getFieldValue( "Sec-WebSocket-Key" ); + seckey_challenge = generateFinalKey( seckey_challenge ); + + if( !seckey_challenge.equals( seckey_answere ) ) + return HandshakeState.NOT_MATCHED; + String requestedExtension = response.getFieldValue( "Sec-WebSocket-Extensions" ); for( IExtension knownExtension : knownExtensions ) { if( knownExtension.acceptProvidedExtensionAsClient( requestedExtension ) ) { @@ -145,7 +161,12 @@ public IExtension getExtension() { @Override public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) { - super.postProcessHandshakeRequestAsClient( request ); + request.put( "Upgrade", "websocket" ); + request.put( "Connection", "Upgrade" ); // to respond to a Connection keep alives + byte[] random = new byte[16]; + reuseableRandom.nextBytes( random ); + request.put( "Sec-WebSocket-Key", Base64.encodeBytes( random ) ); + request.put( "Sec-WebSocket-Version", "13" );// overwriting the previous StringBuilder requestedExtensions = new StringBuilder(); for( IExtension knownExtension : knownExtensions ) { if( knownExtension.getProvidedExtensionAsClient() != null && !knownExtension.getProvidedExtensionAsClient().equals( "" ) ) { @@ -159,9 +180,13 @@ public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandsha } @Override - public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder - response ) throws InvalidHandshakeException { - super.postProcessHandshakeResponseAsServer( request, response ); + public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder response ) throws InvalidHandshakeException { + response.put( "Upgrade", "websocket" ); + response.put( "Connection", request.getFieldValue( "Connection" ) ); // to respond to a Connection keep alives + String seckey = request.getFieldValue( "Sec-WebSocket-Key" ); + if( seckey == null ) + throw new InvalidHandshakeException( "missing Sec-WebSocket-Key" ); + response.put( "Sec-WebSocket-Accept", generateFinalKey( seckey ) ); if( getExtension().getProvidedExtensionAsServer().length() != 0 ) { response.put( "Sec-WebSocket-Extensions", getExtension().getProvidedExtensionAsServer() ); } @@ -171,7 +196,6 @@ public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake re return response; } - @Override public Draft copyInstance() { ArrayList newExtensions = new ArrayList(); @@ -186,10 +210,49 @@ public ByteBuffer createBinaryFrame( Framedata framedata ) { getExtension().encodeFrame( framedata ); if( WebSocketImpl.DEBUG ) System.out.println( "afterEnconding(" + framedata.getPayloadData().remaining() + "): {" + ( framedata.getPayloadData().remaining() > 1000 ? "too big to display" : new String( framedata.getPayloadData().array() ) ) + "}" ); - return super.createBinaryFrame( framedata ); + return createByteBufferFromFramedata( framedata ); + } + + private ByteBuffer createByteBufferFromFramedata( Framedata framedata ) { + ByteBuffer mes = framedata.getPayloadData(); + boolean mask = role == WebSocket.Role.CLIENT; // framedata.getTransfereMasked(); + int sizebytes = mes.remaining() <= 125 ? 1 : mes.remaining() <= 65535 ? 2 : 8; + ByteBuffer buf = ByteBuffer.allocate( 1 + ( sizebytes > 1 ? sizebytes + 1 : sizebytes ) + ( mask ? 4 : 0 ) + mes.remaining() ); + byte optcode = fromOpcode( framedata.getOpcode() ); + byte one = ( byte ) ( framedata.isFin() ? -128 : 0 ); + one |= optcode; + buf.put( one ); + byte[] payloadlengthbytes = toByteArray( mes.remaining(), sizebytes ); + assert ( payloadlengthbytes.length == sizebytes ); + + if( sizebytes == 1 ) { + buf.put( ( byte ) ( payloadlengthbytes[0] | ( mask ? ( byte ) -128 : 0 ) ) ); + } else if( sizebytes == 2 ) { + buf.put( ( byte ) ( ( byte ) 126 | ( mask ? ( byte ) -128 : 0 ) ) ); + buf.put( payloadlengthbytes ); + } else if( sizebytes == 8 ) { + buf.put( ( byte ) ( ( byte ) 127 | ( mask ? ( byte ) -128 : 0 ) ) ); + buf.put( payloadlengthbytes ); + } else + throw new RuntimeException( "Size representation not supported/specified" ); + + if( mask ) { + ByteBuffer maskkey = ByteBuffer.allocate( 4 ); + maskkey.putInt( reuseableRandom.nextInt() ); + buf.put( maskkey.array() ); + for( int i = 0; mes.hasRemaining(); i++ ) { + buf.put( ( byte ) ( mes.get() ^ maskkey.get( i % 4 ) ) ); + } + } else { + buf.put( mes ); + //Reset the position of the bytebuffer e.g. for additional use + mes.flip(); + } + assert ( buf.remaining() == 0 ) : buf.remaining(); + buf.flip(); + return buf; } - @Override public Framedata translateSingleFrame( ByteBuffer buffer ) throws IncompleteException, InvalidDataException { int maxpacketsize = buffer.remaining(); int realpacketsize = 2; @@ -303,7 +366,7 @@ public List translateFrame( ByteBuffer buffer ) throws InvalidDataExc } catch ( IncompleteException e ) { // extending as much as suggested int oldsize = incompleteframe.limit(); - ByteBuffer extendedframe = ByteBuffer.allocate( checkAlloc( e.getPreferedSize() ) ); + ByteBuffer extendedframe = ByteBuffer.allocate( checkAlloc( e.getPreferredSize() ) ); assert ( extendedframe.limit() > incompleteframe.limit() ); incompleteframe.rewind(); extendedframe.put( incompleteframe ); @@ -320,7 +383,7 @@ public List translateFrame( ByteBuffer buffer ) throws InvalidDataExc } catch ( IncompleteException e ) { // remember the incomplete data buffer.reset(); - int pref = e.getPreferedSize(); + int pref = e.getPreferredSize(); incompleteframe = ByteBuffer.allocate( checkAlloc( pref ) ); incompleteframe.put( buffer ); break; @@ -330,9 +393,35 @@ public List translateFrame( ByteBuffer buffer ) throws InvalidDataExc } } + @Override + public List createFrames( ByteBuffer binary, boolean mask ) { + BinaryFrame curframe = new BinaryFrame(); + curframe.setPayload( binary ); + curframe.setTransferemasked( mask ); + try { + curframe.isValid(); + } catch ( InvalidDataException e ) { + throw new NotSendableException( e ); + } + return Collections.singletonList( ( Framedata ) curframe ); + } + + @Override + public List createFrames( String text, boolean mask ) { + TextFrame curframe = new TextFrame(); + curframe.setPayload( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( text ) ) ); + curframe.setTransferemasked( mask ); + try { + curframe.isValid(); + } catch ( InvalidDataException e ) { + throw new NotSendableException( e ); + } + return Collections.singletonList( ( Framedata ) curframe ); + } + @Override public void reset() { - super.reset(); + incompleteframe = null; if( extension != null ) { extension.reset(); } @@ -352,6 +441,71 @@ private String getServerTime() { return dateFormat.format( calendar.getTime() ); } + /** + * Generate a final key from a input string + * @param in the input string + * @return a final key + */ + private String generateFinalKey( String in ) { + String seckey = in.trim(); + String acc = seckey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + MessageDigest sh1; + try { + sh1 = MessageDigest.getInstance( "SHA1" ); + } catch ( NoSuchAlgorithmException e ) { + throw new RuntimeException( e ); + } + return Base64.encodeBytes( sh1.digest( acc.getBytes() ) ); + } + + private byte[] toByteArray( long val, int bytecount ) { + byte[] buffer = new byte[bytecount]; + int highest = 8 * bytecount - 8; + for( int i = 0; i < bytecount; i++ ) { + buffer[i] = ( byte ) ( val >>> ( highest - 8 * i ) ); + } + return buffer; + } + + + private byte fromOpcode( Framedata.Opcode opcode ) { + if( opcode == Framedata.Opcode.CONTINUOUS ) + return 0; + else if( opcode == Framedata.Opcode.TEXT ) + return 1; + else if( opcode == Framedata.Opcode.BINARY ) + return 2; + else if( opcode == Framedata.Opcode.CLOSING ) + return 8; + else if( opcode == Framedata.Opcode.PING ) + return 9; + else if( opcode == Framedata.Opcode.PONG ) + return 10; + throw new RuntimeException( "Don't know how to handle " + opcode.toString() ); + } + + + private Framedata.Opcode toOpcode( byte opcode ) throws InvalidFrameException { + switch(opcode) { + case 0: + return Framedata.Opcode.CONTINUOUS; + case 1: + return Framedata.Opcode.TEXT; + case 2: + return Framedata.Opcode.BINARY; + // 3-7 are not yet defined + case 8: + return Framedata.Opcode.CLOSING; + case 9: + return Framedata.Opcode.PING; + case 10: + return Framedata.Opcode.PONG; + // 11-15 are not yet defined + default: + throw new InvalidFrameException( "Unknown opcode " + ( short ) opcode ); + } + } + @Override public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws InvalidDataException { Framedata.Opcode curop = frame.getOpcode(); @@ -443,6 +597,11 @@ public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws } } + @Override + public Draft.CloseHandshakeType getCloseHandshakeType() { + return Draft.CloseHandshakeType.TWOWAY; + } + @Override public String toString() { String result = super.toString(); diff --git a/src/main/java/org/java_websocket/drafts/Draft_75.java b/src/main/java/org/java_websocket/drafts/Draft_75.java deleted file mode 100644 index 1b75f44f2..000000000 --- a/src/main/java/org/java_websocket/drafts/Draft_75.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2010-2017 Nathan Rajlich - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -package org.java_websocket.drafts; - -import org.java_websocket.WebSocketImpl; -import org.java_websocket.exceptions.*; -import org.java_websocket.framing.CloseFrame; -import org.java_websocket.framing.Framedata; -import org.java_websocket.framing.Framedata.Opcode; -import org.java_websocket.framing.TextFrame; -import org.java_websocket.handshake.*; -import org.java_websocket.util.Charsetfunctions; - -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -@Deprecated -public class Draft_75 extends Draft { - - /** - * The byte representing CR, or Carriage Return, or \r - */ - public static final byte CR = ( byte ) 0x0D; - /** - * The byte representing LF, or Line Feed, or \n - */ - public static final byte LF = ( byte ) 0x0A; - /** - * The byte representing the beginning of a WebSocket text frame. - */ - public static final byte START_OF_FRAME = ( byte ) 0x00; - /** - * The byte representing the end of a WebSocket text frame. - */ - public static final byte END_OF_FRAME = ( byte ) 0xFF; - - /** - * Is only used to detect protocol violations - */ - protected boolean readingState = false; - - protected List readyframes = new LinkedList(); - protected ByteBuffer currentFrame; - - private final Random reuseableRandom = new Random(); - - @Override - public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) { - return request.getFieldValue( "WebSocket-Origin" ).equals( response.getFieldValue( "Origin" ) ) && basicAccept( response ) ? HandshakeState.MATCHED : HandshakeState.NOT_MATCHED; - } - - @Override - public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) { - if( handshakedata.hasFieldValue( "Origin" ) && basicAccept( handshakedata ) ) { - return HandshakeState.MATCHED; - } - return HandshakeState.NOT_MATCHED; - } - - @Override - public ByteBuffer createBinaryFrame( Framedata framedata ) { - if( framedata.getOpcode() != Opcode.TEXT ) { - throw new RuntimeException( "only text frames supported" ); - } - - ByteBuffer pay = framedata.getPayloadData(); - ByteBuffer b = ByteBuffer.allocate( pay.remaining() + 2 ); - b.put( START_OF_FRAME ); - pay.mark(); - b.put( pay ); - pay.reset(); - b.put( END_OF_FRAME ); - b.flip(); - return b; - } - - @Override - public List createFrames( ByteBuffer binary, boolean mask ) { - throw new RuntimeException( "not yet implemented" ); - } - - @Override - public List createFrames( String text, boolean mask ) { - TextFrame frame = new TextFrame(); - frame.setPayload( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( text ) ) ); - frame.setTransferemasked( mask ); - try { - frame.isValid(); - } catch ( InvalidDataException e ) { - throw new NotSendableException( e ); - } - return Collections.singletonList( ( Framedata ) frame ); - } - - public void processFrame( WebSocketImpl webSocketImpl, Framedata frame ) throws InvalidDataException { - throw new UnsupportedOperationException( "This draft is not supported any more. Please use Draft_6455." ); - } - - @Override - public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) throws InvalidHandshakeException { - request.put( "Upgrade", "WebSocket" ); - request.put( "Connection", "Upgrade" ); - if( !request.hasFieldValue( "Origin" ) ) { - request.put( "Origin", "random" + reuseableRandom.nextInt() ); - } - - return request; - } - - @Override - public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder response ) throws InvalidHandshakeException { - response.setHttpStatusMessage( "Web Socket Protocol Handshake" ); - response.put( "Upgrade", "WebSocket" ); - response.put( "Connection", request.getFieldValue( "Connection" ) ); // to respond to a Connection keep alive - response.put( "WebSocket-Origin", request.getFieldValue( "Origin" ) ); - String location = "ws://" + request.getFieldValue( "Host" ) + request.getResourceDescriptor(); - response.put( "WebSocket-Location", location ); - // TODO handle Sec-WebSocket-Protocol and Set-Cookie - return response; - } - - protected List translateRegularFrame( ByteBuffer buffer ) throws InvalidDataException { - - while( buffer.hasRemaining() ) { - byte newestByte = buffer.get(); - if( newestByte == START_OF_FRAME ) { // Beginning of Frame - if( readingState ) - throw new InvalidFrameException( "unexpected START_OF_FRAME" ); - readingState = true; - } else if( newestByte == END_OF_FRAME ) { // End of Frame - if( !readingState ) - throw new InvalidFrameException( "unexpected END_OF_FRAME" ); - // currentFrame will be null if END_OF_FRAME was send directly after - // START_OF_FRAME, thus we will send 'null' as the sent message. - if( this.currentFrame != null ) { - currentFrame.flip(); - TextFrame curframe = new TextFrame(); - curframe.setPayload( currentFrame ); - readyframes.add( curframe ); - this.currentFrame = null; - buffer.mark(); - } - readingState = false; - } else if( readingState ) { // Regular frame data, add to current frame buffer //TODO This code is very expensive and slow - if( currentFrame == null ) { - currentFrame = createBuffer(); - } else if( !currentFrame.hasRemaining() ) { - currentFrame = increaseBuffer( currentFrame ); - } - currentFrame.put( newestByte ); - } else { - return null; - } - } - - // if no error occurred this block will be reached - /*if( readingState ) { - checkAlloc(currentFrame.position()+1); - }*/ - - List frames = readyframes; - readyframes = new LinkedList(); - return frames; - } - - @Override - public List translateFrame( ByteBuffer buffer ) throws InvalidDataException { - List frames = translateRegularFrame( buffer ); - if( frames == null ) { - throw new InvalidDataException( CloseFrame.PROTOCOL_ERROR ); - } - return frames; - } - - @Override - public void reset() { - readingState = false; - this.currentFrame = null; - } - - @Override - public CloseHandshakeType getCloseHandshakeType() { - return CloseHandshakeType.NONE; - } - - public ByteBuffer createBuffer() { - return ByteBuffer.allocate( INITIAL_FAMESIZE ); - } - - public ByteBuffer increaseBuffer( ByteBuffer full ) throws LimitExedeedException, InvalidDataException { - full.flip(); - ByteBuffer newbuffer = ByteBuffer.allocate( checkAlloc( full.capacity() * 2 ) ); - newbuffer.put( full ); - return newbuffer; - } - - @Override - public Draft copyInstance() { - return new Draft_75(); - } -} diff --git a/src/main/java/org/java_websocket/drafts/Draft_76.java b/src/main/java/org/java_websocket/drafts/Draft_76.java deleted file mode 100644 index c2f613a78..000000000 --- a/src/main/java/org/java_websocket/drafts/Draft_76.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2010-2017 Nathan Rajlich - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -package org.java_websocket.drafts; - -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -import org.java_websocket.WebSocket.Role; -import org.java_websocket.exceptions.IncompleteHandshakeException; -import org.java_websocket.exceptions.InvalidDataException; -import org.java_websocket.exceptions.InvalidFrameException; -import org.java_websocket.exceptions.InvalidHandshakeException; -import org.java_websocket.framing.CloseFrame; -import org.java_websocket.framing.Framedata; -import org.java_websocket.framing.Framedata.Opcode; -import org.java_websocket.handshake.ClientHandshake; -import org.java_websocket.handshake.ClientHandshakeBuilder; -import org.java_websocket.handshake.HandshakeBuilder; -import org.java_websocket.handshake.Handshakedata; -import org.java_websocket.handshake.ServerHandshake; -import org.java_websocket.handshake.ServerHandshakeBuilder; - -@Deprecated -public class Draft_76 extends Draft_75 { - private boolean failed = false; - private static final byte[] closehandshake = { -1, 0 }; - - private final Random reuseableRandom = new Random(); - - - public static byte[] createChallenge( String key1, String key2, byte[] key3 ) throws InvalidHandshakeException { - byte[] part1 = getPart( key1 ); - byte[] part2 = getPart( key2 ); - byte[] challenge = new byte[ 16 ]; - challenge[ 0 ] = part1[ 0 ]; - challenge[ 1 ] = part1[ 1 ]; - challenge[ 2 ] = part1[ 2 ]; - challenge[ 3 ] = part1[ 3 ]; - challenge[ 4 ] = part2[ 0 ]; - challenge[ 5 ] = part2[ 1 ]; - challenge[ 6 ] = part2[ 2 ]; - challenge[ 7 ] = part2[ 3 ]; - challenge[ 8 ] = key3[ 0 ]; - challenge[ 9 ] = key3[ 1 ]; - challenge[ 10 ] = key3[ 2 ]; - challenge[ 11 ] = key3[ 3 ]; - challenge[ 12 ] = key3[ 4 ]; - challenge[ 13 ] = key3[ 5 ]; - challenge[ 14 ] = key3[ 6 ]; - challenge[ 15 ] = key3[ 7 ]; - MessageDigest md5; - try { - md5 = MessageDigest.getInstance( "MD5" ); - } catch ( NoSuchAlgorithmException e ) { - throw new RuntimeException( e ); - } - return md5.digest( challenge ); - } - - private static String generateKey() { - Random r = new Random(); - long maxNumber = 4294967295L; - long spaces = r.nextInt( 12 ) + 1; - int max = new Long( maxNumber / spaces ).intValue(); - max = Math.abs( max ); - int number = r.nextInt( max ) + 1; - long product = number * spaces; - String key = Long.toString( product ); - // always insert atleast one random character - int numChars = r.nextInt( 12 ) + 1; - for( int i = 0 ; i < numChars ; i++ ) { - int position = r.nextInt( key.length() ); - position = Math.abs( position ); - char randChar = (char) ( r.nextInt( 95 ) + 33 ); - // exclude numbers here - if( randChar >= 48 && randChar <= 57 ) { - randChar -= 15; - } - key = new StringBuilder( key ).insert( position, randChar ).toString(); - } - for( int i = 0 ; i < spaces ; i++ ) { - int position = r.nextInt( key.length() - 1 ) + 1; - position = Math.abs( position ); - key = new StringBuilder( key ).insert( position, "\u0020" ).toString(); - } - return key; - } - - private static byte[] getPart( String key ) throws InvalidHandshakeException { - try { - long keyNumber = Long.parseLong( key.replaceAll( "[^0-9]", "" ) ); - long keySpace = key.split( "\u0020" ).length - 1; - if( keySpace == 0 ) { - throw new InvalidHandshakeException( "invalid Sec-WebSocket-Key (/key2/)" ); - } - long part = keyNumber / keySpace; - return new byte[]{ (byte) ( part >> 24 ), (byte) ( ( part << 8 ) >> 24 ), (byte) ( ( part << 16 ) >> 24 ), (byte) ( ( part << 24 ) >> 24 ) }; - } catch ( NumberFormatException e ) { - throw new InvalidHandshakeException( "invalid Sec-WebSocket-Key (/key1/ or /key2/)" ); - } - } - - @Override - public HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) { - if( failed ) { - return HandshakeState.NOT_MATCHED; - } - - try { - if( !response.getFieldValue( "Sec-WebSocket-Origin" ).equals( request.getFieldValue( "Origin" ) ) || !basicAccept( response ) ) { - return HandshakeState.NOT_MATCHED; - } - byte[] content = response.getContent(); - if( content == null || content.length == 0 ) { - throw new IncompleteHandshakeException(); - } - if( Arrays.equals( content, createChallenge( request.getFieldValue( "Sec-WebSocket-Key1" ), request.getFieldValue( "Sec-WebSocket-Key2" ), request.getContent() ) ) ) { - return HandshakeState.MATCHED; - } else { - return HandshakeState.NOT_MATCHED; - } - } catch ( InvalidHandshakeException e ) { - throw new RuntimeException( "bad handshakerequest", e ); - } - } - - @Override - public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) { - if( handshakedata.getFieldValue( "Upgrade" ).equals( "WebSocket" ) && handshakedata.getFieldValue( "Connection" ).contains( "Upgrade" ) && handshakedata.getFieldValue( "Sec-WebSocket-Key1" ).length() > 0 && handshakedata.getFieldValue( "Sec-WebSocket-Key2" ).length() > 0 && handshakedata.hasFieldValue( "Origin" ) ) - return HandshakeState.MATCHED; - return HandshakeState.NOT_MATCHED; - } - - @Override - public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) { - request.put( "Upgrade", "WebSocket" ); - request.put( "Connection", "Upgrade" ); - request.put( "Sec-WebSocket-Key1", generateKey() ); - request.put( "Sec-WebSocket-Key2", generateKey() ); - - if( !request.hasFieldValue( "Origin" ) ) { - request.put( "Origin", "random" + reuseableRandom.nextInt() ); - } - - byte[] key3 = new byte[ 8 ]; - reuseableRandom.nextBytes( key3 ); - request.setContent( key3 ); - return request; - - } - - @Override - public HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder response ) throws InvalidHandshakeException { - response.setHttpStatusMessage( "WebSocket Protocol Handshake" ); - response.put( "Upgrade", "WebSocket" ); - response.put( "Connection", request.getFieldValue( "Connection" ) ); // to respond to a Connection keep alive - response.put( "Sec-WebSocket-Origin", request.getFieldValue( "Origin" ) ); - String location = "ws://" + request.getFieldValue( "Host" ) + request.getResourceDescriptor(); - response.put( "Sec-WebSocket-Location", location ); - String key1 = request.getFieldValue( "Sec-WebSocket-Key1" ); - String key2 = request.getFieldValue( "Sec-WebSocket-Key2" ); - byte[] key3 = request.getContent(); - if( key1 == null || key2 == null || key3 == null || key3.length != 8 ) { - throw new InvalidHandshakeException( "Bad keys" ); - } - response.setContent( createChallenge( key1, key2, key3 ) ); - return response; - } - - @Override - public Handshakedata translateHandshake( ByteBuffer buf ) throws InvalidHandshakeException { - - HandshakeBuilder bui = translateHandshakeHttp( buf, role ); - // the first drafts are lacking a protocol number which makes them difficult to distinguish. Sec-WebSocket-Key1 is typical for draft76 - if( ( bui.hasFieldValue( "Sec-WebSocket-Key1" ) || role == Role.CLIENT ) && !bui.hasFieldValue( "Sec-WebSocket-Version" ) ) { - byte[] key3 = new byte[ role == Role.SERVER ? 8 : 16 ]; - try { - buf.get( key3 ); - } catch ( BufferUnderflowException e ) { - throw new IncompleteHandshakeException( buf.capacity() + 16 ); - } - bui.setContent( key3 ); - - } - return bui; - } - - @Override - public List translateFrame( ByteBuffer buffer ) throws InvalidDataException { - buffer.mark(); - List frames = super.translateRegularFrame( buffer ); - if( frames == null ) { - buffer.reset(); - frames = readyframes; - readingState = true; - if( currentFrame == null ) - currentFrame = ByteBuffer.allocate( 2 ); - else { - throw new InvalidFrameException(); - } - if( buffer.remaining() > currentFrame.remaining() ) { - throw new InvalidFrameException(); - } else { - currentFrame.put( buffer ); - } - if( !currentFrame.hasRemaining() ) { - if( Arrays.equals( currentFrame.array(), closehandshake ) ) { - CloseFrame closeFrame = new CloseFrame(); - closeFrame.setCode(CloseFrame.NORMAL); - closeFrame.isValid(); - frames.add(closeFrame); - return frames; - } - else{ - throw new InvalidFrameException(); - } - } else { - readyframes = new LinkedList(); - return frames; - } - } else { - return frames; - } - } - @Override - public ByteBuffer createBinaryFrame( Framedata framedata ) { - if( framedata.getOpcode() == Opcode.CLOSING ) - return ByteBuffer.wrap( closehandshake ); - return super.createBinaryFrame( framedata ); - } - - @Override - public CloseHandshakeType getCloseHandshakeType() { - return CloseHandshakeType.ONEWAY; - } - - @Override - public Draft copyInstance() { - return new Draft_76(); - } -} diff --git a/src/main/java/org/java_websocket/drafts/Draft_17.java b/src/main/java/org/java_websocket/exceptions/IncompleteException.java similarity index 55% rename from src/main/java/org/java_websocket/drafts/Draft_17.java rename to src/main/java/org/java_websocket/exceptions/IncompleteException.java index d76956a7d..bba43dc0d 100644 --- a/src/main/java/org/java_websocket/drafts/Draft_17.java +++ b/src/main/java/org/java_websocket/exceptions/IncompleteException.java @@ -23,36 +23,36 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -package org.java_websocket.drafts; - -import org.java_websocket.exceptions.InvalidHandshakeException; -import org.java_websocket.handshake.ClientHandshake; -import org.java_websocket.handshake.ClientHandshakeBuilder; +package org.java_websocket.exceptions; /** - * Implementation of the Hybi 17 Draft - * Please use the Draft_6455 for your websocket implementation + * Exception which indicates that the frame is not yet complete */ -@Deprecated -public class Draft_17 extends Draft_10 { - @Override - public HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) throws InvalidHandshakeException { - int v = readVersion( handshakedata ); - if( v == 13 ) - return HandshakeState.MATCHED; - return HandshakeState.NOT_MATCHED; - } +public class IncompleteException extends Throwable { - @Override - public ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) { - super.postProcessHandshakeRequestAsClient( request ); - request.put( "Sec-WebSocket-Version", "13" );// overwriting the previous - return request; - } + /** + * It's Serializable. + */ + private static final long serialVersionUID = 7330519489840500997L; - @Override - public Draft copyInstance() { - return new Draft_17(); + /** + * The preferred size + */ + private int preferredSize; + + /** + * Constructor for the preferred size of a frame + * @param preferredSize the preferred size of a frame + */ + public IncompleteException( int preferredSize ) { + this.preferredSize = preferredSize; } + /** + * Getter for the preferredSize + * @return the value of the preferred size + */ + public int getPreferredSize() { + return preferredSize; + } }