Resolved issues: NETTY-280 Add convenient getters and setters for HTTP headers
Resolved issues: NETTY-281 Allow non-string values for HTTP header values
This commit is contained in:
parent
d87d81e398
commit
d0e886c344
@ -48,15 +48,15 @@ public class DefaultHttpChunkTrailer implements HttpChunkTrailer {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addHeader(final String name, final String value) {
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(final String name, final String value) {
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(final String name, final Iterable<String> values) {
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,8 @@ import java.util.Set;
|
||||
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import org.jboss.netty.handler.codec.http.HttpHeaders.Values;
|
||||
|
||||
/**
|
||||
* The default {@link HttpMessage} implementation.
|
||||
@ -44,15 +46,15 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
setProtocolVersion(version);
|
||||
}
|
||||
|
||||
public void addHeader(final String name, final String value) {
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(final String name, final String value) {
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(final String name, final Iterable<String> values) {
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
}
|
||||
|
||||
@ -60,16 +62,14 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
headers.removeHeader(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public long getContentLength() {
|
||||
return getContentLength(0);
|
||||
return HttpHeaders.getContentLength(this);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public long getContentLength(long defaultValue) {
|
||||
List<String> contentLength = getHeaders(HttpHeaders.Names.CONTENT_LENGTH);
|
||||
if (contentLength != null && contentLength.size() > 0) {
|
||||
return Long.parseLong(contentLength.get(0));
|
||||
}
|
||||
return defaultValue;
|
||||
return HttpHeaders.getContentLength(this, defaultValue);
|
||||
}
|
||||
|
||||
public boolean isChunked() {
|
||||
@ -88,17 +88,44 @@ public class DefaultHttpMessage implements HttpMessage {
|
||||
}
|
||||
|
||||
public boolean isKeepAlive() {
|
||||
if (HttpHeaders.Values.CLOSE.equalsIgnoreCase(getHeader(HttpHeaders.Names.CONNECTION))) {
|
||||
HttpVersion version = getProtocolVersion();
|
||||
if (!version.getProtocolName().equals("HTTP")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getProtocolVersion().equals(HttpVersion.HTTP_1_0) &&
|
||||
!HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(getHeader(HttpHeaders.Names.CONNECTION))) {
|
||||
String connection = getHeader(Names.CONNECTION);
|
||||
if (HttpHeaders.Values.CLOSE.equalsIgnoreCase(connection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version.equals(HttpVersion.HTTP_1_0) &&
|
||||
!HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(connection)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setKeepAlive(boolean keepAlive) {
|
||||
HttpVersion version = getProtocolVersion();
|
||||
if (!version.getProtocolName().equals("HTTP")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (version.equals(HttpVersion.HTTP_1_0)) {
|
||||
if (keepAlive) {
|
||||
setHeader(Names.CONNECTION, Values.KEEP_ALIVE);
|
||||
} else {
|
||||
removeHeader(Names.CONNECTION);
|
||||
}
|
||||
} else {
|
||||
if (keepAlive) {
|
||||
removeHeader(Names.CONNECTION);
|
||||
} else {
|
||||
setHeader(Names.CONNECTION, Values.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearHeaders() {
|
||||
headers.clearHeaders();
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public interface HttpChunk {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addHeader(String name, String value) {
|
||||
public void addHeader(String name, Object value) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
@ -88,11 +88,11 @@ public interface HttpChunk {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
public void setHeader(String name, String value) {
|
||||
public void setHeader(String name, Object value) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
|
||||
public void setHeader(String name, Iterable<String> values) {
|
||||
public void setHeader(String name, Iterable<?> values) {
|
||||
throw new IllegalStateException("read-only");
|
||||
}
|
||||
};
|
||||
|
@ -74,21 +74,21 @@ public interface HttpChunkTrailer extends HttpChunk {
|
||||
/**
|
||||
* Adds a new trailing header with the specified name and value.
|
||||
*/
|
||||
void addHeader(String name, String value);
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new trailing header with the specified name and value.
|
||||
* If there is an existing trailing header with the same name, the existing
|
||||
* one is removed.
|
||||
*/
|
||||
void setHeader(String name, String value);
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new trailing header with the specified name and values.
|
||||
* If there is an existing trailing header with the same name, the existing
|
||||
* one is removed.
|
||||
*/
|
||||
void setHeader(String name, Iterable<String> values);
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the trailing header with the specified name.
|
||||
|
@ -409,6 +409,57 @@ public class HttpHeaders {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link HttpMessage#getContent()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length or {@code 0} if this message does not have
|
||||
* the {@code "Content-Length"} header
|
||||
*/
|
||||
public static long getContentLength(HttpMessage message) {
|
||||
return getContentLength(message, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link HttpMessage#getContent()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length or {@code defaultValue} if this message does
|
||||
* not have the {@code "Content-Length"} header
|
||||
*/
|
||||
public static long getContentLength(HttpMessage message, long defaultValue) {
|
||||
String contentLength = message.getHeader(Names.CONTENT_LENGTH);
|
||||
if (contentLength != null) {
|
||||
return Long.parseLong(contentLength);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static void setContentLength(HttpMessage message, long value) {
|
||||
message.setHeader(Names.CONTENT_LENGTH, value);
|
||||
}
|
||||
|
||||
public static String getHost(HttpMessage message) {
|
||||
return message.getHeader(Names.HOST);
|
||||
}
|
||||
|
||||
public static String getHost(HttpMessage message, String defaultValue) {
|
||||
String host = getHost(message);
|
||||
if (host == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
public static void setHost(HttpMessage message, String value) {
|
||||
message.setHeader(Names.HOST, value);
|
||||
}
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static int hash(String name) {
|
||||
@ -469,12 +520,13 @@ public class HttpHeaders {
|
||||
HttpCodecUtil.validateHeaderName(name);
|
||||
}
|
||||
|
||||
void addHeader(final String name, final String value) {
|
||||
void addHeader(final String name, final Object value) {
|
||||
validateHeaderName(name);
|
||||
HttpCodecUtil.validateHeaderValue(value);
|
||||
String strVal = toString(value);
|
||||
HttpCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
addHeader0(h, i, name, value);
|
||||
addHeader0(h, i, name, strVal);
|
||||
}
|
||||
|
||||
private void addHeader0(int h, int i, final String name, final String value) {
|
||||
@ -536,43 +588,34 @@ public class HttpHeaders {
|
||||
}
|
||||
}
|
||||
|
||||
void setHeader(final String name, final String value) {
|
||||
void setHeader(final String name, final Object value) {
|
||||
validateHeaderName(name);
|
||||
HttpCodecUtil.validateHeaderValue(value);
|
||||
String strVal = toString(value);
|
||||
HttpCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
removeHeader0(h, i, name);
|
||||
addHeader0(h, i, name, value);
|
||||
addHeader0(h, i, name, strVal);
|
||||
}
|
||||
|
||||
void setHeader(final String name, final Iterable<String> values) {
|
||||
validateHeaderName(name);
|
||||
void setHeader(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
boolean empty = true;
|
||||
for (String v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
HttpCodecUtil.validateHeaderValue(v);
|
||||
empty = false;
|
||||
}
|
||||
validateHeaderName(name);
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
|
||||
removeHeader0(h, i, name);
|
||||
if (empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String v: values) {
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
addHeader0(h, i, name, v);
|
||||
String strVal = toString(v);
|
||||
HttpCodecUtil.validateHeaderValue(strVal);
|
||||
addHeader0(h, i, name, strVal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,6 +691,13 @@ public class HttpHeaders {
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static final class Entry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
|
@ -101,19 +101,19 @@ public interface HttpMessage {
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
void addHeader(String name, String value);
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
void setHeader(String name, String value);
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
void setHeader(String name, Iterable<String> values);
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
@ -126,25 +126,15 @@ public interface HttpMessage {
|
||||
void clearHeaders();
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link #getContent()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length or {@code 0} if this message does not have
|
||||
* the {@code "Content-Length"} header
|
||||
* @deprecated Use {@link HttpHeaders#getContentLength(HttpMessage)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
long getContentLength();
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link #getContent()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length or {@code defaultValue} if this message does
|
||||
* not have the {@code "Content-Length"} header
|
||||
* @deprecated Use {@link HttpHeaders#getContentLength(HttpMessage, long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
long getContentLength(long defaultValue);
|
||||
|
||||
/**
|
||||
@ -175,7 +165,37 @@ public interface HttpMessage {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if the connection can remain open and
|
||||
* thus 'kept alive'.
|
||||
* thus 'kept alive'. In HTTP, this property is determined by the value of the
|
||||
* {@code "Connection"} header and the protocol version of this message.
|
||||
* <p>
|
||||
* Please note that the default implementation of this method only
|
||||
* understands HTTP. If the protocol version of this message indicates
|
||||
* other derived protocols such as RTSP and ICAP, it will return false by
|
||||
* default.
|
||||
*/
|
||||
boolean isKeepAlive();
|
||||
|
||||
/**
|
||||
* Sets the value of the {@code "Connection"} header depending on the
|
||||
* protocol version of this message. The default implementation sets or
|
||||
* removes the {@code "Connection"} header with the following rules:
|
||||
* <ul>
|
||||
* <li>If protocol version is HTTP/1.1 or later:
|
||||
* <ul>
|
||||
* <li>set to {@code "close"} if {@code keepAlive} is {@code false}.</li>
|
||||
* <li>remove otherwise.</li>
|
||||
* </ul></li>
|
||||
* <li>If protocol version is HTTP/1.0:
|
||||
* <ul>
|
||||
* <li>set to {@code "keep-alive"} if {@code keepAlive} is {@code true}.</li>
|
||||
* <li>remove otherwise.</li>
|
||||
* </ul></li>
|
||||
* <li>do nothing if the protocol name is not {@code "HTTP"}.</li>
|
||||
* </ul>
|
||||
* Please note that the default implementation of this method only
|
||||
* understands HTTP. If the protocol version of this message indicates
|
||||
* other derived protocols such as RTSP and ICAP, it will do nothing by
|
||||
* default.
|
||||
*/
|
||||
void setKeepAlive(boolean keepAlive);
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
message.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
return message;
|
||||
} else {
|
||||
long contentLength = message.getContentLength(-1);
|
||||
long contentLength = HttpHeaders.getContentLength(message, -1);
|
||||
if (contentLength == 0 || contentLength == -1 && isDecodingRequest()) {
|
||||
content = ChannelBuffers.EMPTY_BUFFER;
|
||||
return reset();
|
||||
@ -228,7 +228,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
message.setChunked(true);
|
||||
// chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT_AS_CHUNKS
|
||||
// state reads data chunk by chunk.
|
||||
chunkSize = message.getContentLength(-1);
|
||||
chunkSize = HttpHeaders.getContentLength(message, -1);
|
||||
return message;
|
||||
}
|
||||
break;
|
||||
@ -415,7 +415,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
}
|
||||
|
||||
private void readFixedLengthContent(ChannelBuffer buffer) {
|
||||
long length = message.getContentLength(-1);
|
||||
long length = HttpHeaders.getContentLength(message, -1);
|
||||
assert length <= Integer.MAX_VALUE;
|
||||
|
||||
if (content == null) {
|
||||
@ -461,7 +461,7 @@ public abstract class HttpMessageDecoder extends ReplayingDecoder<HttpMessageDec
|
||||
// yet, HttpMessage.isChunked() should return true only when
|
||||
// 'Transfer-Encoding' is 'chunked'.
|
||||
nextState = State.READ_CHUNK_SIZE;
|
||||
} else if (message.getContentLength(-1) >= 0) {
|
||||
} else if (HttpHeaders.getContentLength(message, -1) >= 0) {
|
||||
nextState = State.READ_FIXED_LENGTH_CONTENT;
|
||||
} else {
|
||||
nextState = State.READ_VARIABLE_LENGTH_CONTENT;
|
||||
|
Loading…
Reference in New Issue
Block a user