Change the WebSocket API to use HttpHeaders instead of Map<String, String> for custom headers / Cleanup
This commit is contained in:
parent
540bc99549
commit
3b79008eda
@ -65,7 +65,7 @@ public abstract class DefaultHttpMessage extends DefaultHttpObject implements Ht
|
|||||||
}
|
}
|
||||||
|
|
||||||
void appendHeaders(StringBuilder buf) {
|
void appendHeaders(StringBuilder buf) {
|
||||||
for (Map.Entry<String, String> e: headers().entries()) {
|
for (Map.Entry<String, String> e: headers()) {
|
||||||
buf.append(e.getKey());
|
buf.append(e.getKey());
|
||||||
buf.append(": ");
|
buf.append(": ");
|
||||||
buf.append(e.getValue());
|
buf.append(e.getValue());
|
||||||
|
@ -44,7 +44,7 @@ import io.netty.handler.codec.MessageToMessageDecoder;
|
|||||||
public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object> {
|
public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object> {
|
||||||
|
|
||||||
private EmbeddedByteChannel decoder;
|
private EmbeddedByteChannel decoder;
|
||||||
private HttpMessage header;
|
private HttpMessage message;
|
||||||
private boolean decodeStarted;
|
private boolean decodeStarted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,8 +61,8 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
if (msg instanceof HttpMessage) {
|
if (msg instanceof HttpMessage) {
|
||||||
assert header == null;
|
assert message == null;
|
||||||
header = (HttpMessage) msg;
|
message = (HttpMessage) msg;
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
@ -72,11 +72,12 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
|
|||||||
|
|
||||||
if (!decodeStarted) {
|
if (!decodeStarted) {
|
||||||
decodeStarted = true;
|
decodeStarted = true;
|
||||||
HttpMessage header = this.header;
|
HttpMessage message = this.message;
|
||||||
this.header = null;
|
HttpHeaders headers = message.headers();
|
||||||
|
this.message = null;
|
||||||
|
|
||||||
// Determine the content encoding.
|
// Determine the content encoding.
|
||||||
String contentEncoding = header.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
|
String contentEncoding = headers.get(HttpHeaders.Names.CONTENT_ENCODING);
|
||||||
if (contentEncoding != null) {
|
if (contentEncoding != null) {
|
||||||
contentEncoding = contentEncoding.trim();
|
contentEncoding = contentEncoding.trim();
|
||||||
} else {
|
} else {
|
||||||
@ -90,21 +91,21 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
|
|||||||
if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) {
|
if (HttpHeaders.Values.IDENTITY.equals(targetContentEncoding)) {
|
||||||
// Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
|
// Do NOT set the 'Content-Encoding' header if the target encoding is 'identity'
|
||||||
// as per: http://tools.ietf.org/html/rfc2616#section-14.11
|
// as per: http://tools.ietf.org/html/rfc2616#section-14.11
|
||||||
header.headers().remove(HttpHeaders.Names.CONTENT_ENCODING);
|
headers.remove(HttpHeaders.Names.CONTENT_ENCODING);
|
||||||
} else {
|
} else {
|
||||||
header.headers().set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
|
headers.set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
|
||||||
}
|
}
|
||||||
Object[] decoded = decodeContent(header, c);
|
Object[] decoded = decodeContent(message, c);
|
||||||
|
|
||||||
// Replace the content.
|
// Replace the content.
|
||||||
if (header.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
if (headers.contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||||
header.headers().set(
|
headers.set(
|
||||||
HttpHeaders.Names.CONTENT_LENGTH,
|
HttpHeaders.Names.CONTENT_LENGTH,
|
||||||
Integer.toString(((ByteBufHolder) decoded[1]).data().readableBytes()));
|
Integer.toString(((ByteBufHolder) decoded[1]).data().readableBytes()));
|
||||||
}
|
}
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
return new Object[] { header, c };
|
return new Object[] { message, c };
|
||||||
}
|
}
|
||||||
return decodeContent(null, c);
|
return decodeContent(null, c);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpMessa
|
|||||||
|
|
||||||
private final Queue<String> acceptEncodingQueue = new ArrayDeque<String>();
|
private final Queue<String> acceptEncodingQueue = new ArrayDeque<String>();
|
||||||
private EmbeddedByteChannel encoder;
|
private EmbeddedByteChannel encoder;
|
||||||
private HttpMessage header;
|
private HttpMessage message;
|
||||||
private boolean encodeStarted;
|
private boolean encodeStarted;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,26 +84,24 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpMessa
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
if (msg instanceof HttpMessage) {
|
if (msg instanceof HttpMessage) {
|
||||||
assert header == null;
|
assert message == null;
|
||||||
|
|
||||||
// check if this message is also of type HttpContent is such case just make a safe copy of the headers
|
// check if this message is also of type HttpContent is such case just make a safe copy of the headers
|
||||||
// as the content will get handled later and this simplify the handling
|
// as the content will get handled later and this simplify the handling
|
||||||
if (msg instanceof HttpContent) {
|
if (msg instanceof HttpContent) {
|
||||||
if (msg instanceof HttpRequest) {
|
if (msg instanceof HttpRequest) {
|
||||||
HttpRequest reqHeader = (HttpRequest) msg;
|
HttpRequest req = (HttpRequest) msg;
|
||||||
header = new DefaultHttpRequest(reqHeader.protocolVersion(), reqHeader.method(),
|
message = new DefaultHttpRequest(req.protocolVersion(), req.method(), req.uri());
|
||||||
reqHeader.uri());
|
message.headers().set(req.headers());
|
||||||
HttpHeaders.setHeaders(reqHeader, header);
|
|
||||||
} else if (msg instanceof HttpResponse) {
|
} else if (msg instanceof HttpResponse) {
|
||||||
HttpResponse responseHeader = (HttpResponse) msg;
|
HttpResponse res = (HttpResponse) msg;
|
||||||
header = new DefaultHttpResponse(responseHeader.protocolVersion(),
|
message = new DefaultHttpResponse(res.protocolVersion(), res.status());
|
||||||
responseHeader.status());
|
message.headers().set(res.headers());
|
||||||
HttpHeaders.setHeaders(responseHeader, header);
|
|
||||||
} else {
|
} else {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
header = (HttpMessage) msg;
|
message = (HttpMessage) msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
@ -114,21 +112,22 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpMessa
|
|||||||
|
|
||||||
if (!encodeStarted) {
|
if (!encodeStarted) {
|
||||||
encodeStarted = true;
|
encodeStarted = true;
|
||||||
HttpMessage header = this.header;
|
HttpMessage message = this.message;
|
||||||
this.header = null;
|
HttpHeaders headers = message.headers();
|
||||||
|
this.message = null;
|
||||||
|
|
||||||
// Determine the content encoding.
|
// Determine the content encoding.
|
||||||
String acceptEncoding = acceptEncodingQueue.poll();
|
String acceptEncoding = acceptEncodingQueue.poll();
|
||||||
if (acceptEncoding == null) {
|
if (acceptEncoding == null) {
|
||||||
throw new IllegalStateException("cannot send more responses than requests");
|
throw new IllegalStateException("cannot send more responses than requests");
|
||||||
}
|
}
|
||||||
Result result = beginEncode(header, c, acceptEncoding);
|
Result result = beginEncode(message, c, acceptEncoding);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
if (c instanceof LastHttpContent) {
|
if (c instanceof LastHttpContent) {
|
||||||
return new Object[] { header, new DefaultLastHttpContent(c.data()) };
|
return new Object[] { message, new DefaultLastHttpContent(c.data()) };
|
||||||
} else {
|
} else {
|
||||||
return new Object[] { header, new DefaultHttpContent(c.data()) };
|
return new Object[] { message, new DefaultHttpContent(c.data()) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,18 +135,18 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpMessa
|
|||||||
|
|
||||||
// Encode the content and remove or replace the existing headers
|
// Encode the content and remove or replace the existing headers
|
||||||
// so that the message looks like a decoded message.
|
// so that the message looks like a decoded message.
|
||||||
header.headers().set(
|
headers.set(
|
||||||
HttpHeaders.Names.CONTENT_ENCODING,
|
HttpHeaders.Names.CONTENT_ENCODING,
|
||||||
result.getTargetContentEncoding());
|
result.getTargetContentEncoding());
|
||||||
|
|
||||||
Object[] encoded = encodeContent(header, c);
|
Object[] encoded = encodeContent(message, c);
|
||||||
|
|
||||||
if (!HttpHeaders.isTransferEncodingChunked(header) && encoded.length == 3) {
|
if (!HttpHeaders.isTransferEncodingChunked(message) && encoded.length == 3) {
|
||||||
if (header.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
if (headers.contains(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||||
long length = ((ByteBufHolder) encoded[1]).data().readableBytes() +
|
long length = ((ByteBufHolder) encoded[1]).data().readableBytes() +
|
||||||
((ByteBufHolder) encoded[2]).data().readableBytes();
|
((ByteBufHolder) encoded[2]).data().readableBytes();
|
||||||
|
|
||||||
header.headers().set(
|
headers.set(
|
||||||
HttpHeaders.Names.CONTENT_LENGTH,
|
HttpHeaders.Names.CONTENT_LENGTH,
|
||||||
Long.toString(length));
|
Long.toString(length));
|
||||||
}
|
}
|
||||||
|
@ -584,17 +584,18 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
|||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
|
public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
|
||||||
|
HttpHeaders h = message.headers();
|
||||||
if (message.protocolVersion().isKeepAliveDefault()) {
|
if (message.protocolVersion().isKeepAliveDefault()) {
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
message.headers().remove(Names.CONNECTION);
|
h.remove(Names.CONNECTION);
|
||||||
} else {
|
} else {
|
||||||
message.headers().set(Names.CONNECTION, Values.CLOSE);
|
h.set(Names.CONNECTION, Values.CLOSE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (keepAlive) {
|
if (keepAlive) {
|
||||||
message.headers().set(Names.CONNECTION, Values.KEEP_ALIVE);
|
h.set(Names.CONNECTION, Values.KEEP_ALIVE);
|
||||||
} else {
|
} else {
|
||||||
message.headers().remove(Names.CONNECTION);
|
h.remove(Names.CONNECTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -879,18 +880,19 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
|||||||
*/
|
*/
|
||||||
private static int getWebSocketContentLength(HttpMessage message) {
|
private static int getWebSocketContentLength(HttpMessage message) {
|
||||||
// WebSockset messages have constant content-lengths.
|
// WebSockset messages have constant content-lengths.
|
||||||
|
HttpHeaders h = message.headers();
|
||||||
if (message instanceof HttpRequest) {
|
if (message instanceof HttpRequest) {
|
||||||
HttpRequest req = (HttpRequest) message;
|
HttpRequest req = (HttpRequest) message;
|
||||||
if (HttpMethod.GET.equals(req.method()) &&
|
if (HttpMethod.GET.equals(req.method()) &&
|
||||||
req.headers().contains(Names.SEC_WEBSOCKET_KEY1) &&
|
h.contains(Names.SEC_WEBSOCKET_KEY1) &&
|
||||||
req.headers().contains(Names.SEC_WEBSOCKET_KEY2)) {
|
h.contains(Names.SEC_WEBSOCKET_KEY2)) {
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
} else if (message instanceof HttpResponse) {
|
} else if (message instanceof HttpResponse) {
|
||||||
HttpResponse res = (HttpResponse) message;
|
HttpResponse res = (HttpResponse) message;
|
||||||
if (res.status().code() == 101 &&
|
if (res.status().code() == 101 &&
|
||||||
res.headers().contains(Names.SEC_WEBSOCKET_ORIGIN) &&
|
h.contains(Names.SEC_WEBSOCKET_ORIGIN) &&
|
||||||
res.headers().contains(Names.SEC_WEBSOCKET_LOCATION)) {
|
h.contains(Names.SEC_WEBSOCKET_LOCATION)) {
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1015,14 +1017,6 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the headers on the dst like they are set on the src
|
|
||||||
*/
|
|
||||||
public static void setHeaders(HttpMessage src, HttpMessage dst) {
|
|
||||||
for (String name: src.headers().names()) {
|
|
||||||
dst.headers().set(name, src.headers().getAll(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Validates the name of a header
|
* Validates the name of a header
|
||||||
*
|
*
|
||||||
|
@ -26,8 +26,6 @@ import io.netty.handler.codec.MessageToMessageDecoder;
|
|||||||
import io.netty.handler.codec.TooLongFrameException;
|
import io.netty.handler.codec.TooLongFrameException;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpHeaders.*;
|
import static io.netty.handler.codec.http.HttpHeaders.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,10 +144,8 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpHeaders headers = currentMessage.headers();
|
currentMessage.headers().set(m.headers());
|
||||||
for (String name: m.headers().names()) {
|
|
||||||
headers.set(name, m.headers().get(name));
|
|
||||||
}
|
|
||||||
// A streamed message - initialize the cumulative buffer, and wait for incoming chunks.
|
// A streamed message - initialize the cumulative buffer, and wait for incoming chunks.
|
||||||
removeTransferEncodingChunked(currentMessage);
|
removeTransferEncodingChunked(currentMessage);
|
||||||
return null;
|
return null;
|
||||||
@ -194,9 +190,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
|
|||||||
// Merge trailing headers into the message.
|
// Merge trailing headers into the message.
|
||||||
if (chunk instanceof LastHttpContent) {
|
if (chunk instanceof LastHttpContent) {
|
||||||
LastHttpContent trailer = (LastHttpContent) chunk;
|
LastHttpContent trailer = (LastHttpContent) chunk;
|
||||||
for (Entry<String, String> header: trailer.trailingHeaders()) {
|
currentMessage.headers().add(trailer.trailingHeaders());
|
||||||
currentMessage.headers().add(header.getKey(), header.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the 'Content-Length' header.
|
// Set the 'Content-Length' header.
|
||||||
|
@ -493,18 +493,20 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
|||||||
private State readHeaders(ByteBuf buffer) {
|
private State readHeaders(ByteBuf buffer) {
|
||||||
headerSize = 0;
|
headerSize = 0;
|
||||||
final HttpMessage message = this.message;
|
final HttpMessage message = this.message;
|
||||||
|
final HttpHeaders headers = message.headers();
|
||||||
|
|
||||||
String line = readHeader(buffer);
|
String line = readHeader(buffer);
|
||||||
String name = null;
|
String name = null;
|
||||||
String value = null;
|
String value = null;
|
||||||
if (!line.isEmpty()) {
|
if (!line.isEmpty()) {
|
||||||
message.headers().clear();
|
headers.clear();
|
||||||
do {
|
do {
|
||||||
char firstChar = line.charAt(0);
|
char firstChar = line.charAt(0);
|
||||||
if (name != null && (firstChar == ' ' || firstChar == '\t')) {
|
if (name != null && (firstChar == ' ' || firstChar == '\t')) {
|
||||||
value = value + ' ' + line.trim();
|
value = value + ' ' + line.trim();
|
||||||
} else {
|
} else {
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
message.headers().add(name, value);
|
headers.add(name, value);
|
||||||
}
|
}
|
||||||
String[] header = splitHeader(line);
|
String[] header = splitHeader(line);
|
||||||
name = header[0];
|
name = header[0];
|
||||||
@ -516,7 +518,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
|
|||||||
|
|
||||||
// Add the last header.
|
// Add the last header.
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
message.headers().add(name, value);
|
headers.add(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +195,10 @@ public class HttpPostRequestDecoder {
|
|||||||
this.charset = charset;
|
this.charset = charset;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
// Fill default values
|
// Fill default values
|
||||||
if (this.request.headers().contains(HttpHeaders.Names.CONTENT_TYPE)) {
|
|
||||||
checkMultipart(this.request.headers().get(HttpHeaders.Names.CONTENT_TYPE));
|
String contentType = this.request.headers().get(HttpHeaders.Names.CONTENT_TYPE);
|
||||||
|
if (contentType != null) {
|
||||||
|
checkMultipart(contentType);
|
||||||
} else {
|
} else {
|
||||||
isMultipart = false;
|
isMultipart = false;
|
||||||
}
|
}
|
||||||
|
@ -618,10 +618,12 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
|
|||||||
} else {
|
} else {
|
||||||
throw new ErrorDataEncoderException("Header already encoded");
|
throw new ErrorDataEncoderException("Header already encoded");
|
||||||
}
|
}
|
||||||
List<String> contentTypes = request.headers().getAll(HttpHeaders.Names.CONTENT_TYPE);
|
|
||||||
List<String> transferEncoding = request.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
|
HttpHeaders headers = request.headers();
|
||||||
|
List<String> contentTypes = headers.getAll(HttpHeaders.Names.CONTENT_TYPE);
|
||||||
|
List<String> transferEncoding = headers.getAll(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||||
if (contentTypes != null) {
|
if (contentTypes != null) {
|
||||||
request.headers().remove(HttpHeaders.Names.CONTENT_TYPE);
|
headers.remove(HttpHeaders.Names.CONTENT_TYPE);
|
||||||
for (String contentType : contentTypes) {
|
for (String contentType : contentTypes) {
|
||||||
// "multipart/form-data; boundary=--89421926422648"
|
// "multipart/form-data; boundary=--89421926422648"
|
||||||
if (contentType.toLowerCase().startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA)) {
|
if (contentType.toLowerCase().startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA)) {
|
||||||
@ -629,17 +631,17 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
|
|||||||
} else if (contentType.toLowerCase().startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
|
} else if (contentType.toLowerCase().startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
|
||||||
// ignore
|
// ignore
|
||||||
} else {
|
} else {
|
||||||
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, contentType);
|
headers.add(HttpHeaders.Names.CONTENT_TYPE, contentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isMultipart) {
|
if (isMultipart) {
|
||||||
String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " + HttpHeaders.Values.BOUNDARY + '='
|
String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " + HttpHeaders.Values.BOUNDARY + '='
|
||||||
+ multipartDataBoundary;
|
+ multipartDataBoundary;
|
||||||
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, value);
|
headers.add(HttpHeaders.Names.CONTENT_TYPE, value);
|
||||||
} else {
|
} else {
|
||||||
// Not multipart
|
// Not multipart
|
||||||
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
|
headers.add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
|
||||||
}
|
}
|
||||||
// Now consider size for chunk or not
|
// Now consider size for chunk or not
|
||||||
long realSize = globalBodySize;
|
long realSize = globalBodySize;
|
||||||
@ -649,16 +651,16 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
|
|||||||
realSize -= 1; // last '&' removed
|
realSize -= 1; // last '&' removed
|
||||||
iterator = multipartHttpDatas.listIterator();
|
iterator = multipartHttpDatas.listIterator();
|
||||||
}
|
}
|
||||||
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize));
|
headers.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize));
|
||||||
if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
|
if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
|
||||||
isChunked = true;
|
isChunked = true;
|
||||||
if (transferEncoding != null) {
|
if (transferEncoding != null) {
|
||||||
request.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
headers.remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||||
for (String v : transferEncoding) {
|
for (String v : transferEncoding) {
|
||||||
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
|
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
|
||||||
// ignore
|
// ignore
|
||||||
} else {
|
} else {
|
||||||
request.headers().add(HttpHeaders.Names.TRANSFER_ENCODING, v);
|
headers.add(HttpHeaders.Names.TRANSFER_ENCODING, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ import io.netty.channel.Channel;
|
|||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelPromise;
|
import io.netty.channel.ChannelPromise;
|
||||||
import io.netty.handler.codec.http.FullHttpResponse;
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for web socket client handshake implementations
|
* Base class for web socket client handshake implementations
|
||||||
@ -38,7 +38,7 @@ public abstract class WebSocketClientHandshaker {
|
|||||||
|
|
||||||
private String actualSubprotocol;
|
private String actualSubprotocol;
|
||||||
|
|
||||||
protected final Map<String, String> customHeaders;
|
protected final HttpHeaders customHeaders;
|
||||||
|
|
||||||
private final int maxFramePayloadLength;
|
private final int maxFramePayloadLength;
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public abstract class WebSocketClientHandshaker {
|
|||||||
* Maximum length of a frame's payload
|
* Maximum length of a frame's payload
|
||||||
*/
|
*/
|
||||||
protected WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol,
|
protected WebSocketClientHandshaker(URI webSocketUrl, WebSocketVersion version, String subprotocol,
|
||||||
Map<String, String> customHeaders, int maxFramePayloadLength) {
|
HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
this.webSocketUrl = webSocketUrl;
|
this.webSocketUrl = webSocketUrl;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
expectedSubprotocol = subprotocol;
|
expectedSubprotocol = subprotocol;
|
||||||
|
@ -23,6 +23,7 @@ import io.netty.channel.ChannelPromise;
|
|||||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpRequest;
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpResponse;
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Values;
|
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
@ -34,7 +35,6 @@ import io.netty.handler.codec.http.HttpVersion;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -66,7 +66,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
* Maximum length of a frame's payload
|
* Maximum length of a frame's payload
|
||||||
*/
|
*/
|
||||||
public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
public WebSocketClientHandshaker00(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
Map<String, String> customHeaders, int maxFramePayloadLength) {
|
HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +142,10 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
|
|
||||||
// Format request
|
// Format request
|
||||||
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET);
|
HttpHeaders headers = request.headers();
|
||||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
headers.add(Names.UPGRADE, Values.WEBSOCKET)
|
||||||
request.headers().add(Names.HOST, wsURL.getHost());
|
.add(Names.CONNECTION, Values.UPGRADE)
|
||||||
|
.add(Names.HOST, wsURL.getHost());
|
||||||
|
|
||||||
int wsPort = wsURL.getPort();
|
int wsPort = wsURL.getPort();
|
||||||
String originValue = "http://" + wsURL.getHost();
|
String originValue = "http://" + wsURL.getHost();
|
||||||
@ -154,23 +155,22 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
originValue = originValue + ':' + wsPort;
|
originValue = originValue + ':' + wsPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.headers().add(Names.ORIGIN, originValue);
|
headers.add(Names.ORIGIN, originValue)
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_KEY1, key1);
|
.add(Names.SEC_WEBSOCKET_KEY1, key1)
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_KEY2, key2);
|
.add(Names.SEC_WEBSOCKET_KEY2, key2);
|
||||||
|
|
||||||
String expectedSubprotocol = getExpectedSubprotocol();
|
String expectedSubprotocol = getExpectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customHeaders != null) {
|
if (customHeaders != null) {
|
||||||
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
|
headers.add(customHeaders);
|
||||||
request.headers().add(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Content-Length to workaround some known defect.
|
// Set Content-Length to workaround some known defect.
|
||||||
// See also: http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html
|
// See also: http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html
|
||||||
request.headers().set(Names.CONTENT_LENGTH, key3.length);
|
headers.set(Names.CONTENT_LENGTH, key3.length);
|
||||||
request.data().writeBytes(key3);
|
request.data().writeBytes(key3);
|
||||||
|
|
||||||
ChannelFuture future = channel.write(request);
|
ChannelFuture future = channel.write(request);
|
||||||
@ -223,13 +223,15 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
String upgrade = response.headers().get(Names.UPGRADE);
|
HttpHeaders headers = response.headers();
|
||||||
|
|
||||||
|
String upgrade = headers.get(Names.UPGRADE);
|
||||||
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||||
+ upgrade);
|
+ upgrade);
|
||||||
}
|
}
|
||||||
|
|
||||||
String connection = response.headers().get(Names.CONNECTION);
|
String connection = headers.get(Names.CONNECTION);
|
||||||
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||||
+ connection);
|
+ connection);
|
||||||
@ -240,7 +242,7 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
|||||||
throw new WebSocketHandshakeException("Invalid challenge");
|
throw new WebSocketHandshakeException("Invalid challenge");
|
||||||
}
|
}
|
||||||
|
|
||||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
String subprotocol = headers.get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||||
setActualSubprotocol(subprotocol);
|
setActualSubprotocol(subprotocol);
|
||||||
|
|
||||||
setHandshakeComplete();
|
setHandshakeComplete();
|
||||||
|
@ -23,6 +23,7 @@ import io.netty.channel.ChannelPromise;
|
|||||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpRequest;
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpResponse;
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Values;
|
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
@ -35,7 +36,6 @@ import io.netty.logging.InternalLoggerFactory;
|
|||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -72,7 +72,7 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
* Maximum length of a frame's payload
|
* Maximum length of a frame's payload
|
||||||
*/
|
*/
|
||||||
public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
public WebSocketClientHandshaker07(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
boolean allowExtensions, Map<String, String> customHeaders, int maxFramePayloadLength) {
|
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
||||||
this.allowExtensions = allowExtensions;
|
this.allowExtensions = allowExtensions;
|
||||||
}
|
}
|
||||||
@ -125,10 +125,12 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
|
|
||||||
// Format request
|
// Format request
|
||||||
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
HttpHeaders headers = request.headers();
|
||||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
|
||||||
request.headers().add(Names.HOST, wsURL.getHost());
|
.add(Names.CONNECTION, Values.UPGRADE)
|
||||||
|
.add(Names.SEC_WEBSOCKET_KEY, key)
|
||||||
|
.add(Names.HOST, wsURL.getHost());
|
||||||
|
|
||||||
int wsPort = wsURL.getPort();
|
int wsPort = wsURL.getPort();
|
||||||
String originValue = "http://" + wsURL.getHost();
|
String originValue = "http://" + wsURL.getHost();
|
||||||
@ -137,19 +139,17 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||||
originValue = originValue + ':' + wsPort;
|
originValue = originValue + ':' + wsPort;
|
||||||
}
|
}
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
headers.add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||||
|
|
||||||
String expectedSubprotocol = getExpectedSubprotocol();
|
String expectedSubprotocol = getExpectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "7");
|
headers.add(Names.SEC_WEBSOCKET_VERSION, "7");
|
||||||
|
|
||||||
if (customHeaders != null) {
|
if (customHeaders != null) {
|
||||||
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
|
headers.add(customHeaders);
|
||||||
request.headers().add(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelFuture future = channel.write(request);
|
ChannelFuture future = channel.write(request);
|
||||||
@ -194,30 +194,29 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
|||||||
@Override
|
@Override
|
||||||
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
||||||
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
||||||
|
final HttpHeaders headers = response.headers();
|
||||||
|
|
||||||
if (!response.status().equals(status)) {
|
if (!response.status().equals(status)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
String upgrade = response.headers().get(Names.UPGRADE);
|
String upgrade = headers.get(Names.UPGRADE);
|
||||||
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||||
+ response.headers().get(Names.UPGRADE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String connection = response.headers().get(Names.CONNECTION);
|
String connection = headers.get(Names.CONNECTION);
|
||||||
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||||
+ response.headers().get(Names.CONNECTION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
throw new WebSocketHandshakeException(String.format(
|
||||||
expectedChallengeResponseString));
|
"Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString));
|
||||||
}
|
}
|
||||||
|
|
||||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
String subprotocol = headers.get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||||
setActualSubprotocol(subprotocol);
|
setActualSubprotocol(subprotocol);
|
||||||
|
|
||||||
setHandshakeComplete();
|
setHandshakeComplete();
|
||||||
|
@ -23,6 +23,7 @@ import io.netty.channel.ChannelPromise;
|
|||||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpRequest;
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpResponse;
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Values;
|
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
@ -35,7 +36,6 @@ import io.netty.logging.InternalLoggerFactory;
|
|||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -72,7 +72,7 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
* Maximum length of a frame's payload
|
* Maximum length of a frame's payload
|
||||||
*/
|
*/
|
||||||
public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
public WebSocketClientHandshaker08(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
boolean allowExtensions, Map<String, String> customHeaders, int maxFramePayloadLength) {
|
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
||||||
this.allowExtensions = allowExtensions;
|
this.allowExtensions = allowExtensions;
|
||||||
}
|
}
|
||||||
@ -125,10 +125,12 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
|
|
||||||
// Format request
|
// Format request
|
||||||
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
HttpHeaders headers = request.headers();
|
||||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
|
||||||
request.headers().add(Names.HOST, wsURL.getHost());
|
.add(Names.CONNECTION, Values.UPGRADE)
|
||||||
|
.add(Names.SEC_WEBSOCKET_KEY, key)
|
||||||
|
.add(Names.HOST, wsURL.getHost());
|
||||||
|
|
||||||
int wsPort = wsURL.getPort();
|
int wsPort = wsURL.getPort();
|
||||||
String originValue = "http://" + wsURL.getHost();
|
String originValue = "http://" + wsURL.getHost();
|
||||||
@ -137,19 +139,17 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||||
originValue = originValue + ':' + wsPort;
|
originValue = originValue + ':' + wsPort;
|
||||||
}
|
}
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
headers.add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||||
|
|
||||||
String expectedSubprotocol = getExpectedSubprotocol();
|
String expectedSubprotocol = getExpectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "8");
|
headers.add(Names.SEC_WEBSOCKET_VERSION, "8");
|
||||||
|
|
||||||
if (customHeaders != null) {
|
if (customHeaders != null) {
|
||||||
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
|
headers.add(customHeaders);
|
||||||
request.headers().add(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelFuture future = channel.write(request);
|
ChannelFuture future = channel.write(request);
|
||||||
@ -194,30 +194,29 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
|||||||
@Override
|
@Override
|
||||||
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
||||||
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
||||||
|
final HttpHeaders headers = response.headers();
|
||||||
|
|
||||||
if (!response.status().equals(status)) {
|
if (!response.status().equals(status)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
String upgrade = response.headers().get(Names.UPGRADE);
|
String upgrade = headers.get(Names.UPGRADE);
|
||||||
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||||
+ response.headers().get(Names.UPGRADE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String connection = response.headers().get(Names.CONNECTION);
|
String connection = headers.get(Names.CONNECTION);
|
||||||
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||||
+ response.headers().get(Names.CONNECTION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
throw new WebSocketHandshakeException(String.format(
|
||||||
expectedChallengeResponseString));
|
"Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString));
|
||||||
}
|
}
|
||||||
|
|
||||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
String subprotocol = headers.get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||||
setActualSubprotocol(subprotocol);
|
setActualSubprotocol(subprotocol);
|
||||||
|
|
||||||
setHandshakeComplete();
|
setHandshakeComplete();
|
||||||
|
@ -22,6 +22,7 @@ import io.netty.channel.ChannelPipeline;
|
|||||||
import io.netty.channel.ChannelPromise;
|
import io.netty.channel.ChannelPromise;
|
||||||
import io.netty.handler.codec.http.DefaultHttpRequest;
|
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpResponse;
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Values;
|
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
@ -35,7 +36,6 @@ import io.netty.logging.InternalLoggerFactory;
|
|||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -72,7 +72,7 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
* Maximum length of a frame's payload
|
* Maximum length of a frame's payload
|
||||||
*/
|
*/
|
||||||
public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
public WebSocketClientHandshaker13(URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
boolean allowExtensions, Map<String, String> customHeaders, int maxFramePayloadLength) {
|
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
super(webSocketURL, version, subprotocol, customHeaders, maxFramePayloadLength);
|
||||||
this.allowExtensions = allowExtensions;
|
this.allowExtensions = allowExtensions;
|
||||||
}
|
}
|
||||||
@ -125,10 +125,12 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
|
|
||||||
// Format request
|
// Format request
|
||||||
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
|
||||||
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
|
HttpHeaders headers = request.headers();
|
||||||
request.headers().add(Names.CONNECTION, Values.UPGRADE);
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
|
headers.add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase())
|
||||||
request.headers().add(Names.HOST, wsURL.getHost());
|
.add(Names.CONNECTION, Values.UPGRADE)
|
||||||
|
.add(Names.SEC_WEBSOCKET_KEY, key)
|
||||||
|
.add(Names.HOST, wsURL.getHost());
|
||||||
|
|
||||||
int wsPort = wsURL.getPort();
|
int wsPort = wsURL.getPort();
|
||||||
String originValue = "http://" + wsURL.getHost();
|
String originValue = "http://" + wsURL.getHost();
|
||||||
@ -137,19 +139,17 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
// See http://tools.ietf.org/html/rfc6454#section-6.2
|
||||||
originValue = originValue + ':' + wsPort;
|
originValue = originValue + ':' + wsPort;
|
||||||
}
|
}
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
headers.add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
|
||||||
|
|
||||||
String expectedSubprotocol = getExpectedSubprotocol();
|
String expectedSubprotocol = getExpectedSubprotocol();
|
||||||
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
headers.add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "13");
|
headers.add(Names.SEC_WEBSOCKET_VERSION, "13");
|
||||||
|
|
||||||
if (customHeaders != null) {
|
if (customHeaders != null) {
|
||||||
for (Map.Entry<String, String> e: customHeaders.entrySet()) {
|
headers.add(customHeaders);
|
||||||
request.headers().add(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelFuture future = channel.write(request);
|
ChannelFuture future = channel.write(request);
|
||||||
@ -193,30 +193,29 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
|||||||
@Override
|
@Override
|
||||||
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
public void finishHandshake(Channel channel, FullHttpResponse response) {
|
||||||
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
|
||||||
|
final HttpHeaders headers = response.headers();
|
||||||
|
|
||||||
if (!response.status().equals(status)) {
|
if (!response.status().equals(status)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
String upgrade = response.headers().get(Names.UPGRADE);
|
String upgrade = headers.get(Names.UPGRADE);
|
||||||
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||||
+ response.headers().get(Names.UPGRADE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String connection = response.headers().get(Names.CONNECTION);
|
String connection = headers.get(Names.CONNECTION);
|
||||||
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
|
||||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||||
+ response.headers().get(Names.CONNECTION));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
|
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||||
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
|
||||||
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
|
throw new WebSocketHandshakeException(String.format(
|
||||||
expectedChallengeResponseString));
|
"Invalid challenge. Actual: %s. Expected: %s", accept, expectedChallengeResponseString));
|
||||||
}
|
}
|
||||||
|
|
||||||
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
|
String subprotocol = headers.get(Names.SEC_WEBSOCKET_PROTOCOL);
|
||||||
setActualSubprotocol(subprotocol);
|
setActualSubprotocol(subprotocol);
|
||||||
|
|
||||||
setHandshakeComplete();
|
setHandshakeComplete();
|
||||||
|
@ -15,8 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.codec.http.websocketx;
|
package io.netty.handler.codec.http.websocketx;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.websocketx.WebSocketVersion.*;
|
import static io.netty.handler.codec.http.websocketx.WebSocketVersion.*;
|
||||||
|
|
||||||
@ -48,7 +49,7 @@ public final class WebSocketClientHandshakerFactory {
|
|||||||
*/
|
*/
|
||||||
public static WebSocketClientHandshaker newHandshaker(
|
public static WebSocketClientHandshaker newHandshaker(
|
||||||
URI webSocketURL, WebSocketVersion version, String subprotocol,
|
URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
boolean allowExtensions, Map<String, String> customHeaders) {
|
boolean allowExtensions, HttpHeaders customHeaders) {
|
||||||
return newHandshaker(webSocketURL, version, subprotocol, allowExtensions, customHeaders, 65536);
|
return newHandshaker(webSocketURL, version, subprotocol, allowExtensions, customHeaders, 65536);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ public final class WebSocketClientHandshakerFactory {
|
|||||||
*/
|
*/
|
||||||
public static WebSocketClientHandshaker newHandshaker(
|
public static WebSocketClientHandshaker newHandshaker(
|
||||||
URI webSocketURL, WebSocketVersion version, String subprotocol,
|
URI webSocketURL, WebSocketVersion version, String subprotocol,
|
||||||
boolean allowExtensions, Map<String, String> customHeaders, int maxFramePayloadLength) {
|
boolean allowExtensions, HttpHeaders customHeaders, int maxFramePayloadLength) {
|
||||||
if (version == V13) {
|
if (version == V13) {
|
||||||
return new WebSocketClientHandshaker13(
|
return new WebSocketClientHandshaker13(
|
||||||
webSocketURL, V13, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength);
|
webSocketURL, V13, subprotocol, allowExtensions, customHeaders, maxFramePayloadLength);
|
||||||
|
@ -235,7 +235,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
|||||||
SpdyHeaders.removeUrl(spdyVersion, requestFrame);
|
SpdyHeaders.removeUrl(spdyVersion, requestFrame);
|
||||||
SpdyHeaders.removeVersion(spdyVersion, requestFrame);
|
SpdyHeaders.removeVersion(spdyVersion, requestFrame);
|
||||||
|
|
||||||
FullHttpRequest httpRequestWithEntity = new DefaultFullHttpRequest(httpVersion, method, url);
|
FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, url);
|
||||||
|
|
||||||
// Remove the scheme header
|
// Remove the scheme header
|
||||||
SpdyHeaders.removeScheme(spdyVersion, requestFrame);
|
SpdyHeaders.removeScheme(spdyVersion, requestFrame);
|
||||||
@ -244,20 +244,20 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
|||||||
// Replace the SPDY host header with the HTTP host header
|
// Replace the SPDY host header with the HTTP host header
|
||||||
String host = SpdyHeaders.getHost(requestFrame);
|
String host = SpdyHeaders.getHost(requestFrame);
|
||||||
SpdyHeaders.removeHost(requestFrame);
|
SpdyHeaders.removeHost(requestFrame);
|
||||||
HttpHeaders.setHost(httpRequestWithEntity, host);
|
HttpHeaders.setHost(req, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, String> e: requestFrame.getHeaders()) {
|
for (Map.Entry<String, String> e: requestFrame.getHeaders()) {
|
||||||
httpRequestWithEntity.headers().add(e.getKey(), e.getValue());
|
req.headers().add(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Connection and Keep-Alive headers are no longer valid
|
// The Connection and Keep-Alive headers are no longer valid
|
||||||
HttpHeaders.setKeepAlive(httpRequestWithEntity, true);
|
HttpHeaders.setKeepAlive(req, true);
|
||||||
|
|
||||||
// Transfer-Encoding header is not valid
|
// Transfer-Encoding header is not valid
|
||||||
httpRequestWithEntity.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
req.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||||
|
|
||||||
return httpRequestWithEntity;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FullHttpResponse createHttpResponse(int spdyVersion, SpdyHeaderBlock responseFrame)
|
private static FullHttpResponse createHttpResponse(int spdyVersion, SpdyHeaderBlock responseFrame)
|
||||||
@ -268,18 +268,18 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
|||||||
SpdyHeaders.removeStatus(spdyVersion, responseFrame);
|
SpdyHeaders.removeStatus(spdyVersion, responseFrame);
|
||||||
SpdyHeaders.removeVersion(spdyVersion, responseFrame);
|
SpdyHeaders.removeVersion(spdyVersion, responseFrame);
|
||||||
|
|
||||||
FullHttpResponse httpResponseWithEntity = new DefaultFullHttpResponse(version, status);
|
FullHttpResponse res = new DefaultFullHttpResponse(version, status);
|
||||||
for (Map.Entry<String, String> e: responseFrame.getHeaders()) {
|
for (Map.Entry<String, String> e: responseFrame.getHeaders()) {
|
||||||
httpResponseWithEntity.headers().add(e.getKey(), e.getValue());
|
res.headers().add(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Connection and Keep-Alive headers are no longer valid
|
// The Connection and Keep-Alive headers are no longer valid
|
||||||
HttpHeaders.setKeepAlive(httpResponseWithEntity, true);
|
HttpHeaders.setKeepAlive(res, true);
|
||||||
|
|
||||||
// Transfer-Encoding header is not valid
|
// Transfer-Encoding header is not valid
|
||||||
httpResponseWithEntity.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
res.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||||
httpResponseWithEntity.headers().remove(HttpHeaders.Names.TRAILER);
|
res.headers().remove(HttpHeaders.Names.TRAILER);
|
||||||
|
|
||||||
return httpResponseWithEntity;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,32 +15,33 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.codec.http;
|
package io.netty.handler.codec.http;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class DefaultHttpRequestTest {
|
public class DefaultHttpRequestTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderRemoval() {
|
public void testHeaderRemoval() {
|
||||||
HttpMessage m = new DefaultHttpRequest(
|
HttpMessage m = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
|
||||||
HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
|
HttpHeaders h = m.headers();
|
||||||
|
|
||||||
// Insert sample keys.
|
// Insert sample keys.
|
||||||
for (int i = 0; i < 1000; i ++) {
|
for (int i = 0; i < 1000; i ++) {
|
||||||
m.headers().set(String.valueOf(i), "");
|
h.set(String.valueOf(i), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove in reversed order.
|
// Remove in reversed order.
|
||||||
for (int i = 999; i >= 0; i --) {
|
for (int i = 999; i >= 0; i --) {
|
||||||
m.headers().remove(String.valueOf(i));
|
h.remove(String.valueOf(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if random access returns nothing.
|
// Check if random access returns nothing.
|
||||||
for (int i = 0; i < 1000; i ++) {
|
for (int i = 0; i < 1000; i ++) {
|
||||||
Assert.assertNull(m.headers().get(String.valueOf(i)));
|
assertNull(h.get(String.valueOf(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if sequential access returns nothing.
|
// Check if sequential access returns nothing.
|
||||||
Assert.assertTrue(m.headers().isEmpty());
|
assertTrue(h.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,12 @@ import io.netty.buffer.Unpooled;
|
|||||||
import io.netty.channel.embedded.EmbeddedByteChannel;
|
import io.netty.channel.embedded.EmbeddedByteChannel;
|
||||||
import io.netty.handler.codec.DecoderResult;
|
import io.netty.handler.codec.DecoderResult;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class HttpInvalidMessageTest {
|
public class HttpInvalidMessageTest {
|
||||||
|
|
||||||
private final Random rnd = new Random();
|
private final Random rnd = new Random();
|
||||||
@ -35,8 +36,8 @@ public class HttpInvalidMessageTest {
|
|||||||
ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0 with extra\r\n", CharsetUtil.UTF_8));
|
ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0 with extra\r\n", CharsetUtil.UTF_8));
|
||||||
HttpRequest req = (HttpRequest) ch.readInbound();
|
HttpRequest req = (HttpRequest) ch.readInbound();
|
||||||
DecoderResult dr = req.decoderResult();
|
DecoderResult dr = req.decoderResult();
|
||||||
Assert.assertFalse(dr.isSuccess());
|
assertFalse(dr.isSuccess());
|
||||||
Assert.assertFalse(dr.isPartialFailure());
|
assertFalse(dr.isPartialFailure());
|
||||||
ensureInboundTrafficDiscarded(ch);
|
ensureInboundTrafficDiscarded(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,10 +50,10 @@ public class HttpInvalidMessageTest {
|
|||||||
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
|
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
|
||||||
HttpRequest req = (HttpRequest) ch.readInbound();
|
HttpRequest req = (HttpRequest) ch.readInbound();
|
||||||
DecoderResult dr = req.decoderResult();
|
DecoderResult dr = req.decoderResult();
|
||||||
Assert.assertFalse(dr.isSuccess());
|
assertFalse(dr.isSuccess());
|
||||||
Assert.assertTrue(dr.isPartialFailure());
|
assertTrue(dr.isPartialFailure());
|
||||||
Assert.assertEquals("Good Value", req.headers().get("Good_Name"));
|
assertEquals("Good Value", req.headers().get("Good_Name"));
|
||||||
Assert.assertEquals("/maybe-something", req.uri());
|
assertEquals("/maybe-something", req.uri());
|
||||||
ensureInboundTrafficDiscarded(ch);
|
ensureInboundTrafficDiscarded(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,8 +63,8 @@ public class HttpInvalidMessageTest {
|
|||||||
ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 BAD_CODE Bad Server\r\n", CharsetUtil.UTF_8));
|
ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 BAD_CODE Bad Server\r\n", CharsetUtil.UTF_8));
|
||||||
HttpResponse res = (HttpResponse) ch.readInbound();
|
HttpResponse res = (HttpResponse) ch.readInbound();
|
||||||
DecoderResult dr = res.decoderResult();
|
DecoderResult dr = res.decoderResult();
|
||||||
Assert.assertFalse(dr.isSuccess());
|
assertFalse(dr.isSuccess());
|
||||||
Assert.assertFalse(dr.isPartialFailure());
|
assertFalse(dr.isPartialFailure());
|
||||||
ensureInboundTrafficDiscarded(ch);
|
ensureInboundTrafficDiscarded(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +77,10 @@ public class HttpInvalidMessageTest {
|
|||||||
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
|
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
|
||||||
HttpResponse res = (HttpResponse) ch.readInbound();
|
HttpResponse res = (HttpResponse) ch.readInbound();
|
||||||
DecoderResult dr = res.decoderResult();
|
DecoderResult dr = res.decoderResult();
|
||||||
Assert.assertFalse(dr.isSuccess());
|
assertFalse(dr.isSuccess());
|
||||||
Assert.assertTrue(dr.isPartialFailure());
|
assertTrue(dr.isPartialFailure());
|
||||||
Assert.assertEquals("Maybe OK", res.status().reasonPhrase());
|
assertEquals("Maybe OK", res.status().reasonPhrase());
|
||||||
Assert.assertEquals("Good Value", res.headers().get("Good_Name"));
|
assertEquals("Good Value", res.headers().get("Good_Name"));
|
||||||
ensureInboundTrafficDiscarded(ch);
|
ensureInboundTrafficDiscarded(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +92,12 @@ public class HttpInvalidMessageTest {
|
|||||||
ch.writeInbound(Unpooled.copiedBuffer("BAD_LENGTH\r\n", CharsetUtil.UTF_8));
|
ch.writeInbound(Unpooled.copiedBuffer("BAD_LENGTH\r\n", CharsetUtil.UTF_8));
|
||||||
|
|
||||||
HttpRequest req = (HttpRequest) ch.readInbound();
|
HttpRequest req = (HttpRequest) ch.readInbound();
|
||||||
Assert.assertTrue(req.decoderResult().isSuccess());
|
assertTrue(req.decoderResult().isSuccess());
|
||||||
|
|
||||||
HttpContent chunk = (HttpContent) ch.readInbound();
|
HttpContent chunk = (HttpContent) ch.readInbound();
|
||||||
DecoderResult dr = chunk.decoderResult();
|
DecoderResult dr = chunk.decoderResult();
|
||||||
Assert.assertFalse(dr.isSuccess());
|
assertFalse(dr.isSuccess());
|
||||||
Assert.assertFalse(dr.isPartialFailure());
|
assertFalse(dr.isPartialFailure());
|
||||||
ensureInboundTrafficDiscarded(ch);
|
ensureInboundTrafficDiscarded(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ public class HttpInvalidMessageTest {
|
|||||||
buf.setIndex(0, data.length);
|
buf.setIndex(0, data.length);
|
||||||
ch.writeInbound(buf);
|
ch.writeInbound(buf);
|
||||||
ch.checkException();
|
ch.checkException();
|
||||||
Assert.assertNull(ch.readInbound());
|
assertNull(ch.readInbound());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package io.netty.handler.codec.http.websocketx;
|
|||||||
|
|
||||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||||
import io.netty.handler.codec.http.FullHttpRequest;
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
import io.netty.handler.codec.http.HttpRequest;
|
import io.netty.handler.codec.http.HttpRequest;
|
||||||
@ -98,23 +99,25 @@ public class WebSocketRequestBuilder {
|
|||||||
|
|
||||||
public FullHttpRequest build() {
|
public FullHttpRequest build() {
|
||||||
FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, uri);
|
FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, uri);
|
||||||
|
HttpHeaders headers = req.headers();
|
||||||
|
|
||||||
if (host != null) {
|
if (host != null) {
|
||||||
req.headers().set(Names.HOST, host);
|
headers.set(Names.HOST, host);
|
||||||
}
|
}
|
||||||
if (upgrade != null) {
|
if (upgrade != null) {
|
||||||
req.headers().set(Names.UPGRADE, upgrade);
|
headers.set(Names.UPGRADE, upgrade);
|
||||||
}
|
}
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
req.headers().set(Names.CONNECTION, connection);
|
headers.set(Names.CONNECTION, connection);
|
||||||
}
|
}
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
req.headers().set(Names.SEC_WEBSOCKET_KEY, key);
|
headers.set(Names.SEC_WEBSOCKET_KEY, key);
|
||||||
}
|
}
|
||||||
if (origin != null) {
|
if (origin != null) {
|
||||||
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, origin);
|
headers.set(Names.SEC_WEBSOCKET_ORIGIN, origin);
|
||||||
}
|
}
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
req.headers().set(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
|
headers.set(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
|
||||||
}
|
}
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ import io.netty.channel.ChannelPipeline;
|
|||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioEventLoopGroup;
|
import io.netty.channel.socket.nio.NioEventLoopGroup;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.HttpRequestEncoder;
|
import io.netty.handler.codec.http.HttpRequestEncoder;
|
||||||
import io.netty.handler.codec.http.HttpResponseDecoder;
|
import io.netty.handler.codec.http.HttpResponseDecoder;
|
||||||
@ -54,7 +56,6 @@ import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
|||||||
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class WebSocketClient {
|
public class WebSocketClient {
|
||||||
|
|
||||||
@ -72,8 +73,8 @@ public class WebSocketClient {
|
|||||||
throw new IllegalArgumentException("Unsupported protocol: " + protocol);
|
throw new IllegalArgumentException("Unsupported protocol: " + protocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap<String, String> customHeaders = new HashMap<String, String>();
|
HttpHeaders customHeaders = new DefaultHttpHeaders();
|
||||||
customHeaders.put("MyHeader", "MyValue");
|
customHeaders.add("MyHeader", "MyValue");
|
||||||
|
|
||||||
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
|
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
|
||||||
// If you change it to V00, ping is not supported and remember to change
|
// If you change it to V00, ping is not supported and remember to change
|
||||||
|
Loading…
x
Reference in New Issue
Block a user