Optimize the decoding and encoding of HTTP for better performance

* No need to calculate the hash of known header names multiple times
* Optimize header encoding
* Also optimize the encoding of known header values
* Optimize encoding of HTTP method, version and status
This commit is contained in:
Norman Maurer 2013-11-24 19:48:02 +01:00
parent 8be11dd79a
commit b067566a7c
35 changed files with 703 additions and 443 deletions

View File

@ -15,6 +15,8 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
@ -31,31 +33,12 @@ public class DefaultHttpHeaders extends HttpHeaders {
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 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);
private final HeaderEntry head = new HeaderEntry();
protected final boolean validate;
public DefaultHttpHeaders() {
@ -67,19 +50,50 @@ public class DefaultHttpHeaders extends HttpHeaders {
head.before = head.after = head;
}
void validateHeaderName0(String headerName) {
void validateHeaderName0(CharSequence headerName) {
validateHeaderName(headerName);
}
@Override
public HttpHeaders add(final String name, final Object value) {
String strVal;
public HttpHeaders add(HttpHeaders headers) {
if (headers instanceof DefaultHttpHeaders) {
DefaultHttpHeaders defaultHttpHeaders = (DefaultHttpHeaders) headers;
HeaderEntry e = defaultHttpHeaders.head.after;
while (e != defaultHttpHeaders.head) {
add(e.key, e.value);
e = e.after;
}
return this;
} else {
return super.add(headers);
}
}
@Override
public HttpHeaders set(HttpHeaders headers) {
if (headers instanceof DefaultHttpHeaders) {
clear();
DefaultHttpHeaders defaultHttpHeaders = (DefaultHttpHeaders) headers;
HeaderEntry e = defaultHttpHeaders.head.after;
while (e != defaultHttpHeaders.head) {
add(e.key, e.value);
e = e.after;
}
return this;
} else {
return super.set(headers);
}
}
@Override
public HttpHeaders add(final CharSequence name, final Object value) {
CharSequence strVal;
if (validate) {
validateHeaderName0(name);
strVal = toString(value);
strVal = toCharsequence(value);
validateHeaderValue(strVal);
} else {
strVal = toString(value);
strVal = toCharsequence(value);
}
int h = hash(name);
int i = index(h);
@ -88,14 +102,14 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public HttpHeaders add(String name, Iterable<?> values) {
public HttpHeaders add(CharSequence name, Iterable<?> values) {
if (validate) {
validateHeaderName0(name);
}
int h = hash(name);
int i = index(h);
for (Object v: values) {
String vstr = toString(v);
CharSequence vstr = toCharsequence(v);
if (validate) {
validateHeaderValue(vstr);
}
@ -104,7 +118,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
return this;
}
private void add0(int h, int i, final String name, final String value) {
private void add0(int h, int i, final CharSequence name, final CharSequence value) {
// Update the hash table.
HeaderEntry e = entries[i];
HeaderEntry newEntry;
@ -116,7 +130,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public HttpHeaders remove(final String name) {
public HttpHeaders remove(final CharSequence name) {
if (name == null) {
throw new NullPointerException("name");
}
@ -126,7 +140,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
return this;
}
private void remove0(int h, int i, String name) {
private void remove0(int h, int i, CharSequence name) {
HeaderEntry e = entries[i];
if (e == null) {
return;
@ -163,14 +177,14 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public HttpHeaders set(final String name, final Object value) {
String strVal;
public HttpHeaders set(final CharSequence name, final Object value) {
CharSequence strVal;
if (validate) {
validateHeaderName0(name);
strVal = toString(value);
strVal = toCharsequence(value);
validateHeaderValue(strVal);
} else {
strVal = toString(value);
strVal = toCharsequence(value);
}
int h = hash(name);
int i = index(h);
@ -180,7 +194,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public HttpHeaders set(final String name, final Iterable<?> values) {
public HttpHeaders set(final CharSequence name, final Iterable<?> values) {
if (values == null) {
throw new NullPointerException("values");
}
@ -196,7 +210,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
if (v == null) {
break;
}
String strVal = toString(v);
CharSequence strVal = toCharsequence(v);
if (validate) {
validateHeaderValue(strVal);
}
@ -214,7 +228,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public String get(final String name) {
public String get(final CharSequence name) {
if (name == null) {
throw new NullPointerException("name");
}
@ -222,7 +236,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
int h = hash(name);
int i = index(h);
HeaderEntry e = entries[i];
String value = null;
CharSequence value = null;
// loop until the first header was found
while (e != null) {
if (e.hash == h && equalsIgnoreCase(name, e.key)) {
@ -231,11 +245,14 @@ public class DefaultHttpHeaders extends HttpHeaders {
e = e.next;
}
return value;
if (value != null) {
return value.toString();
}
return null;
}
@Override
public List<String> getAll(final String name) {
public List<String> getAll(final CharSequence name) {
if (name == null) {
throw new NullPointerException("name");
}
@ -247,7 +264,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
HeaderEntry e = entries[i];
while (e != null) {
if (e.hash == h && equalsIgnoreCase(name, e.key)) {
values.addFirst(e.value);
values.addFirst(e.getValue());
}
e = e.next;
}
@ -273,7 +290,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public boolean contains(String name) {
public boolean contains(CharSequence name) {
return get(name) != null;
}
@ -283,7 +300,7 @@ public class DefaultHttpHeaders extends HttpHeaders {
}
@Override
public boolean contains(String name, String value, boolean ignoreCaseValue) {
public boolean contains(CharSequence name, CharSequence value, boolean ignoreCaseValue) {
if (name == null) {
throw new NullPointerException("name");
}
@ -315,18 +332,26 @@ public class DefaultHttpHeaders extends HttpHeaders {
HeaderEntry e = head.after;
while (e != head) {
names.add(e.key);
names.add(e.getKey());
e = e.after;
}
return names;
}
private static String toString(Object value) {
void encode(ByteBuf buf) {
HeaderEntry e = head.after;
while (e != head) {
e.encode(buf);
e = e.after;
}
}
private static CharSequence toCharsequence(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
return (String) value;
if (value instanceof CharSequence) {
return (CharSequence) value;
}
if (value instanceof Number) {
return value.toString();
@ -368,17 +393,23 @@ public class DefaultHttpHeaders extends HttpHeaders {
private final class HeaderEntry implements Map.Entry<String, String> {
final int hash;
final String key;
String value;
final CharSequence key;
CharSequence value;
HeaderEntry next;
HeaderEntry before, after;
HeaderEntry(int hash, String key, String value) {
HeaderEntry(int hash, CharSequence key, CharSequence value) {
this.hash = hash;
this.key = key;
this.value = value;
}
HeaderEntry() {
hash = -1;
key = null;
value = null;
}
void remove() {
before.after = after;
after.before = before;
@ -393,12 +424,12 @@ public class DefaultHttpHeaders extends HttpHeaders {
@Override
public String getKey() {
return key;
return key.toString();
}
@Override
public String getValue() {
return value;
return value.toString();
}
@Override
@ -407,14 +438,18 @@ public class DefaultHttpHeaders extends HttpHeaders {
throw new NullPointerException("value");
}
validateHeaderValue(value);
String oldValue = this.value;
CharSequence oldValue = this.value;
this.value = value;
return oldValue;
return oldValue.toString();
}
@Override
public String toString() {
return key + '=' + value;
return key.toString() + '=' + value.toString();
}
void encode(ByteBuf buf) {
HttpHeaders.encode(key, value, buf);
}
}
}

View File

@ -100,11 +100,11 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
}
@Override
void validateHeaderName0(String name) {
void validateHeaderName0(CharSequence name) {
super.validateHeaderName0(name);
if (name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) ||
name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) ||
name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) {
if (equalsIgnoreCase(name, HttpHeaders.Names.CONTENT_LENGTH) ||
equalsIgnoreCase(name, HttpHeaders.Names.TRANSFER_ENCODING) ||
equalsIgnoreCase(name, HttpHeaders.Names.TRAILER)) {
throw new IllegalArgumentException(
"prohibited trailing header: " + name);
}

View File

@ -93,10 +93,10 @@ public class HttpContentCompressor extends HttpContentEncoder {
}
@Override
protected Result beginEncode(HttpResponse headers, String acceptEncoding) throws Exception {
protected Result beginEncode(HttpResponse headers, CharSequence acceptEncoding) throws Exception {
String contentEncoding = headers.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
if (contentEncoding != null &&
!HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) {
!HttpHeaders.equalsIgnoreCase(HttpHeaders.Values.IDENTITY, contentEncoding)) {
return null;
}
@ -123,11 +123,11 @@ public class HttpContentCompressor extends HttpContentEncoder {
wrapper, compressionLevel, windowBits, memLevel)));
}
protected ZlibWrapper determineWrapper(String acceptEncoding) {
protected ZlibWrapper determineWrapper(CharSequence acceptEncoding) {
float starQ = -1.0f;
float gzipQ = -1.0f;
float deflateQ = -1.0f;
for (String encoding: StringUtil.split(acceptEncoding, ',')) {
for (String encoding: StringUtil.split(acceptEncoding.toString(), ',')) {
float q = 1.0f;
int equalsPos = encoding.indexOf('=');
if (equalsPos != -1) {

View File

@ -91,13 +91,13 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
if (contentEncoding != null) {
contentEncoding = contentEncoding.trim();
} else {
contentEncoding = HttpHeaders.Values.IDENTITY;
contentEncoding = HttpHeaders.Values.IDENTITY.toString();
}
if ((decoder = newContentDecoder(contentEncoding)) != null) {
// Decode the content and remove or replace the existing headers
// so that the message looks like a decoded message.
String targetContentEncoding = getTargetContentEncoding(contentEncoding);
CharSequence targetContentEncoding = getTargetContentEncoding(contentEncoding);
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
@ -185,7 +185,7 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObj
* @return the expected content encoding of the new content
*/
@SuppressWarnings("unused")
protected String getTargetContentEncoding(String contentEncoding) throws Exception {
protected CharSequence getTargetContentEncoding(String contentEncoding) throws Exception {
return HttpHeaders.Values.IDENTITY;
}

View File

@ -31,18 +31,18 @@ import java.util.Queue;
/**
* Encodes the content of the outbound {@link HttpResponse} and {@link HttpContent}.
* The original content is replaced with the new content encoded by the
* {@link EmbeddedChannel}, which is created by {@link #beginEncode(HttpResponse, String)}.
* {@link EmbeddedChannel}, which is created by {@link #beginEncode(HttpResponse, CharSequence)}.
* Once encoding is finished, the value of the <tt>'Content-Encoding'</tt> header
* is set to the target content encoding, as returned by
* {@link #beginEncode(HttpResponse, String)}.
* {@link #beginEncode(HttpResponse, CharSequence)}.
* Also, the <tt>'Content-Length'</tt> header is updated to the length of the
* encoded content. If there is no supported or allowed encoding in the
* corresponding {@link HttpRequest}'s {@code "Accept-Encoding"} header,
* {@link #beginEncode(HttpResponse, String)} should return {@code null} so that
* {@link #beginEncode(HttpResponse, CharSequence)} should return {@code null} so that
* no encoding occurs (i.e. pass-through).
* <p>
* Please note that this is an abstract class. You have to extend this class
* and implement {@link #beginEncode(HttpResponse, String)} properly to make
* and implement {@link #beginEncode(HttpResponse, CharSequence)} properly to make
* this class functional. For example, refer to the source code of
* {@link HttpContentCompressor}.
* <p>
@ -58,8 +58,8 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
AWAIT_CONTENT
}
private final Queue<String> acceptEncodingQueue = new ArrayDeque<String>();
private String acceptEncoding;
private final Queue<CharSequence> acceptEncodingQueue = new ArrayDeque<CharSequence>();
private CharSequence acceptEncoding;
private EmbeddedChannel encoder;
private State state = State.AWAIT_HEADERS;
@ -71,7 +71,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
@Override
protected void decode(ChannelHandlerContext ctx, HttpRequest msg, List<Object> out)
throws Exception {
String acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
CharSequence acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
if (acceptedEncoding == null) {
acceptedEncoding = HttpHeaders.Values.IDENTITY;
}
@ -228,7 +228,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpReque
* {@code null} if {@code acceptEncoding} is unsupported or rejected
* and thus the content should be handled as-is (i.e. no encoding).
*/
protected abstract Result beginEncode(HttpResponse headers, String acceptEncoding) throws Exception;
protected abstract Result beginEncode(HttpResponse headers, CharSequence acceptEncoding) throws Exception;
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

View File

@ -0,0 +1,60 @@
/*
* 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 io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
final class HttpHeaderEntity implements CharSequence {
private final String name;
private final int hash;
private final byte[] bytes;
public HttpHeaderEntity(String name) {
this.name = name;
hash = HttpHeaders.hash(name);
bytes = name.getBytes(CharsetUtil.US_ASCII);
}
int hash() {
return hash;
}
@Override
public int length() {
return bytes.length;
}
@Override
public char charAt(int index) {
return (char) bytes[index];
}
@Override
public CharSequence subSequence(int start, int end) {
return new HttpHeaderEntity(name.substring(start, end));
}
@Override
public String toString() {
return name;
}
void encode(ByteBuf buf) {
buf.writeBytes(bytes);
}
}

View File

@ -15,6 +15,8 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Collections;
@ -25,6 +27,9 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static io.netty.handler.codec.http.HttpConstants.CR;
import static io.netty.handler.codec.http.HttpConstants.LF;
/**
* Provides the constants for the standard HTTP header names and values and
@ -32,14 +37,17 @@ import java.util.Set;
*/
public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>> {
private static final byte[] HEADER_SEPERATOR = { HttpConstants.COLON, HttpConstants.SP };
private static final byte[] CRLF = { CR, LF };
public static final HttpHeaders EMPTY_HEADERS = new HttpHeaders() {
@Override
public String get(String name) {
public String get(CharSequence name) {
return null;
}
@Override
public List<String> getAll(String name) {
public List<String> getAll(CharSequence name) {
return Collections.emptyList();
}
@ -49,7 +57,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
}
@Override
public boolean contains(String name) {
public boolean contains(CharSequence name) {
return false;
}
@ -64,27 +72,27 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
}
@Override
public HttpHeaders add(String name, Object value) {
public HttpHeaders add(CharSequence name, Object value) {
throw new UnsupportedOperationException("read only");
}
@Override
public HttpHeaders add(String name, Iterable<?> values) {
public HttpHeaders add(CharSequence name, Iterable<?> values) {
throw new UnsupportedOperationException("read only");
}
@Override
public HttpHeaders set(String name, Object value) {
public HttpHeaders set(CharSequence name, Object value) {
throw new UnsupportedOperationException("read only");
}
@Override
public HttpHeaders set(String name, Iterable<?> values) {
public HttpHeaders set(CharSequence name, Iterable<?> values) {
throw new UnsupportedOperationException("read only");
}
@Override
public HttpHeaders remove(String name) {
public HttpHeaders remove(CharSequence name) {
throw new UnsupportedOperationException("read only");
}
@ -106,295 +114,302 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
/**
* {@code "Accept"}
*/
public static final String ACCEPT = "Accept";
public static final CharSequence ACCEPT = newEntity("Accept");
/**
* {@code "Accept-Charset"}
*/
public static final String ACCEPT_CHARSET = "Accept-Charset";
public static final CharSequence ACCEPT_CHARSET = newEntity("Accept-Charset");
/**
* {@code "Accept-Encoding"}
*/
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final CharSequence ACCEPT_ENCODING = newEntity("Accept-Encoding");
/**
* {@code "Accept-Language"}
*/
public static final String ACCEPT_LANGUAGE = "Accept-Language";
public static final CharSequence ACCEPT_LANGUAGE = newEntity("Accept-Language");
/**
* {@code "Accept-Ranges"}
*/
public static final String ACCEPT_RANGES = "Accept-Ranges";
public static final CharSequence ACCEPT_RANGES = newEntity("Accept-Ranges");
/**
* {@code "Accept-Patch"}
*/
public static final String ACCEPT_PATCH = "Accept-Patch";
public static final CharSequence ACCEPT_PATCH = newEntity("Accept-Patch");
/**
* {@code "Access-Control-Allow-Credentials"}
*/
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
public static final CharSequence ACCESS_CONTROL_ALLOW_CREDENTIALS =
newEntity("Access-Control-Allow-Credentials");
/**
* {@code "Access-Control-Allow-Headers"}
*/
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
public static final CharSequence ACCESS_CONTROL_ALLOW_HEADERS =
newEntity("Access-Control-Allow-Headers");
/**
* {@code "Access-Control-Allow-Methods"}
*/
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
public static final CharSequence ACCESS_CONTROL_ALLOW_METHODS =
newEntity("Access-Control-Allow-Methods");
/**
* {@code "Access-Control-Allow-Origin"}
*/
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
public static final CharSequence ACCESS_CONTROL_ALLOW_ORIGIN =
newEntity("Access-Control-Allow-Origin");
/**
* {@code "Access-Control-Expose-Headers"}
*/
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
public static final CharSequence ACCESS_CONTROL_EXPOSE_HEADERS =
newEntity("Access-Control-Expose-Headers");
/**
* {@code "Access-Control-Max-Age"}
*/
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
public static final CharSequence ACCESS_CONTROL_MAX_AGE = newEntity("Access-Control-Max-Age");
/**
* {@code "Access-Control-Request-Headers"}
*/
public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
public static final CharSequence ACCESS_CONTROL_REQUEST_HEADERS =
newEntity("Access-Control-Request-Headers");
/**
* {@code "Access-Control-Request-Method"}
*/
public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
public static final CharSequence ACCESS_CONTROL_REQUEST_METHOD =
newEntity("Access-Control-Request-Method");
/**
* {@code "Age"}
*/
public static final String AGE = "Age";
public static final CharSequence AGE = newEntity("Age");
/**
* {@code "Allow"}
*/
public static final String ALLOW = "Allow";
public static final CharSequence ALLOW = newEntity("Allow");
/**
* {@code "Authorization"}
*/
public static final String AUTHORIZATION = "Authorization";
public static final CharSequence AUTHORIZATION = newEntity("Authorization");
/**
* {@code "Cache-Control"}
*/
public static final String CACHE_CONTROL = "Cache-Control";
public static final CharSequence CACHE_CONTROL = newEntity("Cache-Control");
/**
* {@code "Connection"}
*/
public static final String CONNECTION = "Connection";
public static final CharSequence CONNECTION = newEntity("Connection");
/**
* {@code "Content-Base"}
*/
public static final String CONTENT_BASE = "Content-Base";
public static final CharSequence CONTENT_BASE = newEntity("Content-Base");
/**
* {@code "Content-Encoding"}
*/
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final CharSequence CONTENT_ENCODING = newEntity("Content-Encoding");
/**
* {@code "Content-Language"}
*/
public static final String CONTENT_LANGUAGE = "Content-Language";
public static final CharSequence CONTENT_LANGUAGE = newEntity("Content-Language");
/**
* {@code "Content-Length"}
*/
public static final String CONTENT_LENGTH = "Content-Length";
public static final CharSequence CONTENT_LENGTH = newEntity("Content-Length");
/**
* {@code "Content-Location"}
*/
public static final String CONTENT_LOCATION = "Content-Location";
public static final CharSequence CONTENT_LOCATION = newEntity("Content-Location");
/**
* {@code "Content-Transfer-Encoding"}
*/
public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
public static final CharSequence CONTENT_TRANSFER_ENCODING = newEntity("Content-Transfer-Encoding");
/**
* {@code "Content-MD5"}
*/
public static final String CONTENT_MD5 = "Content-MD5";
public static final CharSequence CONTENT_MD5 = newEntity("Content-MD5");
/**
* {@code "Content-Range"}
*/
public static final String CONTENT_RANGE = "Content-Range";
public static final CharSequence CONTENT_RANGE = newEntity("Content-Range");
/**
* {@code "Content-Type"}
*/
public static final String CONTENT_TYPE = "Content-Type";
public static final CharSequence CONTENT_TYPE = newEntity("Content-Type");
/**
* {@code "Cookie"}
*/
public static final String COOKIE = "Cookie";
public static final CharSequence COOKIE = newEntity("Cookie");
/**
* {@code "Date"}
*/
public static final String DATE = "Date";
public static final CharSequence DATE = newEntity("Date");
/**
* {@code "ETag"}
*/
public static final String ETAG = "ETag";
public static final CharSequence ETAG = newEntity("ETag");
/**
* {@code "Expect"}
*/
public static final String EXPECT = "Expect";
public static final CharSequence EXPECT = newEntity("Expect");
/**
* {@code "Expires"}
*/
public static final String EXPIRES = "Expires";
public static final CharSequence EXPIRES = newEntity("Expires");
/**
* {@code "From"}
*/
public static final String FROM = "From";
public static final CharSequence FROM = newEntity("From");
/**
* {@code "Host"}
*/
public static final String HOST = "Host";
public static final CharSequence HOST = newEntity("Host");
/**
* {@code "If-Match"}
*/
public static final String IF_MATCH = "If-Match";
public static final CharSequence IF_MATCH = newEntity("If-Match");
/**
* {@code "If-Modified-Since"}
*/
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
public static final CharSequence IF_MODIFIED_SINCE = newEntity("If-Modified-Since");
/**
* {@code "If-None-Match"}
*/
public static final String IF_NONE_MATCH = "If-None-Match";
public static final CharSequence IF_NONE_MATCH = newEntity("If-None-Match");
/**
* {@code "If-Range"}
*/
public static final String IF_RANGE = "If-Range";
public static final CharSequence IF_RANGE = newEntity("If-Range");
/**
* {@code "If-Unmodified-Since"}
*/
public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
public static final CharSequence IF_UNMODIFIED_SINCE = newEntity("If-Unmodified-Since");
/**
* {@code "Last-Modified"}
*/
public static final String LAST_MODIFIED = "Last-Modified";
public static final CharSequence LAST_MODIFIED = newEntity("Last-Modified");
/**
* {@code "Location"}
*/
public static final String LOCATION = "Location";
public static final CharSequence LOCATION = newEntity("Location");
/**
* {@code "Max-Forwards"}
*/
public static final String MAX_FORWARDS = "Max-Forwards";
public static final CharSequence MAX_FORWARDS = newEntity("Max-Forwards");
/**
* {@code "Origin"}
*/
public static final String ORIGIN = "Origin";
public static final CharSequence ORIGIN = newEntity("Origin");
/**
* {@code "Pragma"}
*/
public static final String PRAGMA = "Pragma";
public static final CharSequence PRAGMA = newEntity("Pragma");
/**
* {@code "Proxy-Authenticate"}
*/
public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
public static final CharSequence PROXY_AUTHENTICATE = newEntity("Proxy-Authenticate");
/**
* {@code "Proxy-Authorization"}
*/
public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
public static final CharSequence PROXY_AUTHORIZATION = newEntity("Proxy-Authorization");
/**
* {@code "Range"}
*/
public static final String RANGE = "Range";
public static final CharSequence RANGE = newEntity("Range");
/**
* {@code "Referer"}
*/
public static final String REFERER = "Referer";
public static final CharSequence REFERER = newEntity("Referer");
/**
* {@code "Retry-After"}
*/
public static final String RETRY_AFTER = "Retry-After";
public static final CharSequence RETRY_AFTER = newEntity("Retry-After");
/**
* {@code "Sec-WebSocket-Key1"}
*/
public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1";
public static final CharSequence SEC_WEBSOCKET_KEY1 = newEntity("Sec-WebSocket-Key1");
/**
* {@code "Sec-WebSocket-Key2"}
*/
public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2";
public static final CharSequence SEC_WEBSOCKET_KEY2 = newEntity("Sec-WebSocket-Key2");
/**
* {@code "Sec-WebSocket-Location"}
*/
public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location";
public static final CharSequence SEC_WEBSOCKET_LOCATION = newEntity("Sec-WebSocket-Location");
/**
* {@code "Sec-WebSocket-Origin"}
*/
public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin";
public static final CharSequence SEC_WEBSOCKET_ORIGIN = newEntity("Sec-WebSocket-Origin");
/**
* {@code "Sec-WebSocket-Protocol"}
*/
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
public static final CharSequence SEC_WEBSOCKET_PROTOCOL = newEntity("Sec-WebSocket-Protocol");
/**
* {@code "Sec-WebSocket-Version"}
*/
public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
public static final CharSequence SEC_WEBSOCKET_VERSION = newEntity("Sec-WebSocket-Version");
/**
* {@code "Sec-WebSocket-Key"}
*/
public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
public static final CharSequence SEC_WEBSOCKET_KEY = newEntity("Sec-WebSocket-Key");
/**
* {@code "Sec-WebSocket-Accept"}
*/
public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
public static final CharSequence SEC_WEBSOCKET_ACCEPT = newEntity("Sec-WebSocket-Accept");
/**
* {@code "Server"}
*/
public static final String SERVER = "Server";
public static final CharSequence SERVER = newEntity("Server");
/**
* {@code "Set-Cookie"}
*/
public static final String SET_COOKIE = "Set-Cookie";
public static final CharSequence SET_COOKIE = newEntity("Set-Cookie");
/**
* {@code "Set-Cookie2"}
*/
public static final String SET_COOKIE2 = "Set-Cookie2";
public static final CharSequence SET_COOKIE2 = newEntity("Set-Cookie2");
/**
* {@code "TE"}
*/
public static final String TE = "TE";
public static final CharSequence TE = newEntity("TE");
/**
* {@code "Trailer"}
*/
public static final String TRAILER = "Trailer";
public static final CharSequence TRAILER = newEntity("Trailer");
/**
* {@code "Transfer-Encoding"}
*/
public static final String TRANSFER_ENCODING = "Transfer-Encoding";
public static final CharSequence TRANSFER_ENCODING = newEntity("Transfer-Encoding");
/**
* {@code "Upgrade"}
*/
public static final String UPGRADE = "Upgrade";
public static final CharSequence UPGRADE = newEntity("Upgrade");
/**
* {@code "User-Agent"}
*/
public static final String USER_AGENT = "User-Agent";
public static final CharSequence USER_AGENT = newEntity("User-Agent");
/**
* {@code "Vary"}
*/
public static final String VARY = "Vary";
public static final CharSequence VARY = newEntity("Vary");
/**
* {@code "Via"}
*/
public static final String VIA = "Via";
public static final CharSequence VIA = newEntity("Via");
/**
* {@code "Warning"}
*/
public static final String WARNING = "Warning";
public static final CharSequence WARNING = newEntity("Warning");
/**
* {@code "WebSocket-Location"}
*/
public static final String WEBSOCKET_LOCATION = "WebSocket-Location";
public static final CharSequence WEBSOCKET_LOCATION = newEntity("WebSocket-Location");
/**
* {@code "WebSocket-Origin"}
*/
public static final String WEBSOCKET_ORIGIN = "WebSocket-Origin";
public static final CharSequence WEBSOCKET_ORIGIN = newEntity("WebSocket-Origin");
/**
* {@code "WebSocket-Protocol"}
*/
public static final String WEBSOCKET_PROTOCOL = "WebSocket-Protocol";
public static final CharSequence WEBSOCKET_PROTOCOL = newEntity("WebSocket-Protocol");
/**
* {@code "WWW-Authenticate"}
*/
public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
public static final CharSequence WWW_AUTHENTICATE = newEntity("WWW-Authenticate");
private Names() {
}
@ -407,132 +422,132 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
/**
* {@code "application/x-www-form-urlencoded"}
*/
public static final String APPLICATION_X_WWW_FORM_URLENCODED =
"application/x-www-form-urlencoded";
public static final CharSequence APPLICATION_X_WWW_FORM_URLENCODED =
newEntity("application/x-www-form-urlencoded");
/**
* {@code "base64"}
*/
public static final String BASE64 = "base64";
public static final CharSequence BASE64 = newEntity("base64");
/**
* {@code "binary"}
*/
public static final String BINARY = "binary";
public static final CharSequence BINARY = newEntity("binary");
/**
* {@code "boundary"}
*/
public static final String BOUNDARY = "boundary";
public static final CharSequence BOUNDARY = newEntity("boundary");
/**
* {@code "bytes"}
*/
public static final String BYTES = "bytes";
public static final CharSequence BYTES = newEntity("bytes");
/**
* {@code "charset"}
*/
public static final String CHARSET = "charset";
public static final CharSequence CHARSET = newEntity("charset");
/**
* {@code "chunked"}
*/
public static final String CHUNKED = "chunked";
public static final CharSequence CHUNKED = newEntity("chunked");
/**
* {@code "close"}
*/
public static final String CLOSE = "close";
public static final CharSequence CLOSE = newEntity("close");
/**
* {@code "compress"}
*/
public static final String COMPRESS = "compress";
public static final CharSequence COMPRESS = newEntity("compress");
/**
* {@code "100-continue"}
*/
public static final String CONTINUE = "100-continue";
public static final CharSequence CONTINUE = newEntity("100-continue");
/**
* {@code "deflate"}
*/
public static final String DEFLATE = "deflate";
public static final CharSequence DEFLATE = newEntity("deflate");
/**
* {@code "gzip"}
*/
public static final String GZIP = "gzip";
public static final CharSequence GZIP = newEntity("gzip");
/**
* {@code "identity"}
*/
public static final String IDENTITY = "identity";
public static final CharSequence IDENTITY = newEntity("identity");
/**
* {@code "keep-alive"}
*/
public static final String KEEP_ALIVE = "keep-alive";
public static final CharSequence KEEP_ALIVE = newEntity("keep-alive");
/**
* {@code "max-age"}
*/
public static final String MAX_AGE = "max-age";
public static final CharSequence MAX_AGE = newEntity("max-age");
/**
* {@code "max-stale"}
*/
public static final String MAX_STALE = "max-stale";
public static final CharSequence MAX_STALE = newEntity("max-stale");
/**
* {@code "min-fresh"}
*/
public static final String MIN_FRESH = "min-fresh";
public static final CharSequence MIN_FRESH = newEntity("min-fresh");
/**
* {@code "multipart/form-data"}
*/
public static final String MULTIPART_FORM_DATA = "multipart/form-data";
public static final CharSequence MULTIPART_FORM_DATA = newEntity("multipart/form-data");
/**
* {@code "must-revalidate"}
*/
public static final String MUST_REVALIDATE = "must-revalidate";
public static final CharSequence MUST_REVALIDATE = newEntity("must-revalidate");
/**
* {@code "no-cache"}
*/
public static final String NO_CACHE = "no-cache";
public static final CharSequence NO_CACHE = newEntity("no-cache");
/**
* {@code "no-store"}
*/
public static final String NO_STORE = "no-store";
public static final CharSequence NO_STORE = newEntity("no-store");
/**
* {@code "no-transform"}
*/
public static final String NO_TRANSFORM = "no-transform";
public static final CharSequence NO_TRANSFORM = newEntity("no-transform");
/**
* {@code "none"}
*/
public static final String NONE = "none";
public static final CharSequence NONE = newEntity("none");
/**
* {@code "only-if-cached"}
*/
public static final String ONLY_IF_CACHED = "only-if-cached";
public static final CharSequence ONLY_IF_CACHED = newEntity("only-if-cached");
/**
* {@code "private"}
*/
public static final String PRIVATE = "private";
public static final CharSequence PRIVATE = newEntity("private");
/**
* {@code "proxy-revalidate"}
*/
public static final String PROXY_REVALIDATE = "proxy-revalidate";
public static final CharSequence PROXY_REVALIDATE = newEntity("proxy-revalidate");
/**
* {@code "public"}
*/
public static final String PUBLIC = "public";
public static final CharSequence PUBLIC = newEntity("public");
/**
* {@code "quoted-printable"}
*/
public static final String QUOTED_PRINTABLE = "quoted-printable";
public static final CharSequence QUOTED_PRINTABLE = newEntity("quoted-printable");
/**
* {@code "s-maxage"}
*/
public static final String S_MAXAGE = "s-maxage";
public static final CharSequence S_MAXAGE = newEntity("s-maxage");
/**
* {@code "trailers"}
*/
public static final String TRAILERS = "trailers";
public static final CharSequence TRAILERS = newEntity("trailers");
/**
* {@code "Upgrade"}
*/
public static final String UPGRADE = "Upgrade";
public static final CharSequence UPGRADE = newEntity("Upgrade");
/**
* {@code "WebSocket"}
*/
public static final String WEBSOCKET = "WebSocket";
public static final CharSequence WEBSOCKET = newEntity("WebSocket");
private Values() {
}
@ -600,7 +615,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
*
* @return the header value or {@code null} if there is no such header
*/
public static String getHeader(HttpMessage message, String name) {
public static String getHeader(HttpMessage message, CharSequence name) {
return message.headers().get(name);
}
@ -612,7 +627,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @return the header value or the {@code defaultValue} if there is no such
* header
*/
public static String getHeader(HttpMessage message, String name, String defaultValue) {
public static String getHeader(HttpMessage message, CharSequence name, String defaultValue) {
String value = message.headers().get(name);
if (value == null) {
return defaultValue;
@ -628,7 +643,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* and {@link Calendar} which are formatted to the date format defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>.
*/
public static void setHeader(HttpMessage message, String name, Object value) {
public static void setHeader(HttpMessage message, CharSequence name, Object value) {
message.headers().set(name, value);
}
@ -646,7 +661,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* }
* </pre>
*/
public static void setHeader(HttpMessage message, String name, Iterable<?> values) {
public static void setHeader(HttpMessage message, CharSequence name, Iterable<?> values) {
message.headers().set(name, values);
}
@ -657,14 +672,14 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* and {@link Calendar} which are formatted to the date format defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>.
*/
public static void addHeader(HttpMessage message, String name, Object value) {
public static void addHeader(HttpMessage message, CharSequence name, Object value) {
message.headers().add(name, value);
}
/**
* Removes the header with the specified name.
*/
public static void removeHeader(HttpMessage message, String name) {
public static void removeHeader(HttpMessage message, CharSequence name) {
message.headers().remove(name);
}
@ -684,7 +699,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @throws NumberFormatException
* if there is no such header or the header value is not a number
*/
public static int getIntHeader(HttpMessage message, String name) {
public static int getIntHeader(HttpMessage message, CharSequence name) {
String value = getHeader(message, name);
if (value == null) {
throw new NumberFormatException("header not found: " + name);
@ -700,7 +715,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @return the header value or the {@code defaultValue} if there is no such
* header or the header value is not a number
*/
public static int getIntHeader(HttpMessage message, String name, int defaultValue) {
public static int getIntHeader(HttpMessage message, CharSequence name, int defaultValue) {
String value = getHeader(message, name);
if (value == null) {
return defaultValue;
@ -717,7 +732,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* Sets a new integer header with the specified name and value. If there
* is an existing header with the same name, the existing header is removed.
*/
public static void setIntHeader(HttpMessage message, String name, int value) {
public static void setIntHeader(HttpMessage message, CharSequence name, int value) {
message.headers().set(name, value);
}
@ -725,14 +740,14 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* Sets a new integer header with the specified name and values. If there
* is an existing header with the same name, the existing header is removed.
*/
public static void setIntHeader(HttpMessage message, String name, Iterable<Integer> values) {
public static void setIntHeader(HttpMessage message, CharSequence name, Iterable<Integer> values) {
message.headers().set(name, values);
}
/**
* Adds a new integer header with the specified name and value.
*/
public static void addIntHeader(HttpMessage message, String name, int value) {
public static void addIntHeader(HttpMessage message, CharSequence name, int value) {
message.headers().add(name, value);
}
@ -745,7 +760,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @throws ParseException
* if there is no such header or the header value is not a formatted date
*/
public static Date getDateHeader(HttpMessage message, String name) throws ParseException {
public static Date getDateHeader(HttpMessage message, CharSequence name) throws ParseException {
String value = getHeader(message, name);
if (value == null) {
throw new ParseException("header not found: " + name, 0);
@ -761,7 +776,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @return the header value or the {@code defaultValue} if there is no such
* header or the header value is not a formatted date
*/
public static Date getDateHeader(HttpMessage message, String name, Date defaultValue) {
public static Date getDateHeader(HttpMessage message, CharSequence name, Date defaultValue) {
final String value = getHeader(message, name);
if (value == null) {
return defaultValue;
@ -780,7 +795,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* The specified value is formatted as defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
*/
public static void setDateHeader(HttpMessage message, String name, Date value) {
public static void setDateHeader(HttpMessage message, CharSequence name, Date value) {
if (value != null) {
message.headers().set(name, HttpHeaderDateFormat.get().format(value));
} else {
@ -794,7 +809,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* The specified values are formatted as defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
*/
public static void setDateHeader(HttpMessage message, String name, Iterable<Date> values) {
public static void setDateHeader(HttpMessage message, CharSequence name, Iterable<Date> values) {
message.headers().set(name, values);
}
@ -803,7 +818,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* value is formatted as defined in
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
*/
public static void addDateHeader(HttpMessage message, String name, Date value) {
public static void addDateHeader(HttpMessage message, CharSequence name, Date value) {
message.headers().add(name, value);
}
@ -1010,7 +1025,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
*
* @param headerName The header name being validated
*/
static void validateHeaderName(String headerName) {
static void validateHeaderName(CharSequence headerName) {
//Check to see if the name is null
if (headerName == null) {
throw new NullPointerException("Header names cannot be null");
@ -1042,7 +1057,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
*
* @param headerValue The value being validated
*/
static void validateHeaderValue(String headerValue) {
static void validateHeaderValue(CharSequence headerValue) {
//Check to see if the value is null
if (headerValue == null) {
throw new NullPointerException("Header values cannot be null");
@ -1183,6 +1198,72 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
}
return true;
}
static int hash(CharSequence name) {
if (name instanceof HttpHeaderEntity) {
return ((HttpHeaderEntity) name).hash();
}
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;
}
}
static void encode(HttpHeaders headers, ByteBuf buf) {
if (headers instanceof DefaultHttpHeaders) {
((DefaultHttpHeaders) headers).encode(buf);
} else {
for (Entry<String, String> header: headers) {
encode(header.getKey(), header.getValue(), buf);
}
}
}
static void encode(CharSequence key, CharSequence value, ByteBuf buf) {
encodeAscii(key, buf);
buf.writeBytes(HEADER_SEPERATOR);
encodeAscii(value, buf);
buf.writeBytes(CRLF);
}
public static void encodeAscii(CharSequence seq, ByteBuf buf) {
if (seq instanceof HttpHeaderEntity) {
((HttpHeaderEntity) seq).encode(buf);
} else {
encodeAscii0(seq, buf);
}
}
static void encodeAscii0(CharSequence seq, ByteBuf buf) {
int length = seq.length();
for (int i = 0 ; i < length; i++) {
buf.writeByte((byte) seq.charAt(i));
}
}
/**
* Create a new {@link CharSequence} which is optimized for reuse as {@link HttpHeaders} name or value.
* So if you have a Header name or value that you want to reuse you should make use of this.
*/
public static CharSequence newEntity(String name) {
if (name == null) {
throw new NullPointerException("name");
}
return new HttpHeaderEntity(name);
}
protected HttpHeaders() { }
/**
@ -1192,7 +1273,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param name The name of the header to search
* @return The first header value or {@code null} if there is no such header
*/
public abstract String get(String name);
public abstract String get(CharSequence name);
/**
* Returns the values of headers with the specified name
@ -1201,7 +1282,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @return A {@link List} of header values which will be empty if no values
* are found
*/
public abstract List<String> getAll(String name);
public abstract List<String> getAll(CharSequence name);
/**
* Returns the all headers that this message contains.
@ -1217,7 +1298,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param name The name of the header to search for
* @return True if at least one header is found
*/
public abstract boolean contains(String name);
public abstract boolean contains(CharSequence name);
/**
* Checks if no header exists.
@ -1244,7 +1325,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
*
* @return {@code this}
*/
public abstract HttpHeaders add(String name, Object value);
public abstract HttpHeaders add(CharSequence name, Object value);
/**
* Adds a new header with the specified name and values.
@ -1263,7 +1344,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param values The values of the headers being set
* @return {@code this}
*/
public abstract HttpHeaders add(String name, Iterable<?> values);
public abstract HttpHeaders add(CharSequence name, Iterable<?> values);
/**
* Adds all header entries of the specified {@code headers}.
@ -1293,7 +1374,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param value The value of the header being set
* @return {@code this}
*/
public abstract HttpHeaders set(String name, Object value);
public abstract HttpHeaders set(CharSequence name, Object value);
/**
* Sets a header with the specified name and values.
@ -1314,7 +1395,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param values The values of the headers being set
* @return {@code this}
*/
public abstract HttpHeaders set(String name, Iterable<?> values);
public abstract HttpHeaders set(CharSequence name, Iterable<?> values);
/**
* Cleans the current header entries and copies all header entries of the specified {@code headers}.
@ -1338,7 +1419,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param name The name of the header to remove
* @return {@code this}
*/
public abstract HttpHeaders remove(String name);
public abstract HttpHeaders remove(CharSequence name);
/**
* Removes all headers from this {@link HttpMessage}.
@ -1355,7 +1436,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
* @param ignoreCaseValue {@code true} if case should be ignored
* @return contains {@code true} if it contains it {@code false} otherwise
*/
public boolean contains(String name, String value, boolean ignoreCaseValue) {
public boolean contains(CharSequence name, CharSequence value, boolean ignoreCaseValue) {
List<String> values = getAll(name);
if (values.isEmpty()) {
return false;

View File

@ -15,6 +15,9 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import java.util.HashMap;
import java.util.Map;
@ -31,7 +34,7 @@ public class HttpMethod implements Comparable<HttpMethod> {
* capabilities of a server, without implying a resource action or initiating a resource
* retrieval.
*/
public static final HttpMethod OPTIONS = new HttpMethod("OPTIONS");
public static final HttpMethod OPTIONS = new HttpMethod("OPTIONS", true);
/**
* The GET getMethod means retrieve whatever information (in the form of an entity) is identified
@ -39,49 +42,49 @@ public class HttpMethod implements Comparable<HttpMethod> {
* produced data which shall be returned as the entity in the response and not the source text
* of the process, unless that text happens to be the output of the process.
*/
public static final HttpMethod GET = new HttpMethod("GET");
public static final HttpMethod GET = new HttpMethod("GET", true);
/**
* The HEAD getMethod is identical to GET except that the server MUST NOT return a message-body
* in the response.
*/
public static final HttpMethod HEAD = new HttpMethod("HEAD");
public static final HttpMethod HEAD = new HttpMethod("HEAD", true);
/**
* The POST getMethod is used to request that the origin server accept the entity enclosed in the
* request as a new subordinate of the resource identified by the Request-URI in the
* Request-Line.
*/
public static final HttpMethod POST = new HttpMethod("POST");
public static final HttpMethod POST = new HttpMethod("POST", true);
/**
* The PUT getMethod requests that the enclosed entity be stored under the supplied Request-URI.
*/
public static final HttpMethod PUT = new HttpMethod("PUT");
public static final HttpMethod PUT = new HttpMethod("PUT", true);
/**
* The PATCH getMethod requests that a set of changes described in the
* request entity be applied to the resource identified by the Request-URI.
*/
public static final HttpMethod PATCH = new HttpMethod("PATCH");
public static final HttpMethod PATCH = new HttpMethod("PATCH", true);
/**
* The DELETE getMethod requests that the origin server delete the resource identified by the
* Request-URI.
*/
public static final HttpMethod DELETE = new HttpMethod("DELETE");
public static final HttpMethod DELETE = new HttpMethod("DELETE", true);
/**
* The TRACE getMethod is used to invoke a remote, application-layer loop- back of the request
* message.
*/
public static final HttpMethod TRACE = new HttpMethod("TRACE");
public static final HttpMethod TRACE = new HttpMethod("TRACE", true);
/**
* This specification reserves the getMethod name CONNECT for use with a proxy that can dynamically
* switch to being a tunnel
*/
public static final HttpMethod CONNECT = new HttpMethod("CONNECT");
public static final HttpMethod CONNECT = new HttpMethod("CONNECT", true);
private static final Map<String, HttpMethod> methodMap =
new HashMap<String, HttpMethod>();
@ -122,6 +125,7 @@ public class HttpMethod implements Comparable<HttpMethod> {
}
private final String name;
private final byte[] bytes;
/**
* Creates a new HTTP getMethod with the specified name. You will not need to
@ -131,6 +135,10 @@ public class HttpMethod implements Comparable<HttpMethod> {
* <a href="http://en.wikipedia.org/wiki/Internet_Content_Adaptation_Protocol">ICAP</a>
*/
public HttpMethod(String name) {
this(name, false);
}
private HttpMethod(String name, boolean bytes) {
if (name == null) {
throw new NullPointerException("name");
}
@ -148,6 +156,11 @@ public class HttpMethod implements Comparable<HttpMethod> {
}
this.name = name;
if (bytes) {
this.bytes = name.getBytes(CharsetUtil.US_ASCII);
} else {
this.bytes = null;
}
}
/**
@ -181,4 +194,12 @@ public class HttpMethod implements Comparable<HttpMethod> {
public int compareTo(HttpMethod o) {
return name().compareTo(o.name());
}
void encode(ByteBuf buf) {
if (bytes == null) {
HttpHeaders.encodeAscii0(name, buf);
} else {
buf.writeBytes(bytes);
}
}
}

View File

@ -23,7 +23,6 @@ import io.netty.util.CharsetUtil;
import io.netty.util.internal.StringUtil;
import java.util.List;
import java.util.Map;
import static io.netty.buffer.Unpooled.*;
import static io.netty.handler.codec.http.HttpConstants.*;
@ -45,7 +44,6 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
private static final byte[] CRLF = { CR, LF };
private static final byte[] ZERO_CRLF = { '0', CR, LF };
private static final byte[] ZERO_CRLF_CRLF = { '0', CR, LF, CR, LF };
private static final byte[] HEADER_SEPARATOR = { COLON, SP };
private static final ByteBuf CRLF_BUF = unreleasableBuffer(directBuffer(CRLF.length).writeBytes(CRLF));
private static final ByteBuf ZERO_CRLF_CRLF_BUF = unreleasableBuffer(directBuffer(ZERO_CRLF_CRLF.length)
.writeBytes(ZERO_CRLF_CRLF));
@ -70,7 +68,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
ByteBuf buf = ctx.alloc().buffer();
// Encode the message.
encodeInitialLine(buf, m);
encodeHeaders(buf, m.headers());
HttpHeaders.encode(m.headers(), buf);
buf.writeBytes(CRLF);
out.add(buf);
state = HttpHeaders.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK;
@ -119,7 +117,7 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
} else {
ByteBuf buf = ctx.alloc().buffer();
buf.writeBytes(ZERO_CRLF);
encodeHeaders(buf, headers);
HttpHeaders.encode(headers, buf);
buf.writeBytes(CRLF);
out.add(buf);
}
@ -165,24 +163,5 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
throw new IllegalStateException("unexpected message type: " + StringUtil.simpleClassName(msg));
}
private static void encodeHeaders(ByteBuf buf, HttpHeaders headers) {
for (Map.Entry<String, String> h: headers) {
encodeHeader(buf, h.getKey(), h.getValue());
}
}
private static void encodeHeader(ByteBuf buf, String header, String value) {
encodeAscii(header, buf);
buf.writeBytes(HEADER_SEPARATOR);
encodeAscii(value, buf);
buf.writeBytes(CRLF);
}
protected static void encodeAscii(String s, ByteBuf buf) {
for (int i = 0; i < s.length(); i++) {
buf.writeByte(s.charAt(i));
}
}
protected abstract void encodeInitialLine(ByteBuf buf, H message) throws Exception;
}

View File

@ -35,7 +35,7 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
encodeAscii(request.getMethod().toString(), buf);
request.getMethod().encode(buf);
buf.writeByte(SP);
// Add / as absolute path if no is present.
@ -57,7 +57,7 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
buf.writeBytes(uri.getBytes(CharsetUtil.UTF_8));
buf.writeByte(SP);
encodeAscii(request.getProtocolVersion().toString(), buf);
request.getProtocolVersion().encode(buf);
buf.writeBytes(CRLF);
}
}

View File

@ -33,11 +33,9 @@ public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
encodeAscii(response.getProtocolVersion().toString(), buf);
response.getProtocolVersion().encode(buf);
buf.writeByte(SP);
encodeAscii(String.valueOf(response.getStatus().code()), buf);
buf.writeByte(SP);
encodeAscii(String.valueOf(response.getStatus().reasonPhrase()), buf);
response.getStatus().encode(buf);
buf.writeBytes(CRLF);
}
}

View File

@ -15,6 +15,11 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.SP;
/**
* The response code and its description of HTTP or its derived protocols, such as
* <a href="http://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol">RTSP</a> and
@ -25,282 +30,290 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
/**
* 100 Continue
*/
public static final HttpResponseStatus CONTINUE = new HttpResponseStatus(100, "Continue");
public static final HttpResponseStatus CONTINUE = new HttpResponseStatus(100, "Continue", true);
/**
* 101 Switching Protocols
*/
public static final HttpResponseStatus SWITCHING_PROTOCOLS = new HttpResponseStatus(101, "Switching Protocols");
public static final HttpResponseStatus SWITCHING_PROTOCOLS =
new HttpResponseStatus(101, "Switching Protocols", true);
/**
* 102 Processing (WebDAV, RFC2518)
*/
public static final HttpResponseStatus PROCESSING = new HttpResponseStatus(102, "Processing");
public static final HttpResponseStatus PROCESSING = new HttpResponseStatus(102, "Processing", true);
/**
* 200 OK
*/
public static final HttpResponseStatus OK = new HttpResponseStatus(200, "OK");
public static final HttpResponseStatus OK = new HttpResponseStatus(200, "OK", true);
/**
* 201 Created
*/
public static final HttpResponseStatus CREATED = new HttpResponseStatus(201, "Created");
public static final HttpResponseStatus CREATED = new HttpResponseStatus(201, "Created", true);
/**
* 202 Accepted
*/
public static final HttpResponseStatus ACCEPTED = new HttpResponseStatus(202, "Accepted");
public static final HttpResponseStatus ACCEPTED = new HttpResponseStatus(202, "Accepted", true);
/**
* 203 Non-Authoritative Information (since HTTP/1.1)
*/
public static final HttpResponseStatus NON_AUTHORITATIVE_INFORMATION =
new HttpResponseStatus(203, "Non-Authoritative Information");
new HttpResponseStatus(203, "Non-Authoritative Information", true);
/**
* 204 No Content
*/
public static final HttpResponseStatus NO_CONTENT = new HttpResponseStatus(204, "No Content");
public static final HttpResponseStatus NO_CONTENT = new HttpResponseStatus(204, "No Content", true);
/**
* 205 Reset Content
*/
public static final HttpResponseStatus RESET_CONTENT = new HttpResponseStatus(205, "Reset Content");
public static final HttpResponseStatus RESET_CONTENT = new HttpResponseStatus(205, "Reset Content", true);
/**
* 206 Partial Content
*/
public static final HttpResponseStatus PARTIAL_CONTENT = new HttpResponseStatus(206, "Partial Content");
public static final HttpResponseStatus PARTIAL_CONTENT = new HttpResponseStatus(206, "Partial Content", true);
/**
* 207 Multi-Status (WebDAV, RFC2518)
*/
public static final HttpResponseStatus MULTI_STATUS = new HttpResponseStatus(207, "Multi-Status");
public static final HttpResponseStatus MULTI_STATUS = new HttpResponseStatus(207, "Multi-Status", true);
/**
* 300 Multiple Choices
*/
public static final HttpResponseStatus MULTIPLE_CHOICES = new HttpResponseStatus(300, "Multiple Choices");
public static final HttpResponseStatus MULTIPLE_CHOICES = new HttpResponseStatus(300, "Multiple Choices", true);
/**
* 301 Moved Permanently
*/
public static final HttpResponseStatus MOVED_PERMANENTLY = new HttpResponseStatus(301, "Moved Permanently");
public static final HttpResponseStatus MOVED_PERMANENTLY = new HttpResponseStatus(301, "Moved Permanently", true);
/**
* 302 Found
*/
public static final HttpResponseStatus FOUND = new HttpResponseStatus(302, "Found");
public static final HttpResponseStatus FOUND = new HttpResponseStatus(302, "Found", true);
/**
* 303 See Other (since HTTP/1.1)
*/
public static final HttpResponseStatus SEE_OTHER = new HttpResponseStatus(303, "See Other");
public static final HttpResponseStatus SEE_OTHER = new HttpResponseStatus(303, "See Other", true);
/**
* 304 Not Modified
*/
public static final HttpResponseStatus NOT_MODIFIED = new HttpResponseStatus(304, "Not Modified");
public static final HttpResponseStatus NOT_MODIFIED = new HttpResponseStatus(304, "Not Modified", true);
/**
* 305 Use Proxy (since HTTP/1.1)
*/
public static final HttpResponseStatus USE_PROXY = new HttpResponseStatus(305, "Use Proxy");
public static final HttpResponseStatus USE_PROXY = new HttpResponseStatus(305, "Use Proxy", true);
/**
* 307 Temporary Redirect (since HTTP/1.1)
*/
public static final HttpResponseStatus TEMPORARY_REDIRECT = new HttpResponseStatus(307, "Temporary Redirect");
public static final HttpResponseStatus TEMPORARY_REDIRECT = new HttpResponseStatus(307, "Temporary Redirect", true);
/**
* 400 Bad Request
*/
public static final HttpResponseStatus BAD_REQUEST = new HttpResponseStatus(400, "Bad Request");
public static final HttpResponseStatus BAD_REQUEST = new HttpResponseStatus(400, "Bad Request", true);
/**
* 401 Unauthorized
*/
public static final HttpResponseStatus UNAUTHORIZED = new HttpResponseStatus(401, "Unauthorized");
public static final HttpResponseStatus UNAUTHORIZED = new HttpResponseStatus(401, "Unauthorized", true);
/**
* 402 Payment Required
*/
public static final HttpResponseStatus PAYMENT_REQUIRED = new HttpResponseStatus(402, "Payment Required");
public static final HttpResponseStatus PAYMENT_REQUIRED = new HttpResponseStatus(402, "Payment Required", true);
/**
* 403 Forbidden
*/
public static final HttpResponseStatus FORBIDDEN = new HttpResponseStatus(403, "Forbidden");
public static final HttpResponseStatus FORBIDDEN = new HttpResponseStatus(403, "Forbidden", true);
/**
* 404 Not Found
*/
public static final HttpResponseStatus NOT_FOUND = new HttpResponseStatus(404, "Not Found");
public static final HttpResponseStatus NOT_FOUND = new HttpResponseStatus(404, "Not Found", true);
/**
* 405 Method Not Allowed
*/
public static final HttpResponseStatus METHOD_NOT_ALLOWED = new HttpResponseStatus(405, "Method Not Allowed");
public static final HttpResponseStatus METHOD_NOT_ALLOWED = new HttpResponseStatus(405, "Method Not Allowed", true);
/**
* 406 Not Acceptable
*/
public static final HttpResponseStatus NOT_ACCEPTABLE = new HttpResponseStatus(406, "Not Acceptable");
public static final HttpResponseStatus NOT_ACCEPTABLE = new HttpResponseStatus(406, "Not Acceptable", true);
/**
* 407 Proxy Authentication Required
*/
public static final HttpResponseStatus PROXY_AUTHENTICATION_REQUIRED =
new HttpResponseStatus(407, "Proxy Authentication Required");
new HttpResponseStatus(407, "Proxy Authentication Required", true);
/**
* 408 Request Timeout
*/
public static final HttpResponseStatus REQUEST_TIMEOUT = new HttpResponseStatus(408, "Request Timeout");
public static final HttpResponseStatus REQUEST_TIMEOUT = new HttpResponseStatus(408, "Request Timeout", true);
/**
* 409 Conflict
*/
public static final HttpResponseStatus CONFLICT = new HttpResponseStatus(409, "Conflict");
public static final HttpResponseStatus CONFLICT = new HttpResponseStatus(409, "Conflict", true);
/**
* 410 Gone
*/
public static final HttpResponseStatus GONE = new HttpResponseStatus(410, "Gone");
public static final HttpResponseStatus GONE = new HttpResponseStatus(410, "Gone", true);
/**
* 411 Length Required
*/
public static final HttpResponseStatus LENGTH_REQUIRED = new HttpResponseStatus(411, "Length Required");
public static final HttpResponseStatus LENGTH_REQUIRED = new HttpResponseStatus(411, "Length Required", true);
/**
* 412 Precondition Failed
*/
public static final HttpResponseStatus PRECONDITION_FAILED = new HttpResponseStatus(412, "Precondition Failed");
public static final HttpResponseStatus PRECONDITION_FAILED =
new HttpResponseStatus(412, "Precondition Failed", true);
/**
* 413 Request Entity Too Large
*/
public static final HttpResponseStatus REQUEST_ENTITY_TOO_LARGE =
new HttpResponseStatus(413, "Request Entity Too Large");
new HttpResponseStatus(413, "Request Entity Too Large", true);
/**
* 414 Request-URI Too Long
*/
public static final HttpResponseStatus REQUEST_URI_TOO_LONG = new HttpResponseStatus(414, "Request-URI Too Long");
public static final HttpResponseStatus REQUEST_URI_TOO_LONG =
new HttpResponseStatus(414, "Request-URI Too Long", true);
/**
* 415 Unsupported Media Type
*/
public static final HttpResponseStatus UNSUPPORTED_MEDIA_TYPE =
new HttpResponseStatus(415, "Unsupported Media Type");
new HttpResponseStatus(415, "Unsupported Media Type", true);
/**
* 416 Requested Range Not Satisfiable
*/
public static final HttpResponseStatus REQUESTED_RANGE_NOT_SATISFIABLE =
new HttpResponseStatus(416, "Requested Range Not Satisfiable");
new HttpResponseStatus(416, "Requested Range Not Satisfiable", true);
/**
* 417 Expectation Failed
*/
public static final HttpResponseStatus EXPECTATION_FAILED = new HttpResponseStatus(417, "Expectation Failed");
public static final HttpResponseStatus EXPECTATION_FAILED = new HttpResponseStatus(417, "Expectation Failed", true);
/**
* 422 Unprocessable Entity (WebDAV, RFC4918)
*/
public static final HttpResponseStatus UNPROCESSABLE_ENTITY = new HttpResponseStatus(422, "Unprocessable Entity");
public static final HttpResponseStatus UNPROCESSABLE_ENTITY =
new HttpResponseStatus(422, "Unprocessable Entity", true);
/**
* 423 Locked (WebDAV, RFC4918)
*/
public static final HttpResponseStatus LOCKED = new HttpResponseStatus(423, "Locked");
public static final HttpResponseStatus LOCKED = new HttpResponseStatus(423, "Locked", true);
/**
* 424 Failed Dependency (WebDAV, RFC4918)
*/
public static final HttpResponseStatus FAILED_DEPENDENCY = new HttpResponseStatus(424, "Failed Dependency");
public static final HttpResponseStatus FAILED_DEPENDENCY = new HttpResponseStatus(424, "Failed Dependency", true);
/**
* 425 Unordered Collection (WebDAV, RFC3648)
*/
public static final HttpResponseStatus UNORDERED_COLLECTION = new HttpResponseStatus(425, "Unordered Collection");
public static final HttpResponseStatus UNORDERED_COLLECTION =
new HttpResponseStatus(425, "Unordered Collection", true);
/**
* 426 Upgrade Required (RFC2817)
*/
public static final HttpResponseStatus UPGRADE_REQUIRED = new HttpResponseStatus(426, "Upgrade Required");
public static final HttpResponseStatus UPGRADE_REQUIRED = new HttpResponseStatus(426, "Upgrade Required", true);
/**
* 428 Precondition Required (RFC6585)
*/
public static final HttpResponseStatus PRECONDITION_REQUIRED = new HttpResponseStatus(428, "Precondition Required");
public static final HttpResponseStatus PRECONDITION_REQUIRED =
new HttpResponseStatus(428, "Precondition Required", true);
/**
* 429 Too Many Requests (RFC6585)
*/
public static final HttpResponseStatus TOO_MANY_REQUESTS = new HttpResponseStatus(429, "Too Many Requests");
public static final HttpResponseStatus TOO_MANY_REQUESTS = new HttpResponseStatus(429, "Too Many Requests", true);
/**
* 431 Request Header Fields Too Large (RFC6585)
*/
public static final HttpResponseStatus REQUEST_HEADER_FIELDS_TOO_LARGE =
new HttpResponseStatus(431, "Request Header Fields Too Large");
new HttpResponseStatus(431, "Request Header Fields Too Large", true);
/**
* 500 Internal Server Error
*/
public static final HttpResponseStatus INTERNAL_SERVER_ERROR =
new HttpResponseStatus(500, "Internal Server Error");
new HttpResponseStatus(500, "Internal Server Error", true);
/**
* 501 Not Implemented
*/
public static final HttpResponseStatus NOT_IMPLEMENTED = new HttpResponseStatus(501, "Not Implemented");
public static final HttpResponseStatus NOT_IMPLEMENTED = new HttpResponseStatus(501, "Not Implemented", true);
/**
* 502 Bad Gateway
*/
public static final HttpResponseStatus BAD_GATEWAY = new HttpResponseStatus(502, "Bad Gateway");
public static final HttpResponseStatus BAD_GATEWAY = new HttpResponseStatus(502, "Bad Gateway", true);
/**
* 503 Service Unavailable
*/
public static final HttpResponseStatus SERVICE_UNAVAILABLE = new HttpResponseStatus(503, "Service Unavailable");
public static final HttpResponseStatus SERVICE_UNAVAILABLE =
new HttpResponseStatus(503, "Service Unavailable", true);
/**
* 504 Gateway Timeout
*/
public static final HttpResponseStatus GATEWAY_TIMEOUT = new HttpResponseStatus(504, "Gateway Timeout");
public static final HttpResponseStatus GATEWAY_TIMEOUT = new HttpResponseStatus(504, "Gateway Timeout", true);
/**
* 505 HTTP Version Not Supported
*/
public static final HttpResponseStatus HTTP_VERSION_NOT_SUPPORTED =
new HttpResponseStatus(505, "HTTP Version Not Supported");
new HttpResponseStatus(505, "HTTP Version Not Supported", true);
/**
* 506 Variant Also Negotiates (RFC2295)
*/
public static final HttpResponseStatus VARIANT_ALSO_NEGOTIATES =
new HttpResponseStatus(506, "Variant Also Negotiates");
new HttpResponseStatus(506, "Variant Also Negotiates", true);
/**
* 507 Insufficient Storage (WebDAV, RFC4918)
*/
public static final HttpResponseStatus INSUFFICIENT_STORAGE = new HttpResponseStatus(507, "Insufficient Storage");
public static final HttpResponseStatus INSUFFICIENT_STORAGE =
new HttpResponseStatus(507, "Insufficient Storage", true);
/**
* 510 Not Extended (RFC2774)
*/
public static final HttpResponseStatus NOT_EXTENDED = new HttpResponseStatus(510, "Not Extended");
public static final HttpResponseStatus NOT_EXTENDED = new HttpResponseStatus(510, "Not Extended", true);
/**
* 511 Network Authentication Required (RFC6585)
*/
public static final HttpResponseStatus NETWORK_AUTHENTICATION_REQUIRED =
new HttpResponseStatus(511, "Network Authentication Required");
new HttpResponseStatus(511, "Network Authentication Required", true);
/**
* Returns the {@link HttpResponseStatus} represented by the specified code.
@ -443,12 +456,17 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
private final int code;
private final String reasonPhrase;
private final byte[] bytes;
/**
* Creates a new instance with the specified {@code code} and its
* {@code reasonPhrase}.
*/
public HttpResponseStatus(int code, String reasonPhrase) {
this(code, reasonPhrase, false);
}
private HttpResponseStatus(int code, String reasonPhrase, boolean bytes) {
if (code < 0) {
throw new IllegalArgumentException(
"code: " + code + " (expected: 0+)");
@ -471,6 +489,11 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
this.code = code;
this.reasonPhrase = reasonPhrase;
if (bytes) {
this.bytes = (code + " " + reasonPhrase).getBytes(CharsetUtil.US_ASCII);
} else {
this.bytes = null;
}
}
/**
@ -514,4 +537,14 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
buf.append(reasonPhrase);
return buf.toString();
}
void encode(ByteBuf buf) {
if (bytes == null) {
HttpHeaders.encodeAscii0(String.valueOf(code()), buf);
buf.writeByte(SP);
HttpHeaders.encodeAscii0(String.valueOf(reasonPhrase()), buf);
} else {
buf.writeBytes(bytes);
}
}
}

View File

@ -15,6 +15,9 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -34,12 +37,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
/**
* HTTP/1.0
*/
public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false);
public static final HttpVersion HTTP_1_0 = new HttpVersion("HTTP", 1, 0, false, true);
/**
* HTTP/1.1
*/
public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true);
public static final HttpVersion HTTP_1_1 = new HttpVersion("HTTP", 1, 1, true, true);
/**
* Returns an existing or new {@link HttpVersion} instance which matches to
@ -90,6 +93,7 @@ public class HttpVersion implements Comparable<HttpVersion> {
private final int minorVersion;
private final String text;
private final boolean keepAliveDefault;
private final byte[] bytes;
/**
* Creates a new HTTP version with the specified version string. You will
@ -122,6 +126,7 @@ public class HttpVersion implements Comparable<HttpVersion> {
minorVersion = Integer.parseInt(m.group(3));
this.text = protocolName + '/' + majorVersion + '.' + minorVersion;
this.keepAliveDefault = keepAliveDefault;
bytes = null;
}
/**
@ -138,6 +143,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
public HttpVersion(
String protocolName, int majorVersion, int minorVersion,
boolean keepAliveDefault) {
this(protocolName, majorVersion, minorVersion, keepAliveDefault, false);
}
private HttpVersion(
String protocolName, int majorVersion, int minorVersion,
boolean keepAliveDefault, boolean bytes) {
if (protocolName == null) {
throw new NullPointerException("protocolName");
}
@ -166,6 +177,11 @@ public class HttpVersion implements Comparable<HttpVersion> {
this.minorVersion = minorVersion;
text = protocolName + '/' + majorVersion + '.' + minorVersion;
this.keepAliveDefault = keepAliveDefault;
if (bytes) {
this.bytes = text.getBytes(CharsetUtil.US_ASCII);
} else {
this.bytes = null;
}
}
/**
@ -244,4 +260,12 @@ public class HttpVersion implements Comparable<HttpVersion> {
return minorVersion() - o.minorVersion();
}
void encode(ByteBuf buf) {
if (bytes == null) {
HttpHeaders.encodeAscii0(text, buf);
} else {
buf.writeBytes(bytes);
}
}
}

View File

@ -18,7 +18,7 @@ package io.netty.handler.codec.http.multipart;
import java.io.Serializable;
import java.util.Comparator;
final class CaseIgnoringComparator implements Comparator<String>, Serializable {
final class CaseIgnoringComparator implements Comparator<CharSequence>, Serializable {
private static final long serialVersionUID = 4582133183775373862L;
@ -28,8 +28,26 @@ final class CaseIgnoringComparator implements Comparator<String>, Serializable {
}
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
public int compare(CharSequence o1, CharSequence o2) {
int o1Length = o1.length();
int o2Length = o2.length();
int min = Math.min(o1Length, o2Length);
for (int i = 0; i < min; i++) {
char c1 = o1.charAt(i);
char c2 = o2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
return c1 - c2;
}
}
}
}
return o1Length - o2Length;
}
@SuppressWarnings("MethodMayBeStatic")

View File

@ -152,9 +152,9 @@ public class HttpPostRequestDecoder implements InterfaceHttpPostRequestDecoder {
// Check if Post using "multipart/form-data; boundary=--89421926422648"
String[] headerContentType = splitHeaderContentType(contentType);
if (headerContentType[0].toLowerCase().startsWith(
HttpHeaders.Values.MULTIPART_FORM_DATA) &&
HttpHeaders.Values.MULTIPART_FORM_DATA.toString()) &&
headerContentType[1].toLowerCase().startsWith(
HttpHeaders.Values.BOUNDARY)) {
HttpHeaders.Values.BOUNDARY.toString())) {
String[] boundary = StringUtil.split(headerContentType[1], '=');
if (boundary.length != 2) {
throw new ErrorDataDecoderException("Needs a boundary value");

View File

@ -663,9 +663,10 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
headers.remove(HttpHeaders.Names.CONTENT_TYPE);
for (String contentType : contentTypes) {
// "multipart/form-data; boundary=--89421926422648"
if (contentType.toLowerCase().startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA)) {
if (contentType.toLowerCase().startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA.toString())) {
// ignore
} else if (contentType.toLowerCase().startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
} else if (contentType.toLowerCase().startsWith(
HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED.toString())) {
// ignore
} else {
headers.add(HttpHeaders.Names.CONTENT_TYPE, contentType);
@ -694,7 +695,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
if (transferEncoding != null) {
headers.remove(HttpHeaders.Names.TRANSFER_ENCODING);
for (String v : transferEncoding) {
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
if (HttpHeaders.equalsIgnoreCase(v, HttpHeaders.Values.CHUNKED)) {
// ignore
} else {
headers.add(HttpHeaders.Names.TRANSFER_ENCODING, v);

View File

@ -198,13 +198,13 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
HttpHeaders headers = response.headers();
String upgrade = headers.get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ connection);
}

View File

@ -40,7 +40,7 @@ import java.net.URI;
public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker07.class);
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toString().toLowerCase());
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private String expectedChallengeResponseString;
@ -118,7 +118,7 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
HttpHeaders headers = request.headers();
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
headers.add(Names.UPGRADE, WEBSOCKET)
.add(Names.CONNECTION, Values.UPGRADE)
.add(Names.SEC_WEBSOCKET_KEY, key)
.add(Names.HOST, wsURL.getHost());
@ -172,12 +172,12 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -40,6 +40,8 @@ import java.net.URI;
public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker08.class);
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(
HttpHeaders.Values.WEBSOCKET.toString().toLowerCase());
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
@ -118,7 +120,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
HttpHeaders headers = request.headers();
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
headers.add(Names.UPGRADE, WEBSOCKET)
.add(Names.CONNECTION, Values.UPGRADE)
.add(Names.SEC_WEBSOCKET_KEY, key)
.add(Names.HOST, wsURL.getHost());
@ -172,12 +174,12 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -40,6 +40,7 @@ import java.net.URI;
public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker13.class);
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toString().toLowerCase());
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
@ -129,7 +130,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
HttpHeaders headers = request.headers();
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
headers.add(Names.UPGRADE, WEBSOCKET)
.add(Names.CONNECTION, Values.UPGRADE)
.add(Names.SEC_WEBSOCKET_KEY, key)
.add(Names.HOST, wsURL.getHost() + ':' + wsPort);
@ -182,12 +183,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
}
String upgrade = headers.get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
if (!HttpHeaders.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
}
String connection = headers.get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
}

View File

@ -109,8 +109,8 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
protected FullHttpResponse newHandshakeResponse(FullHttpRequest req, HttpHeaders headers) {
// Serve the WebSocket handshake request.
if (!Values.UPGRADE.equalsIgnoreCase(req.headers().get(CONNECTION))
|| !WEBSOCKET.equalsIgnoreCase(req.headers().get(Names.UPGRADE))) {
if (!HttpHeaders.equalsIgnoreCase(Values.UPGRADE, req.headers().get(CONNECTION))
|| !HttpHeaders.equalsIgnoreCase(WEBSOCKET, req.headers().get(Names.UPGRADE))) {
throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
}

View File

@ -23,7 +23,6 @@ import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
@ -35,6 +34,9 @@ import static io.netty.handler.codec.http.HttpVersion.*;
*/
public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(
HttpHeaders.Values.WEBSOCKET.toString().toLowerCase());
public static final String WEBSOCKET_07_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private final boolean allowExtensions;
@ -114,7 +116,7 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 7 Server Handshake key: %s. Response: %s.", key, accept));
}
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.UPGRADE, WEBSOCKET);
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);

View File

@ -23,7 +23,6 @@ import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
@ -35,6 +34,9 @@ import static io.netty.handler.codec.http.HttpVersion.*;
*/
public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(
HttpHeaders.Values.WEBSOCKET.toString().toLowerCase());
public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
private final boolean allowExtensions;
@ -113,7 +115,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept));
}
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.UPGRADE, WEBSOCKET);
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);

View File

@ -23,7 +23,6 @@ import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
@ -33,6 +32,8 @@ import static io.netty.handler.codec.http.HttpVersion.*;
* </p>
*/
public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(
HttpHeaders.Values.WEBSOCKET.toString().toLowerCase());
public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
@ -111,7 +112,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept));
}
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.UPGRADE, WEBSOCKET);
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);

View File

@ -30,179 +30,179 @@ public final class RtspHeaders {
/**
* {@code "Accept"}
*/
public static final String ACCEPT = HttpHeaders.Names.ACCEPT;
public static final CharSequence ACCEPT = HttpHeaders.Names.ACCEPT;
/**
* {@code "Accept-Encoding"}
*/
public static final String ACCEPT_ENCODING = HttpHeaders.Names.ACCEPT_ENCODING;
public static final CharSequence ACCEPT_ENCODING = HttpHeaders.Names.ACCEPT_ENCODING;
/**
* {@code "Accept-Lanugage"}
*/
public static final String ACCEPT_LANGUAGE = HttpHeaders.Names.ACCEPT_LANGUAGE;
public static final CharSequence ACCEPT_LANGUAGE = HttpHeaders.Names.ACCEPT_LANGUAGE;
/**
* {@code "Allow"}
*/
public static final String ALLOW = "Allow";
public static final CharSequence ALLOW = HttpHeaders.newEntity("Allow");
/**
* {@code "Authorization"}
*/
public static final String AUTHORIZATION = HttpHeaders.Names.AUTHORIZATION;
public static final CharSequence AUTHORIZATION = HttpHeaders.Names.AUTHORIZATION;
/**
* {@code "Bandwidth"}
*/
public static final String BANDWIDTH = "Bandwidth";
public static final CharSequence BANDWIDTH = HttpHeaders.newEntity("Bandwidth");
/**
* {@code "Blocksize"}
*/
public static final String BLOCKSIZE = "Blocksize";
public static final CharSequence BLOCKSIZE = HttpHeaders.newEntity("Blocksize");
/**
* {@code "Cache-Control"}
*/
public static final String CACHE_CONTROL = HttpHeaders.Names.CACHE_CONTROL;
public static final CharSequence CACHE_CONTROL = HttpHeaders.Names.CACHE_CONTROL;
/**
* {@code "Conference"}
*/
public static final String CONFERENCE = "Conference";
public static final CharSequence CONFERENCE = HttpHeaders.newEntity("Conference");
/**
* {@code "Connection"}
*/
public static final String CONNECTION = HttpHeaders.Names.CONNECTION;
public static final CharSequence CONNECTION = HttpHeaders.Names.CONNECTION;
/**
* {@code "Content-Base"}
*/
public static final String CONTENT_BASE = HttpHeaders.Names.CONTENT_BASE;
public static final CharSequence CONTENT_BASE = HttpHeaders.Names.CONTENT_BASE;
/**
* {@code "Content-Encoding"}
*/
public static final String CONTENT_ENCODING = HttpHeaders.Names.CONTENT_ENCODING;
public static final CharSequence CONTENT_ENCODING = HttpHeaders.Names.CONTENT_ENCODING;
/**
* {@code "Content-Language"}
*/
public static final String CONTENT_LANGUAGE = HttpHeaders.Names.CONTENT_LANGUAGE;
public static final CharSequence CONTENT_LANGUAGE = HttpHeaders.Names.CONTENT_LANGUAGE;
/**
* {@code "Content-Length"}
*/
public static final String CONTENT_LENGTH = HttpHeaders.Names.CONTENT_LENGTH;
public static final CharSequence CONTENT_LENGTH = HttpHeaders.Names.CONTENT_LENGTH;
/**
* {@code "Content-Location"}
*/
public static final String CONTENT_LOCATION = HttpHeaders.Names.CONTENT_LOCATION;
public static final CharSequence CONTENT_LOCATION = HttpHeaders.Names.CONTENT_LOCATION;
/**
* {@code "Content-Type"}
*/
public static final String CONTENT_TYPE = HttpHeaders.Names.CONTENT_TYPE;
public static final CharSequence CONTENT_TYPE = HttpHeaders.Names.CONTENT_TYPE;
/**
* {@code "CSeq"}
*/
public static final String CSEQ = "CSeq";
public static final CharSequence CSEQ = HttpHeaders.newEntity("CSeq");
/**
* {@code "Date"}
*/
public static final String DATE = HttpHeaders.Names.DATE;
public static final CharSequence DATE = HttpHeaders.Names.DATE;
/**
* {@code "Expires"}
*/
public static final String EXPIRES = HttpHeaders.Names.EXPIRES;
public static final CharSequence EXPIRES = HttpHeaders.Names.EXPIRES;
/**
* {@code "From"}
*/
public static final String FROM = HttpHeaders.Names.FROM;
public static final CharSequence FROM = HttpHeaders.Names.FROM;
/**
* {@code "Host"}
*/
public static final String HOST = HttpHeaders.Names.HOST;
public static final CharSequence HOST = HttpHeaders.Names.HOST;
/**
* {@code "If-Match"}
*/
public static final String IF_MATCH = HttpHeaders.Names.IF_MATCH;
public static final CharSequence IF_MATCH = HttpHeaders.Names.IF_MATCH;
/**
* {@code "If-Modified-Since"}
*/
public static final String IF_MODIFIED_SINCE = HttpHeaders.Names.IF_MODIFIED_SINCE;
public static final CharSequence IF_MODIFIED_SINCE = HttpHeaders.Names.IF_MODIFIED_SINCE;
/**
* {@code "KeyMgmt"}
*/
public static final String KEYMGMT = "KeyMgmt";
public static final CharSequence KEYMGMT = HttpHeaders.newEntity("KeyMgmt");
/**
* {@code "Last-Modified"}
*/
public static final String LAST_MODIFIED = HttpHeaders.Names.LAST_MODIFIED;
public static final CharSequence LAST_MODIFIED = HttpHeaders.Names.LAST_MODIFIED;
/**
* {@code "Proxy-Authenticate"}
*/
public static final String PROXY_AUTHENTICATE = HttpHeaders.Names.PROXY_AUTHENTICATE;
public static final CharSequence PROXY_AUTHENTICATE = HttpHeaders.Names.PROXY_AUTHENTICATE;
/**
* {@code "Proxy-Require"}
*/
public static final String PROXY_REQUIRE = "Proxy-Require";
public static final CharSequence PROXY_REQUIRE = HttpHeaders.newEntity("Proxy-Require");
/**
* {@code "Public"}
*/
public static final String PUBLIC = "Public";
public static final CharSequence PUBLIC = HttpHeaders.newEntity("Public");
/**
* {@code "Range"}
*/
public static final String RANGE = HttpHeaders.Names.RANGE;
public static final CharSequence RANGE = HttpHeaders.Names.RANGE;
/**
* {@code "Referer"}
*/
public static final String REFERER = HttpHeaders.Names.REFERER;
public static final CharSequence REFERER = HttpHeaders.Names.REFERER;
/**
* {@code "Require"}
*/
public static final String REQUIRE = "Require";
public static final CharSequence REQUIRE = HttpHeaders.newEntity("Require");
/**
* {@code "Retry-After"}
*/
public static final String RETRT_AFTER = HttpHeaders.Names.RETRY_AFTER;
public static final CharSequence RETRT_AFTER = HttpHeaders.Names.RETRY_AFTER;
/**
* {@code "RTP-Info"}
*/
public static final String RTP_INFO = "RTP-Info";
public static final CharSequence RTP_INFO = HttpHeaders.newEntity("RTP-Info");
/**
* {@code "Scale"}
*/
public static final String SCALE = "Scale";
public static final CharSequence SCALE = HttpHeaders.newEntity("Scale");
/**
* {@code "Session"}
*/
public static final String SESSION = "Session";
public static final CharSequence SESSION = HttpHeaders.newEntity("Session");
/**
* {@code "Server"}
*/
public static final String SERVER = HttpHeaders.Names.SERVER;
public static final CharSequence SERVER = HttpHeaders.Names.SERVER;
/**
* {@code "Speed"}
*/
public static final String SPEED = "Speed";
public static final CharSequence SPEED = HttpHeaders.newEntity("Speed");
/**
* {@code "Timestamp"}
*/
public static final String TIMESTAMP = "Timestamp";
public static final CharSequence TIMESTAMP = HttpHeaders.newEntity("Timestamp");
/**
* {@code "Transport"}
*/
public static final String TRANSPORT = "Transport";
public static final CharSequence TRANSPORT = HttpHeaders.newEntity("Transport");
/**
* {@code "Unsupported"}
*/
public static final String UNSUPPORTED = "Unsupported";
public static final CharSequence UNSUPPORTED = HttpHeaders.newEntity("Unsupported");
/**
* {@code "User-Agent"}
*/
public static final String USER_AGENT = HttpHeaders.Names.USER_AGENT;
public static final CharSequence USER_AGENT = HttpHeaders.Names.USER_AGENT;
/**
* {@code "Vary"}
*/
public static final String VARY = HttpHeaders.Names.VARY;
public static final CharSequence VARY = HttpHeaders.Names.VARY;
/**
* {@code "Via"}
*/
public static final String VIA = HttpHeaders.Names.VIA;
public static final CharSequence VIA = HttpHeaders.Names.VIA;
/**
* {@code "WWW-Authenticate"}
*/
public static final String WWW_AUTHENTICATE = HttpHeaders.Names.WWW_AUTHENTICATE;
public static final CharSequence WWW_AUTHENTICATE = HttpHeaders.Names.WWW_AUTHENTICATE;
private Names() {
}
@ -215,171 +215,171 @@ public final class RtspHeaders {
/**
* {@code "append"}
*/
public static final String APPEND = "append";
public static final CharSequence APPEND = HttpHeaders.newEntity("append");
/**
* {@code "AVP"}
*/
public static final String AVP = "AVP";
public static final CharSequence AVP = HttpHeaders.newEntity("AVP");
/**
* {@code "bytes"}
*/
public static final String BYTES = HttpHeaders.Values.BYTES;
public static final CharSequence BYTES = HttpHeaders.Values.BYTES;
/**
* {@code "charset"}
*/
public static final String CHARSET = HttpHeaders.Values.CHARSET;
public static final CharSequence CHARSET = HttpHeaders.Values.CHARSET;
/**
* {@code "client_port"}
*/
public static final String CLIENT_PORT = "client_port";
public static final CharSequence CLIENT_PORT = HttpHeaders.newEntity("client_port");
/**
* {@code "clock"}
*/
public static final String CLOCK = "clock";
public static final CharSequence CLOCK = HttpHeaders.newEntity("clock");
/**
* {@code "close"}
*/
public static final String CLOSE = HttpHeaders.Values.CLOSE;
public static final CharSequence CLOSE = HttpHeaders.Values.CLOSE;
/**
* {@code "compress"}
*/
public static final String COMPRESS = HttpHeaders.Values.COMPRESS;
public static final CharSequence COMPRESS = HttpHeaders.Values.COMPRESS;
/**
* {@code "100-continue"}
*/
public static final String CONTINUE = HttpHeaders.Values.CONTINUE;
public static final CharSequence CONTINUE = HttpHeaders.Values.CONTINUE;
/**
* {@code "deflate"}
*/
public static final String DEFLATE = HttpHeaders.Values.DEFLATE;
public static final CharSequence DEFLATE = HttpHeaders.Values.DEFLATE;
/**
* {@code "destination"}
*/
public static final String DESTINATION = "destination";
public static final CharSequence DESTINATION = HttpHeaders.newEntity("destination");
/**
* {@code "gzip"}
*/
public static final String GZIP = HttpHeaders.Values.GZIP;
public static final CharSequence GZIP = HttpHeaders.Values.GZIP;
/**
* {@code "identity"}
*/
public static final String IDENTITY = HttpHeaders.Values.IDENTITY;
public static final CharSequence IDENTITY = HttpHeaders.Values.IDENTITY;
/**
* {@code "interleaved"}
*/
public static final String INTERLEAVED = "interleaved";
public static final CharSequence INTERLEAVED = HttpHeaders.newEntity("interleaved");
/**
* {@code "keep-alive"}
*/
public static final String KEEP_ALIVE = HttpHeaders.Values.KEEP_ALIVE;
public static final CharSequence KEEP_ALIVE = HttpHeaders.Values.KEEP_ALIVE;
/**
* {@code "layers"}
*/
public static final String LAYERS = "layers";
public static final CharSequence LAYERS = HttpHeaders.newEntity("layers");
/**
* {@code "max-age"}
*/
public static final String MAX_AGE = HttpHeaders.Values.MAX_AGE;
public static final CharSequence MAX_AGE = HttpHeaders.Values.MAX_AGE;
/**
* {@code "max-stale"}
*/
public static final String MAX_STALE = HttpHeaders.Values.MAX_STALE;
public static final CharSequence MAX_STALE = HttpHeaders.Values.MAX_STALE;
/**
* {@code "min-fresh"}
*/
public static final String MIN_FRESH = HttpHeaders.Values.MIN_FRESH;
public static final CharSequence MIN_FRESH = HttpHeaders.Values.MIN_FRESH;
/**
* {@code "mode"}
*/
public static final String MODE = "mode";
public static final CharSequence MODE = HttpHeaders.newEntity("mode");
/**
* {@code "multicast"}
*/
public static final String MULTICAST = "multicast";
public static final CharSequence MULTICAST = HttpHeaders.newEntity("multicast");
/**
* {@code "must-revalidate"}
*/
public static final String MUST_REVALIDATE = HttpHeaders.Values.MUST_REVALIDATE;
public static final CharSequence MUST_REVALIDATE = HttpHeaders.Values.MUST_REVALIDATE;
/**
* {@code "none"}
*/
public static final String NONE = HttpHeaders.Values.NONE;
public static final CharSequence NONE = HttpHeaders.Values.NONE;
/**
* {@code "no-cache"}
*/
public static final String NO_CACHE = HttpHeaders.Values.NO_CACHE;
public static final CharSequence NO_CACHE = HttpHeaders.Values.NO_CACHE;
/**
* {@code "no-transform"}
*/
public static final String NO_TRANSFORM = HttpHeaders.Values.NO_TRANSFORM;
public static final CharSequence NO_TRANSFORM = HttpHeaders.Values.NO_TRANSFORM;
/**
* {@code "only-if-cached"}
*/
public static final String ONLY_IF_CACHED = HttpHeaders.Values.ONLY_IF_CACHED;
public static final CharSequence ONLY_IF_CACHED = HttpHeaders.Values.ONLY_IF_CACHED;
/**
* {@code "port"}
*/
public static final String PORT = "port";
public static final CharSequence PORT = HttpHeaders.newEntity("port");
/**
* {@code "private"}
*/
public static final String PRIVATE = HttpHeaders.Values.PRIVATE;
public static final CharSequence PRIVATE = HttpHeaders.Values.PRIVATE;
/**
* {@code "proxy-revalidate"}
*/
public static final String PROXY_REVALIDATE = HttpHeaders.Values.PROXY_REVALIDATE;
public static final CharSequence PROXY_REVALIDATE = HttpHeaders.Values.PROXY_REVALIDATE;
/**
* {@code "public"}
*/
public static final String PUBLIC = HttpHeaders.Values.PUBLIC;
public static final CharSequence PUBLIC = HttpHeaders.Values.PUBLIC;
/**
* {@code "RTP"}
*/
public static final String RTP = "RTP";
public static final CharSequence RTP = HttpHeaders.newEntity("RTP");
/**
* {@code "rtptime"}
*/
public static final String RTPTIME = "rtptime";
public static final CharSequence RTPTIME = HttpHeaders.newEntity("rtptime");
/**
* {@code "seq"}
*/
public static final String SEQ = "seq";
public static final CharSequence SEQ = HttpHeaders.newEntity("seq");
/**
* {@code "server_port"}
*/
public static final String SERVER_PORT = "server_port";
public static final CharSequence SERVER_PORT = HttpHeaders.newEntity("server_port");
/**
* {@code "ssrc"}
*/
public static final String SSRC = "ssrc";
public static final CharSequence SSRC = HttpHeaders.newEntity("ssrc");
/**
* {@code "TCP"}
*/
public static final String TCP = "TCP";
public static final CharSequence TCP = HttpHeaders.newEntity("TCP");
/**
* {@code "time"}
*/
public static final String TIME = "time";
public static final CharSequence TIME = HttpHeaders.newEntity("time");
/**
* {@code "timeout"}
*/
public static final String TIMEOUT = "timeout";
public static final CharSequence TIMEOUT = HttpHeaders.newEntity("timeout");
/**
* {@code "ttl"}
*/
public static final String TTL = "ttl";
public static final CharSequence TTL = HttpHeaders.newEntity("ttl");
/**
* {@code "UDP"}
*/
public static final String UDP = "UDP";
public static final CharSequence UDP = HttpHeaders.newEntity("UDP");
/**
* {@code "unicast"}
*/
public static final String UNICAST = "unicast";
public static final CharSequence UNICAST = HttpHeaders.newEntity("unicast");
/**
* {@code "url"}
*/
public static final String URL = "url";
public static final CharSequence URL = HttpHeaders.newEntity("url");
private Values() { }
}

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.CharsetUtil;
@ -38,11 +39,11 @@ public class RtspRequestEncoder extends RtspObjectEncoder<HttpRequest> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request)
throws Exception {
encodeAscii(request.getMethod().toString(), buf);
HttpHeaders.encodeAscii(request.getMethod().toString(), buf);
buf.writeByte(SP);
buf.writeBytes(request.getUri().getBytes(CharsetUtil.UTF_8));
buf.writeByte(SP);
encodeAscii(request.getProtocolVersion().toString(), buf);
HttpHeaders.encodeAscii(request.getProtocolVersion().toString(), buf);
buf.writeBytes(CRLF);
}
}

View File

@ -17,6 +17,7 @@ package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
@ -38,11 +39,11 @@ public class RtspResponseEncoder extends RtspObjectEncoder<HttpResponse> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response)
throws Exception {
encodeAscii(response.getProtocolVersion().toString(), buf);
HttpHeaders.encodeAscii(response.getProtocolVersion().toString(), buf);
buf.writeByte(SP);
buf.writeBytes(String.valueOf(response.getStatus().code()).getBytes(CharsetUtil.US_ASCII));
buf.writeByte(SP);
encodeAscii(String.valueOf(response.getStatus().reasonPhrase()), buf);
HttpHeaders.encodeAscii(String.valueOf(response.getStatus().reasonPhrase()), buf);
buf.writeBytes(CRLF);
}
}

View File

@ -33,7 +33,7 @@ public class HttpContentEncoderTest {
private static final class TestEncoder extends HttpContentEncoder {
@Override
protected Result beginEncode(HttpResponse headers, String acceptEncoding) {
protected Result beginEncode(HttpResponse headers, CharSequence acceptEncoding) {
return new Result("test", new EmbeddedChannel(new MessageToByteEncoder<ByteBuf>() {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {

View File

@ -127,7 +127,7 @@ public class WebSocketRequestBuilder {
.method(HttpMethod.GET)
.uri("/test")
.host("server.example.com")
.upgrade(WEBSOCKET.toLowerCase())
.upgrade(WEBSOCKET.toString().toLowerCase())
.key("dGhlIHNhbXBsZSBub25jZQ==")
.origin("http://example.com")
.version13()

View File

@ -45,7 +45,7 @@ public class WebSocketServerHandshaker00Test {
HTTP_1_1, HttpMethod.GET, "/chat", Unpooled.copiedBuffer("^n:ds[4U", CharsetUtil.US_ASCII));
req.headers().set(Names.HOST, "server.example.com");
req.headers().set(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.headers().set(Names.UPGRADE, WEBSOCKET.toString().toLowerCase());
req.headers().set(Names.CONNECTION, "Upgrade");
req.headers().set(Names.ORIGIN, "http://example.com");
req.headers().set(Names.SEC_WEBSOCKET_KEY1, "4 @1 46546xW%0l 1 5");

View File

@ -41,7 +41,7 @@ public class WebSocketServerHandshaker08Test {
FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
req.headers().set(Names.HOST, "server.example.com");
req.headers().set(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.headers().set(Names.UPGRADE, WEBSOCKET.toString().toLowerCase());
req.headers().set(Names.CONNECTION, "Upgrade");
req.headers().set(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");

View File

@ -41,7 +41,7 @@ public class WebSocketServerHandshaker13Test {
FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
req.headers().set(Names.HOST, "server.example.com");
req.headers().set(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.headers().set(Names.UPGRADE, WEBSOCKET.toString().toLowerCase());
req.headers().set(Names.CONNECTION, "Upgrade");
req.headers().set(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");

View File

@ -93,7 +93,7 @@ public class WebSocketServerProtocolHandlerTest {
.uri("/test")
.key(null)
.connection("Upgrade")
.upgrade(WEBSOCKET.toLowerCase())
.upgrade(WEBSOCKET.toString().toLowerCase())
.version13()
.build();

View File

@ -188,8 +188,8 @@ public class HttpUploadClient {
HttpHeaders headers = request.headers();
headers.set(HttpHeaders.Names.HOST, host);
headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
headers.set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ','
+ HttpHeaders.Values.DEFLATE);
headers.set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP.toString() + ','
+ HttpHeaders.Values.DEFLATE.toString());
headers.set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
headers.set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");

View File

@ -286,9 +286,9 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
responseContent.setLength(0);
// Decide whether to close the connection or not.
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))
boolean close = request.headers().contains(CONNECTION, HttpHeaders.Values.CLOSE, true)
|| request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)
&& !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));
&& !request.headers().contains(CONNECTION, HttpHeaders.Values.KEEP_ALIVE, true);
// Build the response object.
FullHttpResponse response = new DefaultFullHttpResponse(