Backport HttpHeaders / SpdyHeaders from Netty 4.

This commit is contained in:
Jeff Pinner 2013-10-17 10:58:28 -07:00 committed by Trustin Lee
parent f739579339
commit 2e5cbeabc4
55 changed files with 2147 additions and 1073 deletions

View File

@ -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);

View File

@ -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()));
}
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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());

View File

@ -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;
}
};
/**

View File

@ -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()));

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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.

View File

@ -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()));
}

View File

@ -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()));
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}
}

View File

@ -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(": ");

View File

@ -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();

View File

@ -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) {

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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());
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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) {

View File

@ -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());