HTTP/2 defines using String instead of CharSequence
Motivation: Http2CodecUtils has some static variables which are defined as Strings instead of CharSequence. One of these defines is used as a header name and should be AsciiString. Modifications: - Change the String defines in Http2CodecUtils to CharSequence Result: Types are more consistently using CharSequence and adding the upgrade header will require less work.
This commit is contained in:
parent
1d4d5fe312
commit
c7e3f6c6fd
@ -75,13 +75,13 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator implements Ch
|
||||
/**
|
||||
* Returns the name of the protocol supported by this codec, as indicated by the {@code 'UPGRADE'} header.
|
||||
*/
|
||||
String protocol();
|
||||
CharSequence protocol();
|
||||
|
||||
/**
|
||||
* Sets any protocol-specific headers required to the upgrade request. Returns the names of
|
||||
* all headers that were added. These headers will be used to populate the CONNECTION header.
|
||||
*/
|
||||
Collection<String> setUpgradeHeaders(ChannelHandlerContext ctx, HttpRequest upgradeRequest);
|
||||
Collection<CharSequence> setUpgradeHeaders(ChannelHandlerContext ctx, HttpRequest upgradeRequest);
|
||||
|
||||
/**
|
||||
* Performs an HTTP protocol upgrade from the source codec. This method is responsible for
|
||||
@ -257,12 +257,12 @@ public class HttpClientUpgradeHandler extends HttpObjectAggregator implements Ch
|
||||
request.headers().set(HttpHeaderNames.UPGRADE, upgradeCodec.protocol());
|
||||
|
||||
// Add all protocol-specific headers to the request.
|
||||
Set<String> connectionParts = new LinkedHashSet<String>(2);
|
||||
Set<CharSequence> connectionParts = new LinkedHashSet<CharSequence>(2);
|
||||
connectionParts.addAll(upgradeCodec.setUpgradeHeaders(ctx, request));
|
||||
|
||||
// Set the CONNECTION header from the set of all protocol-specific headers that were added.
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String part : connectionParts) {
|
||||
for (CharSequence part : connectionParts) {
|
||||
builder.append(part);
|
||||
builder.append(',');
|
||||
}
|
||||
|
@ -156,6 +156,10 @@ public final class HttpHeaderValues {
|
||||
* {@code "none"}
|
||||
*/
|
||||
public static final AsciiString NONE = new AsciiString("none");
|
||||
/**
|
||||
* {@code "0"}
|
||||
*/
|
||||
public static final AsciiString ZERO = new AsciiString("0");
|
||||
/**
|
||||
* {@code "only-if-cached"}
|
||||
*/
|
||||
|
@ -14,6 +14,10 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import static io.netty.util.AsciiString.containsContentEqualsIgnoreCase;
|
||||
import static io.netty.util.AsciiString.containsAllContentEqualsIgnoreCase;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@ -53,7 +57,7 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
* Gets all protocol-specific headers required by this protocol for a successful upgrade.
|
||||
* Any supplied header will be required to appear in the {@link HttpHeaderNames#CONNECTION} header as well.
|
||||
*/
|
||||
Collection<String> requiredUpgradeHeaders();
|
||||
Collection<CharSequence> requiredUpgradeHeaders();
|
||||
|
||||
/**
|
||||
* Adds any headers to the 101 Switching protocols response that are appropriate for this protocol.
|
||||
@ -87,7 +91,7 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
*
|
||||
* @return a new {@link UpgradeCodec}, or {@code null} if the specified protocol name is not supported
|
||||
*/
|
||||
UpgradeCodec newUpgradeCodec(String protocol);
|
||||
UpgradeCodec newUpgradeCodec(CharSequence protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,10 +100,10 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
* (if required) can be sent using the new protocol.
|
||||
*/
|
||||
public static final class UpgradeEvent implements ReferenceCounted {
|
||||
private final String protocol;
|
||||
private final CharSequence protocol;
|
||||
private final FullHttpRequest upgradeRequest;
|
||||
|
||||
private UpgradeEvent(String protocol, FullHttpRequest upgradeRequest) {
|
||||
private UpgradeEvent(CharSequence protocol, FullHttpRequest upgradeRequest) {
|
||||
this.protocol = protocol;
|
||||
this.upgradeRequest = upgradeRequest;
|
||||
}
|
||||
@ -107,7 +111,7 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
/**
|
||||
* The protocol that the channel has been upgraded to.
|
||||
*/
|
||||
public String protocol() {
|
||||
public CharSequence protocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@ -163,8 +167,6 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String UPGRADE_STRING = HttpHeaderNames.UPGRADE.toString();
|
||||
|
||||
private final SourceCodec sourceCodec;
|
||||
private final UpgradeCodecFactory upgradeCodecFactory;
|
||||
private boolean handlingUpgrade;
|
||||
@ -262,12 +264,12 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
*/
|
||||
private boolean upgrade(final ChannelHandlerContext ctx, final FullHttpRequest request) {
|
||||
// Select the best protocol based on those requested in the UPGRADE header.
|
||||
final ArrayList<String> requestedProtocols = splitHeader(request.headers().get(HttpHeaderNames.UPGRADE));
|
||||
final List<CharSequence> requestedProtocols = splitHeader(request.headers().get(HttpHeaderNames.UPGRADE));
|
||||
final int numRequestedProtocols = requestedProtocols.size();
|
||||
UpgradeCodec upgradeCodec = null;
|
||||
String upgradeProtocol = null;
|
||||
CharSequence upgradeProtocol = null;
|
||||
for (int i = 0; i < numRequestedProtocols; i ++) {
|
||||
final String p = requestedProtocols.get(i);
|
||||
final CharSequence p = requestedProtocols.get(i);
|
||||
final UpgradeCodec c = upgradeCodecFactory.newUpgradeCodec(p);
|
||||
if (c != null) {
|
||||
upgradeProtocol = p;
|
||||
@ -288,9 +290,10 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
}
|
||||
|
||||
// Make sure the CONNECTION header contains UPGRADE as well as all protocol-specific headers.
|
||||
Collection<String> requiredHeaders = upgradeCodec.requiredUpgradeHeaders();
|
||||
List<String> values = splitHeader(connectionHeader);
|
||||
if (!values.contains(UPGRADE_STRING) || !values.containsAll(requiredHeaders)) {
|
||||
Collection<CharSequence> requiredHeaders = upgradeCodec.requiredUpgradeHeaders();
|
||||
List<CharSequence> values = splitHeader(connectionHeader);
|
||||
if (!containsContentEqualsIgnoreCase(values, HttpHeaderNames.UPGRADE) ||
|
||||
!containsAllContentEqualsIgnoreCase(values, requiredHeaders)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -340,11 +343,12 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
/**
|
||||
* Creates the 101 Switching Protocols response message.
|
||||
*/
|
||||
private static FullHttpResponse createUpgradeResponse(String upgradeProtocol) {
|
||||
DefaultFullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, SWITCHING_PROTOCOLS);
|
||||
private static FullHttpResponse createUpgradeResponse(CharSequence upgradeProtocol) {
|
||||
DefaultFullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, SWITCHING_PROTOCOLS,
|
||||
Unpooled.EMPTY_BUFFER, false);
|
||||
res.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE);
|
||||
res.headers().add(HttpHeaderNames.UPGRADE, upgradeProtocol);
|
||||
res.headers().add(HttpHeaderNames.CONTENT_LENGTH, "0");
|
||||
res.headers().add(HttpHeaderNames.CONTENT_LENGTH, HttpHeaderValues.ZERO);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -352,9 +356,9 @@ public class HttpServerUpgradeHandler extends HttpObjectAggregator {
|
||||
* Splits a comma-separated header value. The returned set is case-insensitive and contains each
|
||||
* part with whitespace removed.
|
||||
*/
|
||||
private static ArrayList<String> splitHeader(CharSequence header) {
|
||||
private static List<CharSequence> splitHeader(CharSequence header) {
|
||||
final StringBuilder builder = new StringBuilder(header.length());
|
||||
final ArrayList<String> protocols = new ArrayList<String>(4);
|
||||
final List<CharSequence> protocols = new ArrayList<CharSequence>(4);
|
||||
for (int i = 0; i < header.length(); ++i) {
|
||||
char c = header.charAt(i);
|
||||
if (Character.isWhitespace(c)) {
|
||||
|
@ -41,7 +41,7 @@ import java.util.List;
|
||||
*/
|
||||
public class Http2ClientUpgradeCodec implements HttpClientUpgradeHandler.UpgradeCodec {
|
||||
|
||||
private static final List<String> UPGRADE_HEADERS = Collections.singletonList(HTTP_UPGRADE_SETTINGS_HEADER);
|
||||
private static final List<CharSequence> UPGRADE_HEADERS = Collections.singletonList(HTTP_UPGRADE_SETTINGS_HEADER);
|
||||
|
||||
private final String handlerName;
|
||||
private final Http2ConnectionHandler connectionHandler;
|
||||
@ -69,14 +69,14 @@ public class Http2ClientUpgradeCodec implements HttpClientUpgradeHandler.Upgrade
|
||||
}
|
||||
|
||||
@Override
|
||||
public String protocol() {
|
||||
public CharSequence protocol() {
|
||||
return HTTP_UPGRADE_PROTOCOL_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> setUpgradeHeaders(ChannelHandlerContext ctx,
|
||||
public Collection<CharSequence> setUpgradeHeaders(ChannelHandlerContext ctx,
|
||||
HttpRequest upgradeRequest) {
|
||||
String settingsValue = getSettingsHeaderValue(ctx);
|
||||
CharSequence settingsValue = getSettingsHeaderValue(ctx);
|
||||
upgradeRequest.headers().set(HTTP_UPGRADE_SETTINGS_HEADER, settingsValue);
|
||||
return UPGRADE_HEADERS;
|
||||
}
|
||||
@ -95,7 +95,7 @@ public class Http2ClientUpgradeCodec implements HttpClientUpgradeHandler.Upgrade
|
||||
* Converts the current settings for the handler to the Base64-encoded representation used in
|
||||
* the HTTP2-Settings upgrade header.
|
||||
*/
|
||||
private String getSettingsHeaderValue(ChannelHandlerContext ctx) {
|
||||
private CharSequence getSettingsHeaderValue(ChannelHandlerContext ctx) {
|
||||
ByteBuf buf = null;
|
||||
ByteBuf encodedBuf = null;
|
||||
try {
|
||||
|
@ -23,6 +23,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.DefaultChannelPromise;
|
||||
import io.netty.handler.ssl.ApplicationProtocolNames;
|
||||
import io.netty.util.AsciiString;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
|
||||
import static io.netty.buffer.Unpooled.directBuffer;
|
||||
@ -36,9 +37,9 @@ import static io.netty.util.CharsetUtil.UTF_8;
|
||||
public final class Http2CodecUtil {
|
||||
public static final int CONNECTION_STREAM_ID = 0;
|
||||
public static final int HTTP_UPGRADE_STREAM_ID = 1;
|
||||
public static final String HTTP_UPGRADE_SETTINGS_HEADER = "HTTP2-Settings";
|
||||
public static final String HTTP_UPGRADE_PROTOCOL_NAME = "h2c";
|
||||
public static final String TLS_UPGRADE_PROTOCOL_NAME = ApplicationProtocolNames.HTTP_2;
|
||||
public static final CharSequence HTTP_UPGRADE_SETTINGS_HEADER = new AsciiString("HTTP2-Settings");
|
||||
public static final CharSequence HTTP_UPGRADE_PROTOCOL_NAME = "h2c";
|
||||
public static final CharSequence TLS_UPGRADE_PROTOCOL_NAME = ApplicationProtocolNames.HTTP_2;
|
||||
|
||||
public static final int PING_FRAME_PAYLOAD_LENGTH = 8;
|
||||
public static final short MAX_UNSIGNED_BYTE = 0xFF;
|
||||
|
@ -41,7 +41,7 @@ import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
*/
|
||||
public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.UpgradeCodec {
|
||||
|
||||
private static final List<String> REQUIRED_UPGRADE_HEADERS =
|
||||
private static final List<CharSequence> REQUIRED_UPGRADE_HEADERS =
|
||||
Collections.singletonList(HTTP_UPGRADE_SETTINGS_HEADER);
|
||||
|
||||
private final String handlerName;
|
||||
@ -72,7 +72,7 @@ public class Http2ServerUpgradeCodec implements HttpServerUpgradeHandler.Upgrade
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> requiredUpgradeHeaders() {
|
||||
public Collection<CharSequence> requiredUpgradeHeaders() {
|
||||
return REQUIRED_UPGRADE_HEADERS;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import io.netty.util.internal.PlatformDependent;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
@ -887,6 +888,42 @@ public final class AsciiString extends ByteString implements CharSequence, Compa
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if {@code collection} contains {@code value} and using
|
||||
* {@link #contentEqualsIgnoreCase(CharSequence, CharSequence)} to compare values.
|
||||
* @param collection The collection to look for and equivalent element as {@code value}.
|
||||
* @param value The value to look for in {@code collection}.
|
||||
* @return {@code true} if {@code collection} contains {@code value} according to
|
||||
* {@link #contentEqualsIgnoreCase(CharSequence, CharSequence)}. {@code false} otherwise.
|
||||
* @see #contentEqualsIgnoreCase(CharSequence, CharSequence)
|
||||
*/
|
||||
public static boolean containsContentEqualsIgnoreCase(Collection<CharSequence> collection, CharSequence value) {
|
||||
for (CharSequence v : collection) {
|
||||
if (contentEqualsIgnoreCase(value, v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if {@code a} contains all of the values in {@code b} using
|
||||
* {@link #contentEqualsIgnoreCase(CharSequence, CharSequence)} to compare values.
|
||||
* @param a The collection under test.
|
||||
* @param b The values to test for.
|
||||
* @return {@code true} if {@code a} contains all of the values in {@code b} using
|
||||
* {@link #contentEqualsIgnoreCase(CharSequence, CharSequence)} to compare values. {@code false} otherwise.
|
||||
* @see #contentEqualsIgnoreCase(CharSequence, CharSequence)
|
||||
*/
|
||||
public static boolean containsAllContentEqualsIgnoreCase(Collection<CharSequence> a, Collection<CharSequence> b) {
|
||||
for (CharSequence v : b) {
|
||||
if (!containsContentEqualsIgnoreCase(a, v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the content of both {@link CharSequence}'s are equals. This only supports 8-bit ASCII.
|
||||
*/
|
||||
|
@ -31,6 +31,7 @@ import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory;
|
||||
import io.netty.handler.codec.http2.Http2CodecUtil;
|
||||
import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.util.AsciiString;
|
||||
|
||||
/**
|
||||
* Sets up the Netty pipeline for the example server. Depending on the endpoint config, sets up the
|
||||
@ -40,8 +41,8 @@ public class Http2ServerInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private static final UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() {
|
||||
@Override
|
||||
public UpgradeCodec newUpgradeCodec(String protocol) {
|
||||
if (Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME.equals(protocol)) {
|
||||
public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
|
||||
if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
|
||||
return new Http2ServerUpgradeCodec(new HelloWorldHttp2Handler());
|
||||
} else {
|
||||
return null;
|
||||
|
Loading…
Reference in New Issue
Block a user