protected void sendMessage(byte[] aMessage, MessageOpCode aOpCode) { if (!isClosing()) { int messageLength = aMessage.length; if (messageLength <= getMaxPayloadSize()) { // create and send fragment WebSocketFragment fragment = new WebSocketFragment(aOpCode, true, sendWithMask(), aMessage); sendMessage(fragment); } else { List<WebSocketFragment> fragments = new ArrayList<WebSocketFragment>(); int fragmentCount = messageLength / getMaxPayloadSize(); if (messageLength % getMaxPayloadSize() > 0) { fragmentCount++; } // build fragments for (int i = 0; i < fragmentCount; i++) { WebSocketFragment fragment = null; int fragmentLength = getMaxPayloadSize(); if (i == 0) { fragment = new WebSocketFragment( aOpCode, false, sendWithMask(), WebSocketUtil.copySubArray(aMessage, i * getMaxPayloadSize(), fragmentLength)); } else if (i == fragmentCount - 1) { fragmentLength = messageLength % getMaxPayloadSize(); if (fragmentLength == 0) { fragmentLength = getMaxPayloadSize(); } fragment = new WebSocketFragment( MessageOpCode.CONTINUATION, true, sendWithMask(), WebSocketUtil.copySubArray(aMessage, i * getMaxPayloadSize(), fragmentLength)); } else { fragment = new WebSocketFragment( MessageOpCode.CONTINUATION, false, sendWithMask(), WebSocketUtil.copySubArray(aMessage, i * getMaxPayloadSize(), fragmentLength)); } fragments.add(fragment); } // send fragments for (WebSocketFragment fragment : fragments) { sendMessage(fragment); } } } }
protected void handleMessageData(byte[] aData) { // grab last fragment, use if not complete WebSocketFragment fragment = pendingFragments.peek(); if (fragment == null || fragment.isValid()) { // assign web socket fragment since the last one was complete fragment = new WebSocketFragment(aData); pendingFragments.offer(fragment); } else if (fragment != null) { fragment.appendFragment(aData); if (fragment.canBeParsed()) { fragment.parseContent(); } } // if we have a complete fragment, handle it if (fragment.isValid()) { // handle complete fragment handleCompleteFragment(fragment); // if we have extra data, handle it if (aData.length > fragment.getMessageLength()) { handleMessageData( WebSocketUtil.copySubArray( aData, fragment.getMessageLength(), aData.length - fragment.getMessageLength())); } } }
protected void handleClose(WebSocketFragment aFragment) { // parse close message boolean hasInvalidUtf8 = false; try { byte[] data = aFragment.getPayloadData(); if (data != null) { if (data.length >= 2) { closeStatus = WebSocketUtil.convertBytesToShort(data, 0); if (data.length > 2) { closeMessage = convertFromBytesToString(WebSocketUtil.copySubArray(data, 2, data.length - 2)); } } } } catch (CharacterCodingException e) { logger.error("An error occurred while decoding from UTF8 to get text in close message.", e); sendErrorToObserver(e); hasInvalidUtf8 = true; } // actually close if (isClosing()) { closeSocket(); } else { setClosing(true); if (hasInvalidUtf8) { close(WebSocketCloseStatusInvalidUtf8, null); } else { close(0, null); } } }
public void parseContent() { if (getFragment() != null && getFragment().length >= getPayloadStart() + getPayloadLength()) { // set payload if (hasMask()) { setPayloadData( WebSocketFragment.unmask( getMask(), getFragment(), getPayloadStart(), getPayloadLength())); } else { setPayloadData( WebSocketUtil.copySubArray(getFragment(), getPayloadStart(), getPayloadLength())); } } }
public boolean parseHeader(byte[] aData, int aOffset) { // get header data bits int bufferLength = 14; byte[] data = aData; // do we have an existing fragment to work with if (getFragment() != null) { if (getFragment().length >= bufferLength) { data = getFragment(); } else { byte[] both; if ((aData != null ? aData.length : 0) - aOffset >= bufferLength - getFragment().length) { both = WebSocketUtil.appendPartialArray( getFragment(), aData, aOffset, bufferLength - getFragment().length); } else { both = WebSocketUtil.appendArray(getFragment(), aData); } data = both; } } if (data != null && data.length - aOffset < bufferLength) { bufferLength = data.length - aOffset; } if (bufferLength < 0 || data == null) { return false; } byte[] buffer = WebSocketUtil.copySubArray(data, 0, bufferLength); // determine opcode if (bufferLength > 0) { int index = 0; setFinal((buffer[index] & 0x80) != 0); setRSV1((buffer[index] & 0x40) != 0); setRSV2((buffer[index] & 0x20) != 0); setRSV3((buffer[index] & 0x20) != 0); setOpCode(buffer[index++] & 0x0F); // handle data depending on opcode switch (getOpCode()) { case TEXT: setPayloadType(PayloadType.TEXT); break; case BINARY: setPayloadType(PayloadType.BINARY); break; } // handle content, if any if (bufferLength > 1) { // do we have a mask boolean hasMask = (buffer[index] & 0x80) != 0; // get payload length Long dataLength = new Integer(buffer[index++] & 0x7F).longValue(); if (dataLength == 126) { // exit if we are missing bytes if (bufferLength < 4) { return false; } dataLength = new Integer(WebSocketUtil.convertBytesToShort(buffer, index)).longValue(); index += 2; } else if (dataLength == 127) { // exit if we are missing bytes if (bufferLength < 10) { return false; } dataLength = WebSocketUtil.convertBytesToLong(buffer, index); index += 8; } // if applicable, set mask value if (hasMask) { // exit if we are missing bytes if (bufferLength < index + 4) { return false; } // grab mask setMask(WebSocketUtil.convertBytesToInt(buffer, index)); index += 4; } payloadStart = index; if (dataLength > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Implementation does not support payload lengths in excess of " + Integer.MAX_VALUE + ": " + dataLength); } payloadLength = dataLength.intValue(); return true; } } return false; }