package io.undertow.protocols.http2;
import java.nio.ByteBuffer;
import io.undertow.UndertowMessages;
import io.undertow.util.HttpString;
final class Hpack {
private static final byte LOWER_DIFF = 'a' - 'A';
static final int DEFAULT_TABLE_SIZE = 4096;
private static final int MAX_INTEGER_OCTETS = 8;
private static final int[] PREFIX_TABLE;
static final HeaderField[] STATIC_TABLE;
static final int STATIC_TABLE_LENGTH;
static {
PREFIX_TABLE = new int[32];
for (int i = 0; i < 32; ++i) {
int n = 0;
for (int j = 0; j < i; ++j) {
n = n << 1;
n |= 1;
}
PREFIX_TABLE[i] = n;
}
HeaderField[] fields = new HeaderField[62];
fields[1] = new HeaderField(new HttpString(":authority"), null);
fields[2] = new HeaderField(new HttpString(":method"), "GET");
fields[3] = new HeaderField(new HttpString(":method"), "POST");
fields[4] = new HeaderField(new HttpString(":path"), "/");
fields[5] = new HeaderField(new HttpString(":path"), "/index.html");
fields[6] = new HeaderField(new HttpString(":scheme"), "http");
fields[7] = new HeaderField(new HttpString(":scheme"), "https");
fields[8] = new HeaderField(new HttpString(":status"), "200");
fields[9] = new HeaderField(new HttpString(":status"), "204");
fields[10] = new HeaderField(new HttpString(":status"), "206");
fields[11] = new HeaderField(new HttpString(":status"), "304");
fields[12] = new HeaderField(new HttpString(":status"), "400");
fields[13] = new HeaderField(new HttpString(":status"), "404");
fields[14] = new HeaderField(new HttpString(":status"), "500");
fields[15] = new HeaderField(new HttpString("accept-charset"), null);
fields[16] = new HeaderField(new HttpString("accept-encoding"), "gzip, deflate");
fields[17] = new HeaderField(new HttpString("accept-language"), null);
fields[18] = new HeaderField(new HttpString("accept-ranges"), null);
fields[19] = new HeaderField(new HttpString("accept"), null);
fields[20] = new HeaderField(new HttpString("access-control-allow-origin"), null);
fields[21] = new HeaderField(new HttpString("age"), null);
fields[22] = new HeaderField(new HttpString("allow"), null);
fields[23] = new HeaderField(new HttpString("authorization"), null);
fields[24] = new HeaderField(new HttpString("cache-control"), null);
fields[25] = new HeaderField(new HttpString("content-disposition"), null);
fields[26] = new HeaderField(new HttpString("content-encoding"), null);
fields[27] = new HeaderField(new HttpString("content-language"), null);
fields[28] = new HeaderField(new HttpString("content-length"), null);
fields[29] = new HeaderField(new HttpString("content-location"), null);
fields[30] = new HeaderField(new HttpString("content-range"), null);
fields[31] = new HeaderField(new HttpString("content-type"), null);
fields[32] = new HeaderField(new HttpString("cookie"), null);
fields[33] = new HeaderField(new HttpString("date"), null);
fields[34] = new HeaderField(new HttpString("etag"), null);
fields[35] = new HeaderField(new HttpString("expect"), null);
fields[36] = new HeaderField(new HttpString("expires"), null);
fields[37] = new HeaderField(new HttpString("from"), null);
fields[38] = new HeaderField(new HttpString("host"), null);
fields[39] = new HeaderField(new HttpString("if-match"), null);
fields[40] = new HeaderField(new HttpString("if-modified-since"), null);
fields[41] = new HeaderField(new HttpString("if-none-match"), null);
fields[42] = new HeaderField(new HttpString("if-range"), null);
fields[43] = new HeaderField(new HttpString("if-unmodified-since"), null);
fields[44] = new HeaderField(new HttpString("last-modified"), null);
fields[45] = new HeaderField(new HttpString("link"), null);
fields[46] = new HeaderField(new HttpString("location"), null);
fields[47] = new HeaderField(new HttpString("max-forwards"), null);
fields[48] = new HeaderField(new HttpString("proxy-authenticate"), null);
fields[49] = new HeaderField(new HttpString("proxy-authorization"), null);
fields[50] = new HeaderField(new HttpString("range"), null);
fields[51] = new HeaderField(new HttpString("referer"), null);
fields[52] = new HeaderField(new HttpString("refresh"), null);
fields[53] = new HeaderField(new HttpString("retry-after"), null);
fields[54] = new HeaderField(new HttpString("server"), null);
fields[55] = new HeaderField(new HttpString("set-cookie"), null);
fields[56] = new HeaderField(new HttpString("strict-transport-security"), null);
fields[57] = new HeaderField(new HttpString("transfer-encoding"), null);
fields[58] = new HeaderField(new HttpString("user-agent"), null);
fields[59] = new HeaderField(new HttpString("vary"), null);
fields[60] = new HeaderField(new HttpString("via"), null);
fields[61] = new HeaderField(new HttpString("www-authenticate"), null);
STATIC_TABLE = fields;
STATIC_TABLE_LENGTH = STATIC_TABLE.length - 1;
}
static class {
final HttpString ;
final String ;
final int ;
(HttpString name, String value) {
this.name = name;
this.value = value;
if (value != null) {
this.size = 32 + name.length() + value.length();
} else {
this.size = -1;
}
}
}
static int decodeInteger(ByteBuffer source, int n) throws HpackException {
if (source.remaining() == 0) {
return -1;
}
if(n >= PREFIX_TABLE.length) {
throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS);
}
int count = 1;
int sp = source.position();
int mask = PREFIX_TABLE[n];
int i = mask & source.get();
int b;
if (i < PREFIX_TABLE[n]) {
return i;
} else {
int m = 0;
do {
if(count++ > MAX_INTEGER_OCTETS) {
throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS);
}
if (source.remaining() == 0) {
source.position(sp);
return -1;
}
if(m >= PREFIX_TABLE.length) {
throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS);
}
b = source.get();
i = i + (b & 127) * (PREFIX_TABLE[m] + 1);
m += 7;
} while ((b & 128) == 128);
}
return i;
}
static void encodeInteger(ByteBuffer source, int value, int n) {
int twoNminus1 = PREFIX_TABLE[n];
int pos = source.position() - 1;
if (value < twoNminus1) {
source.put(pos, (byte) (source.get(pos) | value));
} else {
source.put(pos, (byte) (source.get(pos) | twoNminus1));
value = value - twoNminus1;
while (value >= 128) {
source.put((byte) (value % 128 + 128));
value = value / 128;
}
source.put((byte) value);
}
}
static byte toLower(byte b) {
if (b >= 'A' && b <= 'Z') {
return (byte) (b + LOWER_DIFF);
}
return b;
}
private Hpack() {}
}