/* * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
import java.nio.ByteBuffer;
/* Copied from jdk.internal.net.http.websocket.Frame */ finalclass Frame {
final Opcode opcode; final ByteBuffer data; finalboolean last;
/* * Reads all remaining bytes from the given input buffer, masks them * with the supplied mask and writes the resulting bytes to the given * output buffer. * * The source and the destination buffers may be the same instance.
*/ staticvoid transferMasking(ByteBuffer src, ByteBuffer dst, int mask) { if (src.remaining() > dst.remaining()) { thrownew IllegalArgumentException();
} new Masker().mask(mask).transferMasking(src, dst);
}
/* * Clears this instance's state and sets the mask. * * The behaviour is as if the mask was set on a newly created instance.
*/
Masker mask(int value) {
acc.clear().putInt(value).putInt(value).flip(); for (int i = 0; i < maskBytes.length; i++) {
maskBytes[i] = acc.get(i);
}
offset = 0;
maskLong = acc.getLong(0); returnthis;
}
/* * Reads as many remaining bytes as possible from the given input * buffer, masks them with the previously set mask and writes the * resulting bytes to the given output buffer. * * The source and the destination buffers may be the same instance. If * the mask hasn't been previously set it is assumed to be 0.
*/
Masker transferMasking(ByteBuffer src, ByteBuffer dst) {
begin(src, dst);
loop(src, dst);
end(src, dst); returnthis;
}
/* * Applies up to 3 remaining from the previous pass bytes of the mask.
*/ privatevoid begin(ByteBuffer src, ByteBuffer dst) { if (offset == 0) { // No partially applied mask from the previous invocation return;
} int i = src.position(), j = dst.position(); finalint srcLim = src.limit(), dstLim = dst.limit(); for (; offset < 4 && i < srcLim && j < dstLim; i++, j++, offset++)
{
dst.put(j, (byte) (src.get(i) ^ maskBytes[offset]));
}
offset &= 3; // Will become 0 if the mask has been fully applied
src.position(i);
dst.position(j);
}
/* * Gallops one long (mask + mask) at a time.
*/ privatevoid loop(ByteBuffer src, ByteBuffer dst) { int i = src.position(); int j = dst.position(); finalint srcLongLim = src.limit() - 7, dstLongLim = dst.limit() - 7; for (; i < srcLongLim && j < dstLongLim; i += 8, j += 8) {
dst.putLong(j, src.getLong(i) ^ maskLong);
} if (i > src.limit()) {
src.position(i - 8);
} else {
src.position(i);
} if (j > dst.limit()) {
dst.position(j - 8);
} else {
dst.position(j);
}
}
/* * Applies up to 7 remaining from the "galloping" phase bytes of the * mask.
*/ privatevoid end(ByteBuffer src, ByteBuffer dst) { assert Math.min(src.remaining(), dst.remaining()) < 8; finalint srcLim = src.limit(), dstLim = dst.limit(); int i = src.position(), j = dst.position(); for (; i < srcLim && j < dstLim;
i++, j++, offset = (offset + 1) & 3) // offset cycles through 0..3
{
dst.put(j, (byte) (src.get(i) ^ maskBytes[offset]));
}
src.position(i);
dst.position(j);
}
}
/* * A builder-style writer of frame headers. * * The writer does not enforce any protocol-level rules, it simply writes a * header structure to the given buffer. The order of calls to intermediate * methods is NOT significant.
*/ staticfinalclass HeaderWriter {
/* * Writes the header to the given buffer. * * The buffer must have at least MAX_HEADER_SIZE_BYTES remaining. The * buffer's position is incremented by the number of bytes written.
*/ void write(ByteBuffer buffer) {
buffer.putChar(firstChar); if (payloadLen >= 126) { if (payloadLen < 65536) {
buffer.putChar((char) payloadLen);
} else {
buffer.putLong(payloadLen);
}
} if (mask) {
buffer.putInt(maskingKey);
}
}
}
/* * A consumer of frame parts. * * Frame.Reader invokes the consumer's methods in the following order: * * fin rsv1 rsv2 rsv3 opcode mask payloadLength maskingKey? payloadData+ endFrame
*/ interface Consumer {
void fin(boolean value);
void rsv1(boolean value);
void rsv2(boolean value);
void rsv3(boolean value);
void opcode(Opcode value);
void mask(boolean value);
void payloadLen(long value);
void maskingKey(int value);
/* * Called by the Frame.Reader when a part of the (or a complete) payload * is ready to be consumed. * * The sum of numbers of bytes consumed in each invocation of this * method corresponding to the given frame WILL be equal to * 'payloadLen', reported to `void payloadLen(long value)` before that. * * In particular, if `payloadLen` is 0, then there WILL be a single * invocation to this method. * * No unmasking is done.
*/ void payloadData(ByteBuffer data);
void endFrame();
}
/* * A Reader of frames. * * No protocol-level rules are checked.
*/ staticfinalclass Reader {
/* * Reads at most one frame from the given buffer invoking the consumer's * methods corresponding to the frame parts found. * * As much of the frame's payload, if any, is read. The buffer's * position is updated to reflect the number of bytes read. * * Throws FailWebSocketException if detects the frame is malformed.
*/ void readFrame(ByteBuffer input, Consumer consumer) {
loop: while (true) { byte b; switch (state) { case AWAITING_FIRST_BYTE: if (!input.hasRemaining()) { break loop;
}
b = input.get();
consumer.fin( (b & 0b10000000) != 0);
consumer.rsv1((b & 0b01000000) != 0);
consumer.rsv2((b & 0b00100000) != 0);
consumer.rsv3((b & 0b00010000) != 0);
consumer.opcode(Opcode.ofCode(b));
state = AWAITING_SECOND_BYTE; continue loop; case AWAITING_SECOND_BYTE: if (!input.hasRemaining()) { break loop;
}
b = input.get();
consumer.mask(mask = (b & 0b10000000) != 0); byte p1 = (byte) (b & 0b01111111); if (p1 < 126) { assert p1 >= 0 : p1;
consumer.payloadLen(remainingPayloadLength = p1);
state = mask ? READING_MASK : READING_PAYLOAD;
} elseif (p1 < 127) {
state = READING_16_LENGTH;
} else {
state = READING_64_LENGTH;
} continue loop; case READING_16_LENGTH: if (!input.hasRemaining()) { break loop;
}
b = input.get(); if (accumulator.put(b).position() < 2) { continue loop;
}
remainingPayloadLength = accumulator.flip().getChar(); if (remainingPayloadLength < 126) { throw notMinimalEncoding(remainingPayloadLength);
}
consumer.payloadLen(remainingPayloadLength);
accumulator.clear();
state = mask ? READING_MASK : READING_PAYLOAD; continue loop; case READING_64_LENGTH: if (!input.hasRemaining()) { break loop;
}
b = input.get(); if (accumulator.put(b).position() < 8) { continue loop;
}
remainingPayloadLength = accumulator.flip().getLong(); if (remainingPayloadLength < 0) { throw negativePayload(remainingPayloadLength);
} elseif (remainingPayloadLength < 65536) { throw notMinimalEncoding(remainingPayloadLength);
}
consumer.payloadLen(remainingPayloadLength);
accumulator.clear();
state = mask ? READING_MASK : READING_PAYLOAD; continue loop; case READING_MASK: if (!input.hasRemaining()) { break loop;
}
b = input.get(); if (accumulator.put(b).position() != 4) { continue loop;
}
consumer.maskingKey(accumulator.flip().getInt());
accumulator.clear();
state = READING_PAYLOAD; continue loop; case READING_PAYLOAD: // This state does not require any bytes to be available // in the input buffer in order to proceed int deliverable = (int) Math.min(remainingPayloadLength,
input.remaining()); int oldLimit = input.limit();
input.limit(input.position() + deliverable); if (deliverable != 0 || remainingPayloadLength == 0) {
consumer.payloadData(input);
} int consumed = deliverable - input.remaining(); if (consumed < 0) { // Consumer cannot consume more than there was available thrownew InternalError();
}
input.limit(oldLimit);
remainingPayloadLength -= consumed; if (remainingPayloadLength == 0) {
consumer.endFrame();
state = AWAITING_FIRST_BYTE;
} break loop; default: thrownew InternalError(String.valueOf(state));
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.