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); } @Override public int getCloseCode() { return code; } @Override public String getMessage() { return reason; } @Override public ByteBuffer getPayloadData() { if (code == NOCODE) return emptybytebuffer; return super.getPayloadData(); } 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(); } 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); } } } 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); } @Override public void setPayload(ByteBuffer payload) throws InvalidDataException { super.setPayload(payload); initCloseCode(); initMessage(); } @Override public String toString() { return super.toString() + "code: " + code; } }