Method to check if a Http2 header is present and has a given value
Motivation: With HTTP1, it's very easy to check if a header is present and has a given value: you can simply invoke io.netty.handler.codec.http.HttpHeaders#contains(java.lang.CharSequence, java.lang.CharSequence, boolean) It is not possible to do the same with HTTP2. You have to get the list of all headers (returned as String) and then iterate over it invoking String#equals or String#equalsIgnoreCase Modifications: I've added io.netty.handler.codec.http2.Http2Headers#contains and implemented it in DefaultHttp2Headers, EmptyHttp2Headers and ReadOnlyHttp2Headers. Result: You can use AsciiString constants to check if a header is present in a consice and efficient manner.
This commit is contained in:
parent
36304e1f05
commit
bed74d8380
@ -14,10 +14,6 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http2;
|
||||
|
||||
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.connectionError;
|
||||
import static io.netty.util.AsciiString.CASE_SENSITIVE_HASHER;
|
||||
import static io.netty.util.AsciiString.isUpperCase;
|
||||
import io.netty.handler.codec.CharSequenceValueConverter;
|
||||
import io.netty.handler.codec.DefaultHeaders;
|
||||
import io.netty.util.AsciiString;
|
||||
@ -25,6 +21,10 @@ import io.netty.util.ByteProcessor;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.UnstableApi;
|
||||
|
||||
import static io.netty.handler.codec.http2.Http2Error.*;
|
||||
import static io.netty.handler.codec.http2.Http2Exception.*;
|
||||
import static io.netty.util.AsciiString.*;
|
||||
|
||||
@UnstableApi
|
||||
public class DefaultHttp2Headers
|
||||
extends DefaultHeaders<CharSequence, CharSequence, Http2Headers> implements Http2Headers {
|
||||
@ -183,6 +183,11 @@ public class DefaultHttp2Headers
|
||||
return get(PseudoHeaderName.STATUS.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive) {
|
||||
return contains(name, value, caseInsensitive? CASE_INSENSITIVE_HASHER : CASE_SENSITIVE_HASHER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final HeaderEntry<CharSequence, CharSequence> newHeaderEntry(int h, CharSequence name, CharSequence value,
|
||||
HeaderEntry<CharSequence, CharSequence> next) {
|
||||
|
@ -75,4 +75,9 @@ public final class EmptyHttp2Headers
|
||||
public CharSequence status() {
|
||||
return get(PseudoHeaderName.STATUS.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -146,4 +146,16 @@ public interface Http2Headers extends Headers<CharSequence, CharSequence, Http2H
|
||||
* Gets the {@link PseudoHeaderName#STATUS} header or {@code null} if there is no such header
|
||||
*/
|
||||
CharSequence status();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a header with the {@code name} and {@code value} exists, {@code false} otherwise.
|
||||
* <p>
|
||||
* If {@code caseInsensitive} is {@code true} then a case insensitive compare is done on the value.
|
||||
*
|
||||
* @param name the name of the header to find
|
||||
* @param value the value of the header to find
|
||||
* @param caseInsensitive {@code true} then a case insensitive compare is run to compare values.
|
||||
* otherwise a case sensitive compare is run to compare values.
|
||||
*/
|
||||
boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package io.netty.handler.codec.http2;
|
||||
|
||||
import io.netty.handler.codec.Headers;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.HashingStrategy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -27,9 +28,10 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.netty.handler.codec.CharSequenceValueConverter.INSTANCE;
|
||||
import static io.netty.handler.codec.http2.DefaultHttp2Headers.HTTP2_NAME_VALIDATOR;
|
||||
import static io.netty.util.internal.EmptyArrays.EMPTY_ASCII_STRINGS;
|
||||
import static io.netty.handler.codec.CharSequenceValueConverter.*;
|
||||
import static io.netty.handler.codec.http2.DefaultHttp2Headers.*;
|
||||
import static io.netty.util.AsciiString.*;
|
||||
import static io.netty.util.internal.EmptyArrays.*;
|
||||
|
||||
/**
|
||||
* A variant of {@link Http2Headers} which only supports read-only methods.
|
||||
@ -769,6 +771,30 @@ public final class ReadOnlyHttp2Headers implements Http2Headers {
|
||||
return get(PseudoHeaderName.STATUS.value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name, CharSequence value, boolean caseInsensitive) {
|
||||
final int nameHash = AsciiString.hashCode(name);
|
||||
final HashingStrategy<CharSequence> strategy = caseInsensitive? CASE_INSENSITIVE_HASHER : CASE_SENSITIVE_HASHER;
|
||||
final int valueHash = strategy.hashCode(value);
|
||||
|
||||
return contains(name, nameHash, value, valueHash, strategy, pseudoHeaders)
|
||||
|| contains(name, nameHash, value, valueHash, strategy, otherHeaders);
|
||||
}
|
||||
|
||||
private static boolean contains(CharSequence name, int nameHash, CharSequence value, int valueHash,
|
||||
HashingStrategy<CharSequence> hashingStrategy, AsciiString[] headers) {
|
||||
final int headersEnd = headers.length - 1;
|
||||
for (int i = 0; i < headersEnd; i += 2) {
|
||||
AsciiString roName = headers[i];
|
||||
AsciiString roValue = headers[i + 1];
|
||||
if (roName.hashCode() == nameHash && roValue.hashCode() == valueHash &&
|
||||
roName.contentEqualsIgnoreCase(name) && hashingStrategy.equals(roValue, value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName()).append('[');
|
||||
|
@ -22,12 +22,8 @@ import org.junit.Test;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static io.netty.util.AsciiString.of;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static io.netty.util.AsciiString.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DefaultHttp2HeadersTest {
|
||||
|
||||
@ -147,6 +143,13 @@ public class DefaultHttp2HeadersTest {
|
||||
assertEquals(1, http2Headers.names().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsNameAndValue() {
|
||||
Http2Headers headers = newHeaders();
|
||||
assertFalse(headers.contains("name1", "Value2", false));
|
||||
assertTrue(headers.contains("name1", "Value2", true));
|
||||
}
|
||||
|
||||
private static void verifyAllPseudoHeadersPresent(Http2Headers headers) {
|
||||
for (PseudoHeaderName pseudoName : PseudoHeaderName.values()) {
|
||||
assertNotNull(headers.get(pseudoName.value()));
|
||||
|
@ -22,12 +22,8 @@ import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import static io.netty.handler.codec.http2.DefaultHttp2HeadersTest.verifyPseudoHeadersFirst;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static io.netty.handler.codec.http2.DefaultHttp2HeadersTest.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ReadOnlyHttp2HeadersTest {
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@ -139,7 +135,9 @@ public class ReadOnlyHttp2HeadersTest {
|
||||
@Test
|
||||
public void testContainsNameAndValue() {
|
||||
Http2Headers headers = newClientHeaders();
|
||||
assertTrue(headers.contains("Name1", "Value1"));
|
||||
assertTrue(headers.contains("Name1", "value1"));
|
||||
assertFalse(headers.contains("Name1", "Value1", false));
|
||||
assertTrue(headers.contains("Name1", "Value1", true));
|
||||
assertTrue(headers.contains(Http2Headers.PseudoHeaderName.PATH.value(), "/foo"));
|
||||
assertFalse(headers.contains(Http2Headers.PseudoHeaderName.STATUS.value(), "200"));
|
||||
assertFalse(headers.contains("a missing header", "a missing value"));
|
||||
|
Loading…
Reference in New Issue
Block a user