Package org.java_websocket.drafts

Source Code of org.java_websocket.drafts.Draft

package org.java_websocket.drafts;

import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import org.java_websocket.WebSocket.Role;
import org.java_websocket.exceptions.IncompleteHandshakeException;
import org.java_websocket.exceptions.InvalidDataException;
import org.java_websocket.exceptions.InvalidHandshakeException;
import org.java_websocket.exceptions.LimitExedeedException;
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.HandshakeImpl1Client;
import org.java_websocket.handshake.HandshakeImpl1Server;
import org.java_websocket.handshake.Handshakedata;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.handshake.ServerHandshakeBuilder;
import org.java_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 {

  public enum HandshakeState {
    /** Handshake matched this Draft successfully */
    MATCHED,
    /** Handshake is does not match this Draft */
    NOT_MATCHED
  }
  public enum CloseHandshakeType {
    NONE, ONEWAY, TWOWAY
  }

  public static int MAX_FAME_SIZE = 1000 * 1;
  public static int INITIAL_FAMESIZE = 64;

  public static final byte[] FLASH_POLICY_REQUEST = Charsetfunctions.utf8Bytes( "<policy-file-request/>\0" );

  /** In some cases the handshake will be parsed different depending on whether */
  protected 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, 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 == 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" );
      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<Framedata> createFrames( ByteBuffer binary, boolean mask );

  public abstract List<Framedata> createFrames( String text, boolean mask );

  public List<Framedata> continuousFrame( Opcode op, ByteBuffer buffer, boolean fin ) {
    if( op != Opcode.BINARY && op != Opcode.TEXT && op != Opcode.TEXT ) {
      throw new IllegalArgumentException( "Only Opcode.BINARY or  Opcode.TEXT are allowed" );
    }

    if( continuousFrameType != null ) {
      continuousFrameType = Opcode.CONTINUOUS;
    } else {
      continuousFrameType = op;
    }

    FrameBuilder bui = new FramedataImpl1( continuousFrameType );
    try {
      bui.setPayload( buffer );
    } catch ( InvalidDataException e ) {
      throw new RuntimeException( e ); // can only happen when one builds close frames(Opcode.Close)
    }
    bui.setFin( fin );
    if( fin ) {
      continuousFrameType = null;
    } else {
      continuousFrameType = op;
    }
    return Collections.singletonList( (Framedata) bui );
  }

  public abstract void reset();

  public List<ByteBuffer> createHandshake( Handshakedata handshakedata, Role ownrole ) {
    return createHandshake( handshakedata, ownrole, true );
  }

  public List<ByteBuffer> createHandshake( Handshakedata handshakedata, 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 " + ( (ServerHandshake) handshakedata ).getHttpStatusMessage() );
    } else {
      throw new RuntimeException( "unknow role" );
    }
    bui.append( "\r\n" );
    Iterator<String> 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<Framedata> 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.<br>
   * The copy can be safely used in conjunction with a new websocket connection.
   * */
  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( Role role ) {
    this.role = role;
  }
 
  public Role getRole() {
    return role;
  }

}
TOP

Related Classes of org.java_websocket.drafts.Draft

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.