Backport HttpHeaders / SpdyHeaders from Netty 4.
This commit is contained in:
parent
f739579339
commit
2e5cbeabc4
@ -184,12 +184,12 @@ class HttpTunnelingClientSocketChannel extends AbstractChannel
|
||||
final HttpRequest req = new DefaultHttpRequest(
|
||||
HttpVersion.HTTP_1_1, HttpMethod.POST, serverPath);
|
||||
if (serverName != null) {
|
||||
req.setHeader(HttpHeaders.Names.HOST, serverName);
|
||||
req.headers().set(HttpHeaders.Names.HOST, serverName);
|
||||
}
|
||||
req.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
|
||||
req.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
|
||||
req.setHeader(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY);
|
||||
req.setHeader(HttpHeaders.Names.USER_AGENT, HttpTunnelingClientSocketChannel.class.getName());
|
||||
req.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
|
||||
req.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
|
||||
req.headers().set(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, HttpHeaders.Values.BINARY);
|
||||
req.headers().set(HttpHeaders.Names.USER_AGENT, HttpTunnelingClientSocketChannel.class.getName());
|
||||
|
||||
if (sslHandshakeFuture == null) {
|
||||
realChannel.write(req);
|
||||
|
@ -131,7 +131,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
|
||||
}
|
||||
|
||||
// Cache Validation
|
||||
String ifModifiedSince = request.getHeader(IF_MODIFIED_SINCE);
|
||||
String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
|
||||
if (ifModifiedSince != null && ifModifiedSince.length() != 0) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
|
||||
Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
|
||||
@ -239,7 +239,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
|
||||
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.setContent(ChannelBuffers.copiedBuffer(
|
||||
"Failure: " + status.toString() + "\r\n",
|
||||
CharsetUtil.UTF_8));
|
||||
@ -273,7 +273,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
|
||||
dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
|
||||
|
||||
Calendar time = new GregorianCalendar();
|
||||
response.setHeader(DATE, dateFormatter.format(time.getTime()));
|
||||
response.headers().set(DATE, dateFormatter.format(time.getTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -290,13 +290,13 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
// Date header
|
||||
Calendar time = new GregorianCalendar();
|
||||
response.setHeader(DATE, dateFormatter.format(time.getTime()));
|
||||
response.headers().set(DATE, dateFormatter.format(time.getTime()));
|
||||
|
||||
// Add cache headers
|
||||
time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
|
||||
response.setHeader(EXPIRES, dateFormatter.format(time.getTime()));
|
||||
response.setHeader(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
|
||||
response.setHeader(
|
||||
response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));
|
||||
response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
|
||||
response.headers().set(
|
||||
LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
|
||||
}
|
||||
|
||||
@ -310,7 +310,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler {
|
||||
*/
|
||||
private static void setContentTypeHeader(HttpResponse response, File file) {
|
||||
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
|
||||
response.setHeader(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
|
||||
response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,15 +51,15 @@ public class HttpHelloWorldServerHandler extends SimpleChannelUpstreamHandler {
|
||||
boolean keepAlive = isKeepAlive(req);
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setContent(ChannelBuffers.wrappedBuffer(CONTENT));
|
||||
response.setHeader(CONTENT_TYPE, "text/plain");
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
response.headers().set(CONTENT_TYPE, "text/plain");
|
||||
response.headers().set(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ChannelFuture f = Channels.future(ch);
|
||||
f.addListener(ChannelFutureListener.CLOSE);
|
||||
Channels.write(ctx, f, response);
|
||||
} else {
|
||||
response.setHeader(CONNECTION, Values.KEEP_ALIVE);
|
||||
response.headers().set(CONNECTION, Values.KEEP_ALIVE);
|
||||
Channels.write(ctx, Channels.future(ch), response);
|
||||
}
|
||||
}
|
||||
|
@ -84,15 +84,15 @@ public class HttpSnoopClient {
|
||||
// Prepare the HTTP request.
|
||||
HttpRequest request = new DefaultHttpRequest(
|
||||
HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
|
||||
request.setHeader(HttpHeaders.Names.HOST, host);
|
||||
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
|
||||
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
|
||||
request.headers().set(HttpHeaders.Names.HOST, host);
|
||||
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
|
||||
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
|
||||
|
||||
// Set some example cookies.
|
||||
CookieEncoder httpCookieEncoder = new CookieEncoder(false);
|
||||
httpCookieEncoder.addCookie("my-cookie", "foo");
|
||||
httpCookieEncoder.addCookie("another-cookie", "bar");
|
||||
request.setHeader(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
|
||||
request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
|
||||
|
||||
// Send the HTTP request.
|
||||
channel.write(request);
|
||||
|
@ -36,9 +36,9 @@ public class HttpSnoopClientHandler extends SimpleChannelUpstreamHandler {
|
||||
System.out.println("VERSION: " + response.getProtocolVersion());
|
||||
System.out.println();
|
||||
|
||||
if (!response.getHeaderNames().isEmpty()) {
|
||||
for (String name: response.getHeaderNames()) {
|
||||
for (String value: response.getHeaders(name)) {
|
||||
if (!response.headers().names().isEmpty()) {
|
||||
for (String name: response.headers().names()) {
|
||||
for (String value: response.headers().getAll(name)) {
|
||||
System.out.println("HEADER: " + name + " = " + value);
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
|
||||
buf.append("HOSTNAME: " + getHost(request, "unknown") + "\r\n");
|
||||
buf.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n");
|
||||
|
||||
for (Map.Entry<String, String> h: request.getHeaders()) {
|
||||
for (Map.Entry<String, String> h: request.headers()) {
|
||||
buf.append("HEADER: " + h.getKey() + " = " + h.getValue() + "\r\n");
|
||||
}
|
||||
buf.append("\r\n");
|
||||
@ -103,10 +103,10 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
|
||||
buf.append("END OF CONTENT\r\n");
|
||||
|
||||
HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
|
||||
if (!trailer.getHeaderNames().isEmpty()) {
|
||||
if (!trailer.trailingHeaders().names().isEmpty()) {
|
||||
buf.append("\r\n");
|
||||
for (String name: trailer.getHeaderNames()) {
|
||||
for (String value: trailer.getHeaders(name)) {
|
||||
for (String name: trailer.trailingHeaders().names()) {
|
||||
for (String value: trailer.trailingHeaders().getAll(name)) {
|
||||
buf.append("TRAILING HEADER: " + name + " = " + value + "\r\n");
|
||||
}
|
||||
}
|
||||
@ -127,18 +127,18 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setContent(ChannelBuffers.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
|
||||
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
response.headers().set(CONTENT_LENGTH, response.getContent().readableBytes());
|
||||
// Add keep alive header as per:
|
||||
// - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
|
||||
response.setHeader(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Encode the cookie.
|
||||
String cookieString = request.getHeader(COOKIE);
|
||||
String cookieString = request.headers().get(COOKIE);
|
||||
if (cookieString != null) {
|
||||
CookieDecoder cookieDecoder = new CookieDecoder();
|
||||
Set<Cookie> cookies = cookieDecoder.decode(cookieString);
|
||||
@ -147,16 +147,16 @@ public class HttpSnoopServerHandler extends SimpleChannelUpstreamHandler {
|
||||
CookieEncoder cookieEncoder = new CookieEncoder(true);
|
||||
for (Cookie cookie : cookies) {
|
||||
cookieEncoder.addCookie(cookie);
|
||||
response.addHeader(SET_COOKIE, cookieEncoder.encode());
|
||||
response.headers().add(SET_COOKIE, cookieEncoder.encode());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Browser sent no cookie. Add some.
|
||||
CookieEncoder cookieEncoder = new CookieEncoder(true);
|
||||
cookieEncoder.addCookie("key1", "value1");
|
||||
response.addHeader(SET_COOKIE, cookieEncoder.encode());
|
||||
response.headers().add(SET_COOKIE, cookieEncoder.encode());
|
||||
cookieEncoder.addCookie("key2", "value2");
|
||||
response.addHeader(SET_COOKIE, cookieEncoder.encode());
|
||||
response.headers().add(SET_COOKIE, cookieEncoder.encode());
|
||||
}
|
||||
|
||||
// Write the response.
|
||||
|
@ -187,27 +187,27 @@ public class HttpUploadClient {
|
||||
|
||||
HttpRequest request = new DefaultHttpRequest(
|
||||
HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
|
||||
request.setHeader(HttpHeaders.Names.HOST, host);
|
||||
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
|
||||
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ',' +
|
||||
request.headers().set(HttpHeaders.Names.HOST, host);
|
||||
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
|
||||
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ',' +
|
||||
HttpHeaders.Values.DEFLATE);
|
||||
|
||||
request.setHeader(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
|
||||
request.setHeader(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
|
||||
request.setHeader(HttpHeaders.Names.REFERER, uriSimple.toString());
|
||||
request.setHeader(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
|
||||
request.setHeader(HttpHeaders.Names.ACCEPT,
|
||||
request.headers().set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
|
||||
request.headers().set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
|
||||
request.headers().set(HttpHeaders.Names.REFERER, uriSimple.toString());
|
||||
request.headers().set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
|
||||
request.headers().set(HttpHeaders.Names.ACCEPT,
|
||||
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
//connection will not close but needed
|
||||
// request.setHeader("Connection","keep-alive");
|
||||
// request.setHeader("Keep-Alive","300");
|
||||
// request.headers().set("Connection","keep-alive");
|
||||
// request.headers().set("Keep-Alive","300");
|
||||
|
||||
CookieEncoder httpCookieEncoder = new CookieEncoder(false);
|
||||
httpCookieEncoder.addCookie("my-cookie", "foo");
|
||||
httpCookieEncoder.addCookie("another-cookie", "bar");
|
||||
request.setHeader(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
|
||||
request.headers().set(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode());
|
||||
|
||||
List<Entry<String, String>> headers = request.getHeaders();
|
||||
List<Entry<String, String>> headers = request.headers().entries();
|
||||
// send request
|
||||
channel.write(request);
|
||||
|
||||
@ -256,7 +256,7 @@ public class HttpUploadClient {
|
||||
|
||||
// it is legal to add directly header or cookie into the request until finalize
|
||||
for (Entry<String, String> entry : headers) {
|
||||
request.setHeader(entry.getKey(), entry.getValue());
|
||||
request.headers().set(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// add Form attribute
|
||||
@ -342,7 +342,7 @@ public class HttpUploadClient {
|
||||
|
||||
// it is legal to add directly header or cookie into the request until finalize
|
||||
for (Entry<String, String> entry : headers) {
|
||||
request.setHeader(entry.getKey(), entry.getValue());
|
||||
request.headers().set(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// add Form attribute from previous request in formpost()
|
||||
|
@ -41,9 +41,9 @@ public class HttpUploadClientHandler extends SimpleChannelUpstreamHandler {
|
||||
logger.info("STATUS: " + response.getStatus());
|
||||
logger.info("VERSION: " + response.getProtocolVersion());
|
||||
|
||||
if (!response.getHeaderNames().isEmpty()) {
|
||||
for (String name: response.getHeaderNames()) {
|
||||
for (String value: response.getHeaders(name)) {
|
||||
if (!response.headers().names().isEmpty()) {
|
||||
for (String name: response.headers().names()) {
|
||||
for (String value: response.headers().getAll(name)) {
|
||||
logger.info("HEADER: " + name + " = " + value);
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +123,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
|
||||
responseContent.append("\r\n\r\n");
|
||||
|
||||
// new method
|
||||
List<Entry<String, String>> headers = request.getHeaders();
|
||||
for (Entry<String, String> entry: headers) {
|
||||
for (Entry<String, String> entry: request.headers()) {
|
||||
responseContent.append("HEADER: " + entry.getKey() + '=' +
|
||||
entry.getValue() + "\r\n");
|
||||
}
|
||||
@ -132,7 +131,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
// new method
|
||||
Set<Cookie> cookies;
|
||||
String value = request.getHeader(HttpHeaders.Names.COOKIE);
|
||||
String value = request.headers().get(HttpHeaders.Names.COOKIE);
|
||||
if (value == null) {
|
||||
cookies = Collections.emptySet();
|
||||
} else {
|
||||
@ -320,27 +319,27 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
// Decide whether to close the connection or not.
|
||||
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request
|
||||
.getHeader(HttpHeaders.Names.CONNECTION)) ||
|
||||
.headers().get(HttpHeaders.Names.CONNECTION)) ||
|
||||
request.getProtocolVersion().equals(HttpVersion.HTTP_1_0) &&
|
||||
!HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request
|
||||
.getHeader(HttpHeaders.Names.CONNECTION));
|
||||
.headers().get(HttpHeaders.Names.CONNECTION));
|
||||
|
||||
// Build the response object.
|
||||
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.OK);
|
||||
response.setContent(buf);
|
||||
response.setHeader(HttpHeaders.Names.CONTENT_TYPE,
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
|
||||
"text/plain; charset=UTF-8");
|
||||
|
||||
if (!close) {
|
||||
// There's no need to add 'Content-Length' header
|
||||
// if this is the last response.
|
||||
response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String
|
||||
.valueOf(buf.readableBytes()));
|
||||
}
|
||||
|
||||
Set<Cookie> cookies;
|
||||
String value = request.getHeader(HttpHeaders.Names.COOKIE);
|
||||
String value = request.headers().get(HttpHeaders.Names.COOKIE);
|
||||
if (value == null) {
|
||||
cookies = Collections.emptySet();
|
||||
} else {
|
||||
@ -352,7 +351,7 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
|
||||
CookieEncoder cookieEncoder = new CookieEncoder(true);
|
||||
for (Cookie cookie: cookies) {
|
||||
cookieEncoder.addCookie(cookie);
|
||||
response.addHeader(HttpHeaders.Names.SET_COOKIE, cookieEncoder
|
||||
response.headers().add(HttpHeaders.Names.SET_COOKIE, cookieEncoder
|
||||
.encode());
|
||||
cookieEncoder = new CookieEncoder(true);
|
||||
}
|
||||
@ -468,9 +467,9 @@ public class HttpUploadServerHandler extends SimpleChannelUpstreamHandler {
|
||||
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.OK);
|
||||
response.setContent(buf);
|
||||
response.setHeader(HttpHeaders.Names.CONTENT_TYPE,
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
|
||||
"text/html; charset=UTF-8");
|
||||
response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(buf
|
||||
.readableBytes()));
|
||||
// Write the response.
|
||||
e.getChannel().write(response);
|
||||
|
@ -130,6 +130,6 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
|
||||
}
|
||||
|
||||
private static String getWebSocketLocation(HttpRequest req) {
|
||||
return "ws://" + req.getHeader(HttpHeaders.Names.HOST);
|
||||
return "ws://" + req.headers().get(HttpHeaders.Names.HOST);
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
|
||||
|
||||
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
setContentLength(res, content.readableBytes());
|
||||
|
||||
res.setContent(content);
|
||||
@ -145,6 +145,6 @@ public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
|
||||
}
|
||||
|
||||
private static String getWebSocketLocation(HttpRequest req) {
|
||||
return "ws://" + req.getHeader(HOST) + WEBSOCKET_PATH;
|
||||
return "ws://" + req.headers().get(HOST) + WEBSOCKET_PATH;
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
|
||||
|
||||
ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
|
||||
|
||||
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
setContentLength(res, content.readableBytes());
|
||||
|
||||
res.setContent(content);
|
||||
@ -147,6 +147,6 @@ public class WebSocketSslServerHandler extends SimpleChannelUpstreamHandler {
|
||||
}
|
||||
|
||||
private static String getWebSocketLocation(HttpRequest req) {
|
||||
return "wss://" + req.getHeader(HOST) + WEBSOCKET_PATH;
|
||||
return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH;
|
||||
}
|
||||
}
|
||||
|
@ -15,73 +15,73 @@
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.http;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
|
||||
/**
|
||||
* The default {@link HttpChunkTrailer} implementation.
|
||||
*/
|
||||
public class DefaultHttpChunkTrailer implements HttpChunkTrailer {
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders() {
|
||||
@Override
|
||||
void validateHeaderName(String name) {
|
||||
super.validateHeaderName(name);
|
||||
if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) ||
|
||||
name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) ||
|
||||
name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) {
|
||||
throw new IllegalArgumentException(
|
||||
"prohibited trailing header: " + name);
|
||||
}
|
||||
}
|
||||
};
|
||||
private final HttpHeaders trailingHeaders = new TrailingHeaders(true);
|
||||
|
||||
public boolean isLast() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
trailingHeaders.add(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
trailingHeaders.set(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
trailingHeaders.set(name, values);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeHeader(final String name) {
|
||||
headers.removeHeader(name);
|
||||
trailingHeaders.remove(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void clearHeaders() {
|
||||
headers.clearHeaders();
|
||||
trailingHeaders.clear();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getHeader(final String name) {
|
||||
return headers.getHeader(name);
|
||||
return trailingHeaders.get(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<String> getHeaders(final String name) {
|
||||
return headers.getHeaders(name);
|
||||
return trailingHeaders.getAll(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<Map.Entry<String, String>> getHeaders() {
|
||||
return headers.getHeaders();
|
||||
return trailingHeaders.entries();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean containsHeader(final String name) {
|
||||
return headers.containsHeader(name);
|
||||
return trailingHeaders.contains(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Set<String> getHeaderNames() {
|
||||
return headers.getHeaderNames();
|
||||
return trailingHeaders.names();
|
||||
}
|
||||
|
||||
public ChannelBuffer getContent() {
|
||||
@ -91,4 +91,76 @@ public class DefaultHttpChunkTrailer implements HttpChunkTrailer {
|
||||
public void setContent(ChannelBuffer content) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
public HttpHeaders trailingHeaders() {
|
||||
return trailingHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder(super.toString());
|
||||
buf.append(StringUtil.NEWLINE);
|
||||
appendHeaders(buf);
|
||||
|
||||
// Remove the last newline.
|
||||
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: trailingHeaders()) {
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
buf.append(e.getValue());
|
||||
buf.append(StringUtil.NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TrailingHeaders extends DefaultHttpHeaders {
|
||||
|
||||
TrailingHeaders(boolean validateHeaders) {
|
||||
super(validateHeaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(String name, Object value) {
|
||||
if (validate) {
|
||||
validateName(name);
|
||||
}
|
||||
return super.add(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(String name, Iterable<?> values) {
|
||||
if (validate) {
|
||||
validateName(name);
|
||||
}
|
||||
return super.add(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(String name, Iterable<?> values) {
|
||||
if (validate) {
|
||||
validateName(name);
|
||||
}
|
||||
return super.set(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(String name, Object value) {
|
||||
if (validate) {
|
||||
validateName(name);
|
||||
}
|
||||
return super.set(name, value);
|
||||
}
|
||||
|
||||
private static void validateName(String name) {
|
||||
if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) ||
|
||||
name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) ||
|
||||
name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) {
|
||||
throw new IllegalArgumentException(
|
||||
"prohibited trailing header: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,488 @@
|
||||
/*
|
||||
* Copyright 2012 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.http;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static final Set<String> KNOWN_NAMES = createSet(Names.class);
|
||||
private static final Set<String> KNOWN_VALUES = createSet(Values.class);
|
||||
|
||||
private static Set<String> createSet(Class<?> clazz) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
|
||||
for (Field f: fields) {
|
||||
int m = f.getModifiers();
|
||||
if (Modifier.isPublic(m) && Modifier.isStatic(m) && Modifier.isFinal(m)
|
||||
&& f.getType().isAssignableFrom(String.class)) {
|
||||
try {
|
||||
set.add((String) f.get(null));
|
||||
} catch (Throwable cause) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
private static int hash(String name, boolean validate) {
|
||||
int h = 0;
|
||||
for (int i = name.length() - 1; i >= 0; i --) {
|
||||
char c = name.charAt(i);
|
||||
if (validate) {
|
||||
valideHeaderNameChar(c);
|
||||
}
|
||||
c = toLowerCase(c);
|
||||
h = 31 * h + c;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
return h;
|
||||
} else if (h == Integer.MIN_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return -h;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean eq(String name1, String name2) {
|
||||
if (name1 == name2) {
|
||||
// check for object equality as the user may reuse our static fields in HttpHeaders.Names
|
||||
return true;
|
||||
}
|
||||
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 (toLowerCase(c1) != toLowerCase(c2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static char toLowerCase(char c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 32;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private static int index(int hash) {
|
||||
return hash % BUCKET_SIZE;
|
||||
}
|
||||
|
||||
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
|
||||
private final HeaderEntry head = new HeaderEntry(-1, null, null);
|
||||
protected final boolean validate;
|
||||
|
||||
public DefaultHttpHeaders() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public DefaultHttpHeaders(boolean validate) {
|
||||
head.before = head.after = head;
|
||||
this.validate = validate;
|
||||
}
|
||||
|
||||
void validateHeaderValue0(String headerValue) {
|
||||
if (KNOWN_VALUES.contains(headerValue)) {
|
||||
return;
|
||||
}
|
||||
validateHeaderValue(headerValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(final String name, final Object value) {
|
||||
String strVal = toString(value);
|
||||
boolean validateName = false;
|
||||
if (validate) {
|
||||
validateHeaderValue0(strVal);
|
||||
validateName = !KNOWN_NAMES.contains(name);
|
||||
}
|
||||
|
||||
int h = hash(name, validateName);
|
||||
int i = index(h);
|
||||
add0(h, i, name, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(String name, Iterable<?> values) {
|
||||
boolean validateName = false;
|
||||
if (validate) {
|
||||
validateName = !KNOWN_NAMES.contains(name);
|
||||
}
|
||||
|
||||
int h = hash(name, validateName);
|
||||
int i = index(h);
|
||||
for (Object v: values) {
|
||||
String vstr = toString(v);
|
||||
if (validate) {
|
||||
validateHeaderValue0(vstr);
|
||||
}
|
||||
add0(h, i, name, vstr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void add0(int h, int i, final String name, final String value) {
|
||||
// Update the hash table.
|
||||
HeaderEntry e = entries[i];
|
||||
HeaderEntry newEntry;
|
||||
entries[i] = newEntry = new HeaderEntry(h, name, value);
|
||||
newEntry.next = e;
|
||||
|
||||
// Update the linked list.
|
||||
newEntry.addBefore(head);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders remove(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
int h = hash(name, false);
|
||||
int i = index(h);
|
||||
remove0(h, i, name);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void remove0(int h, int i, String name) {
|
||||
HeaderEntry e = entries[i];
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
e.remove();
|
||||
HeaderEntry next = e.next;
|
||||
if (next != null) {
|
||||
entries[i] = next;
|
||||
e = next;
|
||||
} else {
|
||||
entries[i] = null;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
HeaderEntry next = e.next;
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
if (next.hash == h && eq(name, next.key)) {
|
||||
e.next = next.next;
|
||||
next.remove();
|
||||
} else {
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(final String name, final Object value) {
|
||||
String strVal = toString(value);
|
||||
boolean validateName = false;
|
||||
if (validate) {
|
||||
validateHeaderValue0(strVal);
|
||||
validateName = !KNOWN_NAMES.contains(name);
|
||||
}
|
||||
|
||||
int h = hash(name, validateName);
|
||||
int i = index(h);
|
||||
remove0(h, i, name);
|
||||
add0(h, i, name, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
boolean validateName = false;
|
||||
if (validate) {
|
||||
validateName = !KNOWN_NAMES.contains(name);
|
||||
}
|
||||
|
||||
int h = hash(name, validateName);
|
||||
int i = index(h);
|
||||
|
||||
remove0(h, i, name);
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
String strVal = toString(v);
|
||||
if (validate) {
|
||||
validateHeaderValue0(strVal);
|
||||
}
|
||||
add0(h, i, name, strVal);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders clear() {
|
||||
Arrays.fill(entries, null);
|
||||
head.before = head.after = head;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(final String name) {
|
||||
return get(name, false);
|
||||
}
|
||||
|
||||
private String get(final String name, boolean last) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name, false);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
String value = null;
|
||||
// loop until the first header was found
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
value = e.value;
|
||||
if (last) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
e = e.next;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
LinkedList<String> values = new LinkedList<String>();
|
||||
|
||||
int h = hash(name, false);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
values.addFirst(e.value);
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
List<Map.Entry<String, String>> all =
|
||||
new LinkedList<Map.Entry<String, String>>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
all.add(e);
|
||||
e = e.after;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return new HeaderIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return get(name, true) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return head == head.after;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name, String value, boolean ignoreCaseValue) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name, false);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
if (ignoreCaseValue) {
|
||||
if (e.value.equalsIgnoreCase(value)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (e.value.equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
|
||||
Set<String> names = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
names.add(e.key);
|
||||
e = e.after;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return value.toString();
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return HttpHeaderDateFormat.get().format((Date) value);
|
||||
}
|
||||
if (value instanceof Calendar) {
|
||||
return HttpHeaderDateFormat.get().format(((Calendar) value).getTime());
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private final class HeaderIterator implements Iterator<Map.Entry<String, String>> {
|
||||
|
||||
private HeaderEntry current = head;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current.after != head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<String, String> next() {
|
||||
current = current.after;
|
||||
|
||||
if (current == head) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private final class HeaderEntry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
String value;
|
||||
HeaderEntry next;
|
||||
HeaderEntry before, after;
|
||||
|
||||
HeaderEntry(int hash, String key, String value) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
before.after = after;
|
||||
after.before = before;
|
||||
}
|
||||
|
||||
void addBefore(HeaderEntry e) {
|
||||
after = e;
|
||||
before = e.before;
|
||||
before.after = this;
|
||||
after.before = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setValue(String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
if (validate) {
|
||||
validateHeaderValue0(value);
|
||||
}
|
||||
String oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + '=' + value;
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ import java.util.Set;
|
||||
*/
|
||||
public class DefaultHttpMessage implements HttpMessage {
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
private final HttpHeaders headers = new DefaultHttpHeaders(true);
|
||||
private HttpVersion version;
|
||||
private ChannelBuffer content = ChannelBuffers.EMPTY_BUFFER;
|
||||
private boolean chunked;
|
||||
@ -40,30 +40,28 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
setProtocolVersion(version);
|
||||
}
|
||||
|
||||
public HttpHeaders headers() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
headers.add(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
headers.set(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
headers.set(name, values);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeHeader(final String name) {
|
||||
headers.removeHeader(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public long getContentLength() {
|
||||
return HttpHeaders.getContentLength(this);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public long getContentLength(long defaultValue) {
|
||||
return HttpHeaders.getContentLength(this, defaultValue);
|
||||
headers.remove(name);
|
||||
}
|
||||
|
||||
public boolean isChunked() {
|
||||
@ -82,12 +80,8 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isKeepAlive() {
|
||||
return HttpHeaders.isKeepAlive(this);
|
||||
}
|
||||
|
||||
public void clearHeaders() {
|
||||
headers.clearHeaders();
|
||||
headers.clear();
|
||||
}
|
||||
|
||||
public void setContent(ChannelBuffer content) {
|
||||
@ -101,24 +95,29 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getHeader(final String name) {
|
||||
return headers.getHeader(name);
|
||||
return headers.get(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<String> getHeaders(final String name) {
|
||||
return headers.getHeaders(name);
|
||||
return headers.getAll(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<Map.Entry<String, String>> getHeaders() {
|
||||
return headers.getHeaders();
|
||||
return headers.entries();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean containsHeader(final String name) {
|
||||
return headers.containsHeader(name);
|
||||
return headers.contains(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Set<String> getHeaderNames() {
|
||||
return headers.getHeaderNames();
|
||||
return headers.names();
|
||||
}
|
||||
|
||||
public HttpVersion getProtocolVersion() {
|
||||
@ -156,7 +155,7 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
}
|
||||
|
||||
void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: getHeaders()) {
|
||||
for (Map.Entry<String, String> e: headers()) {
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
buf.append(e.getValue());
|
||||
|
@ -51,45 +51,59 @@ public interface HttpChunk {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addHeader(String name, Object value) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void clearHeaders() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean containsHeader(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getHeader(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Set<String> getHeaderNames() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<String> getHeaders(String name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<Map.Entry<String, String>> getHeaders() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeHeader(String name) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(String name, Object value) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(String name, Iterable<?> values) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
public HttpHeaders trailingHeaders() {
|
||||
return HttpHeaders.EMPTY_HEADERS;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -180,13 +180,13 @@ public class HttpChunkAggregator extends SimpleChannelUpstreamHandler implements
|
||||
// Merge trailing headers into the message.
|
||||
if (chunk instanceof HttpChunkTrailer) {
|
||||
HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
|
||||
for (Entry<String, String> header: trailer.getHeaders()) {
|
||||
currentMessage.setHeader(header.getKey(), header.getValue());
|
||||
for (Entry<String, String> header: trailer.trailingHeaders()) {
|
||||
currentMessage.headers().set(header.getKey(), header.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Set the 'Content-Length' header.
|
||||
currentMessage.setHeader(
|
||||
currentMessage.headers().set(
|
||||
HttpHeaders.Names.CONTENT_LENGTH,
|
||||
String.valueOf(content.readableBytes()));
|
||||
|
||||
|
@ -30,68 +30,57 @@ public interface HttpChunkTrailer extends HttpChunk {
|
||||
boolean isLast();
|
||||
|
||||
/**
|
||||
* Returns the trailing header value with the specified header name.
|
||||
* If there are more than one trailing header value for the specified
|
||||
* header name, the first value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
String getHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the trailing header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
List<String> getHeaders(String name);
|
||||
|
||||
/**
|
||||
* Returns the all header names and values that this trailer contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this trailer.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
List<Map.Entry<String, String>> getHeaders();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a trailing header with
|
||||
* the specified header name.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
boolean containsHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of all trailing header names that this trailer
|
||||
* contains.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
Set<String> getHeaderNames();
|
||||
|
||||
/**
|
||||
* Adds a new trailing header with the specified name and value.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new trailing header with the specified name and value.
|
||||
* If there is an existing trailing header with the same name, the existing
|
||||
* one is removed.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new trailing header with the specified name and values.
|
||||
* If there is an existing trailing header with the same name, the existing
|
||||
* one is removed.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the trailing header with the specified name.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
void removeHeader(String name);
|
||||
|
||||
/**
|
||||
* Removes all trailing headers from this trailer.
|
||||
* @deprecated Use {@link HttpChunkTrailer#trailingHeaders()} instead.
|
||||
*/
|
||||
void clearHeaders();
|
||||
|
||||
/**
|
||||
* Returns the trialing headers of this trailer.
|
||||
*/
|
||||
HttpHeaders trailingHeaders();
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ final class HttpCodecUtil {
|
||||
}
|
||||
|
||||
static boolean isTransferEncodingChunked(HttpMessage m) {
|
||||
List<String> chunked = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
List<String> chunked = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
if (chunked.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@ -120,7 +120,7 @@ final class HttpCodecUtil {
|
||||
}
|
||||
|
||||
static void removeTransferEncodingChunked(HttpMessage m) {
|
||||
List<String> values = m.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
List<String> values = m.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
if (values.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -132,14 +132,14 @@ final class HttpCodecUtil {
|
||||
}
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
m.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
m.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
} else {
|
||||
m.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, values);
|
||||
m.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, values);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isContentLengthSet(HttpMessage m) {
|
||||
List<String> contentLength = m.getHeaders(HttpHeaders.Names.CONTENT_LENGTH);
|
||||
List<String> contentLength = m.headers().getAll(HttpHeaders.Names.CONTENT_LENGTH);
|
||||
return !contentLength.isEmpty();
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ public class HttpContentCompressor extends HttpContentEncoder {
|
||||
@Override
|
||||
protected EncoderEmbedder<ChannelBuffer> newContentEncoder(
|
||||
HttpMessage msg, String acceptEncoding) throws Exception {
|
||||
String contentEncoding = msg.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
String contentEncoding = msg.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
if (contentEncoding != null &&
|
||||
!HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) {
|
||||
// Encoded already.
|
||||
|
@ -68,7 +68,7 @@ public abstract class HttpContentDecoder extends SimpleChannelUpstreamHandler
|
||||
finishDecode();
|
||||
|
||||
// Determine the content encoding.
|
||||
String contentEncoding = m.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
String contentEncoding = m.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
if (contentEncoding != null) {
|
||||
contentEncoding = contentEncoding.trim();
|
||||
} else {
|
||||
@ -83,9 +83,9 @@ public abstract class HttpContentDecoder extends SimpleChannelUpstreamHandler
|
||||
if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) {
|
||||
// Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
|
||||
// as per: http://tools.ietf.org/html/rfc2616#section-14.11
|
||||
m.removeHeader(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
m.headers().remove(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
} else {
|
||||
m.setHeader(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
|
||||
m.headers().set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
|
||||
}
|
||||
|
||||
if (!m.isChunked()) {
|
||||
@ -96,8 +96,8 @@ public abstract class HttpContentDecoder extends SimpleChannelUpstreamHandler
|
||||
|
||||
// Replace the content.
|
||||
m.setContent(content);
|
||||
if (m.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
m.setHeader(
|
||||
if (m.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
m.headers().set(
|
||||
HttpHeaders.Names.CONTENT_LENGTH,
|
||||
Integer.toString(content.readableBytes()));
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public abstract class HttpContentEncoder extends SimpleChannelHandler
|
||||
}
|
||||
|
||||
HttpMessage m = (HttpMessage) msg;
|
||||
String acceptedEncoding = m.getHeader(HttpHeaders.Names.ACCEPT_ENCODING);
|
||||
String acceptedEncoding = m.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
|
||||
if (acceptedEncoding == null) {
|
||||
acceptedEncoding = HttpHeaders.Values.IDENTITY;
|
||||
}
|
||||
@ -100,7 +100,7 @@ public abstract class HttpContentEncoder extends SimpleChannelHandler
|
||||
throw new IllegalStateException("cannot send more responses than requests");
|
||||
}
|
||||
|
||||
String contentEncoding = m.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
String contentEncoding = m.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
|
||||
if (contentEncoding != null &&
|
||||
!HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) {
|
||||
// Content-Encoding is set already and it is not 'identity'.
|
||||
@ -111,7 +111,7 @@ public abstract class HttpContentEncoder extends SimpleChannelHandler
|
||||
if (hasContent && (encoder = newContentEncoder(m, acceptEncoding)) != null) {
|
||||
// Encode the content and remove or replace the existing headers
|
||||
// so that the message looks like a decoded message.
|
||||
m.setHeader(
|
||||
m.headers().set(
|
||||
HttpHeaders.Names.CONTENT_ENCODING,
|
||||
getTargetContentEncoding(acceptEncoding));
|
||||
|
||||
@ -123,8 +123,8 @@ public abstract class HttpContentEncoder extends SimpleChannelHandler
|
||||
|
||||
// Replace the content.
|
||||
m.setContent(content);
|
||||
if (m.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
m.setHeader(
|
||||
if (m.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
m.headers().set(
|
||||
HttpHeaders.Names.CONTENT_LENGTH,
|
||||
Integer.toString(content.readableBytes()));
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,39 +33,33 @@ import org.jboss.netty.buffer.ChannelBuffers;
|
||||
public interface HttpMessage {
|
||||
|
||||
/**
|
||||
* Returns the header value with the specified header name. If there are
|
||||
* more than one header value for the specified header name, the first
|
||||
* value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
String getHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
List<String> getHeaders(String name);
|
||||
|
||||
/**
|
||||
* Returns the all header names and values that this message contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this message.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
List<Map.Entry<String, String>> getHeaders();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a header with the specified
|
||||
* header name.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean containsHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of all header names that this message contains.
|
||||
*/
|
||||
@Deprecated
|
||||
Set<String> getHeaderNames();
|
||||
|
||||
/**
|
||||
@ -78,6 +72,11 @@ public interface HttpMessage {
|
||||
*/
|
||||
void setProtocolVersion(HttpVersion version);
|
||||
|
||||
/**
|
||||
* Returns the headers of this message.
|
||||
*/
|
||||
HttpHeaders headers();
|
||||
|
||||
/**
|
||||
* Returns the content of this message. If there is no content or
|
||||
* {@link #isChunked()} returns {@code true}, an
|
||||
@ -92,44 +91,35 @@ public interface HttpMessage {
|
||||
void setContent(ChannelBuffer content);
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void removeHeader(String name);
|
||||
|
||||
/**
|
||||
* Removes all headers from this message.
|
||||
* @deprecated Use {@link HttpMessage#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void clearHeaders();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link HttpHeaders#getContentLength(HttpMessage)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
long getContentLength();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link HttpHeaders#getContentLength(HttpMessage, long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
long getContentLength(long defaultValue);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if this message does not have any
|
||||
* content but the {@link HttpChunk}s, which is generated by
|
||||
@ -155,10 +145,4 @@ public interface HttpMessage {
|
||||
* this message is {@code "chunked"}.
|
||||
*/
|
||||
void setChunked(boolean chunked);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link HttpHeaders#isKeepAlive(HttpMessage)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean isKeepAlive();
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
// No content is expected.
|
||||
// Remove the headers which are not supposed to be present not
|
||||
// to confuse subsequent handlers.
|
||||
message.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
message.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
return message;
|
||||
}
|
||||
long contentLength = HttpHeaders.getContentLength(message, -1);
|
||||
@ -414,7 +414,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
// - http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html Section 4.4
|
||||
// - https://github.com/netty/netty/issues/222
|
||||
if (code >= 100 && code < 200) {
|
||||
if (code == 101 && !res.containsHeader(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT)) {
|
||||
if (code == 101 && !res.headers().contains(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT)) {
|
||||
// It's Hixie 76 websocket handshake response
|
||||
return false;
|
||||
}
|
||||
@ -486,14 +486,14 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
String name = null;
|
||||
String value = null;
|
||||
if (line.length() != 0) {
|
||||
message.clearHeaders();
|
||||
message.headers().clear();
|
||||
do {
|
||||
char firstChar = line.charAt(0);
|
||||
if (name != null && (firstChar == ' ' || firstChar == '\t')) {
|
||||
value = value + ' ' + line.trim();
|
||||
} else {
|
||||
if (name != null) {
|
||||
message.addHeader(name, value);
|
||||
message.headers().add(name, value);
|
||||
}
|
||||
String[] header = splitHeader(line);
|
||||
name = header[0];
|
||||
@ -505,7 +505,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
|
||||
// Add the last header.
|
||||
if (name != null) {
|
||||
message.addHeader(name, value);
|
||||
message.headers().add(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,7 +538,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
do {
|
||||
char firstChar = line.charAt(0);
|
||||
if (lastHeader != null && (firstChar == ' ' || firstChar == '\t')) {
|
||||
List<String> current = trailer.getHeaders(lastHeader);
|
||||
List<String> current = trailer.trailingHeaders().getAll(lastHeader);
|
||||
if (!current.isEmpty()) {
|
||||
int lastPos = current.size() - 1;
|
||||
String newString = current.get(lastPos) + line.trim();
|
||||
@ -552,7 +552,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
if (!name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) &&
|
||||
!name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) &&
|
||||
!name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) {
|
||||
trailer.addHeader(name, header[1]);
|
||||
trailer.trailingHeaders().add(name, header[1]);
|
||||
}
|
||||
lastHeader = name;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
|
||||
// check if the Transfer-Encoding is set to chunked already.
|
||||
// if not add the header to the message
|
||||
if (!HttpCodecUtil.isTransferEncodingChunked(m)) {
|
||||
m.addHeader(Names.TRANSFER_ENCODING, Values.CHUNKED);
|
||||
m.headers().add(Names.TRANSFER_ENCODING, Values.CHUNKED);
|
||||
}
|
||||
contentMustBeEmpty = true;
|
||||
transferEncodingChunked = true;
|
||||
@ -141,7 +141,7 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
|
||||
|
||||
private static void encodeHeaders(ChannelBuffer buf, HttpMessage message) {
|
||||
try {
|
||||
for (Map.Entry<String, String> h: message.getHeaders()) {
|
||||
for (Map.Entry<String, String> h: message.headers()) {
|
||||
encodeHeader(buf, h.getKey(), h.getValue());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
@ -151,7 +151,7 @@ public abstract class HttpMessageEncoder extends OneToOneEncoder {
|
||||
|
||||
private static void encodeTrailingHeaders(ChannelBuffer buf, HttpChunkTrailer trailer) {
|
||||
try {
|
||||
for (Map.Entry<String, String> h: trailer.getHeaders()) {
|
||||
for (Map.Entry<String, String> h: trailer.trailingHeaders()) {
|
||||
encodeHeader(buf, h.getKey(), h.getValue());
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
|
@ -178,8 +178,8 @@ public class HttpPostRequestDecoder {
|
||||
this.charset = charset;
|
||||
this.factory = factory;
|
||||
// Fill default values
|
||||
if (this.request.containsHeader(HttpHeaders.Names.CONTENT_TYPE)) {
|
||||
checkMultipart(this.request.getHeader(HttpHeaders.Names.CONTENT_TYPE));
|
||||
if (this.request.headers().contains(HttpHeaders.Names.CONTENT_TYPE)) {
|
||||
checkMultipart(this.request.headers().get(HttpHeaders.Names.CONTENT_TYPE));
|
||||
} else {
|
||||
isMultipart = false;
|
||||
}
|
||||
|
@ -614,6 +614,7 @@ public class HttpPostRequestEncoder implements ChunkedInput {
|
||||
* @throws ErrorDataEncoderException if the encoding is in error or if the finalize were already done
|
||||
*/
|
||||
public HttpRequest finalizeRequest() throws ErrorDataEncoderException {
|
||||
HttpHeaders headers = request.headers();
|
||||
// Finalize the multipartHttpDatas
|
||||
if (! headerFinalized) {
|
||||
if (isMultipart) {
|
||||
@ -632,11 +633,10 @@ public class HttpPostRequestEncoder implements ChunkedInput {
|
||||
} else {
|
||||
throw new ErrorDataEncoderException("Header already encoded");
|
||||
}
|
||||
List<String> contentTypes = request.getHeaders(HttpHeaders.Names.CONTENT_TYPE);
|
||||
List<String> transferEncoding =
|
||||
request.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
List<String> contentTypes = headers.getAll(HttpHeaders.Names.CONTENT_TYPE);
|
||||
List<String> transferEncoding = headers.getAll(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
if (contentTypes != null) {
|
||||
request.removeHeader(HttpHeaders.Names.CONTENT_TYPE);
|
||||
headers.remove(HttpHeaders.Names.CONTENT_TYPE);
|
||||
for (String contentType: contentTypes) {
|
||||
// "multipart/form-data; boundary=--89421926422648"
|
||||
if (contentType.toLowerCase().startsWith(
|
||||
@ -646,17 +646,17 @@ public class HttpPostRequestEncoder implements ChunkedInput {
|
||||
HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
|
||||
// ignore
|
||||
} else {
|
||||
request.addHeader(HttpHeaders.Names.CONTENT_TYPE, contentType);
|
||||
headers.add(HttpHeaders.Names.CONTENT_TYPE, contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isMultipart) {
|
||||
String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " +
|
||||
HttpHeaders.Values.BOUNDARY + '=' + multipartDataBoundary;
|
||||
request.addHeader(HttpHeaders.Names.CONTENT_TYPE, value);
|
||||
headers.add(HttpHeaders.Names.CONTENT_TYPE, value);
|
||||
} else {
|
||||
// Not multipart
|
||||
request.addHeader(HttpHeaders.Names.CONTENT_TYPE,
|
||||
headers.add(HttpHeaders.Names.CONTENT_TYPE,
|
||||
HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
|
||||
}
|
||||
// Now consider size for chunk or not
|
||||
@ -667,22 +667,20 @@ public class HttpPostRequestEncoder implements ChunkedInput {
|
||||
realSize -= 1; // last '&' removed
|
||||
iterator = multipartHttpDatas.listIterator();
|
||||
}
|
||||
request.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String
|
||||
.valueOf(realSize));
|
||||
headers.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize));
|
||||
if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
|
||||
isChunked = true;
|
||||
if (transferEncoding != null) {
|
||||
request.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
headers.remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
for (String v: transferEncoding) {
|
||||
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
|
||||
// ignore
|
||||
} else {
|
||||
request.addHeader(HttpHeaders.Names.TRANSFER_ENCODING, v);
|
||||
headers.add(HttpHeaders.Names.TRANSFER_ENCODING, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
request.addHeader(HttpHeaders.Names.TRANSFER_ENCODING,
|
||||
HttpHeaders.Values.CHUNKED);
|
||||
headers.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
|
||||
request.setContent(ChannelBuffers.EMPTY_BUFFER);
|
||||
} else {
|
||||
// get the only one body and set it to the request
|
||||
|
@ -161,9 +161,9 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
||||
|
||||
// Format request
|
||||
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||
request.addHeader(Names.UPGRADE, Values.WEBSOCKET);
|
||||
request.addHeader(Names.CONNECTION, Values.UPGRADE);
|
||||
request.addHeader(Names.HOST, wsURL.getHost());
|
||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET);
|
||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
||||
request.headers().add(Names.HOST, wsURL.getHost());
|
||||
|
||||
int wsPort = wsURL.getPort();
|
||||
String originValue = "http://" + wsURL.getHost();
|
||||
@ -172,24 +172,24 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||
originValue = originValue + ':' + wsPort;
|
||||
}
|
||||
request.addHeader(Names.ORIGIN, originValue);
|
||||
request.headers().add(Names.ORIGIN, originValue);
|
||||
|
||||
request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1);
|
||||
request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_KEY1, key1);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_KEY2, key2);
|
||||
String expectedSubprotocol = getExpectedSubprotocol();
|
||||
if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) {
|
||||
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
}
|
||||
|
||||
if (customHeaders != null) {
|
||||
for (Map.Entry<String, String> e: customHeaders.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
request.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Set Content-Length to workaround some known defect.
|
||||
// See also: http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html
|
||||
request.setHeader(Names.CONTENT_LENGTH, key3.length);
|
||||
request.headers().set(Names.CONTENT_LENGTH, key3.length);
|
||||
request.setContent(ChannelBuffers.copiedBuffer(key3));
|
||||
|
||||
final ChannelFuture handshakeFuture = new DefaultChannelFuture(channel, false);
|
||||
@ -241,13 +241,13 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
|
||||
}
|
||||
|
||||
String upgrade = response.getHeader(Names.UPGRADE);
|
||||
String upgrade = response.headers().get(Names.UPGRADE);
|
||||
if (!Values.WEBSOCKET.equals(upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||
+ upgrade);
|
||||
}
|
||||
|
||||
String connection = response.getHeader(Names.CONNECTION);
|
||||
String connection = response.headers().get(Names.CONNECTION);
|
||||
if (!Values.UPGRADE.equals(connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||
+ connection);
|
||||
@ -258,7 +258,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid challenge");
|
||||
}
|
||||
|
||||
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
setActualSubprotocol(subprotocol);
|
||||
|
||||
setHandshakeComplete();
|
||||
|
@ -128,10 +128,10 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
||||
|
||||
// Format request
|
||||
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.addHeader(Names.CONNECTION, Values.UPGRADE);
|
||||
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.addHeader(Names.HOST, wsURL.getHost());
|
||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.headers().add(Names.HOST, wsURL.getHost());
|
||||
|
||||
int wsPort = wsURL.getPort();
|
||||
String originValue = "http://" + wsURL.getHost();
|
||||
@ -140,18 +140,18 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||
originValue = originValue + ':' + wsPort;
|
||||
}
|
||||
request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||
|
||||
String expectedSubprotocol = getExpectedSubprotocol();
|
||||
if (expectedSubprotocol != null && expectedSubprotocol.length() > 0) {
|
||||
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
}
|
||||
|
||||
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "7");
|
||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "7");
|
||||
|
||||
if (customHeaders != null) {
|
||||
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
request.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,25 +203,25 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
|
||||
}
|
||||
|
||||
String upgrade = response.getHeader(Names.UPGRADE);
|
||||
String upgrade = response.headers().get(Names.UPGRADE);
|
||||
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||
+ response.getHeader(Names.UPGRADE));
|
||||
+ response.headers().get(Names.UPGRADE));
|
||||
}
|
||||
|
||||
String connection = response.getHeader(Names.CONNECTION);
|
||||
String connection = response.headers().get(Names.CONNECTION);
|
||||
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||
+ response.getHeader(Names.CONNECTION));
|
||||
+ response.headers().get(Names.CONNECTION));
|
||||
}
|
||||
|
||||
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
||||
expectedChallengeResponseString));
|
||||
}
|
||||
|
||||
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
setActualSubprotocol(subprotocol);
|
||||
|
||||
setHandshakeComplete();
|
||||
|
@ -147,10 +147,10 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
||||
|
||||
// Format request
|
||||
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.addHeader(Names.CONNECTION, Values.UPGRADE);
|
||||
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.addHeader(Names.HOST, wsURL.getHost());
|
||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.headers().add(Names.HOST, wsURL.getHost());
|
||||
|
||||
int wsPort = wsURL.getPort();
|
||||
String originValue = "http://" + wsURL.getHost();
|
||||
@ -162,18 +162,18 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
||||
|
||||
// Use Sec-WebSocket-Origin
|
||||
// See https://github.com/netty/netty/issues/264
|
||||
request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||
|
||||
String expectedSubprotocol = getExpectedSubprotocol();
|
||||
if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) {
|
||||
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
}
|
||||
|
||||
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "8");
|
||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "8");
|
||||
|
||||
if (customHeaders != null) {
|
||||
for (Map.Entry<String, String> e: customHeaders.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
request.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,29 +223,29 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
|
||||
}
|
||||
|
||||
String upgrade = response.getHeader(Names.UPGRADE);
|
||||
String upgrade = response.headers().get(Names.UPGRADE);
|
||||
// Upgrade header should be matched case-insensitive.
|
||||
// See https://github.com/netty/netty/issues/278
|
||||
if (upgrade == null || !upgrade.toLowerCase().equals(Values.WEBSOCKET.toLowerCase())) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||
+ response.getHeader(Names.UPGRADE));
|
||||
+ response.headers().get(Names.UPGRADE));
|
||||
}
|
||||
|
||||
// Connection header should be matched case-insensitive.
|
||||
// See https://github.com/netty/netty/issues/278
|
||||
String connection = response.getHeader(Names.CONNECTION);
|
||||
String connection = response.headers().get(Names.CONNECTION);
|
||||
if (connection == null || !connection.toLowerCase().equals(Values.UPGRADE.toLowerCase())) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||
+ response.getHeader(Names.CONNECTION));
|
||||
+ response.headers().get(Names.CONNECTION));
|
||||
}
|
||||
|
||||
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
||||
expectedChallengeResponseString));
|
||||
}
|
||||
|
||||
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
setActualSubprotocol(subprotocol);
|
||||
|
||||
setHandshakeComplete();
|
||||
|
@ -148,10 +148,10 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
||||
// Format request
|
||||
int wsPort = wsURL.getPort();
|
||||
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.addHeader(Names.CONNECTION, Values.UPGRADE);
|
||||
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.addHeader(Names.HOST, wsURL.getHost() + ':' + wsPort);
|
||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
||||
request.headers().add(Names.HOST, wsURL.getHost() + ':' + wsPort);
|
||||
|
||||
String originValue = "http://" + wsURL.getHost();
|
||||
if (wsPort != 80 && wsPort != 443) {
|
||||
@ -159,18 +159,18 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||
originValue = originValue + ':' + wsPort;
|
||||
}
|
||||
request.addHeader(Names.ORIGIN, originValue);
|
||||
request.headers().add(Names.ORIGIN, originValue);
|
||||
|
||||
String expectedSubprotocol = getExpectedSubprotocol();
|
||||
if (expectedSubprotocol != null && expectedSubprotocol.length() != 0) {
|
||||
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||
}
|
||||
|
||||
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "13");
|
||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "13");
|
||||
|
||||
if (customHeaders != null) {
|
||||
for (Map.Entry<String, String> e: customHeaders.entrySet()) {
|
||||
request.addHeader(e.getKey(), e.getValue());
|
||||
request.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,29 +220,29 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
|
||||
}
|
||||
|
||||
String upgrade = response.getHeader(Names.UPGRADE);
|
||||
String upgrade = response.headers().get(Names.UPGRADE);
|
||||
// Upgrade header should be matched case-insensitive.
|
||||
// See https://github.com/netty/netty/issues/278
|
||||
if (upgrade == null || !upgrade.toLowerCase().equals(Values.WEBSOCKET.toLowerCase())) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||
+ response.getHeader(Names.UPGRADE));
|
||||
+ response.headers().get(Names.UPGRADE));
|
||||
}
|
||||
|
||||
// Connection header should be matched case-insensitive.
|
||||
// See https://github.com/netty/netty/issues/278
|
||||
String connection = response.getHeader(Names.CONNECTION);
|
||||
String connection = response.headers().get(Names.CONNECTION);
|
||||
if (connection == null || !connection.toLowerCase().equals(Values.UPGRADE.toLowerCase())) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||
+ response.getHeader(Names.CONNECTION));
|
||||
+ response.headers().get(Names.CONNECTION));
|
||||
}
|
||||
|
||||
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
||||
expectedChallengeResponseString));
|
||||
}
|
||||
|
||||
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
setActualSubprotocol(subprotocol);
|
||||
|
||||
setHandshakeComplete();
|
||||
|
@ -133,39 +133,39 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
|
||||
}
|
||||
|
||||
// Serve the WebSocket handshake request.
|
||||
if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
|
||||
|| !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {
|
||||
if (!Values.UPGRADE.equalsIgnoreCase(req.headers().get(CONNECTION))
|
||||
|| !WEBSOCKET.equalsIgnoreCase(req.headers().get(Names.UPGRADE))) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
|
||||
}
|
||||
|
||||
// Hixie 75 does not contain these headers while Hixie 76 does
|
||||
boolean isHixie76 = req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2);
|
||||
boolean isHixie76 = req.headers().contains(SEC_WEBSOCKET_KEY1) && req.headers().contains(SEC_WEBSOCKET_KEY2);
|
||||
|
||||
// Create the WebSocket handshake response.
|
||||
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
|
||||
isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake"));
|
||||
res.addHeader(Names.UPGRADE, WEBSOCKET);
|
||||
res.addHeader(CONNECTION, Values.UPGRADE);
|
||||
res.headers().add(Names.UPGRADE, WEBSOCKET);
|
||||
res.headers().add(CONNECTION, Values.UPGRADE);
|
||||
|
||||
// Fill in the headers and contents depending on handshake method.
|
||||
if (isHixie76) {
|
||||
// New handshake method with a challenge:
|
||||
res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
|
||||
res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
|
||||
String subprotocols = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
|
||||
res.headers().add(SEC_WEBSOCKET_ORIGIN, req.headers().get(ORIGIN));
|
||||
res.headers().add(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
|
||||
String subprotocols = req.headers().get(SEC_WEBSOCKET_PROTOCOL);
|
||||
if (subprotocols != null) {
|
||||
String selectedSubprotocol = selectSubprotocol(subprotocols);
|
||||
if (selectedSubprotocol == null) {
|
||||
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
|
||||
} else {
|
||||
res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
res.headers().add(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
setSelectedSubprotocol(selectedSubprotocol);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the answer of the challenge.
|
||||
String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
|
||||
String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
|
||||
String key1 = req.headers().get(SEC_WEBSOCKET_KEY1);
|
||||
String key2 = req.headers().get(SEC_WEBSOCKET_KEY2);
|
||||
int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1.replaceAll("[^ ]", "").length());
|
||||
int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2.replaceAll("[^ ]", "").length());
|
||||
long c = req.getContent().readLong();
|
||||
@ -176,11 +176,11 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
|
||||
res.setContent(WebSocketUtil.md5(input));
|
||||
} else {
|
||||
// Old Hixie 75 handshake method with no challenge:
|
||||
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
|
||||
res.addHeader(WEBSOCKET_LOCATION, getWebSocketUrl());
|
||||
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
|
||||
res.headers().add(WEBSOCKET_ORIGIN, req.headers().get(ORIGIN));
|
||||
res.headers().add(WEBSOCKET_LOCATION, getWebSocketUrl());
|
||||
String protocol = req.headers().get(WEBSOCKET_PROTOCOL);
|
||||
if (protocol != null) {
|
||||
res.addHeader(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
|
||||
res.headers().add(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
|
||||
}
|
||||
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
|
||||
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
@ -130,16 +130,16 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
|
||||
}
|
||||
|
||||
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.addHeader(Names.CONNECTION, Names.UPGRADE);
|
||||
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.headers().add(Names.CONNECTION, Names.UPGRADE);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
if (subprotocols != null) {
|
||||
String selectedSubprotocol = selectSubprotocol(subprotocols);
|
||||
if (selectedSubprotocol == null) {
|
||||
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
|
||||
} else {
|
||||
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
setSelectedSubprotocol(selectedSubprotocol);
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
|
||||
|
||||
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
|
||||
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
@ -148,16 +148,16 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
|
||||
}
|
||||
|
||||
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.addHeader(Names.CONNECTION, Names.UPGRADE);
|
||||
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.headers().add(Names.CONNECTION, Names.UPGRADE);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
if (subprotocols != null) {
|
||||
String selectedSubprotocol = selectSubprotocol(subprotocols);
|
||||
if (selectedSubprotocol == null) {
|
||||
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
|
||||
} else {
|
||||
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
setSelectedSubprotocol(selectedSubprotocol);
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
|
||||
|
||||
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
|
||||
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
@ -154,16 +154,16 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
|
||||
}
|
||||
|
||||
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.addHeader(Names.CONNECTION, Names.UPGRADE);
|
||||
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
|
||||
res.headers().add(Names.CONNECTION, Names.UPGRADE);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
|
||||
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||
if (subprotocols != null) {
|
||||
String selectedSubprotocol = selectSubprotocol(subprotocols);
|
||||
if (selectedSubprotocol == null) {
|
||||
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
|
||||
} else {
|
||||
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
|
||||
setSelectedSubprotocol(selectedSubprotocol);
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class WebSocketServerHandshakerFactory {
|
||||
*/
|
||||
public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
|
||||
|
||||
String version = req.getHeader(Names.SEC_WEBSOCKET_VERSION);
|
||||
String version = req.headers().get(Names.SEC_WEBSOCKET_VERSION);
|
||||
|
||||
if (version != null) {
|
||||
if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
|
||||
@ -115,7 +115,7 @@ public class WebSocketServerHandshakerFactory {
|
||||
HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.SWITCHING_PROTOCOLS);
|
||||
res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED);
|
||||
res.setHeader(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
|
||||
res.headers().set(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
|
||||
return channel.write(res);
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ public class WebSocketServerProtocolHandshakeHandler extends SimpleChannelUpstre
|
||||
// SSL in use so use Secure WebSockets
|
||||
protocol = "wss";
|
||||
}
|
||||
return protocol + "://" + req.getHeader(HttpHeaders.Names.HOST) + path;
|
||||
return protocol + "://" + req.headers().get(HttpHeaders.Names.HOST) + path;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public abstract class RtspMessageDecoder extends HttpMessageDecoder {
|
||||
if (empty) {
|
||||
return true;
|
||||
}
|
||||
if (!msg.containsHeader(RtspHeaders.Names.CONTENT_LENGTH)) {
|
||||
if (!msg.headers().contains(RtspHeaders.Names.CONTENT_LENGTH)) {
|
||||
return true;
|
||||
}
|
||||
return empty;
|
||||
|
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jboss.netty.handler.codec.spdy;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
public class DefaultSpdyHeaders extends SpdyHeaders {
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static int hash(String name) {
|
||||
int h = 0;
|
||||
for (int i = name.length() - 1; i >= 0; i --) {
|
||||
char c = name.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 32;
|
||||
}
|
||||
h = 31 * h + c;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
return h;
|
||||
} else if (h == Integer.MIN_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return -h;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean eq(String name1, String name2) {
|
||||
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;
|
||||
}
|
||||
|
||||
private static int index(int hash) {
|
||||
return hash % BUCKET_SIZE;
|
||||
}
|
||||
|
||||
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
|
||||
private final HeaderEntry head = new HeaderEntry(-1, null, null);
|
||||
|
||||
DefaultSpdyHeaders() {
|
||||
head.before = head.after = head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void add0(int h, int i, final String name, final String value) {
|
||||
// Update the hash table.
|
||||
HeaderEntry e = entries[i];
|
||||
HeaderEntry newEntry;
|
||||
entries[i] = newEntry = new HeaderEntry(h, name, value);
|
||||
newEntry.next = e;
|
||||
|
||||
// Update the linked list.
|
||||
newEntry.addBefore(head);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders remove(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
remove0(h, i, lowerCaseName);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void remove0(int h, int i, String name) {
|
||||
HeaderEntry e = entries[i];
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
e.remove();
|
||||
HeaderEntry next = e.next;
|
||||
if (next != null) {
|
||||
entries[i] = next;
|
||||
e = next;
|
||||
} else {
|
||||
entries[i] = null;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
HeaderEntry next = e.next;
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
if (next.hash == h && eq(name, next.key)) {
|
||||
e.next = next.next;
|
||||
next.remove();
|
||||
} else {
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
remove0(h, i, lowerCaseName);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
|
||||
remove0(h, i, lowerCaseName);
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
String strVal = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders clear() {
|
||||
for (int i = 0; i < entries.length; i ++) {
|
||||
entries[i] = null;
|
||||
}
|
||||
head.before = head.after = head;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
return e.value;
|
||||
}
|
||||
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
LinkedList<String> values = new LinkedList<String>();
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
values.addFirst(e.value);
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
List<Map.Entry<String, String>> all =
|
||||
new LinkedList<Map.Entry<String, String>>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
all.add(e);
|
||||
e = e.after;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return new HeaderIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return get(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
Set<String> names = new TreeSet<String>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
names.add(e.key);
|
||||
e = e.after;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Iterable<?> values) {
|
||||
SpdyCodecUtil.validateHeaderValue(name);
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
for (Object v: values) {
|
||||
String vstr = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(vstr);
|
||||
add0(h, i, name, vstr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return head == head.after;
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private final class HeaderIterator implements Iterator<Map.Entry<String, String>> {
|
||||
|
||||
private HeaderEntry current = head;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return current.after != head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<String, String> next() {
|
||||
current = current.after;
|
||||
|
||||
if (current == head) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HeaderEntry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
String value;
|
||||
HeaderEntry next;
|
||||
HeaderEntry before, after;
|
||||
|
||||
HeaderEntry(int hash, String key, String value) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
before.after = after;
|
||||
after.before = before;
|
||||
}
|
||||
|
||||
void addBefore(HeaderEntry e) {
|
||||
after = e;
|
||||
before = e.before;
|
||||
before.after = this;
|
||||
after.before = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setValue(String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderValue(value);
|
||||
String oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + '=' + value;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyStreamFrame
|
||||
|
||||
private boolean invalid;
|
||||
private boolean truncated;
|
||||
private final SpdyHeaders headers = new SpdyHeaders();
|
||||
private final SpdyHeaders headers = new DefaultSpdyHeaders();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@ -56,44 +56,58 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyStreamFrame
|
||||
truncated = true;
|
||||
}
|
||||
|
||||
public SpdyHeaders headers() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
headers.add(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
headers.set(name, value);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
headers.set(name, values);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeHeader(final String name) {
|
||||
headers.removeHeader(name);
|
||||
headers.remove(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void clearHeaders() {
|
||||
headers.clearHeaders();
|
||||
headers.clear();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public String getHeader(final String name) {
|
||||
return headers.getHeader(name);
|
||||
return headers.get(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<String> getHeaders(final String name) {
|
||||
return headers.getHeaders(name);
|
||||
return headers.getAll(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public List<Map.Entry<String, String>> getHeaders() {
|
||||
return headers.getHeaders();
|
||||
return headers.entries();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean containsHeader(final String name) {
|
||||
return headers.containsHeader(name);
|
||||
return headers.contains(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Set<String> getHeaderNames() {
|
||||
return headers.getHeaderNames();
|
||||
return headers.names();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,7 +131,7 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyStreamFrame
|
||||
}
|
||||
|
||||
protected void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: getHeaders()) {
|
||||
for (Map.Entry<String, String> e: headers()) {
|
||||
buf.append(" ");
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
|
@ -98,7 +98,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
String name = new String(nameBytes, "UTF-8");
|
||||
|
||||
// Check for identically named headers
|
||||
if (frame.containsHeader(name)) {
|
||||
if (frame.headers().contains(name)) {
|
||||
frame.setInvalid();
|
||||
return;
|
||||
}
|
||||
@ -118,7 +118,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
|
||||
// SPDY/3 allows zero-length (empty) header values
|
||||
if (valueLength == 0) {
|
||||
frame.addHeader(name, "");
|
||||
frame.headers().add(name, "");
|
||||
numHeaders --;
|
||||
this.headerSize = headerSize;
|
||||
continue;
|
||||
@ -154,7 +154,7 @@ public class SpdyHeaderBlockRawDecoder extends SpdyHeaderBlockDecoder {
|
||||
String value = new String(valueBytes, offset, index - offset, "UTF-8");
|
||||
|
||||
try {
|
||||
frame.addHeader(name, value);
|
||||
frame.headers().add(name, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Name contains NULL or non-ascii characters
|
||||
frame.setInvalid();
|
||||
|
@ -35,24 +35,16 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
}
|
||||
|
||||
private void setLengthField(ChannelBuffer buffer, int writerIndex, int length) {
|
||||
if (version < 3) {
|
||||
buffer.setShort(writerIndex, length);
|
||||
} else {
|
||||
buffer.setInt(writerIndex, length);
|
||||
}
|
||||
buffer.setInt(writerIndex, length);
|
||||
}
|
||||
|
||||
private void writeLengthField(ChannelBuffer buffer, int length) {
|
||||
if (version < 3) {
|
||||
buffer.writeShort(length);
|
||||
} else {
|
||||
buffer.writeInt(length);
|
||||
}
|
||||
buffer.writeInt(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelBuffer encode(SpdyHeadersFrame headerFrame) throws Exception {
|
||||
Set<String> names = headerFrame.getHeaderNames();
|
||||
Set<String> names = headerFrame.headers().names();
|
||||
int numHeaders = names.size();
|
||||
if (numHeaders == 0) {
|
||||
return ChannelBuffers.EMPTY_BUFFER;
|
||||
@ -71,7 +63,7 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
int savedIndex = headerBlock.writerIndex();
|
||||
int valueLength = 0;
|
||||
writeLengthField(headerBlock, valueLength);
|
||||
for (String value: headerFrame.getHeaders(name)) {
|
||||
for (String value: headerFrame.headers().getAll(name)) {
|
||||
byte[] valueBytes = value.getBytes("UTF-8");
|
||||
if (valueBytes.length > 0) {
|
||||
headerBlock.writeBytes(valueBytes);
|
||||
@ -79,12 +71,7 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
valueLength += valueBytes.length + 1;
|
||||
}
|
||||
}
|
||||
if (valueLength == 0) {
|
||||
if (version < 3) {
|
||||
throw new IllegalArgumentException(
|
||||
"header value cannot be empty: " + name);
|
||||
}
|
||||
} else {
|
||||
if (valueLength != 0) {
|
||||
valueLength --;
|
||||
}
|
||||
if (valueLength > SPDY_MAX_NV_LENGTH) {
|
||||
|
@ -19,22 +19,88 @@ import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.jboss.netty.handler.codec.http.HttpVersion;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Provides the constants for the standard SPDY HTTP header names and commonly
|
||||
* used utility methods that access a {@link SpdyHeadersFrame}.
|
||||
* @apiviz.stereotype static
|
||||
*/
|
||||
public class SpdyHeaders {
|
||||
public abstract class SpdyHeaders implements Iterable<Map.Entry<String, String>> {
|
||||
|
||||
public static final SpdyHeaders EMPTY_HEADERS = new SpdyHeaders() {
|
||||
|
||||
@Override
|
||||
public List<String> getAll(String name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(String name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(String name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders remove(String name) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders clear() {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String name) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SPDY HTTP header names
|
||||
* @apiviz.stereotype static
|
||||
*/
|
||||
public static final class HttpNames {
|
||||
/**
|
||||
@ -62,8 +128,7 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static final String VERSION = ":version";
|
||||
|
||||
private HttpNames() {
|
||||
}
|
||||
private HttpNames() { }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +139,7 @@ public class SpdyHeaders {
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
*/
|
||||
public static String getHeader(SpdyHeadersFrame frame, String name) {
|
||||
return frame.getHeader(name);
|
||||
return frame.headers().get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +151,7 @@ public class SpdyHeaders {
|
||||
* header
|
||||
*/
|
||||
public static String getHeader(SpdyHeadersFrame frame, String name, String defaultValue) {
|
||||
String value = frame.getHeader(name);
|
||||
String value = frame.headers().get(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
@ -98,7 +163,7 @@ public class SpdyHeaders {
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public static void setHeader(SpdyHeadersFrame frame, String name, Object value) {
|
||||
frame.setHeader(name, value);
|
||||
frame.headers().set(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,42 +171,42 @@ public class SpdyHeaders {
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public static void setHeader(SpdyHeadersFrame frame, String name, Iterable<?> values) {
|
||||
frame.setHeader(name, values);
|
||||
frame.headers().set(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
public static void addHeader(SpdyHeadersFrame frame, String name, Object value) {
|
||||
frame.addHeader(name, value);
|
||||
frame.headers().add(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the SPDY host header.
|
||||
*/
|
||||
public static void removeHost(SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.HOST);
|
||||
frame.headers().remove(HttpNames.HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SPDY host header.
|
||||
*/
|
||||
public static String getHost(SpdyHeadersFrame frame) {
|
||||
return frame.getHeader(HttpNames.HOST);
|
||||
return frame.headers().get(HttpNames.HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SPDY host header.
|
||||
*/
|
||||
public static void setHost(SpdyHeadersFrame frame, String host) {
|
||||
frame.setHeader(HttpNames.HOST, host);
|
||||
frame.headers().set(HttpNames.HOST, host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the HTTP method header.
|
||||
*/
|
||||
public static void removeMethod(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.METHOD);
|
||||
frame.headers().remove(HttpNames.METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +214,7 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static HttpMethod getMethod(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
try {
|
||||
return HttpMethod.valueOf(frame.getHeader(HttpNames.METHOD));
|
||||
return HttpMethod.valueOf(frame.headers().get(HttpNames.METHOD));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
@ -159,35 +224,35 @@ public class SpdyHeaders {
|
||||
* Sets the HTTP method header.
|
||||
*/
|
||||
public static void setMethod(int spdyVersion, SpdyHeadersFrame frame, HttpMethod method) {
|
||||
frame.setHeader(HttpNames.METHOD, method.getName());
|
||||
frame.headers().set(HttpNames.METHOD, method.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the URL scheme header.
|
||||
*/
|
||||
public static void removeScheme(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.SCHEME);
|
||||
frame.headers().remove(HttpNames.SCHEME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the URL scheme header.
|
||||
*/
|
||||
public static String getScheme(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
return frame.getHeader(HttpNames.SCHEME);
|
||||
return frame.headers().get(HttpNames.SCHEME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL scheme header.
|
||||
*/
|
||||
public static void setScheme(int spdyVersion, SpdyHeadersFrame frame, String scheme) {
|
||||
frame.setHeader(HttpNames.SCHEME, scheme);
|
||||
frame.headers().set(HttpNames.SCHEME, scheme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the HTTP response status header.
|
||||
*/
|
||||
public static void removeStatus(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.STATUS);
|
||||
frame.headers().remove(HttpNames.STATUS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +260,7 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static HttpResponseStatus getStatus(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
try {
|
||||
String status = frame.getHeader(HttpNames.STATUS);
|
||||
String status = frame.headers().get(HttpNames.STATUS);
|
||||
int space = status.indexOf(' ');
|
||||
if (space == -1) {
|
||||
return HttpResponseStatus.valueOf(Integer.parseInt(status));
|
||||
@ -218,35 +283,35 @@ public class SpdyHeaders {
|
||||
* Sets the HTTP response status header.
|
||||
*/
|
||||
public static void setStatus(int spdyVersion, SpdyHeadersFrame frame, HttpResponseStatus status) {
|
||||
frame.setHeader(HttpNames.STATUS, status.toString());
|
||||
frame.headers().set(HttpNames.STATUS, status.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the URL path header.
|
||||
*/
|
||||
public static void removeUrl(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.PATH);
|
||||
frame.headers().remove(HttpNames.PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the URL path header.
|
||||
*/
|
||||
public static String getUrl(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
return frame.getHeader(HttpNames.PATH);
|
||||
return frame.headers().get(HttpNames.PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL path header.
|
||||
*/
|
||||
public static void setUrl(int spdyVersion, SpdyHeadersFrame frame, String path) {
|
||||
frame.setHeader(HttpNames.PATH, path);
|
||||
frame.headers().set(HttpNames.PATH, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the HTTP version header.
|
||||
*/
|
||||
public static void removeVersion(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
frame.removeHeader(HttpNames.VERSION);
|
||||
frame.headers().remove(HttpNames.VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,7 +319,7 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static HttpVersion getVersion(int spdyVersion, SpdyHeadersFrame frame) {
|
||||
try {
|
||||
return HttpVersion.valueOf(frame.getHeader(HttpNames.VERSION));
|
||||
return HttpVersion.valueOf(frame.headers().get(HttpNames.VERSION));
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
@ -264,289 +329,85 @@ public class SpdyHeaders {
|
||||
* Sets the HTTP version header.
|
||||
*/
|
||||
public static void setVersion(int spdyVersion, SpdyHeadersFrame frame, HttpVersion httpVersion) {
|
||||
frame.setHeader(HttpNames.VERSION, httpVersion.getText());
|
||||
frame.headers().set(HttpNames.VERSION, httpVersion.getText());
|
||||
}
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static int hash(String name) {
|
||||
int h = 0;
|
||||
for (int i = name.length() - 1; i >= 0; i --) {
|
||||
char c = name.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 32;
|
||||
}
|
||||
h = 31 * h + c;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
return h;
|
||||
} else if (h == Integer.MIN_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return -h;
|
||||
}
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
private static boolean eq(String name1, String name2) {
|
||||
int nameLen = name1.length();
|
||||
if (nameLen != name2.length()) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the header value with the specified header name. If there is
|
||||
* more than one header value for the specified header name, the first
|
||||
* value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
*/
|
||||
public abstract String get(String name);
|
||||
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* Returns the header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
*/
|
||||
public abstract List<String> getAll(String name);
|
||||
|
||||
private static int index(int hash) {
|
||||
return hash % BUCKET_SIZE;
|
||||
}
|
||||
/**
|
||||
* Returns all header names and values that this frame contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this message.
|
||||
*/
|
||||
public abstract List<Map.Entry<String, String>> entries();
|
||||
|
||||
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
|
||||
private final HeaderEntry head = new HeaderEntry(-1, null, null);
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a header with the specified
|
||||
* header name.
|
||||
*/
|
||||
public abstract boolean contains(String name);
|
||||
|
||||
SpdyHeaders() {
|
||||
head.before = head.after = head;
|
||||
}
|
||||
/**
|
||||
* Returns the {@link Set} of all header names that this frame contains.
|
||||
*/
|
||||
public abstract Set<String> names();
|
||||
|
||||
void addHeader(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
public abstract SpdyHeaders add(String name, Object value);
|
||||
|
||||
private void addHeader0(int h, int i, final String name, final String value) {
|
||||
// Update the hash table.
|
||||
HeaderEntry e = entries[i];
|
||||
HeaderEntry newEntry;
|
||||
entries[i] = newEntry = new HeaderEntry(h, name, value);
|
||||
newEntry.next = e;
|
||||
/**
|
||||
* Adds a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders add(String name, Iterable<?> values);
|
||||
|
||||
// Update the linked list.
|
||||
newEntry.addBefore(head);
|
||||
}
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders set(String name, Object value);
|
||||
|
||||
void removeHeader(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
}
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders set(String name, Iterable<?> values);
|
||||
|
||||
private void removeHeader0(int h, int i, String name) {
|
||||
HeaderEntry e = entries[i];
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
*/
|
||||
public abstract SpdyHeaders remove(String name);
|
||||
|
||||
for (;;) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
e.remove();
|
||||
HeaderEntry next = e.next;
|
||||
if (next != null) {
|
||||
entries[i] = next;
|
||||
e = next;
|
||||
} else {
|
||||
entries[i] = null;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Removes all headers from this frame.
|
||||
*/
|
||||
public abstract SpdyHeaders clear();
|
||||
|
||||
for (;;) {
|
||||
HeaderEntry next = e.next;
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
if (next.hash == h && eq(name, next.key)) {
|
||||
e.next = next.next;
|
||||
next.remove();
|
||||
} else {
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setHeader(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
|
||||
void setHeader(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
String strVal = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
}
|
||||
|
||||
void clearHeaders() {
|
||||
for (int i = 0; i < entries.length; i ++) {
|
||||
entries[i] = null;
|
||||
}
|
||||
head.before = head.after = head;
|
||||
}
|
||||
|
||||
String getHeader(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
return e.value;
|
||||
}
|
||||
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> getHeaders(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
LinkedList<String> values = new LinkedList<String>();
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
values.addFirst(e.value);
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
List<Map.Entry<String, String>> getHeaders() {
|
||||
List<Map.Entry<String, String>> all =
|
||||
new LinkedList<Map.Entry<String, String>>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
all.add(e);
|
||||
e = e.after;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
boolean containsHeader(String name) {
|
||||
return getHeader(name) != null;
|
||||
}
|
||||
|
||||
Set<String> getHeaderNames() {
|
||||
Set<String> names = new TreeSet<String>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
names.add(e.key);
|
||||
e = e.after;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static final class HeaderEntry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
String value;
|
||||
HeaderEntry next;
|
||||
HeaderEntry before, after;
|
||||
|
||||
HeaderEntry(int hash, String key, String value) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
before.after = after;
|
||||
after.before = before;
|
||||
}
|
||||
|
||||
void addBefore(HeaderEntry e) {
|
||||
after = e;
|
||||
before = e.before;
|
||||
before.after = this;
|
||||
after.before = this;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String setValue(String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderValue(value);
|
||||
String oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + '=' + value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Checks if no header exists.
|
||||
*/
|
||||
public abstract boolean isEmpty();
|
||||
}
|
||||
|
@ -47,65 +47,67 @@ public interface SpdyHeadersFrame extends SpdyStreamFrame {
|
||||
void setTruncated();
|
||||
|
||||
/**
|
||||
* Returns the header value with the specified header name. If there is
|
||||
* more than one header value for the specified header name, the first
|
||||
* value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
* Returns the {@link SpdyHeaders}.
|
||||
*/
|
||||
SpdyHeaders headers();
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
String getHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
List<String> getHeaders(String name);
|
||||
|
||||
/**
|
||||
* Returns all header names and values that this block contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this message.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
List<Map.Entry<String, String>> getHeaders();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a header with the specified
|
||||
* header name.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
boolean containsHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of all header names that this block contains.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
Set<String> getHeaderNames();
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void removeHeader(String name);
|
||||
|
||||
/**
|
||||
* Removes all headers from this block.
|
||||
* @deprecated Use {@link SpdyHeaders#headers()} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
void clearHeaders();
|
||||
}
|
||||
|
@ -240,8 +240,8 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
||||
|
||||
// Ignore trailers in a truncated HEADERS frame.
|
||||
if (!spdyHeadersFrame.isTruncated()) {
|
||||
for (Map.Entry<String, String> e : spdyHeadersFrame.getHeaders()) {
|
||||
httpMessage.addHeader(e.getKey(), e.getValue());
|
||||
for (Map.Entry<String, String> e : spdyHeadersFrame.headers()) {
|
||||
httpMessage.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,15 +315,15 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
||||
HttpHeaders.setHost(httpRequest, host);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e: requestFrame.getHeaders()) {
|
||||
httpRequest.addHeader(e.getKey(), e.getValue());
|
||||
for (Map.Entry<String, String> e: requestFrame.headers()) {
|
||||
httpRequest.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
// The Connection and Keep-Alive headers are no longer valid
|
||||
HttpHeaders.setKeepAlive(httpRequest, true);
|
||||
|
||||
// Transfer-Encoding header is not valid
|
||||
httpRequest.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
httpRequest.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
|
||||
return httpRequest;
|
||||
}
|
||||
@ -337,16 +337,16 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
||||
SpdyHeaders.removeVersion(spdyVersion, responseFrame);
|
||||
|
||||
HttpResponse httpResponse = new DefaultHttpResponse(version, status);
|
||||
for (Map.Entry<String, String> e: responseFrame.getHeaders()) {
|
||||
httpResponse.addHeader(e.getKey(), e.getValue());
|
||||
for (Map.Entry<String, String> e: responseFrame.headers()) {
|
||||
httpResponse.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
// The Connection and Keep-Alive headers are no longer valid
|
||||
HttpHeaders.setKeepAlive(httpResponse, true);
|
||||
|
||||
// Transfer-Encoding header is not valid
|
||||
httpResponse.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
httpResponse.removeHeader(HttpHeaders.Names.TRAILER);
|
||||
httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
httpResponse.headers().remove(HttpHeaders.Names.TRAILER);
|
||||
|
||||
return httpResponse;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
} else if (msg instanceof HttpResponse) {
|
||||
|
||||
HttpResponse httpResponse = (HttpResponse) msg;
|
||||
if (httpResponse.containsHeader(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) {
|
||||
if (httpResponse.headers().contains(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) {
|
||||
SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpResponse);
|
||||
currentStreamId = spdySynStreamFrame.getStreamId();
|
||||
ChannelFuture future = getMessageFuture(ctx, e, currentStreamId, httpResponse);
|
||||
@ -196,7 +196,7 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
if (chunk.isLast()) {
|
||||
if (chunk instanceof HttpChunkTrailer) {
|
||||
HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
|
||||
List<Map.Entry<String, String>> trailers = trailer.getHeaders();
|
||||
HttpHeaders trailers = trailer.trailingHeaders();
|
||||
if (trailers.isEmpty()) {
|
||||
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(streamId);
|
||||
spdyDataFrame.setLast(true);
|
||||
@ -206,7 +206,7 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(streamId);
|
||||
spdyHeadersFrame.setLast(true);
|
||||
for (Map.Entry<String, String> entry: trailers) {
|
||||
spdyHeadersFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
spdyHeadersFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
Channels.write(ctx, future, spdyHeadersFrame, remoteAddress);
|
||||
}
|
||||
@ -292,10 +292,10 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
|
||||
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
|
||||
// headers are not valid and MUST not be sent.
|
||||
httpMessage.removeHeader(HttpHeaders.Names.CONNECTION);
|
||||
httpMessage.removeHeader("Keep-Alive");
|
||||
httpMessage.removeHeader("Proxy-Connection");
|
||||
httpMessage.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
httpMessage.headers().remove(HttpHeaders.Names.CONNECTION);
|
||||
httpMessage.headers().remove("Keep-Alive");
|
||||
httpMessage.headers().remove("Proxy-Connection");
|
||||
httpMessage.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
|
||||
SpdySynStreamFrame spdySynStreamFrame =
|
||||
new DefaultSpdySynStreamFrame(streamId, associatedToStreamId, priority);
|
||||
@ -317,11 +317,9 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
}
|
||||
|
||||
// Replace the HTTP host header with the SPDY host header
|
||||
if (spdyVersion >= 3) {
|
||||
String host = HttpHeaders.getHost(httpMessage);
|
||||
httpMessage.removeHeader(HttpHeaders.Names.HOST);
|
||||
SpdyHeaders.setHost(spdySynStreamFrame, host);
|
||||
}
|
||||
String host = HttpHeaders.getHost(httpMessage);
|
||||
httpMessage.headers().remove(HttpHeaders.Names.HOST);
|
||||
SpdyHeaders.setHost(spdySynStreamFrame, host);
|
||||
|
||||
// Set the SPDY scheme header
|
||||
if (scheme == null) {
|
||||
@ -330,8 +328,8 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
SpdyHeaders.setScheme(spdyVersion, spdySynStreamFrame, scheme);
|
||||
|
||||
// Transfer the remaining HTTP headers
|
||||
for (Map.Entry<String, String> entry: httpMessage.getHeaders()) {
|
||||
spdySynStreamFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<String, String> entry: httpMessage.headers()) {
|
||||
spdySynStreamFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return spdySynStreamFrame;
|
||||
@ -347,10 +345,10 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
|
||||
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
|
||||
// headers are not valid and MUST not be sent.
|
||||
httpResponse.removeHeader(HttpHeaders.Names.CONNECTION);
|
||||
httpResponse.removeHeader("Keep-Alive");
|
||||
httpResponse.removeHeader("Proxy-Connection");
|
||||
httpResponse.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
httpResponse.headers().remove(HttpHeaders.Names.CONNECTION);
|
||||
httpResponse.headers().remove("Keep-Alive");
|
||||
httpResponse.headers().remove("Proxy-Connection");
|
||||
httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||
spdySynReplyFrame.setLast(!chunked && !httpResponse.getContent().readable());
|
||||
@ -360,8 +358,8 @@ public class SpdyHttpEncoder implements ChannelDownstreamHandler {
|
||||
SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, httpResponse.getProtocolVersion());
|
||||
|
||||
// Transfer the remaining HTTP headers
|
||||
for (Map.Entry<String, String> entry: httpResponse.getHeaders()) {
|
||||
spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<String, String> entry: httpResponse.headers()) {
|
||||
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return spdySynReplyFrame;
|
||||
|
@ -62,7 +62,7 @@ public final class SpdyHttpHeaders {
|
||||
* Removes the {@code "X-SPDY-Stream-ID"} header.
|
||||
*/
|
||||
public static void removeStreamId(HttpMessage message) {
|
||||
message.removeHeader(Names.STREAM_ID);
|
||||
message.headers().remove(Names.STREAM_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ public final class SpdyHttpHeaders {
|
||||
* Removes the {@code "X-SPDY-Associated-To-Stream-ID"} header.
|
||||
*/
|
||||
public static void removeAssociatedToStreamId(HttpMessage message) {
|
||||
message.removeHeader(Names.ASSOCIATED_TO_STREAM_ID);
|
||||
message.headers().remove(Names.ASSOCIATED_TO_STREAM_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +107,7 @@ public final class SpdyHttpHeaders {
|
||||
* Removes the {@code "X-SPDY-Priority"} header.
|
||||
*/
|
||||
public static void removePriority(HttpMessage message) {
|
||||
message.removeHeader(Names.PRIORITY);
|
||||
message.headers().remove(Names.PRIORITY);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,41 +131,41 @@ public final class SpdyHttpHeaders {
|
||||
* Removes the {@code "X-SPDY-URL"} header.
|
||||
*/
|
||||
public static void removeUrl(HttpMessage message) {
|
||||
message.removeHeader(Names.URL);
|
||||
message.headers().remove(Names.URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code "X-SPDY-URL"} header.
|
||||
*/
|
||||
public static String getUrl(HttpMessage message) {
|
||||
return message.getHeader(Names.URL);
|
||||
return message.headers().get(Names.URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code "X-SPDY-URL"} header.
|
||||
*/
|
||||
public static void setUrl(HttpMessage message, String url) {
|
||||
message.setHeader(Names.URL, url);
|
||||
message.headers().set(Names.URL, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the {@code "X-SPDY-Scheme"} header.
|
||||
*/
|
||||
public static void removeScheme(HttpMessage message) {
|
||||
message.removeHeader(Names.SCHEME);
|
||||
message.headers().remove(Names.SCHEME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code "X-SPDY-Scheme"} header.
|
||||
*/
|
||||
public static String getScheme(HttpMessage message) {
|
||||
return message.getHeader(Names.SCHEME);
|
||||
return message.headers().get(Names.SCHEME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code "X-SPDY-Scheme"} header.
|
||||
*/
|
||||
public static void setScheme(HttpMessage message, String scheme) {
|
||||
message.setHeader(Names.SCHEME, scheme);
|
||||
message.headers().set(Names.SCHEME, scheme);
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ public class SpdyHttpResponseStreamIdHandler extends SimpleChannelHandler {
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
if (e.getMessage() instanceof HttpMessage) {
|
||||
boolean contains = ((HttpMessage) e.getMessage()).containsHeader(SpdyHttpHeaders.Names.STREAM_ID);
|
||||
boolean contains = ((HttpMessage) e.getMessage()).headers().contains(SpdyHttpHeaders.Names.STREAM_ID);
|
||||
if (!contains) {
|
||||
ids.add(NO_ID);
|
||||
} else {
|
||||
@ -54,7 +54,7 @@ public class SpdyHttpResponseStreamIdHandler extends SimpleChannelHandler {
|
||||
if (e.getMessage() instanceof HttpResponse) {
|
||||
HttpResponse response = (HttpResponse) e.getMessage();
|
||||
Integer id = ids.poll();
|
||||
if (id != null && id.intValue() != NO_ID && !response.containsHeader(SpdyHttpHeaders.Names.STREAM_ID)) {
|
||||
if (id != null && id.intValue() != NO_ID && !response.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) {
|
||||
SpdyHttpHeaders.setStreamId(response, id);
|
||||
}
|
||||
}
|
||||
|
@ -27,20 +27,20 @@ public class DefaultHttpMessageTest {
|
||||
|
||||
// Insert sample keys.
|
||||
for (int i = 0; i < 1000; i ++) {
|
||||
m.setHeader(String.valueOf(i), "");
|
||||
m.headers().set(String.valueOf(i), "");
|
||||
}
|
||||
|
||||
// Remove in reversed order.
|
||||
for (int i = 999; i >= 0; i --) {
|
||||
m.removeHeader(String.valueOf(i));
|
||||
m.headers().remove(String.valueOf(i));
|
||||
}
|
||||
|
||||
// Check if random access returns nothing.
|
||||
for (int i = 0; i < 1000; i ++) {
|
||||
Assert.assertNull(m.getHeader(String.valueOf(i)));
|
||||
Assert.assertNull(m.headers().get(String.valueOf(i)));
|
||||
}
|
||||
|
||||
// Check if sequential access returns nothing.
|
||||
Assert.assertTrue(m.getHeaders().isEmpty());
|
||||
Assert.assertTrue(m.headers().entries().isEmpty());
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public class HttpChunkAggregatorTest {
|
||||
HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024);
|
||||
DecoderEmbedder<HttpMessage> embedder = new DecoderEmbedder<HttpMessage>(aggr);
|
||||
HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1);
|
||||
HttpHeaders.setHeader(message, "X-Test", true);
|
||||
message.headers().set("X-Test", true);
|
||||
message.setChunked(true);
|
||||
HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII));
|
||||
HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII));
|
||||
@ -53,7 +53,7 @@ public class HttpChunkAggregatorTest {
|
||||
assertNotNull(aggratedMessage);
|
||||
|
||||
assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
|
||||
assertEquals(aggratedMessage.getHeader("X-Test"), Boolean.TRUE.toString());
|
||||
assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString());
|
||||
checkContentBuffer(aggratedMessage);
|
||||
assertNull(embedder.poll());
|
||||
|
||||
@ -75,12 +75,12 @@ public class HttpChunkAggregatorTest {
|
||||
HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024);
|
||||
DecoderEmbedder<HttpMessage> embedder = new DecoderEmbedder<HttpMessage>(aggr);
|
||||
HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1);
|
||||
HttpHeaders.setHeader(message, "X-Test", true);
|
||||
message.headers().set("X-Test", true);
|
||||
message.setChunked(true);
|
||||
HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII));
|
||||
HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII));
|
||||
HttpChunkTrailer trailer = new DefaultHttpChunkTrailer();
|
||||
trailer.setHeader("X-Trailer", true);
|
||||
trailer.trailingHeaders().set("X-Trailer", true);
|
||||
|
||||
assertFalse(embedder.offer(message));
|
||||
assertFalse(embedder.offer(chunk1));
|
||||
@ -93,8 +93,8 @@ public class HttpChunkAggregatorTest {
|
||||
assertNotNull(aggratedMessage);
|
||||
|
||||
assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
|
||||
assertEquals(aggratedMessage.getHeader("X-Test"), Boolean.TRUE.toString());
|
||||
assertEquals(aggratedMessage.getHeader("X-Trailer"), Boolean.TRUE.toString());
|
||||
assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString());
|
||||
assertEquals(aggratedMessage.headers().get("X-Trailer"), Boolean.TRUE.toString());
|
||||
checkContentBuffer(aggratedMessage);
|
||||
|
||||
assertNull(embedder.poll());
|
||||
@ -167,8 +167,8 @@ public class HttpChunkAggregatorTest {
|
||||
HttpChunkAggregator aggr = new HttpChunkAggregator(1024 * 1024);
|
||||
DecoderEmbedder<HttpMessage> embedder = new DecoderEmbedder<HttpMessage>(aggr);
|
||||
HttpMessage message = new DefaultHttpMessage(HttpVersion.HTTP_1_1);
|
||||
HttpHeaders.setHeader(message, "X-Test", true);
|
||||
HttpHeaders.setHeader(message, "Transfer-Encoding", "Chunked");
|
||||
message.headers().set("X-Test", true);
|
||||
message.headers().set("Transfer-Encoding", "Chunked");
|
||||
message.setChunked(true);
|
||||
HttpChunk chunk1 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test", CharsetUtil.US_ASCII));
|
||||
HttpChunk chunk2 = new DefaultHttpChunk(ChannelBuffers.copiedBuffer("test2", CharsetUtil.US_ASCII));
|
||||
@ -184,7 +184,7 @@ public class HttpChunkAggregatorTest {
|
||||
assertNotNull(aggratedMessage);
|
||||
|
||||
assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
|
||||
assertEquals(aggratedMessage.getHeader("X-Test"), Boolean.TRUE.toString());
|
||||
assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString());
|
||||
checkContentBuffer(aggratedMessage);
|
||||
assertNull(embedder.poll());
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ public class HttpPostRequestDecoderTest {
|
||||
final DefaultHttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "http://localhost");
|
||||
|
||||
req.setContent(ChannelBuffers.EMPTY_BUFFER);
|
||||
req.setHeader(HttpHeaders.Names.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
|
||||
req.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
|
||||
req.headers().set(HttpHeaders.Names.CONTENT_TYPE, "multipart/form-data; boundary=" + boundary);
|
||||
req.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED);
|
||||
req.setChunked(true);
|
||||
|
||||
// Force to use memory-based data.
|
||||
|
@ -98,22 +98,22 @@ public class WebSocketRequestBuilder {
|
||||
public HttpRequest build() {
|
||||
HttpRequest req = new DefaultHttpRequest(httpVersion, method, uri);
|
||||
if (host != null) {
|
||||
req.setHeader(Names.HOST, host);
|
||||
req.headers().set(Names.HOST, host);
|
||||
}
|
||||
if (upgrade != null) {
|
||||
req.setHeader(Names.UPGRADE, upgrade);
|
||||
req.headers().set(Names.UPGRADE, upgrade);
|
||||
}
|
||||
if (connection != null) {
|
||||
req.setHeader(Names.CONNECTION, connection);
|
||||
req.headers().set(Names.CONNECTION, connection);
|
||||
}
|
||||
if (key != null) {
|
||||
req.setHeader(Names.SEC_WEBSOCKET_KEY, key);
|
||||
req.headers().set(Names.SEC_WEBSOCKET_KEY, key);
|
||||
}
|
||||
if (origin != null) {
|
||||
req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, origin);
|
||||
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, origin);
|
||||
}
|
||||
if (version != null) {
|
||||
req.setHeader(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
|
||||
req.headers().set(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ public class SpdyFrameDecoderTest {
|
||||
}
|
||||
|
||||
private static void addHeader(SpdyHeadersFrame frame, int headerNameSize, int headerValueSize) {
|
||||
frame.addHeader("k", "v");
|
||||
frame.headers().add("k", "v");
|
||||
StringBuilder headerName = new StringBuilder();
|
||||
for (int i = 0; i < headerNameSize; i++) {
|
||||
headerName.append('h');
|
||||
@ -113,7 +113,7 @@ public class SpdyFrameDecoderTest {
|
||||
for (int i = 0; i < headerValueSize; i++) {
|
||||
headerValue.append('a');
|
||||
}
|
||||
frame.addHeader(headerName.toString(), headerValue.toString());
|
||||
frame.headers().add(headerName.toString(), headerValue.toString());
|
||||
}
|
||||
|
||||
protected ChannelFactory newClientSocketChannelFactory(Executor executor) {
|
||||
|
@ -46,7 +46,7 @@ public class SpdySessionHandlerTest {
|
||||
assertEquals(spdyDataFrame.isLast(), last);
|
||||
}
|
||||
|
||||
private static void assertSynReply(Object msg, int streamId, boolean last, SpdyHeadersFrame headers) {
|
||||
private static void assertSynReply(Object msg, int streamId, boolean last, SpdyHeaders headers) {
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof SpdySynReplyFrame);
|
||||
assertHeaders(msg, streamId, last, headers);
|
||||
@ -74,21 +74,21 @@ public class SpdySessionHandlerTest {
|
||||
assertEquals(spdyGoAwayFrame.getLastGoodStreamId(), lastGoodStreamId);
|
||||
}
|
||||
|
||||
private static void assertHeaders(Object msg, int streamId, boolean last, SpdyHeadersFrame headers) {
|
||||
private static void assertHeaders(Object msg, int streamId, boolean last, SpdyHeaders headers) {
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg instanceof SpdyHeadersFrame);
|
||||
SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
|
||||
assertEquals(spdyHeadersFrame.getStreamId(), streamId);
|
||||
assertEquals(spdyHeadersFrame.isLast(), last);
|
||||
for (String name: headers.getHeaderNames()) {
|
||||
List<String> expectedValues = headers.getHeaders(name);
|
||||
List<String> receivedValues = spdyHeadersFrame.getHeaders(name);
|
||||
for (String name: headers.names()) {
|
||||
List<String> expectedValues = headers.getAll(name);
|
||||
List<String> receivedValues = spdyHeadersFrame.headers().getAll(name);
|
||||
assertTrue(receivedValues.containsAll(expectedValues));
|
||||
receivedValues.removeAll(expectedValues);
|
||||
assertTrue(receivedValues.isEmpty());
|
||||
spdyHeadersFrame.removeHeader(name);
|
||||
spdyHeadersFrame.headers().remove(name);
|
||||
}
|
||||
assertTrue(spdyHeadersFrame.getHeaders().isEmpty());
|
||||
assertTrue(spdyHeadersFrame.headers().isEmpty());
|
||||
}
|
||||
|
||||
private static void testSpdySessionHandler(SpdyVersion spdyVersion, boolean server) {
|
||||
@ -101,7 +101,7 @@ public class SpdySessionHandlerTest {
|
||||
int remoteStreamId = server ? 2 : 1;
|
||||
|
||||
SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0);
|
||||
spdySynStreamFrame.setHeader("Compression", "test");
|
||||
spdySynStreamFrame.headers().set("Compression", "test");
|
||||
|
||||
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamId);
|
||||
spdyDataFrame.setLast(true);
|
||||
@ -130,13 +130,13 @@ public class SpdySessionHandlerTest {
|
||||
|
||||
// Check if frame codec correctly compresses/uncompresses headers
|
||||
sessionHandler.offer(spdySynStreamFrame);
|
||||
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame);
|
||||
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame.headers());
|
||||
assertNull(sessionHandler.peek());
|
||||
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(localStreamId);
|
||||
spdyHeadersFrame.addHeader("HEADER","test1");
|
||||
spdyHeadersFrame.addHeader("HEADER","test2");
|
||||
spdyHeadersFrame.headers().add("HEADER","test1");
|
||||
spdyHeadersFrame.headers().add("HEADER","test2");
|
||||
sessionHandler.offer(spdyHeadersFrame);
|
||||
assertHeaders(sessionHandler.poll(), localStreamId, false, spdyHeadersFrame);
|
||||
assertHeaders(sessionHandler.poll(), localStreamId, false, spdyHeadersFrame.headers());
|
||||
assertNull(sessionHandler.peek());
|
||||
localStreamId += 2;
|
||||
|
||||
@ -268,14 +268,14 @@ public class SpdySessionHandlerTest {
|
||||
int remoteStreamId = server ? 2 : 1;
|
||||
|
||||
SpdySynStreamFrame spdySynStreamFrame = new DefaultSpdySynStreamFrame(localStreamId, 0, (byte) 0);
|
||||
spdySynStreamFrame.setHeader("Compression", "test");
|
||||
spdySynStreamFrame.headers().set("Compression", "test");
|
||||
|
||||
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamId);
|
||||
spdyDataFrame.setLast(true);
|
||||
|
||||
// Send an initial request
|
||||
sessionHandler.offer(spdySynStreamFrame);
|
||||
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame);
|
||||
assertSynReply(sessionHandler.poll(), localStreamId, false, spdySynStreamFrame.headers());
|
||||
assertNull(sessionHandler.peek());
|
||||
sessionHandler.offer(spdyDataFrame);
|
||||
assertDataFrame(sessionHandler.poll(), localStreamId, true);
|
||||
@ -346,8 +346,8 @@ public class SpdySessionHandlerTest {
|
||||
int streamId = spdySynStreamFrame.getStreamId();
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||
spdySynReplyFrame.setLast(spdySynStreamFrame.isLast());
|
||||
for (Map.Entry<String, String> entry: spdySynStreamFrame.getHeaders()) {
|
||||
spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<String, String> entry: spdySynStreamFrame.headers()) {
|
||||
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
Channels.write(e.getChannel(), spdySynReplyFrame, e.getRemoteAddress());
|
||||
|
Loading…
x
Reference in New Issue
Block a user