package org.java_websocket.framing;
import java.nio.ByteBuffer;
import org.java_websocket.exceptions.InvalidDataException;
import org.java_websocket.exceptions.InvalidFrameException;
import org.java_websocket.util.Charsetfunctions;
public class CloseFrameBuilder extends FramedataImpl1 implements CloseFrame {
static final ByteBuffer emptybytebuffer = ByteBuffer.allocate( 0 );
private int code;
private String reason;
public CloseFrameBuilder() {
super( Opcode.CLOSING );
setFin( true );
}
public CloseFrameBuilder( int code ) throws InvalidDataException {
super( Opcode.CLOSING );
setFin( true );
setCodeAndMessage( code, "" );
}
public CloseFrameBuilder( int code , String m ) throws InvalidDataException {
super( Opcode.CLOSING );
setFin( true );
setCodeAndMessage( code, m );
}
private void setCodeAndMessage( int code, String m ) throws InvalidDataException {
if( m == null ) {
m = "";
}
// CloseFrame.TLS_ERROR is not allowed to be transfered over the wire
if( code == CloseFrame.TLS_ERROR ) {
code = CloseFrame.NOCODE;
m = "";
}
if( code == CloseFrame.NOCODE ) {
if( 0 < m.length() ) {
throw new InvalidDataException( PROTOCOL_ERROR, "A close frame must have a closecode if it has a reason" );
}
return;// empty payload
}
byte[] by = Charsetfunctions.utf8Bytes( m );
ByteBuffer buf = ByteBuffer.allocate( 4 );
buf.putInt( code );
buf.position( 2 );
ByteBuffer pay = ByteBuffer.allocate( 2 + by.length );
pay.put( buf );
pay.put( by );
pay.rewind();
setPayload( pay );
}
private void initCloseCode() throws InvalidFrameException {
code = CloseFrame.NOCODE;
ByteBuffer payload = super.getPayloadData();
payload.mark();
if( payload.remaining() >= 2 ) {
ByteBuffer bb = ByteBuffer.allocate( 4 );
bb.position( 2 );
bb.putShort( payload.getShort() );
bb.position( 0 );
code = bb.getInt();
if( code == CloseFrame.ABNORMAL_CLOSE || code == CloseFrame.TLS_ERROR || code == CloseFrame.NOCODE || code > 4999 || code < 1000 || code == 1004 ) {
throw new InvalidFrameException( "closecode must not be sent over the wire: " + code );
}
}
payload.reset();
}
@Override
public int getCloseCode() {
return code;
}
private void initMessage() throws InvalidDataException {
if( code == CloseFrame.NOCODE ) {
reason = Charsetfunctions.stringUtf8( super.getPayloadData() );
} else {
ByteBuffer b = super.getPayloadData();
int mark = b.position();// because stringUtf8 also creates a mark
try {
b.position( b.position() + 2 );
reason = Charsetfunctions.stringUtf8( b );
} catch ( IllegalArgumentException e ) {
throw new InvalidFrameException( e );
} finally {
b.position( mark );
}
}
}
@Override
public String getMessage() {
return reason;
}
@Override
public String toString() {
return super.toString() + "code: " + code;
}
@Override
public void setPayload( ByteBuffer payload ) throws InvalidDataException {
super.setPayload( payload );
initCloseCode();
initMessage();
}
@Override
public ByteBuffer getPayloadData() {
if( code == NOCODE )
return emptybytebuffer;
return super.getPayloadData();
}
}