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.
/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), an agency of the Federal Government.
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain. As a result, a formal
* license is not needed to use the software.
*
* This software is provided by NIST as a service and is expressly
* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY. NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement
*
* .
*
*/
package gov.nist.javax.sip.stack;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import gov.nist.core.CommonLogger;
import gov.nist.core.LogLevels;
import gov.nist.core.StackLogger;
/**
*
* Decodes a web socket frame from wire protocol version 8 format. This code was originally based on webbit.
*
* @author vladimirralev
*
*/
public class WebSocketCodec {
private static StackLogger logger = CommonLogger
.getLogger(WebSocketCodec.class);
private static final byte OPCODE_CONT = 0x0;
private static final byte OPCODE_TEXT = 0x1;
private static final byte OPCODE_BINARY = 0x2;
private static final byte OPCODE_CLOSE = 0x8;
private static final byte OPCODE_PING = 0x9;
private static final byte OPCODE_PONG = 0xA;
private static final byte[] trivialMask = new byte[] {1,1,1,1};
// Websocket metadata
private int fragmentedFramesCount;
private boolean frameFinalFlag;
private int frameRsv;
private int frameOpcode;
private long framePayloadLength;
private byte[] maskingKey = new byte[4];
private final boolean allowExtensions;
private final boolean maskedPayload;
private boolean closeOpcodeReceived;
// THe payload inside the websocket frame starts at this index
private int payloadStartIndex = -1;
// Buffering incomplete and overflowing frames
private byte[] decodeBuffer = new byte[2048];
private int writeIndex = 0;
private int readIndex;
// Total webscoket frame (metadata + payload)
private long totalPacketLength = -1;
public WebSocketCodec(boolean maskedPayload, boolean allowExtensions) {
this.maskedPayload = maskedPayload;
this.allowExtensions = allowExtensions;
}
private byte readNextByte() {
if(readIndex >= writeIndex) {
throw new IllegalStateException();
}
return this.decodeBuffer[readIndex++];
}
public byte[] decode(InputStream is)
throws Exception {
do {
// Attempt to resize the decode buffer when it's approaching capacity
int bytesLeft = decodeBuffer.length - writeIndex;
int availToRead = is.available();
if(availToRead > bytesLeft - 1) {
int newSize = Math.max(2*decodeBuffer.length, 4*availToRead);
if(logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Increasing buffer size from " + decodeBuffer.length +
" avail " + availToRead + " newSize " + newSize);
}
byte[] resizeBuffer = new byte[newSize];
System.arraycopy(this.decodeBuffer, 0, resizeBuffer, 0, writeIndex);
this.decodeBuffer = resizeBuffer;
}
int bytesRead = is.read(decodeBuffer, writeIndex, bytesLeft);
if(bytesRead < 0) bytesRead = 0;
// Update the count in the buffer
writeIndex += bytesRead;
} while(is.available()>0);
// Start over from scratch. If the frame is big this may be repeated a few times O(logN) and doesn't affect performance
readIndex = 0;
// All TCP slow-start algorithms will be cut off right here without further analysis
if(writeIndex<4) {
if(logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Abort decode. Write index is at " + writeIndex);
}
return null;
}
byte b = readNextByte();
frameFinalFlag = (b & 0x80) != 0;
frameRsv = (b & 0x70) >> 4;
frameOpcode = b & 0x0F;
if(logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Decoding WebSocket Frame opCode=" + frameOpcode);
}
if(frameOpcode == 8) {
//https://code.google.com/p/chromium/issues/detail?id=388243#c15
this.closeOpcodeReceived = true;
}
// MASK, PAYLOAD LEN 1
b = readNextByte();
boolean frameMasked = (b & 0x80) != 0;
int framePayloadLen1 = b & 0x7F;
if (frameRsv != 0 && !allowExtensions) {
protocolViolation("RSV != 0 and no extension negotiated, RSV:" + frameRsv);
return null;
}
if (maskedPayload && !frameMasked) {
protocolViolation("unmasked client to server frame");
return null;
}
protocolChecks();
try {
// Read frame payload length
if (framePayloadLen1 == 126) {
int byte1 = 0xff & readNextByte();
int byte2 = 0xff & readNextByte();
int value = (byte1<<8) | byte2;
framePayloadLength = value;
} else if (framePayloadLen1 == 127) {
long value = 0;
for(int q=0;q<8;q++) {
byte nextByte = readNextByte();
long valuePart = ((long)(0xff&nextByte));
valuePart <<= (7-q)*8;
value |= valuePart;
}
framePayloadLength = value;
if (framePayloadLength < 65536) {
protocolViolation("invalid data frame length (not using minimal length encoding): " + framePayloadLength);
return null;
}
} else {
framePayloadLength = framePayloadLen1;
}
if(framePayloadLength < 0) {
protocolViolation("Negative payload size: " + framePayloadLength);
}
if(logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Decoding WebSocket Frame length=" + framePayloadLength);
}
// Analyze the mask
if (frameMasked) {
for(int q=0; q<4 ;q++)
maskingKey[q] = readNextByte();
}
}
catch (IllegalStateException e) {
// the stream has ended we don't have enough data to continue
return null;
}
// Remember the payload position
payloadStartIndex = readIndex;
totalPacketLength = readIndex + framePayloadLength;
// Check if we have enough data at all
if(writeIndex < totalPacketLength) {
if(logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
logger.logDebug("Abort decode. Write index is at " + writeIndex + " and totalPacketLength is " + totalPacketLength);
}
return null; // wait for more data
}
// Unmask data if needed and only if the condition above is true
if (frameMasked) {
unmask(decodeBuffer, payloadStartIndex, (int) (payloadStartIndex + framePayloadLength));
}
// Finally isolate the unmasked payload, the bytes are plaintext here
byte[] plainTextBytes = new byte[(int) framePayloadLength];
System.arraycopy(decodeBuffer, payloadStartIndex, plainTextBytes, 0, (int) framePayloadLength);
// Now move the pending data to the begining of the buffer so we can continue having good stream
for(int q=1; q