HTTP/2 Headers Code Using String instead of AsciiString

Motivation:
The HTTP/2 headers code should be using binary string (currently AsciiString) objects instead of String objects. The DefaultHttp2HeadersEncoder was still using String for sensitiveHeaders.

Modifications:
- Remove the usage of String from DefaultHttp2HeadersEncoder.
- Introduce an interface to determine if a header name/value is sensitive or not to 1. prevent necessarily creating/copying sets. 2. Allow the name/value to be considered when checking if sensitive.

Result:
No more String in DefaultHttp2HeadersEncoder and less required set creation/operations.
This commit is contained in:
Scott Mitchell 2015-03-31 14:23:51 -07:00
parent 9517edd498
commit 609e065fcf
2 changed files with 36 additions and 10 deletions

View File

@ -16,10 +16,11 @@
package io.netty.handler.codec.http2; package io.netty.handler.codec.http2;
import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_TABLE_SIZE; import static io.netty.handler.codec.http2.Http2CodecUtil.DEFAULT_HEADER_TABLE_SIZE;
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR; import static io.netty.handler.codec.http2.Http2Error.COMPRESSION_ERROR;
import static io.netty.handler.codec.http2.Http2Error.INTERNAL_ERROR;
import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR; import static io.netty.handler.codec.http2.Http2Error.PROTOCOL_ERROR;
import static io.netty.handler.codec.http2.Http2Exception.connectionError; import static io.netty.handler.codec.http2.Http2Exception.connectionError;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
import io.netty.handler.codec.AsciiString; import io.netty.handler.codec.AsciiString;
@ -28,26 +29,23 @@ import io.netty.handler.codec.BinaryHeaders.EntryVisitor;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Collections;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import com.twitter.hpack.Encoder; import com.twitter.hpack.Encoder;
public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2HeadersEncoder.Configuration { public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2HeadersEncoder.Configuration {
private final Encoder encoder; private final Encoder encoder;
private final ByteArrayOutputStream tableSizeChangeOutput = new ByteArrayOutputStream(); private final ByteArrayOutputStream tableSizeChangeOutput = new ByteArrayOutputStream();
private final Set<String> sensitiveHeaders = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); private final SensitivityDetector sensitivityDetector;
private final Http2HeaderTable headerTable; private final Http2HeaderTable headerTable;
public DefaultHttp2HeadersEncoder() { public DefaultHttp2HeadersEncoder() {
this(DEFAULT_HEADER_TABLE_SIZE, Collections.<String>emptySet()); this(DEFAULT_HEADER_TABLE_SIZE, NEVER_SENSITIVE);
} }
public DefaultHttp2HeadersEncoder(int maxHeaderTableSize, Set<String> sensitiveHeaders) { public DefaultHttp2HeadersEncoder(int maxHeaderTableSize, SensitivityDetector sensitivityDetector) {
this.sensitivityDetector = checkNotNull(sensitivityDetector, "sensitiveDetector");
encoder = new Encoder(maxHeaderTableSize); encoder = new Encoder(maxHeaderTableSize);
this.sensitiveHeaders.addAll(sensitiveHeaders);
headerTable = new Http2HeaderTableEncoder(); headerTable = new Http2HeaderTableEncoder();
} }
@ -111,8 +109,7 @@ public class DefaultHttp2HeadersEncoder implements Http2HeadersEncoder, Http2Hea
} }
private void encodeHeader(AsciiString key, AsciiString value, OutputStream stream) throws IOException { private void encodeHeader(AsciiString key, AsciiString value, OutputStream stream) throws IOException {
boolean sensitive = sensitiveHeaders.contains(key.toString()); encoder.encodeHeader(stream, key.array(), value.array(), sensitivityDetector.isSensitive(key, value));
encoder.encodeHeader(stream, key.array(), value.array(), sensitive);
} }
/** /**

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.http2; package io.netty.handler.codec.http2;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.AsciiString;
/** /**
* Encodes {@link Http2Headers} into HPACK-encoded headers blocks. * Encodes {@link Http2Headers} into HPACK-encoded headers blocks.
@ -31,6 +32,24 @@ public interface Http2HeadersEncoder {
Http2HeaderTable headerTable(); Http2HeaderTable headerTable();
} }
/**
* Determine if a header name/value pair is treated as
* <a href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-7.1.3">sensitive</a>.
* If the object can be dynamically modified and shared across multiple connections it may need to be thread safe.
*/
interface SensitivityDetector {
/**
* Determine if a header {@code name}/{@code value} pair should be treated as
* <a href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-7.1.3">sensitive</a>.
* @param name The name for the header.
* @param value The value of the header.
* @return {@code true} if a header {@code name}/{@code value} pair should be treated as
* <a href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-7.1.3">sensitive</a>.
* {@code false} otherwise.
*/
boolean isSensitive(AsciiString name, AsciiString value);
}
/** /**
* Encodes the given headers and writes the output headers block to the given output buffer. * Encodes the given headers and writes the output headers block to the given output buffer.
* *
@ -43,4 +62,14 @@ public interface Http2HeadersEncoder {
* Get the {@link Configuration} for this {@link Http2HeadersEncoder} * Get the {@link Configuration} for this {@link Http2HeadersEncoder}
*/ */
Configuration configuration(); Configuration configuration();
/**
* Always return {@code false} for {@link SensitivityDetector#isSensitive(AsciiString, AsciiString)}.
*/
SensitivityDetector NEVER_SENSITIVE = new SensitivityDetector() {
@Override
public boolean isSensitive(AsciiString name, AsciiString value) {
return false;
}
};
} }