/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package okhttp3.internal.ws;

import okio.Buffer;
import okio.ByteString;

public final class WebSocketProtocol {
  
Magic value which must be appended to the key in a response header.
/** Magic value which must be appended to the key in a response header. */
static final String ACCEPT_MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; /* Each frame starts with two bytes of data. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +-+-+-+-+-------+ +-+-------------+ |F|R|R|R| OP | |M| LENGTH | |I|S|S|S| CODE | |A| | |N|V|V|V| | |S| | | |1|2|3| | |K| | +-+-+-+-+-------+ +-+-------------+ */
Byte 0 flag for whether this is the final fragment in a message.
/** Byte 0 flag for whether this is the final fragment in a message. */
static final int B0_FLAG_FIN = 0b10000000;
Byte 0 reserved flag 1. Must be 0 unless negotiated otherwise.
/** Byte 0 reserved flag 1. Must be 0 unless negotiated otherwise. */
static final int B0_FLAG_RSV1 = 0b01000000;
Byte 0 reserved flag 2. Must be 0 unless negotiated otherwise.
/** Byte 0 reserved flag 2. Must be 0 unless negotiated otherwise. */
static final int B0_FLAG_RSV2 = 0b00100000;
Byte 0 reserved flag 3. Must be 0 unless negotiated otherwise.
/** Byte 0 reserved flag 3. Must be 0 unless negotiated otherwise. */
static final int B0_FLAG_RSV3 = 0b00010000;
Byte 0 mask for the frame opcode.
/** Byte 0 mask for the frame opcode. */
static final int B0_MASK_OPCODE = 0b00001111;
Flag in the opcode which indicates a control frame.
/** Flag in the opcode which indicates a control frame. */
static final int OPCODE_FLAG_CONTROL = 0b00001000;
Byte 1 flag for whether the payload data is masked.

If this flag is set, the next four bytes represent the mask key. These bytes appear after any additional bytes specified by B1_MASK_LENGTH.

/** * Byte 1 flag for whether the payload data is masked. <p> If this flag is set, the next four * bytes represent the mask key. These bytes appear after any additional bytes specified by {@link * #B1_MASK_LENGTH}. */
static final int B1_FLAG_MASK = 0b10000000;
Byte 1 mask for the payload length.

If this value is PAYLOAD_SHORT, the next two bytes represent the length. If this value is PAYLOAD_LONG, the next eight bytes represent the length.

/** * Byte 1 mask for the payload length. <p> If this value is {@link #PAYLOAD_SHORT}, the next two * bytes represent the length. If this value is {@link #PAYLOAD_LONG}, the next eight bytes * represent the length. */
static final int B1_MASK_LENGTH = 0b01111111; static final int OPCODE_CONTINUATION = 0x0; static final int OPCODE_TEXT = 0x1; static final int OPCODE_BINARY = 0x2; static final int OPCODE_CONTROL_CLOSE = 0x8; static final int OPCODE_CONTROL_PING = 0x9; static final int OPCODE_CONTROL_PONG = 0xa;
Maximum length of frame payload. Larger payloads, if supported by the frame type, can use the special values PAYLOAD_SHORT or PAYLOAD_LONG.
/** * Maximum length of frame payload. Larger payloads, if supported by the frame type, can use the * special values {@link #PAYLOAD_SHORT} or {@link #PAYLOAD_LONG}. */
static final long PAYLOAD_BYTE_MAX = 125L;
Maximum length of close message in bytes.
/** Maximum length of close message in bytes. */
static final long CLOSE_MESSAGE_MAX = PAYLOAD_BYTE_MAX - 2;
Value for B1_MASK_LENGTH which indicates the next two bytes are the unsigned length.
/** * Value for {@link #B1_MASK_LENGTH} which indicates the next two bytes are the unsigned length. */
static final int PAYLOAD_SHORT = 126;
Maximum length of a frame payload to be denoted as PAYLOAD_SHORT.
/** Maximum length of a frame payload to be denoted as {@link #PAYLOAD_SHORT}. */
static final long PAYLOAD_SHORT_MAX = 0xffffL;
Value for B1_MASK_LENGTH which indicates the next eight bytes are the unsigned length.
/** * Value for {@link #B1_MASK_LENGTH} which indicates the next eight bytes are the unsigned * length. */
static final int PAYLOAD_LONG = 127;
Used when an unchecked exception was thrown in a listener.
/** Used when an unchecked exception was thrown in a listener. */
static final int CLOSE_CLIENT_GOING_AWAY = 1001;
Used when an empty close frame was received (i.e., without a status code).
/** Used when an empty close frame was received (i.e., without a status code). */
static final int CLOSE_NO_STATUS_CODE = 1005; static void toggleMask(Buffer.UnsafeCursor cursor, byte[] key) { int keyIndex = 0; int keyLength = key.length; do { byte[] buffer = cursor.data; for (int i = cursor.start, end = cursor.end; i < end; i++, keyIndex++) { keyIndex %= keyLength; // Reassign to prevent overflow breaking counter. buffer[i] = (byte) (buffer[i] ^ key[keyIndex]); } } while (cursor.next() != -1); } static String closeCodeExceptionMessage(int code) { if (code < 1000 || code >= 5000) { return "Code must be in range [1000,5000): " + code; } else if ((code >= 1004 && code <= 1006) || (code >= 1012 && code <= 2999)) { return "Code " + code + " is reserved and may not be used."; } else { return null; } } static void validateCloseCode(int code) { String message = closeCodeExceptionMessage(code); if (message != null) throw new IllegalArgumentException(message); } public static String acceptHeader(String key) { return ByteString.encodeUtf8(key + WebSocketProtocol.ACCEPT_MAGIC).sha1().base64(); } private WebSocketProtocol() { throw new AssertionError("No instances."); } }