Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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 com.bugvm.websocket.drafts;
import com.bugvm.websocket.WebSocket;
import com.bugvm.websocket.framing.BinaryFrame;
import com.bugvm.websocket.framing.CloseFrame;
import com.bugvm.websocket.framing.ContinuousFrame;
import com.bugvm.websocket.framing.DataFrame;
import com.bugvm.websocket.framing.Framedata;
import com.bugvm.websocket.framing.TextFrame;
import com.bugvm.websocket.handshake.ServerHandshake;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import com.bugvm.websocket.exceptions.IncompleteHandshakeException;
import com.bugvm.websocket.exceptions.InvalidDataException;
import com.bugvm.websocket.exceptions.InvalidHandshakeException;
import com.bugvm.websocket.exceptions.LimitExedeedException;
import com.bugvm.websocket.framing.Framedata.Opcode;
import com.bugvm.websocket.handshake.ClientHandshake;
import com.bugvm.websocket.handshake.ClientHandshakeBuilder;
import com.bugvm.websocket.handshake.HandshakeBuilder;
import com.bugvm.websocket.handshake.HandshakeImpl1Client;
import com.bugvm.websocket.handshake.HandshakeImpl1Server;
import com.bugvm.websocket.handshake.Handshakedata;
import com.bugvm.websocket.handshake.ServerHandshakeBuilder;
import com.bugvm.websocket.util.Charsetfunctions;
/**
* Base class for everything of a websocket specification which is not common such as the way the handshake is read or frames are transfered.
**/
public abstract class Draft {
/**
* Enum which represents the states a handshake may be in
*/
public enum HandshakeState {
/** Handshake matched this Draft successfully */
MATCHED,
/** Handshake is does not match this Draft */
NOT_MATCHED
}
/**
* Enum which represents type of handshake is required for a close
*/
public enum CloseHandshakeType {
NONE, ONEWAY, TWOWAY
}
public static int MAX_FAME_SIZE = 1000;
public static int INITIAL_FAMESIZE = 64;
public static final byte[] FLASH_POLICY_REQUEST = Charsetfunctions.utf8Bytes( "\0" );
/** In some cases the handshake will be parsed different depending on whether */
protected WebSocket.Role role = null;
protected Opcode continuousFrameType = null;
public static ByteBuffer readLine( ByteBuffer buf ) {
ByteBuffer sbuf = ByteBuffer.allocate( buf.remaining() );
byte prev = '0';
byte cur = '0';
while ( buf.hasRemaining() ) {
prev = cur;
cur = buf.get();
sbuf.put( cur );
if( prev == (byte) '\r' && cur == (byte) '\n' ) {
sbuf.limit( sbuf.position() - 2 );
sbuf.position( 0 );
return sbuf;
}
}
// ensure that there wont be any bytes skipped
buf.position( buf.position() - sbuf.position() );
return null;
}
public static String readStringLine( ByteBuffer buf ) {
ByteBuffer b = readLine( buf );
return b == null ? null : Charsetfunctions.stringAscii( b.array(), 0, b.limit() );
}
public static HandshakeBuilder translateHandshakeHttp( ByteBuffer buf, WebSocket.Role role ) throws InvalidHandshakeException , IncompleteHandshakeException {
HandshakeBuilder handshake;
String line = readStringLine( buf );
if( line == null )
throw new IncompleteHandshakeException( buf.capacity() + 128 );
String[] firstLineTokens = line.split( " ", 3 );// eg. HTTP/1.1 101 Switching the Protocols
if( firstLineTokens.length != 3 ) {
throw new InvalidHandshakeException();
}
if( role == WebSocket.Role.CLIENT ) {
// translating/parsing the response from the SERVER
handshake = new HandshakeImpl1Server();
ServerHandshakeBuilder serverhandshake = (ServerHandshakeBuilder) handshake;
serverhandshake.setHttpStatus( Short.parseShort( firstLineTokens[ 1 ] ) );
serverhandshake.setHttpStatusMessage( firstLineTokens[ 2 ] );
} else {
// translating/parsing the request from the CLIENT
ClientHandshakeBuilder clienthandshake = new HandshakeImpl1Client();
clienthandshake.setResourceDescriptor( firstLineTokens[ 1 ] );
handshake = clienthandshake;
}
line = readStringLine( buf );
while ( line != null && line.length() > 0 ) {
String[] pair = line.split( ":", 2 );
if( pair.length != 2 )
throw new InvalidHandshakeException( "not an http header" );
// If the handshake contains already a specific key, append the new value
if ( handshake.hasFieldValue( pair[ 0 ] ) ) {
handshake.put( pair[0], handshake.getFieldValue( pair[ 0 ] ) + "; " + pair[1].replaceFirst( "^ +", "" ) );
} else {
handshake.put( pair[0], pair[1].replaceFirst( "^ +", "" ) );
}
line = readStringLine( buf );
}
if( line == null )
throw new IncompleteHandshakeException();
return handshake;
}
public abstract HandshakeState acceptHandshakeAsClient( ClientHandshake request, ServerHandshake response ) throws InvalidHandshakeException;
public abstract HandshakeState acceptHandshakeAsServer( ClientHandshake handshakedata ) throws InvalidHandshakeException;
protected boolean basicAccept( Handshakedata handshakedata ) {
return handshakedata.getFieldValue( "Upgrade" ).equalsIgnoreCase( "websocket" ) && handshakedata.getFieldValue( "Connection" ).toLowerCase( Locale.ENGLISH ).contains( "upgrade" );
}
public abstract ByteBuffer createBinaryFrame( Framedata framedata ); // TODO Allow to send data on the base of an Iterator or InputStream
public abstract List createFrames( ByteBuffer binary, boolean mask );
public abstract List createFrames( String text, boolean mask );
public List continuousFrame( Opcode op, ByteBuffer buffer, boolean fin ) {
if(op != Opcode.BINARY && op != Opcode.TEXT) {
throw new IllegalArgumentException( "Only Opcode.BINARY or Opcode.TEXT are allowed" );
}
DataFrame bui = null;
if( continuousFrameType != null ) {
bui = new ContinuousFrame();
} else {
continuousFrameType = op;
if (op == Opcode.BINARY) {
bui = new BinaryFrame();
} else if (op == Opcode.TEXT) {
bui = new TextFrame();
}
}
bui.setPayload( buffer );
bui.setFin( fin );
try {
bui.isValid();
} catch ( InvalidDataException e ) {
throw new RuntimeException( e ); // can only happen when one builds close frames(Opcode.Close)
}
if( fin ) {
continuousFrameType = null;
} else {
continuousFrameType = op;
}
return Collections.singletonList( (Framedata) bui );
}
public abstract void reset();
public List createHandshake( Handshakedata handshakedata, WebSocket.Role ownrole ) {
return createHandshake( handshakedata, ownrole, true );
}
public List createHandshake(Handshakedata handshakedata, WebSocket.Role ownrole, boolean withcontent ) {
StringBuilder bui = new StringBuilder( 100 );
if( handshakedata instanceof ClientHandshake ) {
bui.append( "GET " );
bui.append( ( (ClientHandshake) handshakedata ).getResourceDescriptor() );
bui.append( " HTTP/1.1" );
} else if( handshakedata instanceof ServerHandshake ) {
bui.append("HTTP/1.1 101 ").append(((ServerHandshake) handshakedata).getHttpStatusMessage());
} else {
throw new RuntimeException( "unknown role" );
}
bui.append( "\r\n" );
Iterator it = handshakedata.iterateHttpFields();
while ( it.hasNext() ) {
String fieldname = it.next();
String fieldvalue = handshakedata.getFieldValue( fieldname );
bui.append( fieldname );
bui.append( ": " );
bui.append( fieldvalue );
bui.append( "\r\n" );
}
bui.append( "\r\n" );
byte[] httpheader = Charsetfunctions.asciiBytes( bui.toString() );
byte[] content = withcontent ? handshakedata.getContent() : null;
ByteBuffer bytebuffer = ByteBuffer.allocate( ( content == null ? 0 : content.length ) + httpheader.length );
bytebuffer.put( httpheader );
if( content != null )
bytebuffer.put( content );
bytebuffer.flip();
return Collections.singletonList( bytebuffer );
}
public abstract ClientHandshakeBuilder postProcessHandshakeRequestAsClient( ClientHandshakeBuilder request ) throws InvalidHandshakeException;
public abstract HandshakeBuilder postProcessHandshakeResponseAsServer( ClientHandshake request, ServerHandshakeBuilder response ) throws InvalidHandshakeException;
public abstract List translateFrame( ByteBuffer buffer ) throws InvalidDataException;
public abstract CloseHandshakeType getCloseHandshakeType();
/**
* Drafts must only be by one websocket at all. To prevent drafts to be used more than once the Websocket implementation should call this method in order to create a new usable version of a given draft instance.
* The copy can be safely used in conjunction with a new websocket connection.
* @return a copy of the draft
*/
public abstract Draft copyInstance();
public Handshakedata translateHandshake( ByteBuffer buf ) throws InvalidHandshakeException {
return translateHandshakeHttp( buf, role );
}
public int checkAlloc( int bytecount ) throws LimitExedeedException , InvalidDataException {
if( bytecount < 0 )
throw new InvalidDataException( CloseFrame.PROTOCOL_ERROR, "Negative count" );
return bytecount;
}
public void setParseMode( WebSocket.Role role ) {
this.role = role;
}
public WebSocket.Role getRole() {
return role;
}
}