package io.vertx.core.http.impl.headers;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import io.netty.util.HashingStrategy;
import io.vertx.core.MultiMap;
import io.vertx.core.http.impl.HttpUtils;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static io.netty.handler.codec.http.HttpConstants.*;
import static io.netty.util.AsciiString.*;
public final class extends HttpHeaders implements MultiMap {
static final BiConsumer<CharSequence, CharSequence> ;
static {
if (!io.vertx.core.http.HttpHeaders.DISABLE_HTTP_HEADERS_VALIDATION) {
HTTP_VALIDATOR = HttpUtils::validateHeader;
} else {
HTTP_VALIDATOR = null;
}
}
public static HeadersMultiMap () {
return new HeadersMultiMap(HTTP_VALIDATOR);
}
public static HeadersMultiMap () {
return new HeadersMultiMap();
}
@Override
public MultiMap (MultiMap headers) {
return set0(headers);
}
@Override
public MultiMap (Map<String, String> headers) {
return set0(headers.entrySet());
}
@Override
public int () {
return names().size();
}
private final BiConsumer<CharSequence, CharSequence> ;
private final HeadersMultiMap.MapEntry[] = new HeadersMultiMap.MapEntry[16];
private final HeadersMultiMap.MapEntry = new HeadersMultiMap.MapEntry();
public () {
this(null);
}
public (BiConsumer<CharSequence, CharSequence> validator) {
this.validator = validator;
head.before = head.after = head;
}
@Override
public HeadersMultiMap (CharSequence name, CharSequence value) {
Objects.requireNonNull(value);
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
add0(h, i, name, value);
return this;
}
@Override
public HeadersMultiMap (CharSequence name, Object value) {
return add(name, (CharSequence)value);
}
@Override
public HttpHeaders (String name, Object value) {
return add((CharSequence) name, (CharSequence) value);
}
@Override
public HeadersMultiMap (String name, String strVal) {
return add((CharSequence) name, strVal);
}
@Override
public HeadersMultiMap (CharSequence name, Iterable values) {
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
for (Object vstr: values) {
add0(h, i, name, (CharSequence) vstr);
}
return this;
}
@Override
public HeadersMultiMap (String name, Iterable values) {
return add((CharSequence) name, values);
}
@Override
public MultiMap (MultiMap headers) {
return addAll(headers.entries());
}
@Override
public MultiMap (Map<String, String> map) {
return addAll(map.entrySet());
}
private MultiMap (Iterable<Map.Entry<String, String>> headers) {
for (Map.Entry<String, String> entry: headers) {
add(entry.getKey(), entry.getValue());
}
return this;
}
@Override
public HeadersMultiMap (CharSequence name) {
Objects.requireNonNull(name, "name");
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
remove0(h, i, name);
return this;
}
@Override
public HeadersMultiMap (final String name) {
return remove((CharSequence) name);
}
@Override
public HeadersMultiMap (CharSequence name, CharSequence value) {
return set0(name, value);
}
@Override
public HeadersMultiMap (String name, String value) {
return set((CharSequence)name, value);
}
@Override
public HeadersMultiMap (String name, Object value) {
return set((CharSequence)name, (CharSequence) value);
}
@Override
public HeadersMultiMap (CharSequence name, Object value) {
return set(name, (CharSequence)value);
}
@Override
public HeadersMultiMap (CharSequence name, Iterable values) {
Objects.requireNonNull(values, "values");
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
remove0(h, i, name);
for (Object v: values) {
if (v == null) {
break;
}
add0(h, i, name, (CharSequence) v);
}
return this;
}
@Override
public HeadersMultiMap (String name, Iterable values) {
return set((CharSequence) name, values);
}
@Override
public boolean (CharSequence name, CharSequence value, boolean ignoreCase) {
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
HeadersMultiMap.MapEntry e = entries[i];
HashingStrategy<CharSequence> strategy = ignoreCase ? CASE_INSENSITIVE_HASHER : CASE_SENSITIVE_HASHER;
while (e != null) {
CharSequence key = e.key;
if (e.hash == h && (name == key || AsciiString.contentEqualsIgnoreCase(name, key))) {
if (strategy.equals(value, e.getValue())) {
return true;
}
}
e = e.next;
}
return false;
}
@Override
public boolean (String name, String value, boolean ignoreCase) {
return contains((CharSequence) name, value, ignoreCase);
}
@Override
public boolean (CharSequence name) {
return get0(name) != null;
}
@Override
public boolean (String name) {
return contains((CharSequence) name);
}
@Override
public String (CharSequence name) {
Objects.requireNonNull(name, "name");
CharSequence ret = get0(name);
return ret != null ? ret.toString() : null;
}
@Override
public String (String name) {
return get((CharSequence) name);
}
@Override
public List<String> (CharSequence name) {
Objects.requireNonNull(name, "name");
LinkedList<String> values = new LinkedList<>();
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
HeadersMultiMap.MapEntry e = entries[i];
while (e != null) {
CharSequence key = e.key;
if (e.hash == h && (name == key || AsciiString.contentEqualsIgnoreCase(name, key))) {
values.addFirst(e.getValue().toString());
}
e = e.next;
}
return values;
}
@Override
public List<String> (String name) {
return getAll((CharSequence) name);
}
@Override
public void (Consumer<? super Map.Entry<String, String>> action) {
HeadersMultiMap.MapEntry e = head.after;
while (e != head) {
action.accept(new AbstractMap.SimpleEntry<>(e.key.toString(), e.value.toString()));
e = e.after;
}
}
@Override
public List<Map.Entry<String, String>> () {
return MultiMap.super.entries();
}
@Override
public Iterator<Map.Entry<String, String>> () {
return new Iterator<Map.Entry<String, String>>() {
MapEntry = head;
@Override
public boolean () {
return curr.after != head;
}
@Override
public Map.Entry<String, String> () {
MapEntry next = curr.after;
if (next == head){
throw new NoSuchElementException();
}
curr = next;
return new Map.Entry<String, String>() {
@Override
public String () {
return next.key.toString();
}
@Override
public String () {
return next.value.toString();
}
@Override
public String (String value) {
return next.setValue(value).toString();
}
@Override
public String () {
return getKey() + "=" + getValue();
}
};
}
};
}
@Override
public boolean () {
return head == head.after;
}
@Override
public Set<String> () {
Set<String> names = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
HeadersMultiMap.MapEntry e = head.after;
while (e != head) {
names.add(e.getKey().toString());
e = e.after;
}
return names;
}
@Override
public HeadersMultiMap () {
Arrays.fill(entries, null);
head.before = head.after = head;
return this;
}
public String () {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry: this) {
sb.append(entry).append('\n');
}
return sb.toString();
}
@Override
public Integer (CharSequence name) {
throw new UnsupportedOperationException();
}
@Override
public int (CharSequence name, int defaultValue) {
throw new UnsupportedOperationException();
}
@Override
public Short (CharSequence name) {
throw new UnsupportedOperationException();
}
@Override
public short (CharSequence name, short defaultValue) {
throw new UnsupportedOperationException();
}
@Override
public Long (CharSequence name) {
throw new UnsupportedOperationException();
}
@Override
public long (CharSequence name, long defaultValue) {
throw new UnsupportedOperationException();
}
@Override
public Iterator<Map.Entry<CharSequence, CharSequence>> () {
return new Iterator<Map.Entry<CharSequence, CharSequence>>() {
HeadersMultiMap.MapEntry = head.after;
@Override
public boolean () {
return current != head;
}
@Override
public Map.Entry<CharSequence, CharSequence> () {
Map.Entry<CharSequence, CharSequence> next = current;
current = current.after;
return next;
}
};
}
@Override
public HttpHeaders (CharSequence name, int value) {
throw new UnsupportedOperationException();
}
@Override
public HttpHeaders (CharSequence name, short value) {
throw new UnsupportedOperationException();
}
@Override
public HttpHeaders (CharSequence name, int value) {
return set(name, Integer.toString(value));
}
@Override
public HttpHeaders (CharSequence name, short value) {
throw new UnsupportedOperationException();
}
public void (ByteBuf buf) {
HeadersMultiMap.MapEntry current = head.after;
while (current != head) {
encoderHeader(current.key, current.value, buf);
current = current.after;
}
}
private static final int COLON_AND_SPACE_SHORT = (COLON << 8) | SP;
static final int = (CR << 8) | LF;
static void (CharSequence name, CharSequence value, ByteBuf buf) {
final int nameLen = name.length();
final int valueLen = value.length();
final int entryLen = nameLen + valueLen + 4;
buf.ensureWritable(entryLen);
int offset = buf.writerIndex();
writeAscii(buf, offset, name);
offset += nameLen;
ByteBufUtil.setShortBE(buf, offset, COLON_AND_SPACE_SHORT);
offset += 2;
writeAscii(buf, offset, value);
offset += valueLen;
ByteBufUtil.setShortBE(buf, offset, CRLF_SHORT);
offset += 2;
buf.writerIndex(offset);
}
private static void (ByteBuf buf, int offset, CharSequence value) {
if (value instanceof AsciiString) {
ByteBufUtil.copy((AsciiString) value, 0, buf, offset, value.length());
} else {
buf.setCharSequence(offset, value, CharsetUtil.US_ASCII);
}
}
private final class implements Map.Entry<CharSequence, CharSequence> {
final int ;
final CharSequence ;
CharSequence ;
HeadersMultiMap.MapEntry ;
HeadersMultiMap.MapEntry , ;
() {
this.hash = -1;
this.key = null;
this.value = null;
}
(int hash, CharSequence key, CharSequence value) {
this.hash = hash;
this.key = key;
this.value = value;
}
void () {
before.after = after;
after.before = before;
after = null;
before = null;
}
void (HeadersMultiMap.MapEntry e) {
after = e;
before = e.before;
before.after = this;
after.before = this;
}
@Override
public CharSequence () {
return key;
}
@Override
public CharSequence () {
return value;
}
@Override
public CharSequence (CharSequence value) {
Objects.requireNonNull(value, "value");
if (validator != null) {
validator.accept("", value);
}
CharSequence oldValue = this.value;
this.value = value;
return oldValue;
}
@Override
public String () {
return getKey() + "=" + getValue();
}
}
private void (int h, int i, CharSequence name) {
HeadersMultiMap.MapEntry e = entries[i];
MapEntry prev = null;
while (e != null) {
MapEntry next = e.next;
CharSequence key = e.key;
if (e.hash == h && (name == key || AsciiString.contentEqualsIgnoreCase(name, key))) {
if (prev == null) {
entries[i] = next;
} else {
prev.next = next;
}
e.remove();
} else {
prev = e;
}
e = next;
}
}
private void (int h, int i, final CharSequence name, final CharSequence value) {
if (validator != null) {
validator.accept(name, value);
}
HeadersMultiMap.MapEntry e = entries[i];
HeadersMultiMap.MapEntry newEntry;
entries[i] = newEntry = new HeadersMultiMap.MapEntry(h, name, value);
newEntry.next = e;
newEntry.addBefore(head);
}
private HeadersMultiMap (final CharSequence name, final CharSequence strVal) {
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
remove0(h, i, name);
if (strVal != null) {
add0(h, i, name, strVal);
}
return this;
}
private CharSequence (CharSequence name) {
int h = AsciiString.hashCode(name);
int i = h & 0x0000000F;
HeadersMultiMap.MapEntry e = entries[i];
CharSequence value = null;
while (e != null) {
CharSequence key = e.key;
if (e.hash == h && (name == key || AsciiString.contentEqualsIgnoreCase(name, key))) {
value = e.getValue();
}
e = e.next;
}
return value;
}
private MultiMap (Iterable<Map.Entry<String, String>> map) {
clear();
for (Map.Entry<String, String> entry: map) {
add(entry.getKey(), entry.getValue());
}
return this;
}
}