
org.java_websocket.drafts.Draft_75 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Java-WebSocket Show documentation
Show all versions of Java-WebSocket Show documentation
A barebones WebSocket client and server implementation written 100% in Java
package org.java_websocket.drafts;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.java_websocket.exceptions.InvalidDataException;
import org.java_websocket.exceptions.InvalidHandshakeException;
import org.java_websocket.exceptions.NotSendableException;
import org.java_websocket.framing.CloseFrame;
import org.java_websocket.framing.FrameBuilder;
import org.java_websocket.framing.Framedata;
import org.java_websocket.framing.Framedata.Opcode;
import org.java_websocket.framing.FramedataImpl1;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ClientHandshakeBuilder;
import org.java_websocket.handshake.HandshakeBuilder;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.handshake.ServerHandshakeBuilder;
import org.java_websocket.util.Charsetfunctions;
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;
protected boolean readingState = false;
private boolean inframe = 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 ) {
FrameBuilder frame = new FramedataImpl1();
try {
frame.setPayload( ByteBuffer.wrap( Charsetfunctions.utf8Bytes( text ) ) );
} catch ( InvalidDataException e ) {
throw new NotSendableException( e );
}
frame.setFin( true );
frame.setOptcode( Opcode.TEXT );
frame.setTransferemasked( mask );
return Collections.singletonList( (Framedata) frame );
}
@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 )
return null;
readingState = true;
} else if( newestByte == END_OF_FRAME ) { // End of Frame
if( !readingState )
return null;
// 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();
FramedataImpl1 curframe = new FramedataImpl1();
curframe.setPayload( currentFrame );
curframe.setFin( true );
curframe.setOptcode( inframe ? Opcode.CONTINUOUS : Opcode.TEXT );
readyframes.add( curframe );
this.currentFrame = null;
buffer.mark();
}
readingState = false;
inframe = 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( readingState ) {
FramedataImpl1 curframe = new FramedataImpl1();
currentFrame.flip();
curframe.setPayload( currentFrame );
curframe.setFin( false );
curframe.setOptcode( inframe ? Opcode.CONTINUOUS : Opcode.TEXT );
inframe = true;
readyframes.add( curframe );
}
List frames = readyframes;
readyframes = new LinkedList();
this.currentFrame = null;
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 ) {
full.flip();
ByteBuffer newbuffer = ByteBuffer.allocate( full.capacity() * 2 );
newbuffer.put( full );
return newbuffer;
}
@Override
public Draft copyInstance() {
return new Draft_75();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy