package jdk.internal.net.http.hpack;
import jdk.internal.net.http.hpack.HPACK.Logger;
import java.util.List;
import java.util.NoSuchElementException;
import static jdk.internal.net.http.common.Utils.pow2Size;
import static jdk.internal.net.http.hpack.HPACK.Logger.Level.EXTRA;
import static jdk.internal.net.http.hpack.HPACK.Logger.Level.NORMAL;
import static java.lang.String.format;
class {
protected static final List<HeaderField> = List.of(
new HeaderField(""),
new HeaderField(":authority"),
new HeaderField(":method", "GET"),
new HeaderField(":method", "POST"),
new HeaderField(":path", "/"),
new HeaderField(":path", "/index.html"),
new HeaderField(":scheme", "http"),
new HeaderField(":scheme", "https"),
new HeaderField(":status", "200"),
new HeaderField(":status", "204"),
new HeaderField(":status", "206"),
new HeaderField(":status", "304"),
new HeaderField(":status", "400"),
new HeaderField(":status", "404"),
new HeaderField(":status", "500"),
new HeaderField("accept-charset"),
new HeaderField("accept-encoding", "gzip, deflate"),
new HeaderField("accept-language"),
new HeaderField("accept-ranges"),
new HeaderField("accept"),
new HeaderField("access-control-allow-origin"),
new HeaderField("age"),
new HeaderField("allow"),
new HeaderField("authorization"),
new HeaderField("cache-control"),
new HeaderField("content-disposition"),
new HeaderField("content-encoding"),
new HeaderField("content-language"),
new HeaderField("content-length"),
new HeaderField("content-location"),
new HeaderField("content-range"),
new HeaderField("content-type"),
new HeaderField("cookie"),
new HeaderField("date"),
new HeaderField("etag"),
new HeaderField("expect"),
new HeaderField("expires"),
new HeaderField("from"),
new HeaderField("host"),
new HeaderField("if-match"),
new HeaderField("if-modified-since"),
new HeaderField("if-none-match"),
new HeaderField("if-range"),
new HeaderField("if-unmodified-since"),
new HeaderField("last-modified"),
new HeaderField("link"),
new HeaderField("location"),
new HeaderField("max-forwards"),
new HeaderField("proxy-authenticate"),
new HeaderField("proxy-authorization"),
new HeaderField("range"),
new HeaderField("referer"),
new HeaderField("refresh"),
new HeaderField("retry-after"),
new HeaderField("server"),
new HeaderField("set-cookie"),
new HeaderField("strict-transport-security"),
new HeaderField("transfer-encoding"),
new HeaderField("user-agent"),
new HeaderField("vary"),
new HeaderField("via"),
new HeaderField("www-authenticate"));
protected static final int = staticTable.size() - 1;
protected static final int = 32;
private final Logger ;
private int ;
private int ;
public (int maxSize, Logger logger) {
this.logger = logger;
setMaxSize(maxSize);
}
public int () {
return size;
}
public int () {
return maxSize;
}
public int () {
return STATIC_TABLE_LENGTH + buffer.size;
}
HeaderField (int index) {
checkIndex(index);
if (index <= STATIC_TABLE_LENGTH) {
return staticTable.get(index);
} else {
return buffer.get(index - STATIC_TABLE_LENGTH - 1);
}
}
void (CharSequence name, CharSequence value) {
put(new HeaderField(name.toString(), value.toString()));
}
private void (HeaderField h) {
if (logger.isLoggable(NORMAL)) {
logger.log(NORMAL, () -> format("adding ('%s', '%s')",
h.name, h.value));
}
int entrySize = sizeOf(h);
if (logger.isLoggable(EXTRA)) {
logger.log(EXTRA, () -> format("size of ('%s', '%s') is %s",
h.name, h.value, entrySize));
}
while (entrySize > maxSize - size && size != 0) {
if (logger.isLoggable(EXTRA)) {
logger.log(EXTRA, () -> format("insufficient space %s, must evict entry",
(maxSize - size)));
}
evictEntry();
}
if (entrySize > maxSize - size) {
if (logger.isLoggable(EXTRA)) {
logger.log(EXTRA, () -> format("not adding ('%s, '%s'), too big",
h.name, h.value));
}
return;
}
size += entrySize;
add(h);
if (logger.isLoggable(EXTRA)) {
logger.log(EXTRA, () -> format("('%s, '%s') added", h.name, h.value));
logger.log(EXTRA, this::toString);
}
}
void (int maxSize) {
if (maxSize < 0) {
throw new IllegalArgumentException(
"maxSize >= 0: maxSize=" + maxSize);
}
while (maxSize < size && size != 0) {
evictEntry();
}
this.maxSize = maxSize;
int upperBound = maxSize / ENTRY_SIZE;
buffer.resize(upperBound);
}
HeaderField () {
HeaderField f = remove();
int s = sizeOf(f);
this.size -= s;
if (logger.isLoggable(EXTRA)) {
logger.log(EXTRA, () -> format("evicted entry ('%s', '%s') of size %s",
f.name, f.value, s));
logger.log(EXTRA, this::toString);
}
return f;
}
@Override
public String () {
double used = maxSize == 0 ? 0 : 100 * (((double) size) / maxSize);
return format("dynamic length: %d, full length: %s, used space: %s/%s (%.1f%%)",
buffer.size, length(), size, maxSize, used);
}
private int (int index) {
int len = length();
if (index < 1 || index > len) {
throw new IndexOutOfBoundsException(
format("1 <= index <= length(): index=%s, length()=%s",
index, len));
}
return index;
}
int (HeaderField f) {
return f.name.length() + f.value.length() + ENTRY_SIZE;
}
String () {
if (size == 0) {
return "empty.";
}
StringBuilder b = new StringBuilder();
for (int i = 1, size = buffer.size; i <= size; i++) {
HeaderField e = buffer.get(i - 1);
b.append(format("[%3d] (s = %3d) %s: %s\n", i,
sizeOf(e), e.name, e.value));
}
b.append(format(" Table size:%4s", this.size));
return b.toString();
}
protected static final class {
final String ;
final String ;
public (String name) {
this(name, "");
}
public (String name, String value) {
this.name = name;
this.value = value;
}
@Override
public String () {
return value.isEmpty() ? name : name + ": " + value;
}
}
private final CircularBuffer<HeaderField> = new CircularBuffer<>(0);
protected void (HeaderField f) {
buffer.add(f);
}
protected HeaderField () {
return buffer.remove();
}
static final class <E> {
int , , , ;
Object[] ;
(int capacity) {
this.capacity = pow2Size(capacity);
elements = new Object[this.capacity];
}
void (E elem) {
if (size == capacity) {
throw new IllegalStateException(
format("No room for '%s': capacity=%s", elem, capacity));
}
elements[head] = elem;
head = (head + 1) & (capacity - 1);
size++;
}
@SuppressWarnings("unchecked")
E () {
if (size == 0) {
throw new NoSuchElementException("Empty");
}
E elem = (E) elements[tail];
elements[tail] = null;
tail = (tail + 1) & (capacity - 1);
size--;
return elem;
}
@SuppressWarnings("unchecked")
E (int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(
format("0 <= index <= capacity: index=%s, capacity=%s",
index, capacity));
}
int idx = (tail + (size - index - 1)) & (capacity - 1);
return (E) elements[idx];
}
public void (int newCapacity) {
if (newCapacity < size) {
throw new IllegalStateException(
format("newCapacity >= size: newCapacity=%s, size=%s",
newCapacity, size));
}
int capacity = pow2Size(newCapacity);
Object[] newElements = new Object[capacity];
if (tail < head || size == 0) {
System.arraycopy(elements, tail, newElements, 0, size);
} else {
System.arraycopy(elements, tail, newElements, 0, elements.length - tail);
System.arraycopy(elements, 0, newElements, elements.length - tail, head);
}
elements = newElements;
tail = 0;
head = size;
this.capacity = capacity;
}
}
}