Backport the additional AsciiString/TextHeader changes from master

- Add useful static methods to AsciiString
- Add more getters in TextHeaders
- Remove unnecessary utility methods in SpdyHttpHeaders
This commit is contained in:
Trustin Lee 2014-06-14 17:33:34 +09:00
parent 681d460938
commit c076c33901
20 changed files with 220 additions and 214 deletions

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultHttpHeaders.NonValidatingTextHeaders;
import io.netty.handler.codec.http.DefaultHttpHeaders.ValidatingTextHeaders;
import io.netty.util.internal.StringUtil;
@ -113,9 +114,9 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
@Override
protected CharSequence convertName(CharSequence name) {
name = super.convertName(name);
if (HttpHeaders.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH, name) ||
HttpHeaders.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING, name) ||
HttpHeaders.equalsIgnoreCase(HttpHeaders.Names.TRAILER, name)) {
if (AsciiString.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH, name) ||
AsciiString.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING, name) ||
AsciiString.equalsIgnoreCase(HttpHeaders.Names.TRAILER, name)) {
throw new IllegalArgumentException(
"prohibited trailing header: " + name);
}

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.http;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.util.internal.StringUtil;
@ -96,7 +97,7 @@ public class HttpContentCompressor extends HttpContentEncoder {
protected Result beginEncode(HttpResponse headers, String acceptEncoding) throws Exception {
String contentEncoding = headers.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
if (contentEncoding != null &&
!HttpHeaders.equalsIgnoreCase(HttpHeaders.Values.IDENTITY, contentEncoding)) {
!AsciiString.equalsIgnoreCase(HttpHeaders.Values.IDENTITY, contentEncoding)) {
return null;
}

View File

@ -567,14 +567,14 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
*/
public static boolean isKeepAlive(HttpMessage message) {
String connection = message.headers().get(CONNECTION_ENTITY);
if (connection != null && equalsIgnoreCase(CLOSE_ENTITY, connection)) {
if (connection != null && AsciiString.equalsIgnoreCase(CLOSE_ENTITY, connection)) {
return false;
}
if (message.getProtocolVersion().isKeepAliveDefault()) {
return !equalsIgnoreCase(CLOSE_ENTITY, connection);
return !AsciiString.equalsIgnoreCase(CLOSE_ENTITY, connection);
} else {
return equalsIgnoreCase(KEEP_ALIVE_ENTITY, connection);
return AsciiString.equalsIgnoreCase(KEEP_ALIVE_ENTITY, connection);
}
}
@ -1115,7 +1115,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
if (value == null) {
return false;
}
if (equalsIgnoreCase(CONTINUE_ENTITY, value)) {
if (AsciiString.equalsIgnoreCase(CONTINUE_ENTITY, value)) {
return true;
}
@ -1165,7 +1165,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
Iterator<String> valuesIt = values.iterator();
while (valuesIt.hasNext()) {
String value = valuesIt.next();
if (equalsIgnoreCase(value, CHUNKED_ENTITY)) {
if (AsciiString.equalsIgnoreCase(value, CHUNKED_ENTITY)) {
valuesIt.remove();
}
}
@ -1186,39 +1186,11 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
}
/**
* Returns {@code true} if both {@link CharSequence}'s are equals when ignore the case.
* This only supports US_ASCII.
* @deprecated Use {@link AsciiString#equalsIgnoreCase(CharSequence, CharSequence)} instead.
*/
@Deprecated
public static boolean equalsIgnoreCase(CharSequence name1, CharSequence name2) {
if (name1 == name2) {
return true;
}
if (name1 == null || name2 == null) {
return false;
}
int nameLen = name1.length();
if (nameLen != name2.length()) {
return false;
}
for (int i = nameLen - 1; i >= 0; i --) {
char c1 = name1.charAt(i);
char c2 = name2.charAt(i);
if (c1 != c2) {
if (c1 >= 'A' && c1 <= 'Z') {
c1 += 32;
}
if (c2 >= 'A' && c2 <= 'Z') {
c2 += 32;
}
if (c1 != c2) {
return false;
}
}
}
return true;
return AsciiString.equalsIgnoreCase(name1, name2);
}
static void encode(HttpHeaders headers, ByteBuf buf) {
@ -1238,6 +1210,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
buf.writeBytes(CRLF);
}
@Deprecated
public static void encodeAscii(CharSequence seq, ByteBuf buf) {
if (seq instanceof AsciiString) {
((AsciiString) seq).copy(0, buf, seq.length());
@ -1499,7 +1472,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
for (String v: values) {
if (ignoreCase) {
if (equalsIgnoreCase(v, value)) {
if (AsciiString.equalsIgnoreCase(v, value)) {
return true;
}
} else {

View File

@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufProcessor;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.ReplayingDecoder;
import io.netty.handler.codec.TooLongFrameException;
@ -559,9 +560,9 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
} else {
String[] header = splitHeader(line);
String name = header[0];
if (!HttpHeaders.equalsIgnoreCase(name, HttpHeaders.Names.CONTENT_LENGTH) &&
!HttpHeaders.equalsIgnoreCase(name, HttpHeaders.Names.TRANSFER_ENCODING) &&
!HttpHeaders.equalsIgnoreCase(name, HttpHeaders.Names.TRAILER)) {
if (!AsciiString.equalsIgnoreCase(name, HttpHeaders.Names.CONTENT_LENGTH) &&
!AsciiString.equalsIgnoreCase(name, HttpHeaders.Names.TRANSFER_ENCODING) &&
!AsciiString.equalsIgnoreCase(name, HttpHeaders.Names.TRAILER)) {
trailer.trailingHeaders().add(name, header[1]);
}
lastHeader = name;

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultHttpContent;
@ -741,7 +742,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
if (transferEncoding != null) {
headers.remove(HttpHeaders.Names.TRANSFER_ENCODING);
for (String v : transferEncoding) {
if (HttpHeaders.equalsIgnoreCase(v, HttpHeaders.Values.CHUNKED)) {
if (AsciiString.equalsIgnoreCase(v, HttpHeaders.Values.CHUNKED)) {
// ignore
} else {
headers.add(HttpHeaders.Names.TRANSFER_ENCODING, v);

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -198,13 +199,13 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
HttpHeaders headers = response.headers();
String upgrade = headers.get(Names.UPGRADE);
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ connection);
}

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -173,12 +174,12 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -174,12 +175,12 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -184,12 +185,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.AsciiString;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
@ -109,8 +110,8 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
// Serve the WebSocket handshake request.
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, req.headers().get(CONNECTION))
|| !HttpHeaders.equalsIgnoreCase(WEBSOCKET, req.headers().get(Names.UPGRADE))) {
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, req.headers().get(CONNECTION))
|| !AsciiString.equalsIgnoreCase(WEBSOCKET, req.headers().get(Names.UPGRADE))) {
throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
}

View File

@ -28,6 +28,7 @@ import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.spdy.SpdyHttpHeaders.Names;
import java.util.HashMap;
import java.util.List;
@ -138,10 +139,11 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
createHttpResponse(spdyVersion, spdySynStreamFrame);
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);
SpdyHttpHeaders.setAssociatedToStreamId(httpResponseWithEntity, associatedToStreamId);
SpdyHttpHeaders.setPriority(httpResponseWithEntity, spdySynStreamFrame.getPriority());
SpdyHttpHeaders.setUrl(httpResponseWithEntity, URL);
HttpHeaders.setIntHeader(httpResponseWithEntity, Names.STREAM_ID, streamId);
HttpHeaders.setIntHeader(
httpResponseWithEntity, Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId);
HttpHeaders.setIntHeader(httpResponseWithEntity, Names.PRIORITY, spdySynStreamFrame.getPriority());
httpResponseWithEntity.headers().set(Names.URL, URL);
if (spdySynStreamFrame.isLast()) {
HttpHeaders.setContentLength(httpResponseWithEntity, 0);
@ -174,7 +176,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
FullHttpRequest httpRequestWithEntity = createHttpRequest(spdyVersion, spdySynStreamFrame);
// Set the Stream-ID as a header
SpdyHttpHeaders.setStreamId(httpRequestWithEntity, streamId);
HttpHeaders.setIntHeader(httpRequestWithEntity, Names.STREAM_ID, streamId);
if (spdySynStreamFrame.isLast()) {
out.add(httpRequestWithEntity);
@ -213,7 +215,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
FullHttpResponse httpResponseWithEntity = createHttpResponse(spdyVersion, spdySynReplyFrame);
// Set the Stream-ID as a header
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);
HttpHeaders.setIntHeader(httpResponseWithEntity, Names.STREAM_ID, streamId);
if (spdySynReplyFrame.isLast()) {
HttpHeaders.setContentLength(httpResponseWithEntity, 0);

View File

@ -27,6 +27,7 @@ import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.spdy.SpdyHttpHeaders.Names;
import java.util.List;
import java.util.Map;
@ -207,23 +208,24 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
private SpdySynStreamFrame createSynStreamFrame(HttpMessage httpMessage)
throws Exception {
// Get the Stream-ID, Associated-To-Stream-ID, Priority, URL, and scheme from the headers
int streamID = SpdyHttpHeaders.getStreamId(httpMessage);
int associatedToStreamId = SpdyHttpHeaders.getAssociatedToStreamId(httpMessage);
byte priority = SpdyHttpHeaders.getPriority(httpMessage);
String URL = SpdyHttpHeaders.getUrl(httpMessage);
String scheme = SpdyHttpHeaders.getScheme(httpMessage);
SpdyHttpHeaders.removeStreamId(httpMessage);
SpdyHttpHeaders.removeAssociatedToStreamId(httpMessage);
SpdyHttpHeaders.removePriority(httpMessage);
SpdyHttpHeaders.removeUrl(httpMessage);
SpdyHttpHeaders.removeScheme(httpMessage);
final HttpHeaders httpHeaders = httpMessage.headers();
int streamID = HttpHeaders.getIntHeader(httpMessage, Names.STREAM_ID);
int associatedToStreamId = HttpHeaders.getIntHeader(httpMessage, Names.ASSOCIATED_TO_STREAM_ID, 0);
byte priority = (byte) HttpHeaders.getIntHeader(httpMessage, Names.PRIORITY, 0);
String URL = httpHeaders.get(Names.URL);
String scheme = httpHeaders.get(Names.SCHEME);
httpHeaders.remove(Names.STREAM_ID);
httpHeaders.remove(Names.ASSOCIATED_TO_STREAM_ID);
httpHeaders.remove(Names.PRIORITY);
httpHeaders.remove(Names.URL);
httpHeaders.remove(Names.SCHEME);
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
// headers are not valid and MUST not be sent.
httpMessage.headers().remove(HttpHeaders.Names.CONNECTION);
httpMessage.headers().remove("Keep-Alive");
httpMessage.headers().remove("Proxy-Connection");
httpMessage.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
httpHeaders.remove(HttpHeaders.Names.CONNECTION);
httpHeaders.remove("Keep-Alive");
httpHeaders.remove("Proxy-Connection");
httpHeaders.remove(HttpHeaders.Names.TRANSFER_ENCODING);
SpdySynStreamFrame spdySynStreamFrame =
new DefaultSpdySynStreamFrame(streamID, associatedToStreamId, priority);
@ -247,7 +249,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
// Replace the HTTP host header with the SPDY host header
if (spdyVersion >= 3) {
String host = HttpHeaders.getHost(httpMessage);
httpMessage.headers().remove(HttpHeaders.Names.HOST);
httpHeaders.remove(HttpHeaders.Names.HOST);
frameHeaders.set(HOST, host);
}
@ -258,7 +260,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
frameHeaders.set(SCHEME, scheme);
// Transfer the remaining HTTP headers
for (Map.Entry<String, String> entry: httpMessage.headers()) {
for (Map.Entry<String, String> entry: httpHeaders) {
frameHeaders.add(entry.getKey(), entry.getValue());
}
currentStreamId = spdySynStreamFrame.getStreamId();
@ -270,15 +272,16 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
private SpdySynReplyFrame createSynReplyFrame(HttpResponse httpResponse)
throws Exception {
// Get the Stream-ID from the headers
int streamID = SpdyHttpHeaders.getStreamId(httpResponse);
SpdyHttpHeaders.removeStreamId(httpResponse);
final HttpHeaders httpHeaders = httpResponse.headers();
int streamID = HttpHeaders.getIntHeader(httpResponse, Names.STREAM_ID);
httpHeaders.remove(Names.STREAM_ID);
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
// headers are not valid and MUST not be sent.
httpResponse.headers().remove(HttpHeaders.Names.CONNECTION);
httpResponse.headers().remove("Keep-Alive");
httpResponse.headers().remove("Proxy-Connection");
httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
httpHeaders.remove(HttpHeaders.Names.CONNECTION);
httpHeaders.remove("Keep-Alive");
httpHeaders.remove("Proxy-Connection");
httpHeaders.remove(HttpHeaders.Names.TRANSFER_ENCODING);
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
SpdyHeaders frameHeaders = spdySynReplyFrame.headers();
@ -287,7 +290,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
frameHeaders.set(VERSION, httpResponse.getProtocolVersion());
// Transfer the remaining HTTP headers
for (Map.Entry<String, String> entry: httpResponse.headers()) {
for (Map.Entry<String, String> entry: httpHeaders) {
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
}

View File

@ -15,8 +15,7 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.AsciiString;
/**
* Provides the constants for the header names and the utility methods
@ -31,138 +30,26 @@ public final class SpdyHttpHeaders {
/**
* {@code "X-SPDY-Stream-ID"}
*/
public static final String STREAM_ID = "X-SPDY-Stream-ID";
public static final AsciiString STREAM_ID = new AsciiString("X-SPDY-Stream-ID");
/**
* {@code "X-SPDY-Associated-To-Stream-ID"}
*/
public static final String ASSOCIATED_TO_STREAM_ID = "X-SPDY-Associated-To-Stream-ID";
public static final AsciiString ASSOCIATED_TO_STREAM_ID = new AsciiString("X-SPDY-Associated-To-Stream-ID");
/**
* {@code "X-SPDY-Priority"}
*/
public static final String PRIORITY = "X-SPDY-Priority";
public static final AsciiString PRIORITY = new AsciiString("X-SPDY-Priority");
/**
* {@code "X-SPDY-URL"}
*/
public static final String URL = "X-SPDY-URL";
public static final AsciiString URL = new AsciiString("X-SPDY-URL");
/**
* {@code "X-SPDY-Scheme"}
*/
public static final String SCHEME = "X-SPDY-Scheme";
public static final AsciiString SCHEME = new AsciiString("X-SPDY-Scheme");
private Names() { }
}
private SpdyHttpHeaders() {
}
/**
* Removes the {@code "X-SPDY-Stream-ID"} header.
*/
public static void removeStreamId(HttpMessage message) {
message.headers().remove(Names.STREAM_ID);
}
/**
* Returns the value of the {@code "X-SPDY-Stream-ID"} header.
*/
public static int getStreamId(HttpMessage message) {
return HttpHeaders.getIntHeader(message, Names.STREAM_ID);
}
/**
* Sets the {@code "X-SPDY-Stream-ID"} header.
*/
public static void setStreamId(HttpMessage message, int streamId) {
HttpHeaders.setIntHeader(message, Names.STREAM_ID, streamId);
}
/**
* Removes the {@code "X-SPDY-Associated-To-Stream-ID"} header.
*/
public static void removeAssociatedToStreamId(HttpMessage message) {
message.headers().remove(Names.ASSOCIATED_TO_STREAM_ID);
}
/**
* Returns the value of the {@code "X-SPDY-Associated-To-Stream-ID"} header.
*
* @return the header value or {@code 0} if there is no such header or
* if the header value is not a number
*/
public static int getAssociatedToStreamId(HttpMessage message) {
return HttpHeaders.getIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, 0);
}
/**
* Sets the {@code "X-SPDY-Associated-To-Stream-ID"} header.
*/
public static void setAssociatedToStreamId(HttpMessage message, int associatedToStreamId) {
HttpHeaders.setIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId);
}
/**
* Removes the {@code "X-SPDY-Priority"} header.
*/
public static void removePriority(HttpMessage message) {
message.headers().remove(Names.PRIORITY);
}
/**
* Returns the value of the {@code "X-SPDY-Priority"} header.
*
* @return the header value or {@code 0} if there is no such header or
* if the header value is not a number
*/
public static byte getPriority(HttpMessage message) {
return (byte) HttpHeaders.getIntHeader(message, Names.PRIORITY, 0);
}
/**
* Sets the {@code "X-SPDY-Priority"} header.
*/
public static void setPriority(HttpMessage message, byte priority) {
HttpHeaders.setIntHeader(message, Names.PRIORITY, priority);
}
/**
* Removes the {@code "X-SPDY-URL"} header.
*/
public static void removeUrl(HttpMessage message) {
message.headers().remove(Names.URL);
}
/**
* Returns the value of the {@code "X-SPDY-URL"} header.
*/
public static String getUrl(HttpMessage message) {
return message.headers().get(Names.URL);
}
/**
* Sets the {@code "X-SPDY-URL"} header.
*/
public static void setUrl(HttpMessage message, String url) {
message.headers().set(Names.URL, url);
}
/**
* Removes the {@code "X-SPDY-Scheme"} header.
*/
public static void removeScheme(HttpMessage message) {
message.headers().remove(Names.SCHEME);
}
/**
* Returns the value of the {@code "X-SPDY-Scheme"} header.
*/
public static String getScheme(HttpMessage message) {
return message.headers().get(Names.SCHEME);
}
/**
* Sets the {@code "X-SPDY-Scheme"} header.
*/
public static void setScheme(HttpMessage message, String scheme) {
message.headers().set(Names.SCHEME, scheme);
}
private SpdyHttpHeaders() { }
}

View File

@ -17,7 +17,9 @@ package io.netty.handler.codec.spdy;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.spdy.SpdyHttpHeaders.Names;
import io.netty.util.ReferenceCountUtil;
import java.util.LinkedList;
@ -43,7 +45,7 @@ public class SpdyHttpResponseStreamIdHandler extends
protected void encode(ChannelHandlerContext ctx, HttpMessage msg, List<Object> out) throws Exception {
Integer id = ids.poll();
if (id != null && id.intValue() != NO_ID && !msg.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) {
SpdyHttpHeaders.setStreamId(msg, id);
HttpHeaders.setIntHeader(msg, Names.STREAM_ID, id);
}
out.add(ReferenceCountUtil.retain(msg));
@ -56,7 +58,7 @@ public class SpdyHttpResponseStreamIdHandler extends
if (!contains) {
ids.add(NO_ID);
} else {
ids.add(SpdyHttpHeaders.getStreamId((HttpMessage) msg));
ids.add(HttpHeaders.getIntHeader((HttpMessage) msg, Names.STREAM_ID));
}
} else if (msg instanceof SpdyRstStreamFrame) {
ids.remove(((SpdyRstStreamFrame) msg).getStreamId());

View File

@ -15,6 +15,7 @@
*/
package io.netty.handler.codec.http;
import io.netty.handler.codec.AsciiString;
import org.junit.Test;
import java.util.List;
@ -50,9 +51,9 @@ public class HttpHeadersTest {
@Test
public void testEquansIgnoreCase() {
assertThat(HttpHeaders.equalsIgnoreCase(null, null), is(true));
assertThat(HttpHeaders.equalsIgnoreCase(null, "foo"), is(false));
assertThat(HttpHeaders.equalsIgnoreCase("bar", null), is(false));
assertThat(HttpHeaders.equalsIgnoreCase("FoO", "fOo"), is(true));
assertThat(AsciiString.equalsIgnoreCase(null, null), is(true));
assertThat(AsciiString.equalsIgnoreCase(null, "foo"), is(false));
assertThat(AsciiString.equalsIgnoreCase("bar", null), is(false));
assertThat(AsciiString.equalsIgnoreCase("FoO", "fOo"), is(true));
}
}

View File

@ -35,8 +35,12 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
public static final AsciiString EMPTY_STRING = new AsciiString("");
/** XXX: Make sure that this method and {@link #hashCode()} uses the same hashing algorithm */
static int hashCode(CharSequence value) {
/**
* Returns the case-insensitive hash code of the specified string. Note that this method uses the same hashing
* algorithm with {@link #hashCode()} so that you can put both {@link AsciiString}s and arbitrary
* {@link CharSequence}s into the same {@link TextHeaders}.
*/
public static int caseInsensitiveHashCode(CharSequence value) {
if (value instanceof AsciiString) {
return value.hashCode();
}
@ -50,6 +54,57 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
return hash;
}
/**
* Returns {@code true} if both {@link CharSequence}'s are equals when ignore the case.
* This only supports 8-bit ASCII.
*/
public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) {
if (a == b) {
return true;
}
if (a instanceof AsciiString) {
AsciiString aa = (AsciiString) a;
return aa.equalsIgnoreCase(b);
}
if (b instanceof AsciiString) {
AsciiString ab = (AsciiString) b;
return ab.equalsIgnoreCase(a);
}
if (a == null || b == null) {
return false;
}
return a.toString().equalsIgnoreCase(b.toString());
}
/**
* Returns {@code true} if both {@link CharSequence}'s are equals. This only supports 8-bit ASCII.
*/
public static boolean equals(CharSequence a, CharSequence b) {
if (a == b) {
return true;
}
if (a instanceof AsciiString) {
AsciiString aa = (AsciiString) a;
return aa.equals(b);
}
if (b instanceof AsciiString) {
AsciiString ab = (AsciiString) b;
return ab.equals(a);
}
if (a == null || b == null) {
return false;
}
return a.equals(b);
}
private final byte[] value;
private String string;
private int hash;

View File

@ -19,6 +19,7 @@ package io.netty.handler.codec;
import io.netty.util.internal.PlatformDependent;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -59,7 +60,7 @@ public class DefaultTextHeaders implements TextHeaders {
}
protected int hashCode(CharSequence name) {
return AsciiString.hashCode(name);
return AsciiString.caseInsensitiveHashCode(name);
}
protected CharSequence convertName(CharSequence name) {
@ -376,6 +377,20 @@ public class DefaultTextHeaders implements TextHeaders {
return v.toString();
}
@Override
public int getInt(CharSequence name) {
CharSequence v = getUnconverted(name);
if (v == null) {
throw new NoSuchElementException(String.valueOf(name));
}
if (v instanceof AsciiString) {
return ((AsciiString) v).parseInt();
} else {
return Integer.parseInt(v.toString());
}
}
@Override
public int getInt(CharSequence name, int defaultValue) {
CharSequence v = getUnconverted(name);
@ -394,6 +409,20 @@ public class DefaultTextHeaders implements TextHeaders {
}
}
@Override
public long getLong(CharSequence name) {
CharSequence v = getUnconverted(name);
if (v == null) {
throw new NoSuchElementException(String.valueOf(name));
}
if (v instanceof AsciiString) {
return ((AsciiString) v).parseLong();
} else {
return Long.parseLong(v.toString());
}
}
@Override
public long getLong(CharSequence name, long defaultValue) {
CharSequence v = getUnconverted(name);
@ -412,6 +441,16 @@ public class DefaultTextHeaders implements TextHeaders {
}
}
@Override
public long getTimeMillis(CharSequence name) {
CharSequence v = getUnconverted(name);
if (v == null) {
throw new NoSuchElementException(String.valueOf(name));
}
return HttpHeaderDateFormat.get().parse(v.toString());
}
@Override
public long getTimeMillis(CharSequence name, long defaultValue) {
CharSequence v = getUnconverted(name);
@ -786,6 +825,20 @@ public class DefaultTextHeaders implements TextHeaders {
dateFormat3.setTimeZone(tz);
}
long parse(String text) {
Date date = dateFormat1.parse(text, parsePos);
if (date == null) {
date = dateFormat2.parse(text, parsePos);
}
if (date == null) {
date = dateFormat3.parse(text, parsePos);
}
if (date == null) {
PlatformDependent.throwException(new ParseException(text, 0));
}
return date.getTime();
}
long parse(String text, long defaultValue) {
Date date = dateFormat1.parse(text, parsePos);
if (date == null) {

View File

@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
public class EmptyTextHeaders implements TextHeaders {
@ -36,16 +37,31 @@ public class EmptyTextHeaders implements TextHeaders {
return defaultValue;
}
@Override
public int getInt(CharSequence name) {
throw new NoSuchElementException(String.valueOf(name));
}
@Override
public int getInt(CharSequence name, int defaultValue) {
return defaultValue;
}
@Override
public long getLong(CharSequence name) {
throw new NoSuchElementException(String.valueOf(name));
}
@Override
public long getLong(CharSequence name, long defaultValue) {
return defaultValue;
}
@Override
public long getTimeMillis(CharSequence name) {
throw new NoSuchElementException(String.valueOf(name));
}
@Override
public long getTimeMillis(CharSequence name, long defaultValue) {
return defaultValue;

View File

@ -41,8 +41,11 @@ public interface TextHeaders extends Iterable<Map.Entry<String, String>> {
String get(CharSequence name);
String get(CharSequence name, String defaultValue);
int getInt(CharSequence name);
int getInt(CharSequence name, int defaultValue);
long getLong(CharSequence name);
long getLong(CharSequence name, long defaultValue);
long getTimeMillis(CharSequence name);
long getTimeMillis(CharSequence name, long defaultValue);
/**

View File

@ -18,8 +18,10 @@ package io.netty.example.spdy.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.spdy.SpdyHttpHeaders;
import io.netty.handler.codec.spdy.SpdyHttpHeaders.Names;
/**
* Adds a unique client stream ID to the SPDY header. Client stream IDs MUST be odd.
@ -37,7 +39,7 @@ public class SpdyClientStreamIdHandler extends ChannelOutboundHandlerAdapter {
if (acceptOutboundMessage(msg)) {
HttpMessage httpMsg = (HttpMessage) msg;
if (!httpMsg.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) {
SpdyHttpHeaders.setStreamId(httpMsg, currentStreamId);
HttpHeaders.setIntHeader(httpMsg, Names.STREAM_ID, currentStreamId);
// Client stream IDs are always odd
currentStreamId += 2;
}