Second HTTP overhaul

- Rename message types for clarity
  - HttpMessage -> FullHttpMessage
  - HttpHeader -> HttpMessage
  - HttpRequest -> FullHttpRequest
  - HttpResponse -> FulllHttpResponse
  - HttpRequestHeader -> HttpRequest
  - HttpResponseHeader -> HttpResponse
- HttpContent now extends ByteBufHolder; no more content() method
- Make HttpHeaders abstract, make its header access methods public, and
  add DefaultHttpHeaders
- Header accessor methods in HttpMessage and LastHttpContent are
  replaced with HttpMessage.headers() and
  LastHttpContent.trailingHeaders(). Both methods return HttpHeaders.
- Remove setters wherever possible and remove 'get' prefix
- Instead of calling setContent(), a user can either specify the content
  when constructing a message or write content into the buffer.
  (e.g. m.content().writeBytes(...))
- Overall cleanup & fixes
This commit is contained in:
Trustin Lee 2013-01-16 13:22:50 +09:00
parent f136eafd5e
commit 34820511ff
98 changed files with 2173 additions and 2254 deletions

View File

@ -936,6 +936,10 @@ public abstract class AbstractByteBuf implements ByteBuf {
@Override
public String toString() {
if (isFreed()) {
return getClass().getSimpleName() + "(freed)";
}
return getClass().getSimpleName() + '(' +
"ridx=" + readerIndex + ", " +
"widx=" + writerIndex + ", " +

View File

@ -57,9 +57,6 @@ public class DefaultByteBufHolder implements ByteBufHolder {
@Override
public String toString() {
if (isFreed()) {
return "Message{data=(FREED)}";
}
return "Message{data=" + ByteBufUtil.hexDump(data()) + '}';
return getClass().getSimpleName() + '(' + data().toString() + ')';
}
}

View File

@ -22,7 +22,7 @@ import static io.netty.handler.codec.http.CookieEncoderUtil.*;
* the HTTP cookie version 0, 1, and 2.
* <pre>
* // Example
* {@link HttpRequestHeader} req = ...;
* {@link HttpRequest} req = ...;
* res.setHeader("Cookie", {@link ClientCookieEncoder}.encode("JSESSIONID", "1234"));
* </pre>
*

View File

@ -29,7 +29,7 @@ import java.util.TreeSet;
* the HTTP cookie version 0, 1, and 2.
*
* <pre>
* {@link HttpRequestHeader} req = ...;
* {@link HttpRequest} req = ...;
* String value = req.getHeader("Cookie");
* Set&lt;{@link Cookie}&gt; cookies = new {@link CookieDecoder}().decode(value);
* </pre>

View File

@ -0,0 +1,67 @@
/*
* 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.buffer.Unpooled;
/**
* Default implementation of {@link FullHttpRequest}.
*/
public class DefaultFullHttpRequest extends DefaultHttpRequest implements FullHttpRequest {
private final ByteBuf content;
private final HttpHeaders trailingHeader = new DefaultHttpHeaders();
public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) {
this(httpVersion, method, uri, Unpooled.buffer(0));
}
public DefaultFullHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, ByteBuf content) {
super(httpVersion, method, uri);
if (content == null) {
throw new NullPointerException("content");
}
this.content = content;
}
@Override
public HttpHeaders trailingHeaders() {
return trailingHeader;
}
@Override
public ByteBuf data() {
return content;
}
@Override
public boolean isFreed() {
return content.isFreed();
}
@Override
public void free() {
content.free();
}
@Override
public FullHttpRequest copy() {
DefaultFullHttpRequest copy = new DefaultFullHttpRequest(protocolVersion(), method(), uri(), data().copy());
copy.headers().set(headers());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.buffer.Unpooled;
/**
* Default implementation of a {@link FullHttpResponse}.
*/
public class DefaultFullHttpResponse extends DefaultHttpResponse implements FullHttpResponse {
private final ByteBuf content;
private final HttpHeaders trailingHeaders = new DefaultHttpHeaders();
public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status) {
this(version, status, Unpooled.buffer(0));
}
public DefaultFullHttpResponse(HttpVersion version, HttpResponseStatus status, ByteBuf content) {
super(version, status);
if (content == null) {
throw new NullPointerException("content");
}
this.content = content;
}
@Override
public HttpHeaders trailingHeaders() {
return trailingHeaders;
}
@Override
public ByteBuf data() {
return content;
}
@Override
public boolean isFreed() {
return content.isFreed();
}
@Override
public void free() {
content.free();
}
@Override
public FullHttpResponse copy() {
DefaultFullHttpResponse copy = new DefaultFullHttpResponse(protocolVersion(), status(), data().copy());
copy.headers().set(headers());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
}

View File

@ -22,40 +22,40 @@ import io.netty.buffer.ByteBuf;
*/
public class DefaultHttpContent extends DefaultHttpObject implements HttpContent {
private ByteBuf content;
private final ByteBuf content;
/**
* Creates a new instance with the specified chunk content.
*/
public DefaultHttpContent(ByteBuf content) {
setContent(content);
}
@Override
public ByteBuf getContent() {
return content;
}
@Override
public void setContent(ByteBuf content) {
if (content == null) {
throw new NullPointerException("content");
}
this.content = content;
}
@Override
public ByteBuf data() {
return content;
}
@Override
public HttpContent copy() {
return new DefaultHttpContent(data().copy());
}
@Override
public boolean isFreed() {
return content.isFreed();
}
@Override
public void free() {
content.free();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(" size: ");
buf.append(getContent().readableBytes());
buf.append(", decodeResult: ");
buf.append(getDecoderResult());
buf.append(')');
return buf.toString();
return getClass().getSimpleName() + "(data: " + data() + ", decoderResult: " + decoderResult() + ')';
}
}

View File

@ -1,127 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import io.netty.util.internal.StringUtil;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The default {@link HttpHeader} implementation.
*/
public abstract class DefaultHttpHeader extends DefaultHttpObject implements HttpHeader {
private final HttpHeaders headers = new HttpHeaders();
private HttpVersion version;
/**
* Creates a new instance.
*/
protected DefaultHttpHeader(final HttpVersion version) {
setProtocolVersion(version);
}
@Override
public void addHeader(final String name, final Object value) {
headers.addHeader(name, value);
}
@Override
public void setHeader(final String name, final Object value) {
headers.setHeader(name, value);
}
@Override
public void setHeader(final String name, final Iterable<?> values) {
headers.setHeader(name, values);
}
@Override
public void removeHeader(final String name) {
headers.removeHeader(name);
}
@Override
public void clearHeaders() {
headers.clearHeaders();
}
@Override
public String getHeader(final String name) {
return headers.getHeader(name);
}
@Override
public List<String> getHeaders(final String name) {
return headers.getHeaders(name);
}
@Override
public List<Map.Entry<String, String>> getHeaders() {
return headers.getHeaders();
}
@Override
public boolean containsHeader(final String name) {
return headers.containsHeader(name);
}
@Override
public Set<String> getHeaderNames() {
return headers.getHeaderNames();
}
@Override
public HttpVersion getProtocolVersion() {
return version;
}
@Override
public void setProtocolVersion(HttpVersion version) {
if (version == null) {
throw new NullPointerException("version");
}
this.version = version;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append("(version: ");
buf.append(getProtocolVersion().getText());
buf.append(", keepAlive: ");
buf.append(HttpHeaders.isKeepAlive(this));
buf.append(')');
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
void appendHeaders(StringBuilder buf) {
for (Map.Entry<String, String> e: getHeaders()) {
buf.append(e.getKey());
buf.append(": ");
buf.append(e.getValue());
buf.append(StringUtil.NEWLINE);
}
}
}

View File

@ -0,0 +1,359 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
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 boolean eq(String name1, String name2) {
int nameLen = name1.length();
if (nameLen != name2.length()) {
return false;
}
for (int i = nameLen - 1; i >= 0; i --) {
char c1 = name1.charAt(i);
char c2 = name2.charAt(i);
if (c1 != c2) {
if (c1 >= 'A' && c1 <= 'Z') {
c1 += 32;
}
if (c2 >= 'A' && c2 <= 'Z') {
c2 += 32;
}
if (c1 != c2) {
return false;
}
}
}
return true;
}
private static int index(int hash) {
return hash % BUCKET_SIZE;
}
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
private final HeaderEntry head = new HeaderEntry(-1, null, null);
public DefaultHttpHeaders() {
head.before = head.after = head;
}
void validateHeaderName0(String headerName) {
validateHeaderName(headerName);
}
@Override
public void add(final String name, final Object value) {
validateHeaderName0(name);
String strVal = toString(value);
validateHeaderValue(strVal);
int h = hash(name);
int i = index(h);
add0(h, i, name, strVal);
}
@Override
public void add(String name, Iterable<?> values) {
validateHeaderName0(name);
int h = hash(name);
int i = index(h);
for (Object v: values) {
String vstr = toString(v);
validateHeaderValue(vstr);
add0(h, i, name, vstr);
}
}
private void add0(int h, int i, final String name, final String value) {
// Update the hash table.
HeaderEntry e = entries[i];
HeaderEntry newEntry;
entries[i] = newEntry = new HeaderEntry(h, name, value);
newEntry.next = e;
// Update the linked list.
newEntry.addBefore(head);
}
@Override
public void remove(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
int h = hash(name);
int i = index(h);
remove0(h, i, name);
}
private void remove0(int h, int i, String name) {
HeaderEntry e = entries[i];
if (e == null) {
return;
}
for (;;) {
if (e.hash == h && eq(name, e.key)) {
e.remove();
HeaderEntry next = e.next;
if (next != null) {
entries[i] = next;
e = next;
} else {
entries[i] = null;
return;
}
} else {
break;
}
}
for (;;) {
HeaderEntry next = e.next;
if (next == null) {
break;
}
if (next.hash == h && eq(name, next.key)) {
e.next = next.next;
next.remove();
} else {
e = next;
}
}
}
@Override
public void set(final String name, final Object value) {
validateHeaderName0(name);
String strVal = toString(value);
validateHeaderValue(strVal);
int h = hash(name);
int i = index(h);
remove0(h, i, name);
add0(h, i, name, strVal);
}
@Override
public void set(final String name, final Iterable<?> values) {
if (values == null) {
throw new NullPointerException("values");
}
validateHeaderName0(name);
int h = hash(name);
int i = index(h);
remove0(h, i, name);
for (Object v: values) {
if (v == null) {
break;
}
String strVal = toString(v);
validateHeaderValue(strVal);
add0(h, i, name, strVal);
}
}
@Override
public void clear() {
for (int i = 0; i < entries.length; i ++) {
entries[i] = null;
}
head.before = head.after = head;
}
@Override
public String get(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
int h = hash(name);
int i = index(h);
HeaderEntry e = entries[i];
while (e != null) {
if (e.hash == h && eq(name, e.key)) {
return e.value;
}
e = e.next;
}
return null;
}
@Override
public List<String> getAll(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
LinkedList<String> values = new LinkedList<String>();
int h = hash(name);
int i = index(h);
HeaderEntry e = entries[i];
while (e != null) {
if (e.hash == h && eq(name, e.key)) {
values.addFirst(e.value);
}
e = e.next;
}
return values;
}
@Override
public List<Map.Entry<String, String>> entries() {
List<Map.Entry<String, String>> all =
new LinkedList<Map.Entry<String, String>>();
HeaderEntry e = head.after;
while (e != head) {
all.add(e);
e = e.after;
}
return all;
}
@Override
public Iterator<Map.Entry<String, String>> iterator() {
return entries().iterator();
}
@Override
public boolean contains(String name) {
return get(name) != null;
}
@Override
public boolean isEmpty() {
return head == head.after;
}
@Override
public Set<String> names() {
Set<String> names = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
HeaderEntry e = head.after;
while (e != head) {
names.add(e.key);
e = e.after;
}
return names;
}
private static String toString(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
return (String) value;
}
if (value instanceof Number) {
return value.toString();
}
if (value instanceof Date) {
return new HttpHeaderDateFormat().format((Date) value);
}
if (value instanceof Calendar) {
return new HttpHeaderDateFormat().format(((Calendar) value).getTime());
}
return value.toString();
}
private static final class HeaderEntry implements Map.Entry<String, String> {
final int hash;
final String key;
String value;
HeaderEntry next;
HeaderEntry before, after;
HeaderEntry(int hash, String key, String value) {
this.hash = hash;
this.key = key;
this.value = value;
}
void remove() {
before.after = after;
after.before = before;
}
void addBefore(HeaderEntry e) {
after = e;
before = e.before;
before.after = this;
after.before = this;
}
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return value;
}
@Override
public String setValue(String value) {
if (value == null) {
throw new NullPointerException("value");
}
validateHeaderValue(value);
String oldValue = this.value;
this.value = value;
return oldValue;
}
@Override
public String toString() {
return key + '=' + value;
}
}
}

View File

@ -15,31 +15,61 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.internal.StringUtil;
import java.util.Map;
/**
* Combination of {@link HttpHeader} and {@link LastHttpContent} which can be used to <i>combine</i> the headers and
* the actual content. {@link HttpObjectAggregator} makes use of this.
*
* The default {@link HttpMessage} implementation.
*/
public abstract class DefaultHttpMessage extends DefaultHttpHeader implements LastHttpContent {
private ByteBuf content = Unpooled.EMPTY_BUFFER;
public abstract class DefaultHttpMessage extends DefaultHttpObject implements HttpMessage {
public DefaultHttpMessage(HttpVersion version) {
super(version);
}
private final HttpVersion version;
private final HttpHeaders headers = new DefaultHttpHeaders();
@Override
public ByteBuf getContent() {
return content;
}
@Override
public void setContent(ByteBuf content) {
if (content == null) {
throw new NullPointerException("content");
/**
* Creates a new instance.
*/
protected DefaultHttpMessage(final HttpVersion version) {
if (version == null) {
throw new NullPointerException("version");
}
this.version = version;
}
@Override
public HttpHeaders headers() {
return headers;
}
@Override
public HttpVersion protocolVersion() {
return version;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append("(version: ");
buf.append(protocolVersion().getText());
buf.append(", keepAlive: ");
buf.append(HttpHeaders.isKeepAlive(this));
buf.append(')');
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
void appendHeaders(StringBuilder buf) {
for (Map.Entry<String, String> e: headers().entries()) {
buf.append(e.getKey());
buf.append(": ");
buf.append(e.getValue());
buf.append(StringUtil.NEWLINE);
}
this.content = content;
}
}

View File

@ -19,22 +19,22 @@ import io.netty.handler.codec.DecoderResult;
public class DefaultHttpObject implements HttpObject {
private DecoderResult decodeResult = DecoderResult.SUCCESS;
private DecoderResult decoderResult = DecoderResult.SUCCESS;
protected DefaultHttpObject() {
// Disallow direct instantiation
}
@Override
public DecoderResult getDecoderResult() {
return decodeResult;
public DecoderResult decoderResult() {
return decoderResult;
}
@Override
public void setDecoderResult(DecoderResult result) {
if (result == null) {
throw new NullPointerException("result");
public void updateDecoderResult(DecoderResult decoderResult) {
if (decoderResult == null) {
throw new NullPointerException("decoderResult");
}
decodeResult = result;
this.decoderResult = decoderResult;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -15,34 +15,63 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.internal.StringUtil;
/**
* Default implementation of {@link HttpRequest}.
* The default {@link HttpRequest} implementation.
*/
public class DefaultHttpRequest extends DefaultHttpRequestHeader implements HttpRequest {
private ByteBuf content = Unpooled.EMPTY_BUFFER;
public class DefaultHttpRequest extends DefaultHttpMessage implements HttpRequest {
private final HttpMethod method;
private final String uri;
/**
* Creates a new instance.
*
* @param httpVersion the HTTP version of the request
* @param method the HTTP method of the request
* @param uri the URI or path of the request
*/
public DefaultHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri) {
this(httpVersion, method, uri, Unpooled.EMPTY_BUFFER);
}
public DefaultHttpRequest(HttpVersion httpVersion, HttpMethod method, String uri, ByteBuf content) {
super(httpVersion, method, uri);
setContent(content);
}
@Override
public ByteBuf getContent() {
return content;
}
@Override
public void setContent(ByteBuf content) {
if (content == null) {
throw new NullPointerException("content");
super(httpVersion);
if (method == null) {
throw new NullPointerException("method");
}
this.content = content;
if (uri == null) {
throw new NullPointerException("uri");
}
this.method = method;
this.uri = uri;
}
@Override
public HttpMethod method() {
return method;
}
@Override
public String uri() {
return uri;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(", decodeResult: ");
buf.append(decoderResult());
buf.append(')');
buf.append(StringUtil.NEWLINE);
buf.append(method().toString());
buf.append(' ');
buf.append(uri());
buf.append(' ');
buf.append(protocolVersion().getText());
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import io.netty.util.internal.StringUtil;
/**
* The default {@link HttpRequestHeader} implementation.
*/
public class DefaultHttpRequestHeader extends DefaultHttpHeader implements HttpRequestHeader {
private HttpMethod method;
private String uri;
/**
* Creates a new instance.
*
* @param httpVersion the HTTP version of the request
* @param method the HTTP method of the request
* @param uri the URI or path of the request
*/
public DefaultHttpRequestHeader(HttpVersion httpVersion, HttpMethod method, String uri) {
super(httpVersion);
setMethod(method);
setUri(uri);
}
@Override
public HttpMethod getMethod() {
return method;
}
@Override
public void setMethod(HttpMethod method) {
if (method == null) {
throw new NullPointerException("method");
}
this.method = method;
}
@Override
public String getUri() {
return uri;
}
@Override
public void setUri(String uri) {
if (uri == null) {
throw new NullPointerException("uri");
}
this.uri = uri;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(", decodeResult: ");
buf.append(getDecoderResult());
buf.append(')');
buf.append(StringUtil.NEWLINE);
buf.append(getMethod().toString());
buf.append(' ');
buf.append(getUri());
buf.append(' ');
buf.append(getProtocolVersion().getText());
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -15,35 +15,50 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.internal.StringUtil;
/**
* Default implementation of a {@link HttpResponse}.
* The default {@link HttpResponse} implementation.
*/
public class DefaultHttpResponse extends DefaultHttpResponseHeader implements HttpResponse {
private ByteBuf content = Unpooled.EMPTY_BUFFER;
public class DefaultHttpResponse extends DefaultHttpMessage implements HttpResponse {
private final HttpResponseStatus status;
/**
* Creates a new instance.
*
* @param version the HTTP version of this response
* @param status the status of this response
*/
public DefaultHttpResponse(HttpVersion version, HttpResponseStatus status) {
this(version, status, Unpooled.EMPTY_BUFFER);
}
public DefaultHttpResponse(HttpVersion version, HttpResponseStatus status, ByteBuf content) {
super(version, status);
setContent(content);
}
@Override
public ByteBuf getContent() {
return content;
}
@Override
public void setContent(ByteBuf content) {
if (content == null) {
throw new NullPointerException("content");
super(version);
if (status == null) {
throw new NullPointerException("status");
}
this.content = content;
this.status = status;
}
@Override
public HttpResponseStatus status() {
return status;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(", decodeResult: ");
buf.append(decoderResult());
buf.append(')');
buf.append(StringUtil.NEWLINE);
buf.append(protocolVersion().getText());
buf.append(' ');
buf.append(status().toString());
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import io.netty.util.internal.StringUtil;
/**
* The default {@link HttpResponseHeader} implementation.
*/
public class DefaultHttpResponseHeader extends DefaultHttpHeader implements HttpResponseHeader {
private HttpResponseStatus status;
/**
* Creates a new instance.
*
* @param version the HTTP version of this response
* @param status the status of this response
*/
public DefaultHttpResponseHeader(HttpVersion version, HttpResponseStatus status) {
super(version);
setStatus(status);
}
@Override
public HttpResponseStatus getStatus() {
return status;
}
@Override
public void setStatus(HttpResponseStatus status) {
if (status == null) {
throw new NullPointerException("status");
}
this.status = status;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(", decodeResult: ");
buf.append(getDecoderResult());
buf.append(')');
buf.append(StringUtil.NEWLINE);
buf.append(getProtocolVersion().getText());
buf.append(' ');
buf.append(getStatus().toString());
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
// Remove the last newline.
buf.setLength(buf.length() - StringUtil.NEWLINE.length());
return buf.toString();
}
}

View File

@ -19,16 +19,14 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.internal.StringUtil;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* The default {@link LastHttpContent} implementation.
*/
public class DefaultLastHttpContent extends DefaultHttpContent implements LastHttpContent {
private final HttpHeaders headers = new HttpHeaders() {
private final HttpHeaders trailingHeaders = new DefaultHttpHeaders() {
@Override
void validateHeaderName0(String name) {
super.validateHeaderName0(name);
@ -42,7 +40,7 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
};
public DefaultLastHttpContent() {
this(Unpooled.EMPTY_BUFFER);
this(Unpooled.buffer(0));
}
public DefaultLastHttpContent(ByteBuf content) {
@ -50,64 +48,20 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
}
@Override
public void addHeader(final String name, final Object value) {
headers.addHeader(name, value);
public LastHttpContent copy() {
DefaultLastHttpContent copy = new DefaultLastHttpContent(data().copy());
copy.trailingHeaders().set(trailingHeaders());
return copy;
}
@Override
public void setHeader(final String name, final Object value) {
headers.setHeader(name, value);
}
@Override
public void setHeader(final String name, final Iterable<?> values) {
headers.setHeader(name, values);
}
@Override
public void removeHeader(final String name) {
headers.removeHeader(name);
}
@Override
public void clearHeaders() {
headers.clearHeaders();
}
@Override
public String getHeader(final String name) {
return headers.getHeader(name);
}
@Override
public List<String> getHeaders(final String name) {
return headers.getHeaders(name);
}
@Override
public List<Map.Entry<String, String>> getHeaders() {
return headers.getHeaders();
}
@Override
public boolean containsHeader(final String name) {
return headers.containsHeader(name);
}
@Override
public Set<String> getHeaderNames() {
return headers.getHeaderNames();
public HttpHeaders trailingHeaders() {
return trailingHeaders;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(getClass().getSimpleName());
buf.append(", size: ");
buf.append(getContent().readableBytes());
buf.append(", decodeResult: ");
buf.append(getDecoderResult());
buf.append(')');
StringBuilder buf = new StringBuilder(super.toString());
buf.append(StringUtil.NEWLINE);
appendHeaders(buf);
@ -117,7 +71,7 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
}
private void appendHeaders(StringBuilder buf) {
for (Map.Entry<String, String> e: getHeaders()) {
for (Map.Entry<String, String> e: trailingHeaders()) {
buf.append(e.getKey());
buf.append(": ");
buf.append(e.getValue());

View File

@ -0,0 +1,25 @@
/*
* 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;
/**
* Combines {@link FullHttpMessage} and {@link LastHttpContent} into one
* message. So it represent a <i>complete</i> http message.
*/
public interface FullHttpMessage extends HttpMessage, LastHttpContent {
@Override
FullHttpMessage copy();
}

View File

@ -0,0 +1,25 @@
/*
* 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;
/**
* Combinate the {@link HttpRequest} and {@link FullHttpMessage}, so the request is a <i>complete</i> HTTP
* request.
*/
public interface FullHttpRequest extends HttpRequest, FullHttpMessage {
@Override
FullHttpRequest copy();
}

View File

@ -0,0 +1,25 @@
/*
* 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;
/**
* Combination of a {@link HttpResponse} and {@link FullHttpMessage}.
* So it represent a <i>complete</i> http response.
*/
public interface FullHttpResponse extends HttpResponse, FullHttpMessage {
@Override
FullHttpResponse copy();
}

View File

@ -84,8 +84,8 @@ public class HttpClientCodec extends CombinedChannelHandler {
@Override
protected void encode(
ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
if (msg instanceof HttpRequestHeader && !done) {
queue.offer(((HttpRequestHeader) msg).getMethod());
if (msg instanceof HttpRequest && !done) {
queue.offer(((HttpRequest) msg).method());
}
super.encode(ctx, msg, out);
@ -137,8 +137,8 @@ public class HttpClientCodec extends CombinedChannelHandler {
}
@Override
protected boolean isContentAlwaysEmpty(HttpHeader msg) {
final int statusCode = ((HttpResponseHeader) msg).getStatus().getCode();
protected boolean isContentAlwaysEmpty(HttpMessage msg) {
final int statusCode = ((HttpResponse) msg).status().code();
if (statusCode == 100) {
// 100-continue response should be excluded from paired comparison.
return true;
@ -148,7 +148,7 @@ public class HttpClientCodec extends CombinedChannelHandler {
// current response.
HttpMethod method = queue.poll();
char firstChar = method.getName().charAt(0);
char firstChar = method.name().charAt(0);
switch (firstChar) {
case 'H':
// According to 4.3, RFC2616:

View File

@ -15,134 +15,19 @@
*/
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.ByteBufHolder;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.DecoderResult;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An HTTP chunk which is used for HTTP chunked transfer-encoding.
* {@link HttpObjectDecoder} generates {@link HttpContent} after
* {@link HttpHeader} when the content is large or the encoding of the content
* {@link HttpMessage} when the content is large or the encoding of the content
* is 'chunked. If you prefer not to receive {@link HttpContent} in your handler,
* please {@link HttpObjectAggregator} after {@link HttpObjectDecoder} in the
* place {@link HttpObjectAggregator} after {@link HttpObjectDecoder} in the
* {@link ChannelPipeline}.
* @apiviz.landmark
*/
public interface HttpContent extends HttpObject {
HttpContent EMPTY = new HttpContent() {
@Override
public ByteBuf getContent() {
return Unpooled.EMPTY_BUFFER;
}
@Override
public void setContent(ByteBuf content) {
throw new IllegalStateException("read-only");
}
@Override
public DecoderResult getDecoderResult() {
return DecoderResult.SUCCESS;
}
@Override
public void setDecoderResult(DecoderResult result) {
throw new IllegalStateException("read-only");
}
};
/**
* The 'end of content' marker in chunked encoding.
*/
LastHttpContent LAST_CONTENT = new LastHttpContent() {
@Override
public ByteBuf getContent() {
return Unpooled.EMPTY_BUFFER;
}
@Override
public void setContent(ByteBuf content) {
throw new IllegalStateException("read-only");
}
@Override
public void addHeader(String name, Object value) {
throw new IllegalStateException("read-only");
}
@Override
public void clearHeaders() {
// NOOP
}
@Override
public boolean containsHeader(String name) {
return false;
}
@Override
public String getHeader(String name) {
return null;
}
@Override
public Set<String> getHeaderNames() {
return Collections.emptySet();
}
@Override
public List<String> getHeaders(String name) {
return Collections.emptyList();
}
@Override
public List<Map.Entry<String, String>> getHeaders() {
return Collections.emptyList();
}
@Override
public void removeHeader(String name) {
// NOOP
}
@Override
public void setHeader(String name, Object value) {
throw new IllegalStateException("read-only");
}
@Override
public void setHeader(String name, Iterable<?> values) {
throw new IllegalStateException("read-only");
}
@Override
public DecoderResult getDecoderResult() {
return DecoderResult.SUCCESS;
}
@Override
public void setDecoderResult(DecoderResult result) {
throw new IllegalStateException("read-only");
}
};
/**
* Returns the content of this chunk. If this is the 'end of content'
* marker, {@link Unpooled#EMPTY_BUFFER} will be returned.
*/
ByteBuf getContent();
/**
* Sets the content of this chunk. If an empty buffer is specified,
* this chunk becomes the 'end of content' marker.
*/
void setContent(ByteBuf content);
public interface HttpContent extends HttpObject, ByteBufHolder {
@Override
HttpContent copy();
}

View File

@ -21,7 +21,7 @@ import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.util.internal.StringUtil;
/**
* Compresses an {@link HttpHeader} and an {@link HttpContent} in {@code gzip} or
* Compresses an {@link HttpMessage} and an {@link HttpContent} in {@code gzip} or
* {@code deflate} encoding while respecting the {@code "Accept-Encoding"} header.
* If there is no matching encoding, no compression is done. For more
* information on how this handler modifies the message, please refer to
@ -93,8 +93,8 @@ public class HttpContentCompressor extends HttpContentEncoder {
}
@Override
protected Result beginEncode(HttpHeader header, HttpContent msg, String acceptEncoding) throws Exception {
String contentEncoding = header.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
protected Result beginEncode(HttpMessage header, HttpContent msg, String acceptEncoding) throws Exception {
String contentEncoding = header.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
if (contentEncoding != null &&
!HttpHeaders.Values.IDENTITY.equalsIgnoreCase(contentEncoding)) {
return null;

View File

@ -16,13 +16,14 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
/**
* Decodes the content of the received {@link HttpRequestHeader} and {@link HttpContent}.
* Decodes the content of the received {@link HttpRequest} and {@link HttpContent}.
* The original content is replaced with the new content decoded by the
* {@link EmbeddedByteChannel}, which is created by {@link #newContentDecoder(String)}.
* Once decoding is finished, the value of the <tt>'Content-Encoding'</tt>
@ -43,7 +44,7 @@ import io.netty.handler.codec.MessageToMessageDecoder;
public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object> {
private EmbeddedByteChannel decoder;
private HttpHeader header;
private HttpMessage header;
private boolean decodeStarted;
/**
@ -55,13 +56,13 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
@Override
protected Object decode(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponseHeader && ((HttpResponseHeader) msg).getStatus().getCode() == 100) {
if (msg instanceof HttpResponse && ((HttpResponse) msg).status().code() == 100) {
// 100-continue response must be passed through.
return msg;
}
if (msg instanceof HttpHeader) {
if (msg instanceof HttpMessage) {
assert header == null;
header = (HttpHeader) msg;
header = (HttpMessage) msg;
cleanup();
}
@ -71,11 +72,11 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
if (!decodeStarted) {
decodeStarted = true;
HttpHeader header = this.header;
HttpMessage header = this.header;
this.header = null;
// Determine the content encoding.
String contentEncoding = header.getHeader(HttpHeaders.Names.CONTENT_ENCODING);
String contentEncoding = header.headers().get(HttpHeaders.Names.CONTENT_ENCODING);
if (contentEncoding != null) {
contentEncoding = contentEncoding.trim();
} else {
@ -89,17 +90,17 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
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
header.removeHeader(HttpHeaders.Names.CONTENT_ENCODING);
header.headers().remove(HttpHeaders.Names.CONTENT_ENCODING);
} else {
header.setHeader(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
header.headers().set(HttpHeaders.Names.CONTENT_ENCODING, targetContentEncoding);
}
Object[] decoded = decodeContent(header, c);
// Replace the content.
if (header.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) {
header.setHeader(
if (header.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
header.headers().set(
HttpHeaders.Names.CONTENT_LENGTH,
Integer.toString(((HttpContent) decoded[1]).getContent().readableBytes()));
Integer.toString(((ByteBufHolder) decoded[1]).data().readableBytes()));
}
return decoded;
}
@ -108,13 +109,13 @@ public abstract class HttpContentDecoder extends MessageToMessageDecoder<Object>
return decodeContent(null, c);
}
// Because HttpMessage and HttpChunk is a mutable object, we can simply forward it.
// Because FullHttpMessage and HttpChunk is a mutable object, we can simply forward it.
return msg;
}
private Object[] decodeContent(HttpHeader header, HttpContent c) {
private Object[] decodeContent(HttpMessage header, HttpContent c) {
ByteBuf newContent = Unpooled.buffer();
ByteBuf content = c.getContent();
ByteBuf content = c.data();
decode(content, newContent);
if (c instanceof LastHttpContent) {

View File

@ -20,7 +20,7 @@ import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
/**
* Decompresses an {@link HttpHeader} and an {@link HttpContent} compressed in
* Decompresses an {@link HttpMessage} and an {@link HttpContent} compressed in
* {@code gzip} or {@code deflate} encoding. For more information on how this
* handler modifies the message, please refer to {@link HttpContentDecoder}.
*/

View File

@ -16,6 +16,7 @@
package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedByteChannel;
@ -25,20 +26,20 @@ import java.util.ArrayDeque;
import java.util.Queue;
/**
* Encodes the content of the outbound {@link HttpResponseHeader} and {@link HttpContent}.
* Encodes the content of the outbound {@link HttpResponse} and {@link HttpContent}.
* The original content is replaced with the new content encoded by the
* {@link EmbeddedByteChannel}, which is created by {@link #beginEncode(HttpHeader, HttpContent, String)}.
* {@link EmbeddedByteChannel}, which is created by {@link #beginEncode(HttpMessage, HttpContent, String)}.
* 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(HttpHeader, HttpContent, String)}.
* {@link #beginEncode(HttpMessage, HttpContent, String)}.
* 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 HttpRequestHeader}'s {@code "Accept-Encoding"} header,
* {@link #beginEncode(HttpHeader, HttpContent, String)} should return {@code null} so that
* corresponding {@link HttpRequest}'s {@code "Accept-Encoding"} header,
* {@link #beginEncode(HttpMessage, HttpContent, String)} 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(HttpHeader, HttpContent, String)} properly to make
* and implement {@link #beginEncode(HttpMessage, HttpContent, String)} properly to make
* this class functional. For example, refer to the source code of
* {@link HttpContentCompressor}.
* <p>
@ -46,11 +47,11 @@ import java.util.Queue;
* so that this handler can intercept HTTP responses before {@link HttpObjectEncoder}
* converts them into {@link ByteBuf}s.
*/
public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeader, Object> {
public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpMessage, Object> {
private final Queue<String> acceptEncodingQueue = new ArrayDeque<String>();
private EmbeddedByteChannel encoder;
private HttpHeader header;
private HttpMessage header;
private boolean encodeStarted;
/**
@ -58,14 +59,14 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
*/
protected HttpContentEncoder() {
super(
new Class<?>[] { HttpHeader.class },
new Class<?>[] { HttpMessage.class },
new Class<?>[] { HttpObject.class });
}
@Override
protected Object decode(ChannelHandlerContext ctx, HttpHeader msg)
protected Object decode(ChannelHandlerContext ctx, HttpMessage msg)
throws Exception {
String acceptedEncoding = msg.getHeader(HttpHeaders.Names.ACCEPT_ENCODING);
String acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
if (acceptedEncoding == null) {
acceptedEncoding = HttpHeaders.Values.IDENTITY;
}
@ -78,31 +79,31 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
public Object encode(ChannelHandlerContext ctx, Object msg)
throws Exception {
if (msg instanceof HttpResponseHeader && ((HttpResponseHeader) msg).getStatus().getCode() == 100) {
if (msg instanceof HttpResponse && ((HttpResponse) msg).status().code() == 100) {
// 100-continue response must be passed through.
return msg;
}
if (msg instanceof HttpHeader) {
if (msg instanceof HttpMessage) {
assert header == null;
// 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
if (msg instanceof HttpContent) {
if (msg instanceof HttpRequestHeader) {
HttpRequestHeader reqHeader = (HttpRequestHeader) msg;
header = new DefaultHttpRequestHeader(reqHeader.getProtocolVersion(), reqHeader.getMethod(),
reqHeader.getUri());
if (msg instanceof HttpRequest) {
HttpRequest reqHeader = (HttpRequest) msg;
header = new DefaultHttpRequest(reqHeader.protocolVersion(), reqHeader.method(),
reqHeader.uri());
HttpHeaders.setHeaders(reqHeader, header);
} else if (msg instanceof HttpResponseHeader) {
HttpResponseHeader responseHeader = (HttpResponseHeader) msg;
header = new DefaultHttpResponseHeader(responseHeader.getProtocolVersion(),
responseHeader.getStatus());
} else if (msg instanceof HttpResponse) {
HttpResponse responseHeader = (HttpResponse) msg;
header = new DefaultHttpResponse(responseHeader.protocolVersion(),
responseHeader.status());
HttpHeaders.setHeaders(responseHeader, header);
} else {
return msg;
}
} else {
header = (HttpHeader) msg;
header = (HttpMessage) msg;
}
cleanup();
@ -113,7 +114,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
if (!encodeStarted) {
encodeStarted = true;
HttpHeader header = this.header;
HttpMessage header = this.header;
this.header = null;
// Determine the content encoding.
@ -124,25 +125,29 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
Result result = beginEncode(header, c, acceptEncoding);
if (result == null) {
return new Object[] { header, c };
if (c instanceof LastHttpContent) {
return new Object[] { header, new DefaultLastHttpContent(c.data()) };
} else {
return new Object[] { header, new DefaultHttpContent(c.data()) };
}
}
encoder = result.getContentEncoder();
// Encode the content and remove or replace the existing headers
// so that the message looks like a decoded message.
header.setHeader(
header.headers().set(
HttpHeaders.Names.CONTENT_ENCODING,
result.getTargetContentEncoding());
Object[] encoded = encodeContent(header, c);
if (!HttpHeaders.isTransferEncodingChunked(header) && encoded.length == 3) {
if (header.containsHeader(HttpHeaders.Names.CONTENT_LENGTH)) {
long length = ((HttpContent) encoded[1]).getContent().readableBytes() +
((HttpContent) encoded[2]).getContent().readableBytes();
if (header.headers().contains(HttpHeaders.Names.CONTENT_LENGTH)) {
long length = ((ByteBufHolder) encoded[1]).data().readableBytes() +
((ByteBufHolder) encoded[2]).data().readableBytes();
header.setHeader(
header.headers().set(
HttpHeaders.Names.CONTENT_LENGTH,
Long.toString(length));
}
@ -157,9 +162,9 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
return null;
}
private Object[] encodeContent(HttpHeader header, HttpContent c) {
private Object[] encodeContent(HttpMessage header, HttpContent c) {
ByteBuf newContent = Unpooled.buffer();
ByteBuf content = c.getContent();
ByteBuf content = c.data();
encode(content, newContent);
if (c instanceof LastHttpContent) {
@ -200,7 +205,7 @@ public abstract class HttpContentEncoder extends MessageToMessageCodec<HttpHeade
* {@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(HttpHeader header, HttpContent msg, String acceptEncoding) throws Exception;
protected abstract Result beginEncode(HttpMessage header, HttpContent msg, String acceptEncoding) throws Exception;
@Override
public void afterRemove(ChannelHandlerContext ctx) throws Exception {

View File

@ -1,150 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An interface that defines a HTTP message, providing common properties for
* {@link HttpRequestHeader} and {@link HttpResponseHeader}.
* @see HttpResponseHeader
* @see HttpRequestHeader
* @see HttpHeaders
*
* @apiviz.landmark
* @apiviz.has io.netty.handler.codec.http.HttpChunk oneway - - is followed by
*/
public interface HttpHeader extends HttpObject {
/**
* Returns the value of a header with the specified name. If there are
* more than one values for the specified name, the first value is returned.
*
* @param name The name of the header to search
* @return The first header value or {@code null} if there is no such header
*/
String getHeader(String name);
/**
* Returns the values of headers with the specified name
*
* @param name The name of the headers to search
* @return A {@link List} of header values which will be empty if no values
* are found
*/
List<String> getHeaders(String name);
/**
* Returns the all headers that this message contains.
*
* @return A {@link List} of the header name-value entries, which will be
* empty if no pairs are found
*/
List<Map.Entry<String, String>> getHeaders();
/**
* Checks to see if there is a header with the specified name
*
* @param name The name of the header to search for
* @return True if at least one header is found
*/
boolean containsHeader(String name);
/**
* Gets a {@link Set} of all header names that this message contains
*
* @return A {@link Set} of all header names
*/
Set<String> getHeaderNames();
/**
* Returns the protocol version of this {@link HttpHeader}
*
* @return The protocol version
*/
HttpVersion getProtocolVersion();
/**
* Sets the protocol version of this {@link HttpHeader}
*
* @param version The version to set
*/
void setProtocolVersion(HttpVersion version);
/**
* Adds a new header with the specified name and value.
*
* If the specified value is not a {@link String}, it is converted
* into a {@link String} by {@link Object#toString()}, except in the cases
* of {@link Date} 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>.
*
* @param name The name of the header being added
* @param value The value of the header being added
*/
void addHeader(String name, Object value);
/**
* Sets a header with the specified name and value.
*
* If there is an existing header with the same name, it is removed.
* If the specified value is not a {@link String}, it is converted into a
* {@link String} by {@link Object#toString()}, except for {@link Date}
* 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>.
*
* @param name The name of the header being set
* @param value The value of the header being set
*/
void setHeader(String name, Object value);
/**
* Sets a header with the specified name and values.
*
* If there is an existing header with the same name, it is removed.
* This method can be represented approximately as the following code:
* <pre>
* m.removeHeader(name);
* for (Object v: values) {
* if (v == null) {
* break;
* }
* m.addHeader(name, v);
* }
* </pre>
*
* @param name The name of the headers being set
* @param values The values of the headers being set
*/
void setHeader(String name, Iterable<?> values);
/**
* Removes the header with the specified name.
*
* @param name The name of the header to remove
*/
void removeHeader(String name);
/**
* Removes all headers from this {@link HttpHeader}.
*/
void clearHeaders();
}

View File

@ -17,21 +17,89 @@ package io.netty.handler.codec.http;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
/**
* Provides the constants for the standard HTTP header names and values and
* commonly used utility methods that accesses an {@link HttpHeader}.
* commonly used utility methods that accesses an {@link HttpMessage}.
* @apiviz.landmark
* @apiviz.stereotype static
*/
public class HttpHeaders {
public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>> {
public static final HttpHeaders EMPTY_HEADERS = new HttpHeaders() {
@Override
public String get(String name) {
return null;
}
@Override
public List<String> getAll(String name) {
return Collections.emptyList();
}
@Override
public List<Entry<String, String>> entries() {
return Collections.emptyList();
}
@Override
public boolean contains(String name) {
return false;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public Set<String> names() {
return Collections.emptySet();
}
@Override
public void add(String name, Object value) {
throw new UnsupportedOperationException("read only");
}
@Override
public void add(String name, Iterable<?> values) {
throw new UnsupportedOperationException("read only");
}
@Override
public void set(String name, Object value) {
throw new UnsupportedOperationException("read only");
}
@Override
public void set(String name, Iterable<?> values) {
throw new UnsupportedOperationException("read only");
}
@Override
public void remove(String name) {
throw new UnsupportedOperationException("read only");
}
@Override
public void clear() {
throw new UnsupportedOperationException("read only");
}
@Override
public Iterator<Entry<String, String>> iterator() {
return entries().iterator();
}
};
/**
* Standard and CORS HTTP header names.
@ -483,13 +551,13 @@ public class HttpHeaders {
* {@code "Connection"} header first and then the return value of
* {@link HttpVersion#isKeepAliveDefault()}.
*/
public static boolean isKeepAlive(HttpHeader message) {
String connection = message.getHeader(Names.CONNECTION);
public static boolean isKeepAlive(HttpMessage message) {
String connection = message.headers().get(Names.CONNECTION);
if (Values.CLOSE.equalsIgnoreCase(connection)) {
return false;
}
if (message.getProtocolVersion().isKeepAliveDefault()) {
if (message.protocolVersion().isKeepAliveDefault()) {
return !Values.CLOSE.equalsIgnoreCase(connection);
} else {
return Values.KEEP_ALIVE.equalsIgnoreCase(connection);
@ -515,18 +583,18 @@ public class HttpHeaders {
* </ul></li>
* </ul>
*/
public static void setKeepAlive(HttpHeader message, boolean keepAlive) {
if (message.getProtocolVersion().isKeepAliveDefault()) {
public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
if (message.protocolVersion().isKeepAliveDefault()) {
if (keepAlive) {
message.removeHeader(Names.CONNECTION);
message.headers().remove(Names.CONNECTION);
} else {
message.setHeader(Names.CONNECTION, Values.CLOSE);
message.headers().set(Names.CONNECTION, Values.CLOSE);
}
} else {
if (keepAlive) {
message.setHeader(Names.CONNECTION, Values.KEEP_ALIVE);
message.headers().set(Names.CONNECTION, Values.KEEP_ALIVE);
} else {
message.removeHeader(Names.CONNECTION);
message.headers().remove(Names.CONNECTION);
}
}
}
@ -538,8 +606,8 @@ public class HttpHeaders {
*
* @return the header value or {@code null} if there is no such header
*/
public static String getHeader(HttpHeader message, String name) {
return message.getHeader(name);
public static String getHeader(HttpMessage message, String name) {
return message.headers().get(name);
}
/**
@ -550,8 +618,8 @@ public class HttpHeaders {
* @return the header value or the {@code defaultValue} if there is no such
* header
*/
public static String getHeader(HttpHeader message, String name, String defaultValue) {
String value = message.getHeader(name);
public static String getHeader(HttpMessage message, String name, String defaultValue) {
String value = message.headers().get(name);
if (value == null) {
return defaultValue;
}
@ -566,8 +634,8 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, Object value) {
message.setHeader(name, value);
public static void setHeader(HttpMessage message, String name, Object value) {
message.headers().set(name, value);
}
/**
@ -584,8 +652,8 @@ public class HttpHeaders {
* }
* </pre>
*/
public static void setHeader(HttpHeader message, String name, Iterable<?> values) {
message.setHeader(name, values);
public static void setHeader(HttpMessage message, String name, Iterable<?> values) {
message.headers().set(name, values);
}
/**
@ -595,22 +663,22 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, Object value) {
message.addHeader(name, value);
public static void addHeader(HttpMessage message, String name, Object value) {
message.headers().add(name, value);
}
/**
* Removes the header with the specified name.
*/
public static void removeHeader(HttpHeader message, String name) {
message.removeHeader(name);
public static void removeHeader(HttpMessage message, String name) {
message.headers().remove(name);
}
/**
* Removes all headers from the specified message.
*/
public static void clearHeaders(HttpHeader message) {
message.clearHeaders();
public static void clearHeaders(HttpMessage message) {
message.headers().clear();
}
/**
@ -622,7 +690,7 @@ public class HttpHeaders {
* @throws NumberFormatException
* if there is no such header or the header value is not a number
*/
public static int getIntHeader(HttpHeader message, String name) {
public static int getIntHeader(HttpMessage message, String name) {
String value = getHeader(message, name);
if (value == null) {
throw new NumberFormatException("header not found: " + name);
@ -638,7 +706,7 @@ public class HttpHeaders {
* @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(HttpHeader message, String name, int defaultValue) {
public static int getIntHeader(HttpMessage message, String name, int defaultValue) {
String value = getHeader(message, name);
if (value == null) {
return defaultValue;
@ -655,23 +723,23 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, int value) {
message.setHeader(name, value);
public static void setIntHeader(HttpMessage message, String name, int value) {
message.headers().set(name, value);
}
/**
* 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(HttpHeader message, String name, Iterable<Integer> values) {
message.setHeader(name, values);
public static void setIntHeader(HttpMessage message, String name, Iterable<Integer> values) {
message.headers().set(name, values);
}
/**
* Adds a new integer header with the specified name and value.
*/
public static void addIntHeader(HttpHeader message, String name, int value) {
message.addHeader(name, value);
public static void addIntHeader(HttpMessage message, String name, int value) {
message.headers().add(name, value);
}
/**
@ -683,7 +751,7 @@ public class HttpHeaders {
* @throws ParseException
* if there is no such header or the header value is not a formatted date
*/
public static Date getDateHeader(HttpHeader message, String name) throws ParseException {
public static Date getDateHeader(HttpMessage message, String name) throws ParseException {
String value = getHeader(message, name);
if (value == null) {
throw new ParseException("header not found: " + name, 0);
@ -699,7 +767,7 @@ public class HttpHeaders {
* @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(HttpHeader message, String name, Date defaultValue) {
public static Date getDateHeader(HttpMessage message, String name, Date defaultValue) {
final String value = getHeader(message, name);
if (value == null) {
return defaultValue;
@ -718,11 +786,11 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, Date value) {
public static void setDateHeader(HttpMessage message, String name, Date value) {
if (value != null) {
message.setHeader(name, new HttpHeaderDateFormat().format(value));
message.headers().set(name, new HttpHeaderDateFormat().format(value));
} else {
message.setHeader(name, null);
message.headers().set(name, null);
}
}
@ -732,8 +800,8 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, Iterable<Date> values) {
message.setHeader(name, values);
public static void setDateHeader(HttpMessage message, String name, Iterable<Date> values) {
message.headers().set(name, values);
}
/**
@ -741,13 +809,13 @@ public class HttpHeaders {
* 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(HttpHeader message, String name, Date value) {
message.addHeader(name, value);
public static void addDateHeader(HttpMessage message, String name, Date value) {
message.headers().add(name, value);
}
/**
* Returns the length of the content. Please note that this value is
* not retrieved from {@link HttpContent#getContent()} but from the
* not retrieved from {@link HttpContent#data()} but from the
* {@code "Content-Length"} header, and thus they are independent from each
* other.
*
@ -757,7 +825,7 @@ public class HttpHeaders {
* if the message does not have the {@code "Content-Length"} header
* or its value is not a number
*/
public static long getContentLength(HttpHeader message) {
public static long getContentLength(HttpMessage message) {
String value = getHeader(message, Names.CONTENT_LENGTH);
if (value != null) {
return Long.parseLong(value);
@ -776,7 +844,7 @@ public class HttpHeaders {
/**
* Returns the length of the content. Please note that this value is
* not retrieved from {@link HttpContent#getContent()} but from the
* not retrieved from {@link HttpContent#data()} but from the
* {@code "Content-Length"} header, and thus they are independent from each
* other.
*
@ -784,8 +852,8 @@ public class HttpHeaders {
* not have the {@code "Content-Length"} header or its value is not
* a number
*/
public static long getContentLength(HttpHeader message, long defaultValue) {
String contentLength = message.getHeader(Names.CONTENT_LENGTH);
public static long getContentLength(HttpMessage message, long defaultValue) {
String contentLength = message.headers().get(Names.CONTENT_LENGTH);
if (contentLength != null) {
try {
return Long.parseLong(contentLength);
@ -809,20 +877,20 @@ public class HttpHeaders {
* Returns the content length of the specified web socket message. If the
* specified message is not a web socket message, {@code -1} is returned.
*/
private static int getWebSocketContentLength(HttpHeader message) {
private static int getWebSocketContentLength(HttpMessage message) {
// WebSockset messages have constant content-lengths.
if (message instanceof HttpRequestHeader) {
HttpRequestHeader req = (HttpRequestHeader) message;
if (HttpMethod.GET.equals(req.getMethod()) &&
req.containsHeader(Names.SEC_WEBSOCKET_KEY1) &&
req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {
if (message instanceof HttpRequest) {
HttpRequest req = (HttpRequest) message;
if (HttpMethod.GET.equals(req.method()) &&
req.headers().contains(Names.SEC_WEBSOCKET_KEY1) &&
req.headers().contains(Names.SEC_WEBSOCKET_KEY2)) {
return 8;
}
} else if (message instanceof HttpResponseHeader) {
HttpResponseHeader res = (HttpResponseHeader) message;
if (res.getStatus().getCode() == 101 &&
res.containsHeader(Names.SEC_WEBSOCKET_ORIGIN) &&
res.containsHeader(Names.SEC_WEBSOCKET_LOCATION)) {
} else if (message instanceof HttpResponse) {
HttpResponse res = (HttpResponse) message;
if (res.status().code() == 101 &&
res.headers().contains(Names.SEC_WEBSOCKET_ORIGIN) &&
res.headers().contains(Names.SEC_WEBSOCKET_LOCATION)) {
return 16;
}
}
@ -834,30 +902,30 @@ public class HttpHeaders {
/**
* Sets the {@code "Content-Length"} header.
*/
public static void setContentLength(HttpHeader message, long length) {
message.setHeader(Names.CONTENT_LENGTH, length);
public static void setContentLength(HttpMessage message, long length) {
message.headers().set(Names.CONTENT_LENGTH, length);
}
/**
* Returns the value of the {@code "Host"} header.
*/
public static String getHost(HttpHeader message) {
return message.getHeader(Names.HOST);
public static String getHost(HttpMessage message) {
return message.headers().get(Names.HOST);
}
/**
* Returns the value of the {@code "Host"} header. If there is no such
* header, the {@code defaultValue} is returned.
*/
public static String getHost(HttpHeader message, String defaultValue) {
public static String getHost(HttpMessage message, String defaultValue) {
return getHeader(message, Names.HOST, defaultValue);
}
/**
* Sets the {@code "Host"} header.
*/
public static void setHost(HttpHeader message, String value) {
message.setHeader(Names.HOST, value);
public static void setHost(HttpMessage message, String value) {
message.headers().set(Names.HOST, value);
}
/**
@ -866,7 +934,7 @@ public class HttpHeaders {
* @throws ParseException
* if there is no such header or the header value is not a formatted date
*/
public static Date getDate(HttpHeader message) throws ParseException {
public static Date getDate(HttpMessage message) throws ParseException {
return getDateHeader(message, Names.DATE);
}
@ -875,18 +943,18 @@ public class HttpHeaders {
* header or the header is not a formatted date, the {@code defaultValue}
* is returned.
*/
public static Date getDate(HttpHeader message, Date defaultValue) {
public static Date getDate(HttpMessage message, Date defaultValue) {
return getDateHeader(message, Names.DATE, defaultValue);
}
/**
* Sets the {@code "Date"} header.
*/
public static void setDate(HttpHeader message, Date value) {
public static void setDate(HttpMessage message, Date value) {
if (value != null) {
message.setHeader(Names.DATE, new HttpHeaderDateFormat().format(value));
message.headers().set(Names.DATE, new HttpHeaderDateFormat().format(value));
} else {
message.setHeader(Names.DATE, null);
message.headers().set(Names.DATE, null);
}
}
@ -894,19 +962,19 @@ public class HttpHeaders {
* Returns {@code true} if and only if the specified message contains the
* {@code "Expect: 100-continue"} header.
*/
public static boolean is100ContinueExpected(HttpHeader message) {
public static boolean is100ContinueExpected(HttpMessage message) {
// Expect: 100-continue is for requests only.
if (!(message instanceof HttpRequestHeader)) {
if (!(message instanceof HttpRequest)) {
return false;
}
// It works only on HTTP/1.1 or later.
if (message.getProtocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
if (message.protocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
return false;
}
// In most cases, there will be one or zero 'Expect' header.
String value = message.getHeader(Names.EXPECT);
String value = message.headers().get(Names.EXPECT);
if (value == null) {
return false;
}
@ -915,7 +983,7 @@ public class HttpHeaders {
}
// Multiple 'Expect' headers. Search through them.
for (String v: message.getHeaders(Names.EXPECT)) {
for (String v: message.headers().getAll(Names.EXPECT)) {
if (Values.CONTINUE.equalsIgnoreCase(v)) {
return true;
}
@ -928,7 +996,7 @@ public class HttpHeaders {
* If there is any existing {@code "Expect"} header, they are replaced with
* the new one.
*/
public static void set100ContinueExpected(HttpHeader message) {
public static void set100ContinueExpected(HttpMessage message) {
set100ContinueExpected(message, true);
}
@ -939,20 +1007,20 @@ public class HttpHeaders {
* {@code "Expect"} headers are removed. Otherwise, all {@code "Expect"}
* headers are removed completely.
*/
public static void set100ContinueExpected(HttpHeader message, boolean set) {
public static void set100ContinueExpected(HttpMessage message, boolean set) {
if (set) {
message.setHeader(Names.EXPECT, Values.CONTINUE);
message.headers().set(Names.EXPECT, Values.CONTINUE);
} else {
message.removeHeader(Names.EXPECT);
message.headers().remove(Names.EXPECT);
}
}
/**
* Set the headers on the dst like they are set on the src
*/
public static void setHeaders(HttpHeader src, HttpHeader dst) {
for (String name: src.getHeaderNames()) {
dst.setHeader(name, src.getHeaders(name));
public static void setHeaders(HttpMessage src, HttpMessage dst) {
for (String name: src.headers().names()) {
dst.headers().set(name, src.headers().getAll(name));
}
}
/**
@ -1065,13 +1133,13 @@ public class HttpHeaders {
}
/**
* Checks to see if the transfer encoding in a specified {@link HttpHeader} is chunked
* Checks to see if the transfer encoding in a specified {@link HttpMessage} is chunked
*
* @param message The message to check
* @return True if transfer encoding is chunked, otherwise false
*/
public static boolean isTransferEncodingChunked(HttpHeader message) {
List<String> transferEncodingHeaders = message.getHeaders(Names.TRANSFER_ENCODING);
public static boolean isTransferEncodingChunked(HttpMessage message) {
List<String> transferEncodingHeaders = message.headers().getAll(Names.TRANSFER_ENCODING);
if (transferEncodingHeaders.isEmpty()) {
return false;
}
@ -1084,322 +1152,167 @@ public class HttpHeaders {
return false;
}
public static void removeTransferEncodingChunked(HttpHeader m) {
List<String> values = m.getHeaders(Names.TRANSFER_ENCODING);
public static void removeTransferEncodingChunked(HttpMessage m) {
List<String> values = m.headers().getAll(Names.TRANSFER_ENCODING);
values.remove(Values.CHUNKED);
if (values.isEmpty()) {
m.removeHeader(Names.TRANSFER_ENCODING);
m.headers().remove(Names.TRANSFER_ENCODING);
} else {
m.setHeader(Names.TRANSFER_ENCODING, values);
m.headers().set(Names.TRANSFER_ENCODING, values);
}
}
public static void setTransferEncodingChunked(HttpHeader m) {
public static void setTransferEncodingChunked(HttpMessage m) {
addHeader(m, Names.TRANSFER_ENCODING, Values.CHUNKED);
removeHeader(m, Names.CONTENT_LENGTH);
}
public static boolean isContentLengthSet(HttpHeader m) {
List<String> contentLength = m.getHeaders(Names.CONTENT_LENGTH);
public static boolean isContentLengthSet(HttpMessage m) {
List<String> contentLength = m.headers().getAll(Names.CONTENT_LENGTH);
return !contentLength.isEmpty();
}
private static final int BUCKET_SIZE = 17;
protected HttpHeaders() { }
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;
/**
* Returns the value of a header with the specified name. If there are
* more than one values for the specified name, the first value is returned.
*
* @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);
/**
* Returns the values of headers with the specified name
*
* @param name The name of the headers to search
* @return A {@link List} of header values which will be empty if no values
* are found
*/
public abstract List<String> getAll(String name);
/**
* Returns the all headers that this message contains.
*
* @return A {@link List} of the header name-value entries, which will be
* empty if no pairs are found
*/
public abstract List<Map.Entry<String, String>> entries();
/**
* Checks to see if there is a header with the specified name
*
* @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);
/**
* Checks if no header exists.
*/
public abstract boolean isEmpty();
/**
* Gets a {@link Set} of all header names that this message contains
*
* @return A {@link Set} of all header names
*/
public abstract Set<String> names();
/**
* Adds a new header with the specified name and value.
*
* If the specified value is not a {@link String}, it is converted
* into a {@link String} by {@link Object#toString()}, except in the cases
* of {@link Date} 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>.
*
* @param name The name of the header being added
* @param value The value of the header being added
*/
public abstract void add(String name, Object value);
/**
* Adds a new header with the specified name and values.
*
* This method can be represented approximately as the following code:
* <pre>
* for (Object v: values) {
* if (v == null) {
* break;
* }
* headers.add(name, v);
* }
* </pre>
*
* @param name The name of the headers being set
* @param values The values of the headers being set
*/
public abstract void add(String name, Iterable<?> values);
public void add(HttpHeaders headers) {
if (headers == null) {
throw new NullPointerException("headers");
}
if (h > 0) {
return h;
} else if (h == Integer.MIN_VALUE) {
return Integer.MAX_VALUE;
} else {
return -h;
for (Map.Entry<String, String> e: headers) {
add(e.getKey(), e.getValue());
}
}
private static boolean eq(String name1, String name2) {
int nameLen = name1.length();
if (nameLen != name2.length()) {
return false;
/**
* Sets a header with the specified name and value.
*
* If there is an existing header with the same name, it is removed.
* If the specified value is not a {@link String}, it is converted into a
* {@link String} by {@link Object#toString()}, except for {@link Date}
* 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>.
*
* @param name The name of the header being set
* @param value The value of the header being set
*/
public abstract void set(String name, Object value);
/**
* Sets a header with the specified name and values.
*
* If there is an existing header with the same name, it is removed.
* This method can be represented approximately as the following code:
* <pre>
* headers.remove(name);
* for (Object v: values) {
* if (v == null) {
* break;
* }
* headers.add(name, v);
* }
* </pre>
*
* @param name The name of the headers being set
* @param values The values of the headers being set
*/
public abstract void set(String name, Iterable<?> values);
public void set(HttpHeaders headers) {
if (headers == null) {
throw new NullPointerException("headers");
}
for (int i = nameLen - 1; i >= 0; i --) {
char c1 = name1.charAt(i);
char c2 = name2.charAt(i);
if (c1 != c2) {
if (c1 >= 'A' && c1 <= 'Z') {
c1 += 32;
}
if (c2 >= 'A' && c2 <= 'Z') {
c2 += 32;
}
if (c1 != c2) {
return false;
}
}
}
return true;
}
private static int index(int hash) {
return hash % BUCKET_SIZE;
}
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
private final HeaderEntry head = new HeaderEntry(-1, null, null);
HttpHeaders() {
head.before = head.after = head;
}
void validateHeaderName0(String headerName) {
validateHeaderName(headerName);
}
void addHeader(final String name, final Object value) {
validateHeaderName0(name);
String strVal = toString(value);
validateHeaderValue(strVal);
int h = hash(name);
int i = index(h);
addHeader0(h, i, name, strVal);
}
private void addHeader0(int h, int i, final String name, final String value) {
// Update the hash table.
HeaderEntry e = entries[i];
HeaderEntry newEntry;
entries[i] = newEntry = new HeaderEntry(h, name, value);
newEntry.next = e;
// Update the linked list.
newEntry.addBefore(head);
}
void removeHeader(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
int h = hash(name);
int i = index(h);
removeHeader0(h, i, name);
}
private void removeHeader0(int h, int i, String name) {
HeaderEntry e = entries[i];
if (e == null) {
return;
}
for (;;) {
if (e.hash == h && eq(name, e.key)) {
e.remove();
HeaderEntry next = e.next;
if (next != null) {
entries[i] = next;
e = next;
} else {
entries[i] = null;
return;
}
} else {
break;
}
}
for (;;) {
HeaderEntry next = e.next;
if (next == null) {
break;
}
if (next.hash == h && eq(name, next.key)) {
e.next = next.next;
next.remove();
} else {
e = next;
}
clear();
for (Map.Entry<String, String> e: headers) {
add(e.getKey(), e.getValue());
}
}
void setHeader(final String name, final Object value) {
validateHeaderName0(name);
String strVal = toString(value);
validateHeaderValue(strVal);
int h = hash(name);
int i = index(h);
removeHeader0(h, i, name);
addHeader0(h, i, name, strVal);
}
/**
* Removes the header with the specified name.
*
* @param name The name of the header to remove
*/
public abstract void remove(String name);
void setHeader(final String name, final Iterable<?> values) {
if (values == null) {
throw new NullPointerException("values");
}
validateHeaderName0(name);
int h = hash(name);
int i = index(h);
removeHeader0(h, i, name);
for (Object v: values) {
if (v == null) {
break;
}
String strVal = toString(v);
validateHeaderValue(strVal);
addHeader0(h, i, name, strVal);
}
}
void clearHeaders() {
for (int i = 0; i < entries.length; i ++) {
entries[i] = null;
}
head.before = head.after = head;
}
String getHeader(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
int h = hash(name);
int i = index(h);
HeaderEntry e = entries[i];
while (e != null) {
if (e.hash == h && eq(name, e.key)) {
return e.value;
}
e = e.next;
}
return null;
}
List<String> getHeaders(final String name) {
if (name == null) {
throw new NullPointerException("name");
}
LinkedList<String> values = new LinkedList<String>();
int h = hash(name);
int i = index(h);
HeaderEntry e = entries[i];
while (e != null) {
if (e.hash == h && eq(name, e.key)) {
values.addFirst(e.value);
}
e = e.next;
}
return values;
}
List<Map.Entry<String, String>> getHeaders() {
List<Map.Entry<String, String>> all =
new LinkedList<Map.Entry<String, String>>();
HeaderEntry e = head.after;
while (e != head) {
all.add(e);
e = e.after;
}
return all;
}
boolean containsHeader(String name) {
return getHeader(name) != null;
}
Set<String> getHeaderNames() {
Set<String> names = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
HeaderEntry e = head.after;
while (e != head) {
names.add(e.key);
e = e.after;
}
return names;
}
private static String toString(Object value) {
if (value == null) {
return null;
}
if (value instanceof String) {
return (String) value;
}
if (value instanceof Number) {
return value.toString();
}
if (value instanceof Date) {
return new HttpHeaderDateFormat().format((Date) value);
}
if (value instanceof Calendar) {
return new HttpHeaderDateFormat().format(((Calendar) value).getTime());
}
return value.toString();
}
private static final class HeaderEntry implements Map.Entry<String, String> {
final int hash;
final String key;
String value;
HeaderEntry next;
HeaderEntry before, after;
HeaderEntry(int hash, String key, String value) {
this.hash = hash;
this.key = key;
this.value = value;
}
void remove() {
before.after = after;
after.before = before;
}
void addBefore(HeaderEntry e) {
after = e;
before = e.before;
before.after = this;
after.before = this;
}
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return value;
}
@Override
public String setValue(String value) {
if (value == null) {
throw new NullPointerException("value");
}
validateHeaderValue(value);
String oldValue = this.value;
this.value = value;
return oldValue;
}
@Override
public String toString() {
return key + '=' + value;
}
}
/**
* Removes all headers from this {@link HttpMessage}.
*/
public abstract void clear();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -15,9 +15,28 @@
*/
package io.netty.handler.codec.http;
/**
* Combines {@link HttpMessage} and {@link LastHttpContent} into one
* message. So it represent a <i>complete</i> http message.
* An interface that defines a HTTP message, providing common properties for
* {@link HttpRequest} and {@link HttpResponse}.
* @see HttpResponse
* @see HttpRequest
* @see HttpHeaders
*
* @apiviz.landmark
* @apiviz.has io.netty.handler.codec.http.HttpChunk oneway - - is followed by
*/
public interface HttpMessage extends HttpHeader, LastHttpContent {
public interface HttpMessage extends HttpObject {
/**
* Returns the protocol version of this {@link HttpMessage}
*
* @return The protocol version
*/
HttpVersion protocolVersion();
/**
* Returns the headers of this message.
*/
HttpHeaders headers();
}

View File

@ -154,13 +154,13 @@ public class HttpMethod implements Comparable<HttpMethod> {
/**
* Returns the name of this method.
*/
public String getName() {
public String name() {
return name;
}
@Override
public int hashCode() {
return getName().hashCode();
return name().hashCode();
}
@Override
@ -170,16 +170,16 @@ public class HttpMethod implements Comparable<HttpMethod> {
}
HttpMethod that = (HttpMethod) o;
return getName().equals(that.getName());
return name().equals(that.name());
}
@Override
public String toString() {
return getName();
return name();
}
@Override
public int compareTo(HttpMethod o) {
return getName().compareTo(o.getName());
return name().compareTo(o.name());
}
}

View File

@ -18,6 +18,14 @@ package io.netty.handler.codec.http;
import io.netty.handler.codec.DecoderResult;
public interface HttpObject {
DecoderResult getDecoderResult();
void setDecoderResult(DecoderResult result);
/**
* Returns the result of decoding this message.
*/
DecoderResult decoderResult();
/**
* Updates the result of decoding this message. This method is supposed to be invoked by {@link HttpObjectDecoder}.
* Do not call this method unless you know what you are doing.
*/
void updateDecoderResult(DecoderResult result);
}

View File

@ -15,7 +15,6 @@
*/
package io.netty.handler.codec.http;
import static io.netty.handler.codec.http.HttpHeaders.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
@ -29,9 +28,11 @@ import io.netty.util.CharsetUtil;
import java.util.Map.Entry;
import static io.netty.handler.codec.http.HttpHeaders.*;
/**
* A {@link ChannelHandler} that aggregates an {@link HttpHeader}
* and its following {@link HttpContent}s into a single {@link HttpHeader} with
* A {@link ChannelHandler} that aggregates an {@link HttpMessage}
* and its following {@link HttpContent}s into a single {@link HttpMessage} with
* no following {@link HttpContent}s. It is useful when you don't want to take
* care of HTTP messages whose transfer encoding is 'chunked'. Insert this
* handler after {@link HttpObjectDecoder} in the {@link ChannelPipeline}:
@ -53,7 +54,7 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
"HTTP/1.1 100 Continue\r\n\r\n", CharsetUtil.US_ASCII);
private final int maxContentLength;
private HttpMessage currentMessage;
private FullHttpMessage currentMessage;
private int maxCumulationBufferComponents = DEFAULT_MAX_COMPOSITEBUFFER_COMPONENTS;
private ChannelHandlerContext ctx;
@ -111,10 +112,12 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
@Override
protected Object decode(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
HttpMessage currentMessage = this.currentMessage;
FullHttpMessage currentMessage = this.currentMessage;
if (msg instanceof HttpHeader) {
HttpHeader m = (HttpHeader) msg;
if (msg instanceof HttpMessage) {
assert currentMessage == null;
HttpMessage m = (HttpMessage) msg;
// Handle the 'Expect: 100-continue' header if necessary.
// TODO: Respond with 413 Request Entity Too Large
@ -125,41 +128,40 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
ctx.write(CONTINUE.duplicate());
}
if (!m.getDecoderResult().isSuccess()) {
if (!m.decoderResult().isSuccess()) {
removeTransferEncodingChunked(m);
this.currentMessage = null;
return m;
}
if (msg instanceof HttpRequestHeader) {
HttpRequestHeader header = (HttpRequestHeader) msg;
this.currentMessage = new DefaultHttpRequest(header.getProtocolVersion(),
header.getMethod(), header.getUri());
} else {
HttpResponseHeader header = (HttpResponseHeader) msg;
this.currentMessage = new DefaultHttpResponse(header.getProtocolVersion(), header.getStatus());
if (msg instanceof HttpRequest) {
HttpRequest header = (HttpRequest) msg;
this.currentMessage = currentMessage = new DefaultFullHttpRequest(header.protocolVersion(),
header.method(), header.uri(), Unpooled.compositeBuffer(maxCumulationBufferComponents));
} else if (msg instanceof HttpResponse) {
HttpResponse header = (HttpResponse) msg;
this.currentMessage = currentMessage = new DefaultFullHttpResponse(
header.protocolVersion(), header.status(),
Unpooled.compositeBuffer(maxCumulationBufferComponents));
} else {
throw new Error();
}
for (String name: m.getHeaderNames()) {
this.currentMessage.setHeader(name, m.getHeaders(name));
HttpHeaders headers = currentMessage.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.
removeTransferEncodingChunked(m);
this.currentMessage.setContent(Unpooled.compositeBuffer(maxCumulationBufferComponents));
removeTransferEncodingChunked(currentMessage);
return null;
} else if (msg instanceof HttpContent) {
// Sanity check
if (currentMessage == null) {
throw new IllegalStateException(
"received " + HttpContent.class.getSimpleName() +
" without " + HttpHeader.class.getSimpleName() +
" or last message's transfer encoding was 'SINGLE'");
}
assert currentMessage != null;
// Merge the received chunk into the content of the current message.
HttpContent chunk = (HttpContent) msg;
ByteBuf content = currentMessage.getContent();
CompositeByteBuf content = (CompositeByteBuf) currentMessage.data();
if (content.readableBytes() > maxContentLength - chunk.getContent().readableBytes()) {
if (content.readableBytes() > maxContentLength - chunk.data().readableBytes()) {
// TODO: Respond with 413 Request Entity Too Large
// and discard the traffic or close the connection.
// No need to notify the upstream handlers - just log.
@ -170,12 +172,17 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
}
// Append the content of the chunk
appendToCumulation(chunk.getContent());
if (chunk.data().readable()) {
content.addComponent(chunk.data());
content.writerIndex(content.writerIndex() + chunk.data().readableBytes());
} else {
chunk.free();
}
final boolean last;
if (!chunk.getDecoderResult().isSuccess()) {
currentMessage.setDecoderResult(
DecoderResult.partialFailure(chunk.getDecoderResult().cause()));
if (!chunk.decoderResult().isSuccess()) {
currentMessage.updateDecoderResult(
DecoderResult.partialFailure(chunk.decoderResult().cause()));
last = true;
} else {
last = msg instanceof LastHttpContent;
@ -187,13 +194,13 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
// Merge trailing headers into the message.
if (chunk instanceof LastHttpContent) {
LastHttpContent trailer = (LastHttpContent) chunk;
for (Entry<String, String> header: trailer.getHeaders()) {
currentMessage.setHeader(header.getKey(), header.getValue());
for (Entry<String, String> header: trailer.trailingHeaders()) {
currentMessage.headers().add(header.getKey(), header.getValue());
}
}
// Set the 'Content-Length' header.
currentMessage.setHeader(
currentMessage.headers().set(
HttpHeaders.Names.CONTENT_LENGTH,
String.valueOf(content.readableBytes()));
@ -203,21 +210,12 @@ public class HttpObjectAggregator extends MessageToMessageDecoder<HttpObject> {
return null;
}
} else {
throw new IllegalStateException(
"Only " + HttpHeader.class.getSimpleName() + " and " +
HttpContent.class.getSimpleName() + " are accepted: " + msg.getClass().getName());
throw new Error();
}
}
private void appendToCumulation(ByteBuf input) {
CompositeByteBuf cumulation = (CompositeByteBuf) currentMessage.getContent();
cumulation.addComponent(input);
cumulation.writerIndex(cumulation.capacity());
}
@Override
public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
}
}

View File

@ -26,7 +26,7 @@ import io.netty.handler.codec.TooLongFrameException;
import java.util.List;
/**
* Decodes {@link ByteBuf}s into {@link HttpHeader}s and
* Decodes {@link ByteBuf}s into {@link HttpMessage}s and
* {@link HttpContent}s.
*
* <h3>Parameters that prevents excessive memory consumption</h3>
@ -59,7 +59,7 @@ import java.util.List;
*
* If the content of an HTTP message is greater than {@code maxChunkSize} or
* the transfer encoding of the HTTP message is 'chunked', this decoder
* generates one {@link HttpHeader} instance and its following
* generates one {@link HttpMessage} instance and its following
* {@link HttpContent}s per single HTTP message to avoid excessive memory
* consumption. For example, the following HTTP message:
* <pre>
@ -76,7 +76,7 @@ import java.util.List;
* </pre>
* triggers {@link HttpRequestDecoder} to generate 3 objects:
* <ol>
* <li>An {@link HttpRequestHeader},</li>
* <li>An {@link HttpRequest},</li>
* <li>The first {@link HttpContent} whose content is {@code 'abcdefghijklmnopqrstuvwxyz'},</li>
* <li>The second {@link LastHttpContent} whose content is {@code '1234567890abcdef'}, which marks
* the end of the content.</li>
@ -103,7 +103,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
private final int maxHeaderSize;
private final int maxChunkSize;
private ByteBuf content;
private HttpHeader message;
private HttpMessage message;
private long chunkSize;
private int headerSize;
private int contentRead;
@ -211,7 +211,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
switch (nextState) {
case READ_FIXED_LENGTH_CONTENT:
if (contentLength > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) {
// Generate HttpMessage first. HttpChunks will follow.
// Generate FullHttpMessage first. HttpChunks will follow.
checkpoint(State.READ_FIXED_LENGTH_CONTENT_AS_CHUNKS);
// chunkSize will be decreased as the READ_FIXED_LENGTH_CONTENT_AS_CHUNKS
// state reads data chunk by chunk.
@ -221,7 +221,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
break;
case READ_VARIABLE_LENGTH_CONTENT:
if (buffer.readableBytes() > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) {
// Generate HttpMessage first. HttpChunks will follow.
// Generate FullHttpMessage first. HttpChunks will follow.
checkpoint(State.READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS);
return message;
}
@ -396,10 +396,10 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
}
}
protected boolean isContentAlwaysEmpty(HttpHeader msg) {
if (msg instanceof HttpResponseHeader) {
HttpResponseHeader res = (HttpResponseHeader) msg;
int code = res.getStatus().getCode();
protected boolean isContentAlwaysEmpty(HttpMessage msg) {
if (msg instanceof HttpResponse) {
HttpResponse res = (HttpResponse) msg;
int code = res.status().code();
// Correctly handle return codes of 1xx.
//
@ -407,7 +407,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
// - http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html Section 4.4
// - https://github.com/netty/netty/issues/222
if (code >= 100 && code < 200) {
if (code == 101 && !res.containsHeader(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT)) {
if (code == 101 && !res.headers().contains(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT)) {
// It's Hixie 76 websocket handshake response
return false;
}
@ -423,12 +423,12 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
}
private Object reset() {
HttpHeader message = this.message;
HttpMessage message = this.message;
ByteBuf content = this.content;
LastHttpContent httpContent;
if (content == null || !content.readable()) {
httpContent = HttpContent.LAST_CONTENT;
httpContent = LastHttpContent.EMPTY_LAST_CONTENT;
} else {
httpContent = new DefaultLastHttpContent(content);
}
@ -441,13 +441,13 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
return messages;
}
private HttpHeader invalidMessage(Exception cause) {
private HttpMessage invalidMessage(Exception cause) {
checkpoint(State.BAD_MESSAGE);
if (message != null) {
message.setDecoderResult(DecoderResult.partialFailure(cause));
message.updateDecoderResult(DecoderResult.partialFailure(cause));
} else {
message = createInvalidMessage();
message.setDecoderResult(DecoderResult.failure(cause));
message.updateDecoderResult(DecoderResult.failure(cause));
}
return message;
}
@ -455,7 +455,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
private HttpContent invalidChunk(Exception cause) {
checkpoint(State.BAD_MESSAGE);
HttpContent chunk = new DefaultHttpContent(Unpooled.EMPTY_BUFFER);
chunk.setDecoderResult(DecoderResult.failure(cause));
chunk.updateDecoderResult(DecoderResult.failure(cause));
return chunk;
}
@ -492,19 +492,19 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
private State readHeaders(ByteBuf buffer) {
headerSize = 0;
final HttpHeader message = this.message;
final HttpMessage message = this.message;
String line = readHeader(buffer);
String name = null;
String value = null;
if (!line.isEmpty()) {
message.clearHeaders();
message.headers().clear();
do {
char firstChar = line.charAt(0);
if (name != null && (firstChar == ' ' || firstChar == '\t')) {
value = value + ' ' + line.trim();
} else {
if (name != null) {
message.addHeader(name, value);
message.headers().add(name, value);
}
String[] header = splitHeader(line);
name = header[0];
@ -516,7 +516,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
// Add the last header.
if (name != null) {
message.addHeader(name, value);
message.headers().add(name, value);
}
}
@ -544,7 +544,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
do {
char firstChar = line.charAt(0);
if (lastHeader != null && (firstChar == ' ' || firstChar == '\t')) {
List<String> current = trailer.getHeaders(lastHeader);
List<String> current = trailer.trailingHeaders().getAll(lastHeader);
if (!current.isEmpty()) {
int lastPos = current.size() - 1;
String newString = current.get(lastPos) + line.trim();
@ -558,7 +558,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
if (!name.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH) &&
!name.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING) &&
!name.equalsIgnoreCase(HttpHeaders.Names.TRAILER)) {
trailer.addHeader(name, header[1]);
trailer.trailingHeaders().add(name, header[1]);
}
lastHeader = name;
}
@ -569,7 +569,7 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
return trailer;
}
return HttpContent.LAST_CONTENT;
return LastHttpContent.EMPTY_LAST_CONTENT;
}
private String readHeader(ByteBuf buffer) {
@ -612,8 +612,8 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<HttpObjectDecod
}
protected abstract boolean isDecodingRequest();
protected abstract HttpHeader createMessage(String[] initialLine) throws Exception;
protected abstract HttpHeader createInvalidMessage();
protected abstract HttpMessage createMessage(String[] initialLine) throws Exception;
protected abstract HttpMessage createInvalidMessage();
private static int getChunkSize(String hex) {
hex = hex.trim();

View File

@ -15,8 +15,6 @@
*/
package io.netty.handler.codec.http;
import static io.netty.buffer.Unpooled.*;
import static io.netty.handler.codec.http.HttpConstants.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
@ -24,8 +22,11 @@ import io.netty.util.CharsetUtil;
import java.util.Map;
import static io.netty.buffer.Unpooled.*;
import static io.netty.handler.codec.http.HttpConstants.*;
/**
* Encodes an {@link HttpHeader} or an {@link HttpContent} into
* Encodes an {@link HttpMessage} or an {@link HttpContent} into
* a {@link ByteBuf}.
*
* <h3>Extensibility</h3>
@ -38,9 +39,14 @@ import java.util.Map;
* implement all abstract methods properly.
* @apiviz.landmark
*/
public abstract class HttpObjectEncoder<H extends HttpHeader> extends MessageToByteEncoder<Object> {
public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageToByteEncoder<Object> {
private boolean chunked;
private static final int ST_INIT = 0;
private static final int ST_CONTENT_NON_CHUNK = 1;
private static final int ST_CONTENT_CHUNK = 2;
@SuppressWarnings("RedundantFieldInitialization")
private int state = ST_INIT;
/**
* Creates a new instance.
@ -49,38 +55,44 @@ public abstract class HttpObjectEncoder<H extends HttpHeader> extends MessageToB
super(HttpObject.class);
}
@SuppressWarnings("unchecked")
@Override
@SuppressWarnings("unchecked")
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
if (msg instanceof HttpHeader) {
HttpHeader m = (HttpHeader) msg;
chunked = HttpHeaders.isTransferEncodingChunked(m);
// Encode the message.
out.markWriterIndex();
if (msg instanceof HttpMessage) {
if (state != ST_INIT) {
throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName());
}
HttpMessage m = (HttpMessage) msg;
// Encode the message.
encodeInitialLine(out, (H) m);
encodeHeaders(out, m);
out.writeByte(CR);
out.writeByte(LF);
state = HttpHeaders.isTransferEncodingChunked(m) ? ST_CONTENT_CHUNK : ST_CONTENT_NON_CHUNK;
}
if (msg instanceof HttpContent) {
HttpContent chunk = (HttpContent) msg;
if (state == ST_INIT) {
throw new IllegalStateException("unexpected message type: " + msg.getClass().getSimpleName());
}
HttpContent chunk = (HttpContent) msg;
ByteBuf content = chunk.data();
int contentLength = content.readableBytes();
if (state == ST_CONTENT_NON_CHUNK) {
if (contentLength > 0) {
out.writeBytes(content, content.readerIndex(), content.readableBytes());
}
if (!chunked) {
ByteBuf content = chunk.getContent();
out.writeBytes(content, content.readerIndex(), content.readableBytes());
} else {
if (chunk instanceof LastHttpContent) {
out.writeByte((byte) '0');
out.writeByte(CR);
out.writeByte(LF);
encodeTrailingHeaders(out, (LastHttpContent) chunk);
out.writeByte(CR);
out.writeByte(LF);
} else {
ByteBuf content = chunk.getContent();
int contentLength = content.readableBytes();
state = ST_INIT;
}
} else if (state == ST_CONTENT_CHUNK) {
if (contentLength > 0) {
out.writeBytes(copiedBuffer(Integer.toHexString(contentLength), CharsetUtil.US_ASCII));
out.writeByte(CR);
out.writeByte(LF);
@ -88,18 +100,30 @@ public abstract class HttpObjectEncoder<H extends HttpHeader> extends MessageToB
out.writeByte(CR);
out.writeByte(LF);
}
if (chunk instanceof LastHttpContent) {
out.writeByte((byte) '0');
out.writeByte(CR);
out.writeByte(LF);
encodeTrailingHeaders(out, (LastHttpContent) chunk);
out.writeByte(CR);
out.writeByte(LF);
state = ST_INIT;
}
} else {
throw new Error();
}
}
}
private static void encodeHeaders(ByteBuf buf, HttpHeader message) {
for (Map.Entry<String, String> h: message.getHeaders()) {
private static void encodeHeaders(ByteBuf buf, HttpMessage message) {
for (Map.Entry<String, String> h: message.headers()) {
encodeHeader(buf, h.getKey(), h.getValue());
}
}
private static void encodeTrailingHeaders(ByteBuf buf, LastHttpContent trailer) {
for (Map.Entry<String, String> h: trailer.getHeaders()) {
for (Map.Entry<String, String> h: trailer.trailingHeaders()) {
encodeHeader(buf, h.getKey(), h.getValue());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -15,9 +15,35 @@
*/
package io.netty.handler.codec.http;
/**
* Combinate the {@link HttpRequestHeader} and {@link HttpMessage}, so the request is a <i>complete</i> HTTP
* request.
* An HTTP request.
*
* <h3>Accessing Query Parameters and Cookie</h3>
* <p>
* Unlike the Servlet API, a query string is constructed and decomposed by
* {@link QueryStringEncoder} and {@link QueryStringDecoder}. {@link Cookie}
* support is also provided separately via {@link CookieDecoder}, {@link ClientCookieEncoder},
* and {@link @ServerCookieEncoder}.
*
* @see HttpResponse
* @see ClientCookieEncoder
* @see ServerCookieEncoder
* @see CookieDecoder
*/
public interface HttpRequest extends HttpRequestHeader, HttpMessage {
public interface HttpRequest extends HttpMessage {
/**
* Returns the {@link HttpMethod} of this {@link HttpRequest}.
*
* @return The {@link HttpMethod} of this {@link HttpRequest}
*/
HttpMethod method();
/**
* Returns the requested URI (or alternatively, path)
*
* @return The URI being requested
*/
String uri();
}

View File

@ -21,7 +21,7 @@ import io.netty.handler.codec.TooLongFrameException;
/**
* Decodes {@link ByteBuf}s into {@link HttpRequestHeader}s and {@link HttpContent}s.
* Decodes {@link ByteBuf}s into {@link HttpRequest}s and {@link HttpContent}s.
*
* <h3>Parameters that prevents excessive memory consumption</h3>
* <table border="1">
@ -71,14 +71,14 @@ public class HttpRequestDecoder extends HttpObjectDecoder {
}
@Override
protected HttpHeader createMessage(String[] initialLine) throws Exception {
return new DefaultHttpRequestHeader(
protected HttpMessage createMessage(String[] initialLine) throws Exception {
return new DefaultHttpRequest(
HttpVersion.valueOf(initialLine[2]), HttpMethod.valueOf(initialLine[0]), initialLine[1]);
}
@Override
protected HttpHeader createInvalidMessage() {
return new DefaultHttpRequestHeader(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request");
protected HttpMessage createInvalidMessage() {
return new DefaultHttpRequest(HttpVersion.HTTP_1_0, HttpMethod.GET, "/bad-request");
}
@Override

View File

@ -15,25 +15,31 @@
*/
package io.netty.handler.codec.http;
import static io.netty.handler.codec.http.HttpConstants.*;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
/**
* Encodes an {@link HttpRequestHeader} or an {@link HttpContent} into
* Encodes an {@link HttpRequest} or an {@link HttpContent} into
* a {@link ByteBuf}.
*/
public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequestHeader> {
public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequest> {
private static final char SLASH = '/';
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequestHeader request) throws Exception {
buf.writeBytes(request.getMethod().toString().getBytes(CharsetUtil.US_ASCII));
public boolean isEncodable(Object msg) throws Exception {
return super.isEncodable(msg) && !(msg instanceof HttpResponse);
}
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request) throws Exception {
buf.writeBytes(request.method().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte(SP);
// Add / as absolute path if no is present.
// See http://tools.ietf.org/html/rfc2616#section-5.1.2
String uri = request.getUri();
String uri = request.uri();
int start = uri.indexOf("://");
if (start != -1) {
int startIndex = start + 3;
@ -44,7 +50,7 @@ public class HttpRequestEncoder extends HttpObjectEncoder<HttpRequestHeader> {
buf.writeBytes(uri.getBytes("UTF-8"));
buf.writeByte(SP);
buf.writeBytes(request.getProtocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(request.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte(CR);
buf.writeByte(LF);
}

View File

@ -1,63 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
/**
* An HTTP request.
*
* <h3>Accessing Query Parameters and Cookie</h3>
* <p>
* Unlike the Servlet API, a query string is constructed and decomposed by
* {@link QueryStringEncoder} and {@link QueryStringDecoder}. {@link Cookie}
* support is also provided separately via {@link CookieDecoder}, {@link ClientCookieEncoder},
* and {@link @ServerCookieEncoder}.
*
* @see HttpResponseHeader
* @see ClientCookieEncoder
* @see ServerCookieEncoder
* @see CookieDecoder
*/
public interface HttpRequestHeader extends HttpHeader {
/**
* Returns the {@link HttpMethod} of this {@link HttpRequestHeader}.
*
* @return The {@link HttpMethod} of this {@link HttpRequestHeader}
*/
HttpMethod getMethod();
/**
* Sets the {@link HttpMethod} of this {@link HttpRequestHeader}.
*
* @param method The {@link HttpMethod} to set
*/
void setMethod(HttpMethod method);
/**
* Returns the requested URI (or alternatively, path)
*
* @return The URI being requested
*/
String getUri();
/**
* Sets the URI (or alternatively, path) being requested.
*
* @param uri The URI being requested
*/
void setUri(String uri);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2013 The Netty Project
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
@ -15,9 +15,26 @@
*/
package io.netty.handler.codec.http;
/**
* Combination of a {@link HttpResponseHeader} and {@link HttpMessage}.
* So it represent a <i>complete</i> http response.
* An HTTP response.
*
* <h3>Accessing Cookies</h3>
* <p>
* Unlike the Servlet API, {@link Cookie} support is provided separately via {@link CookieDecoder},
* {@link ClientCookieEncoder}, and {@link ServerCookieEncoder}.
*
* @see HttpRequest
* @see CookieDecoder
* @see ClientCookieEncoder
* @see ServerCookieEncoder
*/
public interface HttpResponse extends HttpResponseHeader, HttpMessage {
public interface HttpResponse extends HttpMessage {
/**
* Returns the status of this {@link HttpResponse}.
*
* @return The {@link HttpResponseStatus} of this {@link HttpResponse}
*/
HttpResponseStatus status();
}

View File

@ -21,7 +21,7 @@ import io.netty.handler.codec.TooLongFrameException;
/**
* Decodes {@link ByteBuf}s into {@link HttpResponseHeader}s and
* Decodes {@link ByteBuf}s into {@link HttpResponse}s and
* {@link HttpContent}s.
*
* <h3>Parameters that prevents excessive memory consumption</h3>
@ -59,7 +59,7 @@ import io.netty.handler.codec.TooLongFrameException;
* request does not have any content even if there is <tt>Content-Length</tt>
* header. Because {@link HttpResponseDecoder} is not able to determine if the
* response currently being decoded is associated with a <tt>HEAD</tt> request,
* you must override {@link #isContentAlwaysEmpty(HttpHeader)} to return
* you must override {@link #isContentAlwaysEmpty(HttpMessage)} to return
* <tt>true</tt> for the response of the <tt>HEAD</tt> request.
* </p><p>
* If you are writing an HTTP client that issues a <tt>HEAD</tt> request,
@ -102,15 +102,15 @@ public class HttpResponseDecoder extends HttpObjectDecoder {
}
@Override
protected HttpHeader createMessage(String[] initialLine) {
return new DefaultHttpResponseHeader(
protected HttpMessage createMessage(String[] initialLine) {
return new DefaultHttpResponse(
HttpVersion.valueOf(initialLine[0]),
new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2]));
}
@Override
protected HttpHeader createInvalidMessage() {
return new DefaultHttpResponseHeader(HttpVersion.HTTP_1_0, UNKNOWN_STATUS);
protected HttpMessage createInvalidMessage() {
return new DefaultHttpResponse(HttpVersion.HTTP_1_0, UNKNOWN_STATUS);
}
@Override

View File

@ -15,23 +15,29 @@
*/
package io.netty.handler.codec.http;
import static io.netty.handler.codec.http.HttpConstants.*;
import io.netty.buffer.ByteBuf;
import io.netty.util.CharsetUtil;
import static io.netty.handler.codec.http.HttpConstants.*;
/**
* Encodes an {@link HttpResponseHeader} or an {@link HttpContent} into
* Encodes an {@link HttpResponse} or an {@link HttpContent} into
* a {@link ByteBuf}.
*/
public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponseHeader> {
public class HttpResponseEncoder extends HttpObjectEncoder<HttpResponse> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponseHeader response) throws Exception {
buf.writeBytes(response.getProtocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
public boolean isEncodable(Object msg) throws Exception {
return super.isEncodable(msg) && !(msg instanceof HttpRequest);
}
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response) throws Exception {
buf.writeBytes(response.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte(SP);
buf.writeBytes(String.valueOf(response.getStatus().getCode()).getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(String.valueOf(response.status().code()).getBytes(CharsetUtil.US_ASCII));
buf.writeByte(SP);
buf.writeBytes(String.valueOf(response.getStatus().getReasonPhrase()).getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(String.valueOf(response.status().reasonPhrase()).getBytes(CharsetUtil.US_ASCII));
buf.writeByte(CR);
buf.writeByte(LF);
}

View File

@ -1,47 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.codec.http;
/**
* An HTTP response.
*
* <h3>Accessing Cookies</h3>
* <p>
* Unlike the Servlet API, {@link Cookie} support is provided separately via {@link CookieDecoder},
* {@link ClientCookieEncoder}, and {@link ServerCookieEncoder}.
*
* @see HttpRequestHeader
* @see CookieDecoder
* @see ClientCookieEncoder
* @see ServerCookieEncoder
*/
public interface HttpResponseHeader extends HttpHeader {
/**
* Returns the status of this {@link HttpResponseHeader}.
*
* @return The {@link HttpResponseStatus} of this {@link HttpResponseHeader}
*/
HttpResponseStatus getStatus();
/**
* Sets the status of this {@link HttpResponseHeader}
*
* @param status The {@link HttpResponseStatus} to use
*/
void setStatus(HttpResponseStatus status);
}

View File

@ -447,20 +447,20 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
/**
* Returns the code of this status.
*/
public int getCode() {
public int code() {
return code;
}
/**
* Returns the reason phrase of this status.
*/
public String getReasonPhrase() {
public String reasonPhrase() {
return reasonPhrase;
}
@Override
public int hashCode() {
return getCode();
return code();
}
@Override
@ -469,12 +469,12 @@ public class HttpResponseStatus implements Comparable<HttpResponseStatus> {
return false;
}
return getCode() == ((HttpResponseStatus) o).getCode();
return code() == ((HttpResponseStatus) o).code();
}
@Override
public int compareTo(HttpResponseStatus o) {
return getCode() - o.getCode();
return code() - o.code();
}
@Override

View File

@ -15,9 +15,9 @@
*/
package io.netty.handler.codec.http;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.DecoderResult;
/**
* The last {@link HttpContent} which has trailing headers.
@ -25,68 +25,48 @@ import java.util.Set;
public interface LastHttpContent extends HttpContent {
/**
* Returns the trailing header value with the specified header name.
* If there are more than one trailing header value for the specified
* header name, the first value is returned.
*
* @return the header value or {@code null} if there is no such header
* The 'end of content' marker in chunked encoding.
*/
String getHeader(String name);
LastHttpContent EMPTY_LAST_CONTENT = new LastHttpContent() {
/**
* Returns the trailing header values with the specified header name.
*
* @return the {@link List} of header values. An empty list if there is no
* such header.
*/
List<String> getHeaders(String name);
@Override
public ByteBuf data() {
return Unpooled.EMPTY_BUFFER;
}
/**
* Returns the all header names and values that this trailer contains.
*
* @return the {@link List} of the header name-value pairs. An empty list
* if there is no header in this trailer.
*/
List<Map.Entry<String, String>> getHeaders();
@Override
public LastHttpContent copy() {
return EMPTY_LAST_CONTENT;
}
/**
* Returns {@code true} if and only if there is a trailing header with
* the specified header name.
*/
boolean containsHeader(String name);
@Override
public HttpHeaders trailingHeaders() {
return HttpHeaders.EMPTY_HEADERS;
}
/**
* Returns the {@link Set} of all trailing header names that this trailer
* contains.
*/
Set<String> getHeaderNames();
@Override
public DecoderResult decoderResult() {
return DecoderResult.SUCCESS;
}
/**
* Adds a new trailing header with the specified name and value.
*/
void addHeader(String name, Object value);
@Override
public void updateDecoderResult(DecoderResult result) {
throw new UnsupportedOperationException("read only");
}
/**
* 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, Object value);
@Override
public boolean isFreed() {
return false;
}
/**
* 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<?> values);
@Override
public void free() {
// NOOP
}
};
/**
* Removes the trailing header with the specified name.
*/
void removeHeader(String name);
HttpHeaders trailingHeaders();
/**
* Removes all trailing headers from this trailer.
*/
void clearHeaders();
@Override
LastHttpContent copy();
}

View File

@ -54,7 +54,7 @@ import java.util.Map;
* @see QueryStringEncoder
*
* @apiviz.stereotype utility
* @apiviz.has io.netty.handler.codec.http.HttpRequest oneway - - decodes
* @apiviz.has io.netty.handler.codec.http.FullHttpRequest oneway - - decodes
*/
public class QueryStringDecoder {

View File

@ -36,7 +36,7 @@ import java.util.List;
* @see QueryStringDecoder
*
* @apiviz.stereotype utility
* @apiviz.has io.netty.handler.codec.http.HttpRequest oneway - - encodes
* @apiviz.has io.netty.handler.codec.http.FullHttpRequest oneway - - encodes
*/
public class QueryStringEncoder {

View File

@ -15,19 +15,19 @@
*/
package io.netty.handler.codec.http;
import static io.netty.handler.codec.http.CookieEncoderUtil.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import static io.netty.handler.codec.http.CookieEncoderUtil.*;
/**
* Encodes server-side {@link Cookie}s into HTTP header values. This encoder can encode
* the HTTP cookie version 0, 1, and 2.
* <pre>
* // Example
* {@link HttpRequestHeader} req = ...;
* {@link HttpRequest} req = ...;
* res.setHeader("Set-Cookie", {@link ServerCookieEncoder}.encode("JSESSIONID", "1234"));
* </pre>
*

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.http.multipart;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequest;
import java.io.IOException;
import java.nio.charset.Charset;
@ -46,8 +46,8 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
/**
* Keep all HttpDatas until cleanAllHttpDatas() is called.
*/
private final ConcurrentHashMap<HttpRequestHeader, List<HttpData>> requestFileDeleteMap =
new ConcurrentHashMap<HttpRequestHeader, List<HttpData>>();
private final ConcurrentHashMap<HttpRequest, List<HttpData>> requestFileDeleteMap =
new ConcurrentHashMap<HttpRequest, List<HttpData>>();
/**
* HttpData will be in memory if less than default size (16KB).
* The type will be Mixed.
@ -79,7 +79,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
/**
* @return the associated list of Files for the request
*/
private List<HttpData> getList(HttpRequestHeader request) {
private List<HttpData> getList(HttpRequest request) {
List<HttpData> list = requestFileDeleteMap.get(request);
if (list == null) {
list = new ArrayList<HttpData>();
@ -89,7 +89,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
}
@Override
public Attribute createAttribute(HttpRequestHeader request, String name) {
public Attribute createAttribute(HttpRequest request, String name) {
if (useDisk) {
Attribute attribute = new DiskAttribute(name);
List<HttpData> fileToDelete = getList(request);
@ -106,7 +106,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
}
@Override
public Attribute createAttribute(HttpRequestHeader request, String name, String value) {
public Attribute createAttribute(HttpRequest request, String name, String value) {
if (useDisk) {
Attribute attribute;
try {
@ -133,7 +133,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
}
@Override
public FileUpload createFileUpload(HttpRequestHeader request, String name, String filename,
public FileUpload createFileUpload(HttpRequest request, String name, String filename,
String contentType, String contentTransferEncoding, Charset charset,
long size) {
if (useDisk) {
@ -155,7 +155,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
}
@Override
public void removeHttpDataFromClean(HttpRequestHeader request, InterfaceHttpData data) {
public void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data) {
if (data instanceof HttpData) {
List<HttpData> fileToDelete = getList(request);
fileToDelete.remove(data);
@ -163,7 +163,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
}
@Override
public void cleanRequestHttpDatas(HttpRequestHeader request) {
public void cleanRequestHttpDatas(HttpRequest request) {
List<HttpData> fileToDelete = requestFileDeleteMap.remove(request);
if (fileToDelete != null) {
for (HttpData data: fileToDelete) {
@ -175,7 +175,7 @@ public class DefaultHttpDataFactory implements HttpDataFactory {
@Override
public void cleanAllHttpDatas() {
for (HttpRequestHeader request : requestFileDeleteMap.keySet()) {
for (HttpRequest request : requestFileDeleteMap.keySet()) {
List<HttpData> fileToDelete = requestFileDeleteMap.get(request);
if (fileToDelete != null) {
for (HttpData data: fileToDelete) {

View File

@ -15,7 +15,7 @@
*/
package io.netty.handler.codec.http.multipart;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequest;
import java.nio.charset.Charset;
@ -28,20 +28,20 @@ public interface HttpDataFactory {
* @param request associated request
* @return a new Attribute with no value
*/
Attribute createAttribute(HttpRequestHeader request, String name);
Attribute createAttribute(HttpRequest request, String name);
/**
* @param request associated request
* @return a new Attribute
*/
Attribute createAttribute(HttpRequestHeader request, String name, String value);
Attribute createAttribute(HttpRequest request, String name, String value);
/**
* @param request associated request
* @param size the size of the Uploaded file
* @return a new FileUpload
*/
FileUpload createFileUpload(HttpRequestHeader request, String name, String filename,
FileUpload createFileUpload(HttpRequest request, String name, String filename,
String contentType, String contentTransferEncoding, Charset charset,
long size);
@ -50,14 +50,14 @@ public interface HttpDataFactory {
* is still a temporary one as setup at construction)
* @param request associated request
*/
void removeHttpDataFromClean(HttpRequestHeader request, InterfaceHttpData data);
void removeHttpDataFromClean(HttpRequest request, InterfaceHttpData data);
/**
* Remove all InterfaceHttpData from virtual File storage from clean list for the request
*
* @param request associated request
*/
void cleanRequestHttpDatas(HttpRequestHeader request);
void cleanRequestHttpDatas(HttpRequest request);
/**
* Remove all InterfaceHttpData from virtual File storage from clean list for all requests

View File

@ -16,11 +16,11 @@
package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpConstants;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNoBackArrayException;
import io.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize;
@ -50,7 +50,7 @@ public class HttpPostRequestDecoder {
/**
* Request to decode
*/
private final HttpRequestHeader request;
private final HttpRequest request;
/**
* Default charset to use
@ -136,7 +136,7 @@ public class HttpPostRequestDecoder {
* if the default charset was wrong when decoding or other
* errors
*/
public HttpPostRequestDecoder(HttpRequestHeader request) throws ErrorDataDecoderException,
public HttpPostRequestDecoder(HttpRequest request) throws ErrorDataDecoderException,
IncompatibleDataDecoderException {
this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, HttpConstants.DEFAULT_CHARSET);
}
@ -155,7 +155,7 @@ public class HttpPostRequestDecoder {
* if the default charset was wrong when decoding or other
* errors
*/
public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequestHeader request) throws ErrorDataDecoderException,
public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request) throws ErrorDataDecoderException,
IncompatibleDataDecoderException {
this(factory, request, HttpConstants.DEFAULT_CHARSET);
}
@ -176,7 +176,7 @@ public class HttpPostRequestDecoder {
* if the default charset was wrong when decoding or other
* errors
*/
public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequestHeader request, Charset charset)
public HttpPostRequestDecoder(HttpDataFactory factory, HttpRequest request, Charset charset)
throws ErrorDataDecoderException, IncompatibleDataDecoderException {
if (factory == null) {
throw new NullPointerException("factory");
@ -188,15 +188,15 @@ public class HttpPostRequestDecoder {
throw new NullPointerException("charset");
}
this.request = request;
HttpMethod method = request.getMethod();
HttpMethod method = request.method();
if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH)) {
bodyToDecode = true;
}
this.charset = charset;
this.factory = factory;
// Fill default values
if (this.request.containsHeader(HttpHeaders.Names.CONTENT_TYPE)) {
checkMultipart(this.request.getHeader(HttpHeaders.Names.CONTENT_TYPE));
if (this.request.headers().contains(HttpHeaders.Names.CONTENT_TYPE)) {
checkMultipart(this.request.headers().get(HttpHeaders.Names.CONTENT_TYPE));
} else {
isMultipart = false;
}
@ -341,7 +341,7 @@ public class HttpPostRequestDecoder {
* errors
*/
public void offer(HttpContent content) throws ErrorDataDecoderException {
ByteBuf chunked = content.getContent();
ByteBuf chunked = content.data();
if (undecodedChunk == null) {
undecodedChunk = chunked;
} else {

View File

@ -18,11 +18,11 @@ package io.netty.handler.codec.http.multipart;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpConstants;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.stream.ChunkedMessageInput;
import java.io.File;
@ -49,7 +49,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
/**
* Request to encode
*/
private final HttpRequest request;
private final FullHttpRequest request;
/**
* Default charset to use
@ -100,7 +100,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
* @throws ErrorDataEncoderException
* if the request is not a POST
*/
public HttpPostRequestEncoder(HttpRequest request, boolean multipart) throws ErrorDataEncoderException {
public HttpPostRequestEncoder(FullHttpRequest request, boolean multipart) throws ErrorDataEncoderException {
this(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE), request, multipart,
HttpConstants.DEFAULT_CHARSET);
}
@ -118,7 +118,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
* @throws ErrorDataEncoderException
* if the request is not a POST
*/
public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart)
public HttpPostRequestEncoder(HttpDataFactory factory, FullHttpRequest request, boolean multipart)
throws ErrorDataEncoderException {
this(factory, request, multipart, HttpConstants.DEFAULT_CHARSET);
}
@ -138,7 +138,8 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
* @throws ErrorDataEncoderException
* if the request is not a POST
*/
public HttpPostRequestEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset)
public HttpPostRequestEncoder(
HttpDataFactory factory, FullHttpRequest request, boolean multipart, Charset charset)
throws ErrorDataEncoderException {
if (factory == null) {
throw new NullPointerException("factory");
@ -149,7 +150,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
if (charset == null) {
throw new NullPointerException("charset");
}
if (request.getMethod() != HttpMethod.POST) {
if (request.method() != HttpMethod.POST) {
throw new ErrorDataEncoderException("Cannot create a Encoder if not a POST");
}
this.request = request;
@ -598,7 +599,7 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
* @throws ErrorDataEncoderException
* if the encoding is in error or if the finalize were already done
*/
public HttpRequest finalizeRequest() throws ErrorDataEncoderException {
public FullHttpRequest finalizeRequest() throws ErrorDataEncoderException {
// Finalize the multipartHttpDatas
if (!headerFinalized) {
if (isMultipart) {
@ -617,10 +618,10 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
} else {
throw new ErrorDataEncoderException("Header already encoded");
}
List<String> contentTypes = request.getHeaders(HttpHeaders.Names.CONTENT_TYPE);
List<String> transferEncoding = request.getHeaders(HttpHeaders.Names.TRANSFER_ENCODING);
List<String> contentTypes = request.headers().getAll(HttpHeaders.Names.CONTENT_TYPE);
List<String> transferEncoding = request.headers().getAll(HttpHeaders.Names.TRANSFER_ENCODING);
if (contentTypes != null) {
request.removeHeader(HttpHeaders.Names.CONTENT_TYPE);
request.headers().remove(HttpHeaders.Names.CONTENT_TYPE);
for (String contentType : contentTypes) {
// "multipart/form-data; boundary=--89421926422648"
if (contentType.toLowerCase().startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA)) {
@ -628,17 +629,17 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
} else if (contentType.toLowerCase().startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
// ignore
} else {
request.addHeader(HttpHeaders.Names.CONTENT_TYPE, contentType);
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, contentType);
}
}
}
if (isMultipart) {
String value = HttpHeaders.Values.MULTIPART_FORM_DATA + "; " + HttpHeaders.Values.BOUNDARY + '='
+ multipartDataBoundary;
request.addHeader(HttpHeaders.Names.CONTENT_TYPE, value);
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, value);
} else {
// Not multipart
request.addHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
request.headers().add(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
}
// Now consider size for chunk or not
long realSize = globalBodySize;
@ -648,25 +649,25 @@ public class HttpPostRequestEncoder implements ChunkedMessageInput<HttpContent>
realSize -= 1; // last '&' removed
iterator = multipartHttpDatas.listIterator();
}
request.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize));
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(realSize));
if (realSize > HttpPostBodyUtil.chunkSize || isMultipart) {
isChunked = true;
if (transferEncoding != null) {
request.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
request.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
for (String v : transferEncoding) {
if (v.equalsIgnoreCase(HttpHeaders.Values.CHUNKED)) {
// ignore
} else {
request.addHeader(HttpHeaders.Names.TRANSFER_ENCODING, v);
request.headers().add(HttpHeaders.Names.TRANSFER_ENCODING, v);
}
}
}
HttpHeaders.setTransferEncodingChunked(request);
request.setContent(EMPTY_BUFFER);
request.data().clear();
} else {
// get the only one body and set it to the request
HttpContent chunk = nextChunk();
request.setContent(chunk.getContent());
request.data().clear().writeBytes(chunk.data());
}
return request;
}

View File

@ -18,7 +18,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import java.net.URI;
import java.util.Map;
@ -148,5 +148,5 @@ public abstract class WebSocketClientHandshaker {
* @param response
* HTTP response containing the closing handshake details
*/
public abstract void finishHandshake(Channel channel, HttpResponse response);
public abstract void finishHandshake(Channel channel, FullHttpResponse response);
}

View File

@ -15,19 +15,18 @@
*/
package io.netty.handler.codec.http.websocketx;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -142,10 +141,10 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
}
// Format request
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.addHeader(Names.UPGRADE, Values.WEBSOCKET);
request.addHeader(Names.CONNECTION, Values.UPGRADE);
request.addHeader(Names.HOST, wsURL.getHost());
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().add(Names.UPGRADE, Values.WEBSOCKET);
request.headers().add(Names.CONNECTION, Values.UPGRADE);
request.headers().add(Names.HOST, wsURL.getHost());
int wsPort = wsURL.getPort();
String originValue = "http://" + wsURL.getHost();
@ -155,24 +154,24 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
originValue = originValue + ':' + wsPort;
}
request.addHeader(Names.ORIGIN, originValue);
request.addHeader(Names.SEC_WEBSOCKET_KEY1, key1);
request.addHeader(Names.SEC_WEBSOCKET_KEY2, key2);
request.headers().add(Names.ORIGIN, originValue);
request.headers().add(Names.SEC_WEBSOCKET_KEY1, key1);
request.headers().add(Names.SEC_WEBSOCKET_KEY2, key2);
String expectedSubprotocol = getExpectedSubprotocol();
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
}
if (customHeaders != null) {
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
request.headers().add(e.getKey(), e.getValue());
}
}
// Set Content-Length to workaround some known defect.
// See also: http://www.ietf.org/mail-archive/web/hybi/current/msg02149.html
request.setHeader(Names.CONTENT_LENGTH, key3.length);
request.setContent(Unpooled.copiedBuffer(key3));
request.headers().set(Names.CONTENT_LENGTH, key3.length);
request.data().writeBytes(key3);
ChannelFuture future = channel.write(request);
future.addListener(new ChannelFutureListener() {
@ -217,31 +216,31 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void finishHandshake(Channel channel, HttpResponse response) {
public void finishHandshake(Channel channel, FullHttpResponse response) {
final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake");
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
if (!response.status().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
}
String upgrade = response.getHeader(Names.UPGRADE);
String upgrade = response.headers().get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ upgrade);
}
String connection = response.getHeader(Names.CONNECTION);
String connection = response.headers().get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ connection);
}
byte[] challenge = response.getContent().array();
byte[] challenge = response.data().array();
if (!Arrays.equals(challenge, expectedChallengeResponseBytes)) {
throw new WebSocketHandshakeException("Invalid challenge");
}
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
setActualSubprotocol(subprotocol);
setHandshakeComplete();

View File

@ -20,13 +20,13 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -124,11 +124,11 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
}
// Format request
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.addHeader(Names.CONNECTION, Values.UPGRADE);
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
request.addHeader(Names.HOST, wsURL.getHost());
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.headers().add(Names.CONNECTION, Values.UPGRADE);
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
request.headers().add(Names.HOST, wsURL.getHost());
int wsPort = wsURL.getPort();
String originValue = "http://" + wsURL.getHost();
@ -137,18 +137,18 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
// See http://tools.ietf.org/html/rfc6454#section-6.2
originValue = originValue + ':' + wsPort;
}
request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue);
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
String expectedSubprotocol = getExpectedSubprotocol();
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
}
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "7");
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "7");
if (customHeaders != null) {
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
request.headers().add(e.getKey(), e.getValue());
}
}
@ -192,32 +192,32 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void finishHandshake(Channel channel, HttpResponse response) {
public void finishHandshake(Channel channel, FullHttpResponse response) {
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
if (!response.status().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
}
String upgrade = response.getHeader(Names.UPGRADE);
String upgrade = response.headers().get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ response.getHeader(Names.UPGRADE));
+ response.headers().get(Names.UPGRADE));
}
String connection = response.getHeader(Names.CONNECTION);
String connection = response.headers().get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ response.getHeader(Names.CONNECTION));
+ response.headers().get(Names.CONNECTION));
}
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
expectedChallengeResponseString));
}
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
setActualSubprotocol(subprotocol);
setHandshakeComplete();

View File

@ -20,13 +20,13 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -124,11 +124,11 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
}
// Format request
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.addHeader(Names.CONNECTION, Values.UPGRADE);
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
request.addHeader(Names.HOST, wsURL.getHost());
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.headers().add(Names.CONNECTION, Values.UPGRADE);
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
request.headers().add(Names.HOST, wsURL.getHost());
int wsPort = wsURL.getPort();
String originValue = "http://" + wsURL.getHost();
@ -137,18 +137,18 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
// See http://tools.ietf.org/html/rfc6454#section-6.2
originValue = originValue + ':' + wsPort;
}
request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue);
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
String expectedSubprotocol = getExpectedSubprotocol();
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
}
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "8");
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "8");
if (customHeaders != null) {
for (Map.Entry<String, String> e : customHeaders.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
request.headers().add(e.getKey(), e.getValue());
}
}
@ -192,32 +192,32 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void finishHandshake(Channel channel, HttpResponse response) {
public void finishHandshake(Channel channel, FullHttpResponse response) {
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
if (!response.status().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
}
String upgrade = response.getHeader(Names.UPGRADE);
String upgrade = response.headers().get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ response.getHeader(Names.UPGRADE));
+ response.headers().get(Names.UPGRADE));
}
String connection = response.getHeader(Names.CONNECTION);
String connection = response.headers().get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ response.getHeader(Names.CONNECTION));
+ response.headers().get(Names.CONNECTION));
}
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
expectedChallengeResponseString));
}
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
setActualSubprotocol(subprotocol);
setHandshakeComplete();

View File

@ -20,13 +20,13 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpRequestHeader;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -124,11 +124,11 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
}
// Format request
HttpRequestHeader request = new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.addHeader(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.addHeader(Names.CONNECTION, Values.UPGRADE);
request.addHeader(Names.SEC_WEBSOCKET_KEY, key);
request.addHeader(Names.HOST, wsURL.getHost());
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, path);
request.headers().add(Names.UPGRADE, Values.WEBSOCKET.toLowerCase());
request.headers().add(Names.CONNECTION, Values.UPGRADE);
request.headers().add(Names.SEC_WEBSOCKET_KEY, key);
request.headers().add(Names.HOST, wsURL.getHost());
int wsPort = wsURL.getPort();
String originValue = "http://" + wsURL.getHost();
@ -137,18 +137,18 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
// See http://tools.ietf.org/html/rfc6454#section-6.2
originValue = originValue + ':' + wsPort;
}
request.addHeader(Names.SEC_WEBSOCKET_ORIGIN, originValue);
request.headers().add(Names.SEC_WEBSOCKET_ORIGIN, originValue);
String expectedSubprotocol = getExpectedSubprotocol();
if (expectedSubprotocol != null && !expectedSubprotocol.isEmpty()) {
request.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
request.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, expectedSubprotocol);
}
request.addHeader(Names.SEC_WEBSOCKET_VERSION, "13");
request.headers().add(Names.SEC_WEBSOCKET_VERSION, "13");
if (customHeaders != null) {
for (Map.Entry<String, String> e: customHeaders.entrySet()) {
request.addHeader(e.getKey(), e.getValue());
request.headers().add(e.getKey(), e.getValue());
}
}
@ -191,32 +191,32 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
* @throws WebSocketHandshakeException
*/
@Override
public void finishHandshake(Channel channel, HttpResponse response) {
public void finishHandshake(Channel channel, FullHttpResponse response) {
final HttpResponseStatus status = HttpResponseStatus.SWITCHING_PROTOCOLS;
if (!response.getStatus().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.getStatus());
if (!response.status().equals(status)) {
throw new WebSocketHandshakeException("Invalid handshake response status: " + response.status());
}
String upgrade = response.getHeader(Names.UPGRADE);
String upgrade = response.headers().get(Names.UPGRADE);
if (!Values.WEBSOCKET.equalsIgnoreCase(upgrade)) {
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
+ response.getHeader(Names.UPGRADE));
+ response.headers().get(Names.UPGRADE));
}
String connection = response.getHeader(Names.CONNECTION);
String connection = response.headers().get(Names.CONNECTION);
if (!Values.UPGRADE.equalsIgnoreCase(connection)) {
throw new WebSocketHandshakeException("Invalid handshake response connection: "
+ response.getHeader(Names.CONNECTION));
+ response.headers().get(Names.CONNECTION));
}
String accept = response.getHeader(Names.SEC_WEBSOCKET_ACCEPT);
String accept = response.headers().get(Names.SEC_WEBSOCKET_ACCEPT);
if (accept == null || !accept.equals(expectedChallengeResponseString)) {
throw new WebSocketHandshakeException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept,
expectedChallengeResponseString));
}
String subprotocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
String subprotocol = response.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
setActualSubprotocol(subprotocol);
setHandshakeComplete();

View File

@ -18,7 +18,7 @@ package io.netty.handler.codec.http.websocketx;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.util.internal.StringUtil;
import java.util.Collections;
@ -112,7 +112,7 @@ public abstract class WebSocketServerHandshaker {
* @param req
* HTTP Request
*/
public ChannelFuture handshake(Channel channel, HttpRequest req) {
public ChannelFuture handshake(Channel channel, FullHttpRequest req) {
if (channel == null) {
throw new NullPointerException("channel");
}
@ -129,7 +129,7 @@ public abstract class WebSocketServerHandshaker {
* @param promise
* the {@link ChannelPromise} to be notified when the opening handshake is done
*/
public abstract ChannelFuture handshake(Channel channel, HttpRequest req, ChannelPromise promise);
public abstract ChannelFuture handshake(Channel channel, FullHttpRequest req, ChannelPromise promise);
/**
* Performs the closing handshake

View File

@ -22,13 +22,13 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.logging.InternalLogger;
@ -119,64 +119,63 @@ public class WebSocketServerHandshaker00 extends WebSocketServerHandshaker {
* HTTP request
*/
@Override
public ChannelFuture handshake(Channel channel, HttpRequest req, ChannelPromise promise) {
public ChannelFuture handshake(Channel channel, FullHttpRequest req, ChannelPromise promise) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 00 server handshake", channel.id()));
}
// Serve the WebSocket handshake request.
if (!Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
|| !WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {
if (!Values.UPGRADE.equalsIgnoreCase(req.headers().get(CONNECTION))
|| !WEBSOCKET.equalsIgnoreCase(req.headers().get(Names.UPGRADE))) {
throw new WebSocketHandshakeException("not a WebSocket handshake request: missing upgrade");
}
// Hixie 75 does not contain these headers while Hixie 76 does
boolean isHixie76 = req.containsHeader(SEC_WEBSOCKET_KEY1) && req.containsHeader(SEC_WEBSOCKET_KEY2);
boolean isHixie76 = req.headers().contains(SEC_WEBSOCKET_KEY1) && req.headers().contains(SEC_WEBSOCKET_KEY2);
// Create the WebSocket handshake response.
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, new HttpResponseStatus(101,
isHixie76 ? "WebSocket Protocol Handshake" : "Web Socket Protocol Handshake"));
res.addHeader(Names.UPGRADE, WEBSOCKET);
res.addHeader(CONNECTION, Values.UPGRADE);
res.headers().add(Names.UPGRADE, WEBSOCKET);
res.headers().add(CONNECTION, Values.UPGRADE);
// Fill in the headers and contents depending on handshake method.
if (isHixie76) {
// New handshake method with a challenge:
res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
String subprotocols = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
res.headers().add(SEC_WEBSOCKET_ORIGIN, req.headers().get(ORIGIN));
res.headers().add(SEC_WEBSOCKET_LOCATION, getWebSocketUrl());
String subprotocols = req.headers().get(SEC_WEBSOCKET_PROTOCOL);
if (subprotocols != null) {
String selectedSubprotocol = selectSubprotocol(subprotocols);
if (selectedSubprotocol == null) {
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
} else {
res.addHeader(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().add(SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
setSelectedSubprotocol(selectedSubprotocol);
}
}
// Calculate the answer of the challenge.
String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
String key1 = req.headers().get(SEC_WEBSOCKET_KEY1);
String key2 = req.headers().get(SEC_WEBSOCKET_KEY2);
int a = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key1).replaceAll("")) /
BEGINNING_SPACE.matcher(key1).replaceAll("").length());
int b = (int) (Long.parseLong(BEGINNING_DIGIT.matcher(key2).replaceAll("")) /
BEGINNING_SPACE.matcher(key2).replaceAll("").length());
long c = req.getContent().readLong();
long c = req.data().readLong();
ByteBuf input = Unpooled.buffer(16);
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ByteBuf output = Unpooled.wrappedBuffer(WebSocketUtil.md5(input.array()));
res.setContent(output);
res.data().writeBytes(WebSocketUtil.md5(input.array()));
} else {
// Old Hixie 75 handshake method with no challenge:
res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
res.addHeader(WEBSOCKET_LOCATION, getWebSocketUrl());
String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
res.headers().add(WEBSOCKET_ORIGIN, req.headers().get(ORIGIN));
res.headers().add(WEBSOCKET_LOCATION, getWebSocketUrl());
String protocol = req.headers().get(WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
res.headers().add(WEBSOCKET_PROTOCOL, selectSubprotocol(protocol));
}
}

View File

@ -20,12 +20,12 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.logging.InternalLogger;
@ -109,15 +109,16 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
* HTTP request
*/
@Override
public ChannelFuture handshake(Channel channel, HttpRequest req, ChannelPromise promise) {
public ChannelFuture handshake(Channel channel, FullHttpRequest req, ChannelPromise promise) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 7 server handshake", channel.id()));
}
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
FullHttpResponse res =
new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
if (key == null) {
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
}
@ -129,17 +130,16 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 7 Server Handshake key: %s. Response: %s.", key, accept));
}
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.addHeader(Names.CONNECTION, Names.UPGRADE);
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
if (subprotocols != null) {
String selectedSubprotocol = selectSubprotocol(subprotocols);
if (selectedSubprotocol == null) {
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
} else {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
setSelectedSubprotocol(selectedSubprotocol);
}
}

View File

@ -20,12 +20,12 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpResponseHeader;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.logging.InternalLogger;
@ -110,15 +110,15 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
* HTTP request
*/
@Override
public ChannelFuture handshake(Channel channel, HttpRequest req, ChannelPromise promise) {
public ChannelFuture handshake(Channel channel, FullHttpRequest req, ChannelPromise promise) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 8 server handshake", channel.id()));
}
HttpResponseHeader res = new DefaultHttpResponseHeader(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
if (key == null) {
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
}
@ -130,17 +130,16 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 8 Server Handshake key: %s. Response: %s.", key, accept));
}
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.addHeader(Names.CONNECTION, Names.UPGRADE);
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
if (subprotocols != null) {
String selectedSubprotocol = selectSubprotocol(subprotocols);
if (selectedSubprotocol == null) {
throw new WebSocketHandshakeException("Requested subprotocol(s) not supported: " + subprotocols);
} else {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
setSelectedSubprotocol(selectedSubprotocol);
}
}

View File

@ -20,12 +20,12 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.DefaultHttpResponseHeader;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.logging.InternalLogger;
@ -109,15 +109,15 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
* HTTP request
*/
@Override
public ChannelFuture handshake(Channel channel, HttpRequest req, ChannelPromise promise) {
public ChannelFuture handshake(Channel channel, FullHttpRequest req, ChannelPromise promise) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Channel %s WS Version 13 server handshake", channel.id()));
}
HttpResponseHeader res = new DefaultHttpResponseHeader(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.SWITCHING_PROTOCOLS);
String key = req.getHeader(Names.SEC_WEBSOCKET_KEY);
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
if (key == null) {
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
}
@ -129,18 +129,17 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
logger.debug(String.format("WS Version 13 Server Handshake key: %s. Response: %s.", key, accept));
}
res.setStatus(HttpResponseStatus.SWITCHING_PROTOCOLS);
res.addHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.addHeader(Names.CONNECTION, Names.UPGRADE);
res.addHeader(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
res.headers().add(Names.UPGRADE, WEBSOCKET.toLowerCase());
res.headers().add(Names.CONNECTION, Names.UPGRADE);
res.headers().add(Names.SEC_WEBSOCKET_ACCEPT, accept);
String subprotocols = req.headers().get(Names.SEC_WEBSOCKET_PROTOCOL);
if (subprotocols != null) {
String selectedSubprotocol = selectSubprotocol(subprotocols);
if (selectedSubprotocol == null) {
throw new WebSocketHandshakeException(
"Requested subprotocol(s) not supported: " + subprotocols);
} else {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
res.headers().add(Names.SEC_WEBSOCKET_PROTOCOL, selectedSubprotocol);
setSelectedSubprotocol(selectedSubprotocol);
}
}

View File

@ -16,10 +16,10 @@
package io.netty.handler.codec.http.websocketx;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.DefaultHttpResponseHeader;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -81,9 +81,9 @@ public class WebSocketServerHandshakerFactory {
* @return A new WebSocketServerHandshaker for the requested web socket version. Null if web
* socket version is not supported.
*/
public WebSocketServerHandshaker newHandshaker(HttpRequestHeader req) {
public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
String version = req.getHeader(Names.SEC_WEBSOCKET_VERSION);
String version = req.headers().get(Names.SEC_WEBSOCKET_VERSION);
if (version != null) {
if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
// Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification).
@ -113,11 +113,10 @@ public class WebSocketServerHandshakerFactory {
* Channel
*/
public static void sendUnsupportedWebSocketVersionResponse(Channel channel) {
HttpResponseHeader res = new DefaultHttpResponseHeader(
HttpResponse res = new DefaultHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.SWITCHING_PROTOCOLS);
res.setStatus(HttpResponseStatus.UPGRADE_REQUIRED);
res.setHeader(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
HttpResponseStatus.UPGRADE_REQUIRED);
res.headers().set(Names.SEC_WEBSOCKET_VERSION, WebSocketVersion.V13.toHttpHeaderValue());
channel.write(res);
}
}

View File

@ -21,8 +21,8 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.AttributeKey;
@ -92,8 +92,8 @@ public class WebSocketServerProtocolHandler extends ChannelInboundMessageHandler
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof WebSocketHandshakeException) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
response.setContent(Unpooled.wrappedBuffer(cause.getMessage().getBytes()));
FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.wrappedBuffer(cause.getMessage().getBytes()));
ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
} else {
ctx.close();
@ -113,7 +113,8 @@ public class WebSocketServerProtocolHandler extends ChannelInboundMessageHandler
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof WebSocketFrame)) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN);
FullHttpResponse response =
new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN);
ctx.channel().write(response);
} else {
ctx.nextInboundMessageBuffer().add(msg);

View File

@ -15,26 +15,28 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.ssl.SslHandler;
import static io.netty.handler.codec.http.HttpHeaders.*;
import static io.netty.handler.codec.http.HttpMethod.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
/**
* Handles the HTTP handshake (the HTTP Upgrade request) for {@link WebSocketServerProtocolHandler}.
*/
public class WebSocketServerProtocolHandshakeHandler extends ChannelInboundMessageHandlerAdapter<HttpRequest> {
public class WebSocketServerProtocolHandshakeHandler
extends ChannelInboundMessageHandlerAdapter<FullHttpRequest> {
private final String websocketPath;
private final String subprotocols;
@ -48,9 +50,9 @@ public class WebSocketServerProtocolHandshakeHandler extends ChannelInboundMessa
}
@Override
public void messageReceived(final ChannelHandlerContext ctx, HttpRequest req) throws Exception {
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
public void messageReceived(final ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
@ -75,20 +77,20 @@ public class WebSocketServerProtocolHandshakeHandler extends ChannelInboundMessa
}
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequestHeader req, HttpResponseHeader res) {
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
if (!isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
private static String getWebSocketLocation(ChannelPipeline cp, HttpRequestHeader req, String path) {
private static String getWebSocketLocation(ChannelPipeline cp, HttpRequest req, String path) {
String protocol = "ws";
if (cp.get(SslHandler.class) != null) {
// SSL in use so use Secure WebSockets
protocol = "wss";
}
return protocol + "://" + req.getHeader(HttpHeaders.Names.HOST) + path;
return protocol + "://" + req.headers().get(HttpHeaders.Names.HOST) + path;
}
}

View File

@ -19,13 +19,13 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpObjectDecoder;
/**
* Decodes {@link ByteBuf}s into RTSP messages represented in
* {@link io.netty.handler.codec.http.HttpHeader}s.
* {@link io.netty.handler.codec.http.HttpMessage}s.
* <p>
* <h3>Parameters that prevents excessive memory consumption</h3>
* <table border="1">
@ -84,14 +84,14 @@ public abstract class RtspObjectDecoder extends HttpObjectDecoder {
}
@Override
protected boolean isContentAlwaysEmpty(HttpHeader msg) {
protected boolean isContentAlwaysEmpty(HttpMessage msg) {
// Unlike HTTP, RTSP always assumes zero-length body if Content-Length
// header is absent.
boolean empty = super.isContentAlwaysEmpty(msg);
if (empty) {
return true;
}
if (!msg.containsHeader(RtspHeaders.Names.CONTENT_LENGTH)) {
if (!msg.headers().contains(RtspHeaders.Names.CONTENT_LENGTH)) {
return true;
}
return empty;

View File

@ -17,20 +17,19 @@ package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpObjectEncoder;
/**
* Encodes an RTSP message represented in {@link HttpHeader} into
* Encodes an RTSP message represented in {@link FullHttpMessage} into
* a {@link ByteBuf}.
*
* @apiviz.landmark
*/
@Sharable
public abstract class RtspObjectEncoder<H extends HttpHeader> extends HttpObjectEncoder<H> {
public abstract class RtspObjectEncoder<H extends HttpMessage> extends HttpObjectEncoder<H> {
/**
* Creates a new instance.
@ -39,13 +38,7 @@ public abstract class RtspObjectEncoder<H extends HttpHeader> extends HttpObject
}
@Override
protected void encode(ChannelHandlerContext ctx, Object msg,
ByteBuf out) throws Exception {
// Ignore unrelated message types such as HttpChunk.
if (!(msg instanceof HttpHeader)) {
throw new UnsupportedMessageTypeException(msg, HttpHeader.class);
}
super.encode(ctx, msg, out);
public boolean isEncodable(Object msg) throws Exception {
return msg instanceof FullHttpMessage;
}
}

View File

@ -17,12 +17,12 @@ package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.handler.codec.http.DefaultHttpRequestHeader;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpMessage;
/**
* Decodes {@link ByteBuf}s into RTSP requests represented in
* {@link io.netty.handler.codec.http.HttpRequestHeader}s.
* {@link io.netty.handler.codec.http.HttpRequest}s.
* <p>
* <h3>Parameters that prevents excessive memory consumption</h3>
* <table border="1">
@ -65,14 +65,14 @@ public class RtspRequestDecoder extends RtspObjectDecoder {
}
@Override
protected HttpHeader createMessage(String[] initialLine) throws Exception {
return new DefaultHttpRequestHeader(RtspVersions.valueOf(initialLine[2]),
protected HttpMessage createMessage(String[] initialLine) throws Exception {
return new DefaultHttpRequest(RtspVersions.valueOf(initialLine[2]),
RtspMethods.valueOf(initialLine[0]), initialLine[1]);
}
@Override
protected HttpHeader createInvalidMessage() {
return new DefaultHttpRequestHeader(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, "/bad-request");
protected HttpMessage createInvalidMessage() {
return new DefaultHttpRequest(RtspVersions.RTSP_1_0, RtspMethods.OPTIONS, "/bad-request");
}
@Override

View File

@ -16,24 +16,30 @@
package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.CharsetUtil;
/**
* Encodes an RTSP request represented in {@link HttpRequestHeader} into
* Encodes an RTSP request represented in {@link FullHttpRequest} into
* a {@link ByteBuf}.
*/
public class RtspRequestEncoder extends RtspObjectEncoder<HttpRequestHeader> {
public class RtspRequestEncoder extends RtspObjectEncoder<HttpRequest> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequestHeader request)
public boolean isEncodable(Object msg) throws Exception {
return msg instanceof FullHttpRequest;
}
@Override
protected void encodeInitialLine(ByteBuf buf, HttpRequest request)
throws Exception {
buf.writeBytes(request.getMethod().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(request.method().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte((byte) ' ');
buf.writeBytes(request.getUri().getBytes(CharsetUtil.UTF_8));
buf.writeBytes(request.uri().getBytes(CharsetUtil.UTF_8));
buf.writeByte((byte) ' ');
buf.writeBytes(request.getProtocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(request.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte((byte) '\r');
buf.writeByte((byte) '\n');
}

View File

@ -17,13 +17,13 @@ package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.handler.codec.http.DefaultHttpResponseHeader;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpResponseStatus;
/**
* Decodes {@link ByteBuf}s into RTSP responses represented in
* {@link io.netty.handler.codec.http.HttpResponseHeader}s.
* {@link io.netty.handler.codec.http.HttpResponse}s.
* <p>
* <h3>Parameters that prevents excessive memory consumption</h3>
* <table border="1">
@ -69,15 +69,15 @@ public class RtspResponseDecoder extends RtspObjectDecoder {
}
@Override
protected HttpHeader createMessage(String[] initialLine) throws Exception {
return new DefaultHttpResponseHeader(
protected HttpMessage createMessage(String[] initialLine) throws Exception {
return new DefaultHttpResponse(
RtspVersions.valueOf(initialLine[0]),
new HttpResponseStatus(Integer.valueOf(initialLine[1]), initialLine[2]));
}
@Override
protected HttpHeader createInvalidMessage() {
return new DefaultHttpResponseHeader(RtspVersions.RTSP_1_0, UNKNOWN_STATUS);
protected HttpMessage createInvalidMessage() {
return new DefaultHttpResponse(RtspVersions.RTSP_1_0, UNKNOWN_STATUS);
}
@Override

View File

@ -16,25 +16,30 @@
package io.netty.handler.codec.rtsp;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.CharsetUtil;
/**
* Encodes an RTSP response represented in {@link HttpResponseHeader} into
* Encodes an RTSP response represented in {@link FullHttpResponse} into
* a {@link ByteBuf}.
*/
public class RtspResponseEncoder extends RtspObjectEncoder<HttpResponseHeader> {
public class RtspResponseEncoder extends RtspObjectEncoder<HttpResponse> {
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponseHeader response)
public boolean isEncodable(Object msg) throws Exception {
return msg instanceof FullHttpResponse;
}
@Override
protected void encodeInitialLine(ByteBuf buf, HttpResponse response)
throws Exception {
buf.writeBytes(response.getProtocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(response.protocolVersion().toString().getBytes(CharsetUtil.US_ASCII));
buf.writeByte((byte) ' ');
buf.writeBytes(String.valueOf(response.getStatus().getCode()).getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(String.valueOf(response.status().code()).getBytes(CharsetUtil.US_ASCII));
buf.writeByte((byte) ' ');
buf.writeBytes(String.valueOf(response.getStatus().getReasonPhrase()).getBytes(CharsetUtil.US_ASCII));
buf.writeBytes(String.valueOf(response.status().reasonPhrase()).getBytes(CharsetUtil.US_ASCII));
buf.writeByte((byte) '\r');
buf.writeByte((byte) '\n');
}

View File

@ -196,9 +196,9 @@ public class SpdyHeaders {
*/
public static void setMethod(int spdyVersion, SpdyHeaderBlock block, HttpMethod method) {
if (spdyVersion < 3) {
block.setHeader(Spdy2HttpNames.METHOD, method.getName());
block.setHeader(Spdy2HttpNames.METHOD, method.name());
} else {
block.setHeader(HttpNames.METHOD, method.getName());
block.setHeader(HttpNames.METHOD, method.name());
}
}
@ -264,7 +264,7 @@ public class SpdyHeaders {
int code = Integer.parseInt(status.substring(0, space));
String reasonPhrase = status.substring(space + 1);
HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(code);
if (responseStatus.getReasonPhrase().equals(reasonPhrase)) {
if (responseStatus.reasonPhrase().equals(reasonPhrase)) {
return responseStatus;
} else {
return new HttpResponseStatus(code, reasonPhrase);

View File

@ -16,18 +16,17 @@
package io.netty.handler.codec.spdy;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpMessage;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@ -36,13 +35,13 @@ import java.util.Map;
/**
* Decodes {@link SpdySynStreamFrame}s, {@link SpdySynReplyFrame}s,
* and {@link SpdyDataFrame}s into {@link HttpRequest}s and {@link HttpResponse}s.
* and {@link SpdyDataFrame}s into {@link FullHttpRequest}s and {@link FullHttpResponse}s.
*/
public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
private final int spdyVersion;
private final int maxContentLength;
private final Map<Integer, HttpMessage> messageMap = new HashMap<Integer, HttpMessage>();
private final Map<Integer, FullHttpMessage> messageMap = new HashMap<Integer, FullHttpMessage>();
/**
* Creates a new instance.
@ -98,20 +97,21 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
}
try {
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynStreamFrame);
FullHttpResponse httpResponseWithEntity =
createHttpResponse(spdyVersion, spdySynStreamFrame);
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
SpdyHttpHeaders.setStreamId(httpResponse, streamID);
SpdyHttpHeaders.setAssociatedToStreamId(httpResponse, associatedToStreamId);
SpdyHttpHeaders.setPriority(httpResponse, spdySynStreamFrame.getPriority());
SpdyHttpHeaders.setUrl(httpResponse, URL);
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamID);
SpdyHttpHeaders.setAssociatedToStreamId(httpResponseWithEntity, associatedToStreamId);
SpdyHttpHeaders.setPriority(httpResponseWithEntity, spdySynStreamFrame.getPriority());
SpdyHttpHeaders.setUrl(httpResponseWithEntity, URL);
if (spdySynStreamFrame.isLast()) {
HttpHeaders.setContentLength(httpResponse, 0);
return httpResponse;
HttpHeaders.setContentLength(httpResponseWithEntity, 0);
return httpResponseWithEntity;
} else {
// Response body will follow in a series of Data Frames
messageMap.put(Integer.valueOf(streamID), httpResponse);
messageMap.put(Integer.valueOf(streamID), httpResponseWithEntity);
}
} catch (Exception e) {
SpdyRstStreamFrame spdyRstStreamFrame =
@ -121,16 +121,16 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
} else {
// SYN_STREAM frames initiated by the client are HTTP requests
try {
HttpRequest httpRequest = createHttpRequest(spdyVersion, spdySynStreamFrame);
FullHttpRequest httpRequestWithEntity = createHttpRequest(spdyVersion, spdySynStreamFrame);
// Set the Stream-ID as a header
SpdyHttpHeaders.setStreamId(httpRequest, streamID);
SpdyHttpHeaders.setStreamId(httpRequestWithEntity, streamID);
if (spdySynStreamFrame.isLast()) {
return httpRequest;
return httpRequestWithEntity;
} else {
// Request body will follow in a series of Data Frames
messageMap.put(Integer.valueOf(streamID), httpRequest);
messageMap.put(Integer.valueOf(streamID), httpRequestWithEntity);
}
} catch (Exception e) {
// If a client sends a SYN_STREAM without all of the method, url (host and path),
@ -150,17 +150,17 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
int streamID = spdySynReplyFrame.getStreamId();
try {
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynReplyFrame);
FullHttpResponse httpResponseWithEntity = createHttpResponse(spdyVersion, spdySynReplyFrame);
// Set the Stream-ID as a header
SpdyHttpHeaders.setStreamId(httpResponse, streamID);
SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamID);
if (spdySynReplyFrame.isLast()) {
HttpHeaders.setContentLength(httpResponse, 0);
return httpResponse;
HttpHeaders.setContentLength(httpResponseWithEntity, 0);
return httpResponseWithEntity;
} else {
// Response body will follow in a series of Data Frames
messageMap.put(Integer.valueOf(streamID), httpResponse);
messageMap.put(Integer.valueOf(streamID), httpResponseWithEntity);
}
} catch (Exception e) {
// If a client receives a SYN_REPLY without valid status and version headers
@ -174,7 +174,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
Integer streamID = Integer.valueOf(spdyHeadersFrame.getStreamId());
HttpHeader httpMessage = messageMap.get(streamID);
HttpMessage httpMessage = messageMap.get(streamID);
// If message is not in map discard HEADERS frame.
// SpdySessionHandler should prevent this from happening.
@ -183,22 +183,22 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
}
for (Map.Entry<String, String> e: spdyHeadersFrame.getHeaders()) {
httpMessage.addHeader(e.getKey(), e.getValue());
httpMessage.headers().add(e.getKey(), e.getValue());
}
} else if (msg instanceof SpdyDataFrame) {
SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
Integer streamID = Integer.valueOf(spdyDataFrame.getStreamId());
HttpMessage httpMessage = messageMap.get(streamID);
FullHttpMessage fullHttpMessage = messageMap.get(streamID);
// If message is not in map discard Data Frame.
// SpdySessionHandler should prevent this from happening.
if (httpMessage == null) {
if (fullHttpMessage == null) {
return null;
}
ByteBuf content = httpMessage.getContent();
ByteBuf content = fullHttpMessage.data();
if (content.readableBytes() > maxContentLength - spdyDataFrame.getData().readableBytes()) {
messageMap.remove(streamID);
throw new TooLongFrameException(
@ -207,18 +207,12 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
ByteBuf spdyDataFrameData = spdyDataFrame.getData();
int spdyDataFrameDataLen = spdyDataFrameData.readableBytes();
if (content == Unpooled.EMPTY_BUFFER) {
content = Unpooled.buffer(spdyDataFrameDataLen);
content.writeBytes(spdyDataFrameData, spdyDataFrameData.readerIndex(), spdyDataFrameDataLen);
httpMessage.setContent(content);
} else {
content.writeBytes(spdyDataFrameData, spdyDataFrameData.readerIndex(), spdyDataFrameDataLen);
}
content.writeBytes(spdyDataFrameData, spdyDataFrameData.readerIndex(), spdyDataFrameDataLen);
if (spdyDataFrame.isLast()) {
HttpHeaders.setContentLength(httpMessage, content.readableBytes());
HttpHeaders.setContentLength(fullHttpMessage, content.readableBytes());
messageMap.remove(streamID);
return httpMessage;
return fullHttpMessage;
}
} else if (msg instanceof SpdyRstStreamFrame) {
@ -231,7 +225,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
return null;
}
private static HttpRequest createHttpRequest(int spdyVersion, SpdyHeaderBlock requestFrame)
private static FullHttpRequest createHttpRequest(int spdyVersion, SpdyHeaderBlock requestFrame)
throws Exception {
// Create the first line of the request from the name/value pairs
HttpMethod method = SpdyHeaders.getMethod(spdyVersion, requestFrame);
@ -241,7 +235,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
SpdyHeaders.removeUrl(spdyVersion, requestFrame);
SpdyHeaders.removeVersion(spdyVersion, requestFrame);
HttpRequest httpRequest = new DefaultHttpRequest(httpVersion, method, url);
FullHttpRequest httpRequestWithEntity = new DefaultFullHttpRequest(httpVersion, method, url);
// Remove the scheme header
SpdyHeaders.removeScheme(spdyVersion, requestFrame);
@ -250,23 +244,23 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
// Replace the SPDY host header with the HTTP host header
String host = SpdyHeaders.getHost(requestFrame);
SpdyHeaders.removeHost(requestFrame);
HttpHeaders.setHost(httpRequest, host);
HttpHeaders.setHost(httpRequestWithEntity, host);
}
for (Map.Entry<String, String> e: requestFrame.getHeaders()) {
httpRequest.addHeader(e.getKey(), e.getValue());
httpRequestWithEntity.headers().add(e.getKey(), e.getValue());
}
// The Connection and Keep-Alive headers are no longer valid
HttpHeaders.setKeepAlive(httpRequest, true);
HttpHeaders.setKeepAlive(httpRequestWithEntity, true);
// Transfer-Encoding header is not valid
httpRequest.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
httpRequestWithEntity.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
return httpRequest;
return httpRequestWithEntity;
}
private static HttpResponse createHttpResponse(int spdyVersion, SpdyHeaderBlock responseFrame)
private static FullHttpResponse createHttpResponse(int spdyVersion, SpdyHeaderBlock responseFrame)
throws Exception {
// Create the first line of the response from the name/value pairs
HttpResponseStatus status = SpdyHeaders.getStatus(spdyVersion, responseFrame);
@ -274,18 +268,18 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
SpdyHeaders.removeStatus(spdyVersion, responseFrame);
SpdyHeaders.removeVersion(spdyVersion, responseFrame);
HttpResponse httpResponse = new DefaultHttpResponse(version, status);
FullHttpResponse httpResponseWithEntity = new DefaultFullHttpResponse(version, status);
for (Map.Entry<String, String> e: responseFrame.getHeaders()) {
httpResponse.addHeader(e.getKey(), e.getValue());
httpResponseWithEntity.headers().add(e.getKey(), e.getValue());
}
// The Connection and Keep-Alive headers are no longer valid
HttpHeaders.setKeepAlive(httpResponse, true);
HttpHeaders.setKeepAlive(httpResponseWithEntity, true);
// Transfer-Encoding header is not valid
httpResponse.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
httpResponse.removeHeader(HttpHeaders.Names.TRAILER);
httpResponseWithEntity.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
httpResponseWithEntity.headers().remove(HttpHeaders.Names.TRAILER);
return httpResponse;
return httpResponseWithEntity;
}
}

View File

@ -18,26 +18,26 @@ package io.netty.handler.codec.spdy;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.handler.codec.UnsupportedMessageTypeException;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Encodes {@link HttpRequestHeader}s, {@link HttpResponseHeader}s, and {@link HttpContent}s
* Encodes {@link HttpRequest}s, {@link HttpResponse}s, and {@link HttpContent}s
* into {@link SpdySynStreamFrame}s and {@link SpdySynReplyFrame}s.
*
* <h3>Request Annotations</h3>
*
* SPDY specific headers must be added to {@link HttpRequestHeader}s:
* SPDY specific headers must be added to {@link HttpRequest}s:
* <table border=1>
* <tr>
* <th>Header Name</th><th>Header Value</th>
@ -58,7 +58,7 @@ import java.util.Map;
*
* <h3>Response Annotations</h3>
*
* SPDY specific headers must be added to {@link HttpResponseHeader}s:
* SPDY specific headers must be added to {@link HttpResponse}s:
* <table border=1>
* <tr>
* <th>Header Name</th><th>Header Value</th>
@ -71,7 +71,7 @@ import java.util.Map;
*
* <h3>Pushed Resource Annotations</h3>
*
* SPDY specific headers must be added to pushed {@link HttpResponseHeader}s:
* SPDY specific headers must be added to pushed {@link HttpResponse}s:
* <table border=1>
* <tr>
* <th>Header Name</th><th>Header Value</th>
@ -112,8 +112,8 @@ import java.util.Map;
* <h3>Chunked Content</h3>
*
* This encoder associates all {@link HttpContent}s that it receives
* with the most recently received 'chunked' {@link HttpRequestHeader}
* or {@link HttpResponseHeader}.
* with the most recently received 'chunked' {@link HttpRequest}
* or {@link HttpResponse}.
*
* <h3>Pushed Resources</h3>
*
@ -144,16 +144,16 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
public Object encode(ChannelHandlerContext ctx, Object msg) throws Exception {
List<Object> out = new ArrayList<Object>();
if (msg instanceof HttpRequestHeader) {
if (msg instanceof HttpRequest) {
HttpRequestHeader httpRequest = (HttpRequestHeader) msg;
HttpRequest httpRequest = (HttpRequest) msg;
SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpRequest);
out.add(spdySynStreamFrame);
}
if (msg instanceof HttpResponseHeader) {
if (msg instanceof HttpResponse) {
HttpResponseHeader httpResponse = (HttpResponseHeader) msg;
if (httpResponse.containsHeader(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) {
HttpResponse httpResponse = (HttpResponse) msg;
if (httpResponse.headers().contains(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) {
SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpResponse);
out.add(spdySynStreamFrame);
} else {
@ -165,12 +165,12 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
HttpContent chunk = (HttpContent) msg;
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(currentStreamId);
spdyDataFrame.setData(chunk.getContent());
spdyDataFrame.setData(chunk.data());
spdyDataFrame.setLast(chunk instanceof LastHttpContent);
if (chunk instanceof LastHttpContent) {
LastHttpContent trailer = (LastHttpContent) chunk;
List<Map.Entry<String, String>> trailers = trailer.getHeaders();
List<Map.Entry<String, String>> trailers = trailer.trailingHeaders().entries();
if (trailers.isEmpty()) {
out.add(spdyDataFrame);
} else {
@ -194,7 +194,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
return out.toArray();
}
private SpdySynStreamFrame createSynStreamFrame(HttpHeader httpMessage)
private SpdySynStreamFrame createSynStreamFrame(HttpMessage httpMessage)
throws Exception {
// Get the Stream-ID, Associated-To-Stream-ID, Priority, URL, and scheme from the headers
int streamID = SpdyHttpHeaders.getStreamId(httpMessage);
@ -210,33 +210,33 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
// headers are not valid and MUST not be sent.
httpMessage.removeHeader(HttpHeaders.Names.CONNECTION);
httpMessage.removeHeader("Keep-Alive");
httpMessage.removeHeader("Proxy-Connection");
httpMessage.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
httpMessage.headers().remove(HttpHeaders.Names.CONNECTION);
httpMessage.headers().remove("Keep-Alive");
httpMessage.headers().remove("Proxy-Connection");
httpMessage.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
SpdySynStreamFrame spdySynStreamFrame =
new DefaultSpdySynStreamFrame(streamID, associatedToStreamId, priority);
// Unfold the first line of the message into name/value pairs
if (httpMessage instanceof HttpRequest) {
HttpRequestHeader httpRequest = (HttpRequestHeader) httpMessage;
SpdyHeaders.setMethod(spdyVersion, spdySynStreamFrame, httpRequest.getMethod());
SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, httpRequest.getUri());
SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.getProtocolVersion());
if (httpMessage instanceof FullHttpRequest) {
HttpRequest httpRequest = (HttpRequest) httpMessage;
SpdyHeaders.setMethod(spdyVersion, spdySynStreamFrame, httpRequest.method());
SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, httpRequest.uri());
SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.protocolVersion());
}
if (httpMessage instanceof HttpResponseHeader) {
HttpResponseHeader httpResponse = (HttpResponseHeader) httpMessage;
SpdyHeaders.setStatus(spdyVersion, spdySynStreamFrame, httpResponse.getStatus());
if (httpMessage instanceof HttpResponse) {
HttpResponse httpResponse = (HttpResponse) httpMessage;
SpdyHeaders.setStatus(spdyVersion, spdySynStreamFrame, httpResponse.status());
SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, URL);
SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.getProtocolVersion());
SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.protocolVersion());
spdySynStreamFrame.setUnidirectional(true);
}
// Replace the HTTP host header with the SPDY host header
if (spdyVersion >= 3) {
String host = HttpHeaders.getHost(httpMessage);
httpMessage.removeHeader(HttpHeaders.Names.HOST);
httpMessage.headers().remove(HttpHeaders.Names.HOST);
SpdyHeaders.setHost(spdySynStreamFrame, host);
}
@ -247,7 +247,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
SpdyHeaders.setScheme(spdyVersion, spdySynStreamFrame, scheme);
// Transfer the remaining HTTP headers
for (Map.Entry<String, String> entry: httpMessage.getHeaders()) {
for (Map.Entry<String, String> entry: httpMessage.headers()) {
spdySynStreamFrame.addHeader(entry.getKey(), entry.getValue());
}
currentStreamId = spdySynStreamFrame.getStreamId();
@ -255,7 +255,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
return spdySynStreamFrame;
}
private SpdySynReplyFrame createSynReplyFrame(HttpResponseHeader httpResponse)
private SpdySynReplyFrame createSynReplyFrame(HttpResponse httpResponse)
throws Exception {
boolean chunked = HttpHeaders.isTransferEncodingChunked(httpResponse);
@ -265,19 +265,19 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
// The Connection, Keep-Alive, Proxy-Connection, and Transfer-ENcoding
// headers are not valid and MUST not be sent.
httpResponse.removeHeader(HttpHeaders.Names.CONNECTION);
httpResponse.removeHeader("Keep-Alive");
httpResponse.removeHeader("Proxy-Connection");
httpResponse.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);
httpResponse.headers().remove(HttpHeaders.Names.CONNECTION);
httpResponse.headers().remove("Keep-Alive");
httpResponse.headers().remove("Proxy-Connection");
httpResponse.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
// Unfold the first line of the response into name/value pairs
SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, httpResponse.getStatus());
SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, httpResponse.getProtocolVersion());
SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, httpResponse.status());
SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, httpResponse.protocolVersion());
// Transfer the remaining HTTP headers
for (Map.Entry<String, String> entry: httpResponse.getHeaders()) {
for (Map.Entry<String, String> entry: httpResponse.headers()) {
spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
}

View File

@ -15,8 +15,8 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.handler.codec.http.HttpHeader;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
/**
* Provides the constants for the header names and the utility methods
@ -60,29 +60,29 @@ public final class SpdyHttpHeaders {
/**
* Removes the {@code "X-SPDY-Stream-ID"} header.
*/
public static void removeStreamId(HttpHeader message) {
message.removeHeader(Names.STREAM_ID);
public static void removeStreamId(HttpMessage message) {
message.headers().remove(Names.STREAM_ID);
}
/**
* Returns the value of the {@code "X-SPDY-Stream-ID"} header.
*/
public static int getStreamId(HttpHeader message) {
public static int getStreamId(HttpMessage message) {
return HttpHeaders.getIntHeader(message, Names.STREAM_ID);
}
/**
* Sets the {@code "X-SPDY-Stream-ID"} header.
*/
public static void setStreamId(HttpHeader message, int streamId) {
public static void setStreamId(HttpMessage message, int streamId) {
HttpHeaders.setIntHeader(message, Names.STREAM_ID, streamId);
}
/**
* Removes the {@code "X-SPDY-Associated-To-Stream-ID"} header.
*/
public static void removeAssociatedToStreamId(HttpHeader message) {
message.removeHeader(Names.ASSOCIATED_TO_STREAM_ID);
public static void removeAssociatedToStreamId(HttpMessage message) {
message.headers().remove(Names.ASSOCIATED_TO_STREAM_ID);
}
/**
@ -91,22 +91,22 @@ public final class SpdyHttpHeaders {
* @return the header value or {@code 0} if there is no such header or
* if the header value is not a number
*/
public static int getAssociatedToStreamId(HttpHeader message) {
public static int getAssociatedToStreamId(HttpMessage message) {
return HttpHeaders.getIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, 0);
}
/**
* Sets the {@code "X-SPDY-Associated-To-Stream-ID"} header.
*/
public static void setAssociatedToStreamId(HttpHeader message, int associatedToStreamId) {
public static void setAssociatedToStreamId(HttpMessage message, int associatedToStreamId) {
HttpHeaders.setIntHeader(message, Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId);
}
/**
* Removes the {@code "X-SPDY-Priority"} header.
*/
public static void removePriority(HttpHeader message) {
message.removeHeader(Names.PRIORITY);
public static void removePriority(HttpMessage message) {
message.headers().remove(Names.PRIORITY);
}
/**
@ -115,56 +115,56 @@ public final class SpdyHttpHeaders {
* @return the header value or {@code 0} if there is no such header or
* if the header value is not a number
*/
public static byte getPriority(HttpHeader message) {
public static byte getPriority(HttpMessage message) {
return (byte) HttpHeaders.getIntHeader(message, Names.PRIORITY, 0);
}
/**
* Sets the {@code "X-SPDY-Priority"} header.
*/
public static void setPriority(HttpHeader message, byte priority) {
public static void setPriority(HttpMessage message, byte priority) {
HttpHeaders.setIntHeader(message, Names.PRIORITY, priority);
}
/**
* Removes the {@code "X-SPDY-URL"} header.
*/
public static void removeUrl(HttpHeader message) {
message.removeHeader(Names.URL);
public static void removeUrl(HttpMessage message) {
message.headers().remove(Names.URL);
}
/**
* Returns the value of the {@code "X-SPDY-URL"} header.
*/
public static String getUrl(HttpHeader message) {
return message.getHeader(Names.URL);
public static String getUrl(HttpMessage message) {
return message.headers().get(Names.URL);
}
/**
* Sets the {@code "X-SPDY-URL"} header.
*/
public static void setUrl(HttpHeader message, String url) {
message.setHeader(Names.URL, url);
public static void setUrl(HttpMessage message, String url) {
message.headers().set(Names.URL, url);
}
/**
* Removes the {@code "X-SPDY-Scheme"} header.
*/
public static void removeScheme(HttpHeader message) {
message.removeHeader(Names.SCHEME);
public static void removeScheme(HttpMessage message) {
message.headers().remove(Names.SCHEME);
}
/**
* Returns the value of the {@code "X-SPDY-Scheme"} header.
*/
public static String getScheme(HttpHeader message) {
return message.getHeader(Names.SCHEME);
public static String getScheme(HttpMessage message) {
return message.headers().get(Names.SCHEME);
}
/**
* Sets the {@code "X-SPDY-Scheme"} header.
*/
public static void setScheme(HttpHeader message, String scheme) {
message.setHeader(Names.SCHEME, scheme);
public static void setScheme(HttpMessage message, String scheme) {
message.headers().set(Names.SCHEME, scheme);
}
}

View File

@ -15,31 +15,31 @@
*/
package io.netty.handler.codec.spdy;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.HttpMessage;
import java.util.LinkedList;
import java.util.Queue;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import io.netty.handler.codec.http.HttpHeader;
/**
* {@link MessageToMessageCodec} that takes care of adding the right {@link SpdyHttpHeaders.Names#STREAM_ID} to the
* {@link HttpHeader} if one is not present. This makes it possible to just re-use plan handlers current used
* {@link HttpMessage} if one is not present. This makes it possible to just re-use plan handlers current used
* for HTTP.
*/
public class SpdyHttpResponseStreamIdHandler extends
MessageToMessageCodec<Object, HttpHeader> {
MessageToMessageCodec<Object, HttpMessage> {
private static final Integer NO_ID = -1;
private final Queue<Integer> ids = new LinkedList<Integer>();
public SpdyHttpResponseStreamIdHandler() {
super(new Class<?>[] { HttpHeader.class, SpdyRstStreamFrame.class }, new Class<?>[] { HttpHeader.class });
super(new Class<?>[] { HttpMessage.class, SpdyRstStreamFrame.class }, new Class<?>[] { HttpMessage.class });
}
@Override
protected Object encode(ChannelHandlerContext ctx, HttpHeader msg) throws Exception {
protected Object encode(ChannelHandlerContext ctx, HttpMessage msg) throws Exception {
Integer id = ids.poll();
if (id != null && id.intValue() != NO_ID && !msg.containsHeader(SpdyHttpHeaders.Names.STREAM_ID)) {
if (id != null && id.intValue() != NO_ID && !msg.headers().contains(SpdyHttpHeaders.Names.STREAM_ID)) {
SpdyHttpHeaders.setStreamId(msg, id);
}
return msg;
@ -47,12 +47,12 @@ public class SpdyHttpResponseStreamIdHandler extends
@Override
protected Object decode(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpHeader) {
boolean contains = ((HttpHeader) msg).containsHeader(SpdyHttpHeaders.Names.STREAM_ID);
if (msg instanceof HttpMessage) {
boolean contains = ((HttpMessage) msg).headers().contains(SpdyHttpHeaders.Names.STREAM_ID);
if (!contains) {
ids.add(NO_ID);
} else {
ids.add(SpdyHttpHeaders.getStreamId((HttpHeader) msg));
ids.add(SpdyHttpHeaders.getStreamId((HttpMessage) msg));
}
} else if (msg instanceof SpdyRstStreamFrame) {
ids.remove(((SpdyRstStreamFrame) msg).getStreamId());

View File

@ -22,25 +22,25 @@ public class DefaultHttpRequestTest {
@Test
public void testHeaderRemoval() {
HttpHeader m = new DefaultHttpRequestHeader(
HttpMessage m = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
// Insert sample keys.
for (int i = 0; i < 1000; i ++) {
m.setHeader(String.valueOf(i), "");
m.headers().set(String.valueOf(i), "");
}
// Remove in reversed order.
for (int i = 999; i >= 0; i --) {
m.removeHeader(String.valueOf(i));
m.headers().remove(String.valueOf(i));
}
// Check if random access returns nothing.
for (int i = 0; i < 1000; i ++) {
Assert.assertNull(m.getHeader(String.valueOf(i)));
Assert.assertNull(m.headers().get(String.valueOf(i)));
}
// Check if sequential access returns nothing.
Assert.assertTrue(m.getHeaders().isEmpty());
Assert.assertTrue(m.headers().isEmpty());
}
}

View File

@ -15,7 +15,6 @@
*/
package io.netty.handler.codec.http;
import static org.junit.Assert.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
@ -23,20 +22,21 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.handler.codec.TooLongFrameException;
import io.netty.util.CharsetUtil;
import java.util.List;
import org.easymock.EasyMock;
import org.junit.Test;
public class HttpObjectAggregatorTest {
import java.util.List;
import static org.junit.Assert.*;
public class FullHttpMessageDecoderTest {
@Test
public void testAggregate() {
HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
HttpRequestHeader message = new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1,
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
HttpHeaders.setHeader(message, "X-Test", true);
HttpContent chunk1 = new DefaultHttpContent(Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII));
@ -49,18 +49,18 @@ public class HttpObjectAggregatorTest {
// this should trigger a messageReceived event so return true
assertTrue(embedder.writeInbound(chunk3));
assertTrue(embedder.finish());
DefaultHttpRequest aggratedMessage = (DefaultHttpRequest) embedder.readInbound();
DefaultFullHttpRequest aggratedMessage = (DefaultFullHttpRequest) embedder.readInbound();
assertNotNull(aggratedMessage);
assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
assertEquals(aggratedMessage.getHeader("X-Test"), Boolean.TRUE.toString());
assertEquals(chunk1.data().readableBytes() + chunk2.data().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString());
checkContentBuffer(aggratedMessage);
assertNull(embedder.readInbound());
}
private static void checkContentBuffer(DefaultHttpRequest aggregatedMessage) {
CompositeByteBuf buffer = (CompositeByteBuf) aggregatedMessage.getContent();
private static void checkContentBuffer(DefaultFullHttpRequest aggregatedMessage) {
CompositeByteBuf buffer = (CompositeByteBuf) aggregatedMessage.data();
assertEquals(2, buffer.numComponents());
List<ByteBuf> buffers = buffer.decompose(0, buffer.capacity());
assertEquals(2, buffers.size());
@ -74,14 +74,14 @@ public class HttpObjectAggregatorTest {
public void testAggregateWithTrailer() {
HttpObjectAggregator aggr = new HttpObjectAggregator(1024 * 1024);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
HttpRequestHeader message = new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1,
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
HttpHeaders.setHeader(message, "X-Test", true);
HttpHeaders.setTransferEncodingChunked(message);
HttpContent chunk1 = new DefaultHttpContent(Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII));
HttpContent chunk2 = new DefaultHttpContent(Unpooled.copiedBuffer("test2", CharsetUtil.US_ASCII));
LastHttpContent trailer = new DefaultLastHttpContent();
trailer.setHeader("X-Trailer", true);
trailer.trailingHeaders().set("X-Trailer", true);
assertFalse(embedder.writeInbound(message));
assertFalse(embedder.writeInbound(chunk1));
@ -90,12 +90,12 @@ public class HttpObjectAggregatorTest {
// this should trigger a messageReceived event so return true
assertTrue(embedder.writeInbound(trailer));
assertTrue(embedder.finish());
DefaultHttpRequest aggratedMessage = (DefaultHttpRequest) embedder.readInbound();
DefaultFullHttpRequest aggratedMessage = (DefaultFullHttpRequest) embedder.readInbound();
assertNotNull(aggratedMessage);
assertEquals(chunk1.getContent().readableBytes() + chunk2.getContent().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
assertEquals(aggratedMessage.getHeader("X-Test"), Boolean.TRUE.toString());
assertEquals(aggratedMessage.getHeader("X-Trailer"), Boolean.TRUE.toString());
assertEquals(chunk1.data().readableBytes() + chunk2.data().readableBytes(), HttpHeaders.getContentLength(aggratedMessage));
assertEquals(aggratedMessage.headers().get("X-Test"), Boolean.TRUE.toString());
assertEquals(aggratedMessage.headers().get("X-Trailer"), Boolean.TRUE.toString());
checkContentBuffer(aggratedMessage);
assertNull(embedder.readInbound());
@ -107,7 +107,7 @@ public class HttpObjectAggregatorTest {
public void testTooLongFrameException() {
HttpObjectAggregator aggr = new HttpObjectAggregator(4);
EmbeddedMessageChannel embedder = new EmbeddedMessageChannel(aggr);
HttpRequestHeader message = new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1,
HttpRequest message = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost");
HttpContent chunk1 = new DefaultHttpContent(Unpooled.copiedBuffer("test", CharsetUtil.US_ASCII));
HttpContent chunk2 = new DefaultHttpContent(Unpooled.copiedBuffer("test2", CharsetUtil.US_ASCII));

View File

@ -15,15 +15,15 @@
*/
package io.netty.handler.codec.http;
import static org.junit.Assert.*;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.handler.codec.CodecException;
import io.netty.handler.codec.PrematureChannelClosureException;
import io.netty.util.CharsetUtil;
import org.junit.Test;
import static org.junit.Assert.*;
public class HttpClientCodecTest {
private static final String RESPONSE = "HTTP/1.0 200 OK\r\n" + "Date: Fri, 31 Dec 1999 23:59:59 GMT\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 28\r\n" + "\r\n"
@ -38,7 +38,7 @@ public class HttpClientCodecTest {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
ch.writeOutbound(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(RESPONSE, CharsetUtil.ISO_8859_1));
ch.finish();
}
@ -48,7 +48,7 @@ public class HttpClientCodecTest {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
ch.writeOutbound(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1));
ch.finish();
}
@ -58,7 +58,7 @@ public class HttpClientCodecTest {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
assertTrue(ch.writeOutbound(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")));
assertTrue(ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/")));
assertNotNull(ch.readOutbound());
try {
@ -75,7 +75,7 @@ public class HttpClientCodecTest {
HttpClientCodec codec = new HttpClientCodec(4096, 8192, 8192, true);
EmbeddedByteChannel ch = new EmbeddedByteChannel(codec);
ch.writeOutbound(new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeOutbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "http://localhost/"));
ch.writeInbound(Unpooled.copiedBuffer(INCOMPLETE_CHUNKED_RESPONSE, CharsetUtil.ISO_8859_1));
try {

View File

@ -33,8 +33,8 @@ public class HttpInvalidMessageTest {
public void testRequestWithBadInitialLine() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpRequestDecoder());
ch.writeInbound(Unpooled.copiedBuffer("GET / HTTP/1.0 with extra\r\n", CharsetUtil.UTF_8));
HttpRequestHeader req = (HttpRequestHeader) ch.readInbound();
DecoderResult dr = req.getDecoderResult();
HttpRequest req = (HttpRequest) ch.readInbound();
DecoderResult dr = req.decoderResult();
Assert.assertFalse(dr.isSuccess());
Assert.assertFalse(dr.isPartialFailure());
ensureInboundTrafficDiscarded(ch);
@ -47,12 +47,12 @@ public class HttpInvalidMessageTest {
ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
HttpRequestHeader req = (HttpRequestHeader) ch.readInbound();
DecoderResult dr = req.getDecoderResult();
HttpRequest req = (HttpRequest) ch.readInbound();
DecoderResult dr = req.decoderResult();
Assert.assertFalse(dr.isSuccess());
Assert.assertTrue(dr.isPartialFailure());
Assert.assertEquals("Good Value", req.getHeader("Good_Name"));
Assert.assertEquals("/maybe-something", req.getUri());
Assert.assertEquals("Good Value", req.headers().get("Good_Name"));
Assert.assertEquals("/maybe-something", req.uri());
ensureInboundTrafficDiscarded(ch);
}
@ -60,8 +60,8 @@ public class HttpInvalidMessageTest {
public void testResponseWithBadInitialLine() throws Exception {
EmbeddedByteChannel ch = new EmbeddedByteChannel(new HttpResponseDecoder());
ch.writeInbound(Unpooled.copiedBuffer("HTTP/1.0 BAD_CODE Bad Server\r\n", CharsetUtil.UTF_8));
HttpResponseHeader res = (HttpResponseHeader) ch.readInbound();
DecoderResult dr = res.getDecoderResult();
HttpResponse res = (HttpResponse) ch.readInbound();
DecoderResult dr = res.decoderResult();
Assert.assertFalse(dr.isSuccess());
Assert.assertFalse(dr.isPartialFailure());
ensureInboundTrafficDiscarded(ch);
@ -74,12 +74,12 @@ public class HttpInvalidMessageTest {
ch.writeInbound(Unpooled.copiedBuffer("Good_Name: Good Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("Bad=Name: Bad Value\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("\r\n", CharsetUtil.UTF_8));
HttpResponseHeader res = (HttpResponseHeader) ch.readInbound();
DecoderResult dr = res.getDecoderResult();
HttpResponse res = (HttpResponse) ch.readInbound();
DecoderResult dr = res.decoderResult();
Assert.assertFalse(dr.isSuccess());
Assert.assertTrue(dr.isPartialFailure());
Assert.assertEquals("Maybe OK", res.getStatus().getReasonPhrase());
Assert.assertEquals("Good Value", res.getHeader("Good_Name"));
Assert.assertEquals("Maybe OK", res.status().reasonPhrase());
Assert.assertEquals("Good Value", res.headers().get("Good_Name"));
ensureInboundTrafficDiscarded(ch);
}
@ -90,11 +90,11 @@ public class HttpInvalidMessageTest {
ch.writeInbound(Unpooled.copiedBuffer("Transfer-Encoding: chunked\r\n\r\n", CharsetUtil.UTF_8));
ch.writeInbound(Unpooled.copiedBuffer("BAD_LENGTH\r\n", CharsetUtil.UTF_8));
HttpRequestHeader req = (HttpRequestHeader) ch.readInbound();
Assert.assertTrue(req.getDecoderResult().isSuccess());
HttpRequest req = (HttpRequest) ch.readInbound();
Assert.assertTrue(req.decoderResult().isSuccess());
HttpContent chunk = (HttpContent) ch.readInbound();
DecoderResult dr = chunk.getDecoderResult();
DecoderResult dr = chunk.decoderResult();
Assert.assertFalse(dr.isSuccess());
Assert.assertFalse(dr.isPartialFailure());
ensureInboundTrafficDiscarded(ch);

View File

@ -15,14 +15,14 @@
*/
package io.netty.handler.codec.http;
import static org.junit.Assert.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.junit.Test;
import java.nio.charset.Charset;
import static org.junit.Assert.*;
/**
*/
public class HttpRequestEncoderTest {
@ -31,7 +31,7 @@ public class HttpRequestEncoderTest {
public void testUriWithoutPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1,
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);
@ -42,7 +42,7 @@ public class HttpRequestEncoderTest {
public void testUriWithPath() throws Exception {
HttpRequestEncoder encoder = new HttpRequestEncoder();
ByteBuf buffer = Unpooled.buffer(64);
encoder.encodeInitialLine(buffer, new DefaultHttpRequestHeader(HttpVersion.HTTP_1_1,
encoder.encodeInitialLine(buffer, new DefaultHttpRequest(HttpVersion.HTTP_1_1,
HttpMethod.GET, "http://localhost/"));
String req = buffer.toString(Charset.forName("US-ASCII"));
assertEquals("GET http://localhost/ HTTP/1.1\r\n", req);

View File

@ -19,7 +19,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
@ -44,8 +43,8 @@ public class HttpServerCodecTest {
decoderEmbedder.writeInbound(prepareDataChunk(offeredContentLength));
decoderEmbedder.finish();
HttpHeader httpMessage = (HttpHeader) decoderEmbedder.readInbound();
//Assert.assertSame(HttpTransferEncoding.STREAMED, httpMessage.getTransferEncoding());
HttpMessage httpMessage = (HttpMessage) decoderEmbedder.readInbound();
Assert.assertNotNull(httpMessage);
boolean empty = true;
int totalBytesPolled = 0;
@ -55,7 +54,7 @@ public class HttpServerCodecTest {
break;
}
empty = false;
totalBytesPolled += httpChunk.getContent().readableBytes();
totalBytesPolled += httpChunk.data().readableBytes();
Assert.assertFalse(httpChunk instanceof LastHttpContent);
}
Assert.assertFalse(empty);

View File

@ -15,15 +15,15 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.WEBSOCKET;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.HttpHeaders.Names;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
public class WebSocketRequestBuilder {
@ -96,30 +96,30 @@ public class WebSocketRequestBuilder {
return this;
}
public HttpRequest build() {
HttpRequest req = new DefaultHttpRequest(httpVersion, method, uri);
public FullHttpRequest build() {
FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, uri);
if (host != null) {
req.setHeader(Names.HOST, host);
req.headers().set(Names.HOST, host);
}
if (upgrade != null) {
req.setHeader(Names.UPGRADE, upgrade);
req.headers().set(Names.UPGRADE, upgrade);
}
if (connection != null) {
req.setHeader(Names.CONNECTION, connection);
req.headers().set(Names.CONNECTION, connection);
}
if (key != null) {
req.setHeader(Names.SEC_WEBSOCKET_KEY, key);
req.headers().set(Names.SEC_WEBSOCKET_KEY, key);
}
if (origin != null) {
req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, origin);
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, origin);
}
if (version != null) {
req.setHeader(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
req.headers().set(Names.SEC_WEBSOCKET_VERSION, version.toHttpHeaderValue());
}
return req;
}
public static HttpRequestHeader sucessful() {
public static HttpRequest sucessful() {
return new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
.method(HttpMethod.GET)
.uri("/test")

View File

@ -15,26 +15,26 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
public class WebSocketServerHandshaker00Test {
@Test
@ -42,17 +42,16 @@ public class WebSocketServerHandshaker00Test {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
req.setHeader(Names.HOST, "server.example.com");
req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.setHeader(Names.CONNECTION, "Upgrade");
req.setHeader(Names.ORIGIN, "http://example.com");
req.setHeader(Names.SEC_WEBSOCKET_KEY1, "4 @1 46546xW%0l 1 5");
req.setHeader(Names.SEC_WEBSOCKET_KEY2, "12998 5 Y3 1 .P00");
req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
FullHttpRequest req = new DefaultFullHttpRequest(
HTTP_1_1, HttpMethod.GET, "/chat", Unpooled.copiedBuffer("^n:ds[4U", CharsetUtil.US_ASCII));
ByteBuf buffer = Unpooled.copiedBuffer("^n:ds[4U", CharsetUtil.US_ASCII);
req.setContent(buffer);
req.headers().set(Names.HOST, "server.example.com");
req.headers().set(Names.UPGRADE, WEBSOCKET.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");
req.headers().set(Names.SEC_WEBSOCKET_KEY2, "12998 5 Y3 1 .P00");
req.headers().set(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
new WebSocketServerHandshaker00(
"ws://example.com/chat", "chat", Integer.MAX_VALUE).handshake(ch, req);
@ -61,12 +60,12 @@ public class WebSocketServerHandshaker00Test {
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponseHeader res = (HttpResponseHeader) ch2.readInbound();
HttpResponse res = (HttpResponse) ch2.readInbound();
Assert.assertEquals("ws://example.com/chat", res.getHeader(Names.SEC_WEBSOCKET_LOCATION));
Assert.assertEquals("chat", res.getHeader(Names.SEC_WEBSOCKET_PROTOCOL));
Assert.assertEquals("ws://example.com/chat", res.headers().get(Names.SEC_WEBSOCKET_LOCATION));
Assert.assertEquals("chat", res.headers().get(Names.SEC_WEBSOCKET_PROTOCOL));
LastHttpContent content = (LastHttpContent) ch2.readInbound();
Assert.assertEquals("8jKS'y:G*Co,Wxa-", content.getContent().toString(CharsetUtil.US_ASCII));
Assert.assertEquals("8jKS'y:G*Co,Wxa-", content.data().toString(CharsetUtil.US_ASCII));
}
}

View File

@ -15,23 +15,23 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.junit.Assert;
import org.junit.Test;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
public class WebSocketServerHandshaker08Test {
@Test
@ -39,14 +39,14 @@ public class WebSocketServerHandshaker08Test {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
req.setHeader(Names.HOST, "server.example.com");
req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.setHeader(Names.CONNECTION, "Upgrade");
req.setHeader(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");
req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
req.setHeader(Names.SEC_WEBSOCKET_VERSION, "8");
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.CONNECTION, "Upgrade");
req.headers().set(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");
req.headers().set(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
req.headers().set(Names.SEC_WEBSOCKET_VERSION, "8");
new WebSocketServerHandshaker08(
"ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req);
@ -55,10 +55,10 @@ public class WebSocketServerHandshaker08Test {
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponseHeader res = (HttpResponseHeader) ch2.readInbound();
HttpResponse res = (HttpResponse) ch2.readInbound();
Assert.assertEquals(
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getHeader(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.getHeader(Names.SEC_WEBSOCKET_PROTOCOL));
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.headers().get(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.headers().get(Names.SEC_WEBSOCKET_PROTOCOL));
}
}

View File

@ -15,23 +15,23 @@
*/
package io.netty.handler.codec.http.websocketx;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedByteChannel;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.junit.Assert;
import org.junit.Test;
import static io.netty.handler.codec.http.HttpHeaders.Values.*;
import static io.netty.handler.codec.http.HttpVersion.*;
public class WebSocketServerHandshaker13Test {
@Test
@ -39,14 +39,14 @@ public class WebSocketServerHandshaker13Test {
EmbeddedByteChannel ch = new EmbeddedByteChannel(
new HttpObjectAggregator(42), new HttpRequestDecoder(), new HttpResponseEncoder());
HttpRequest req = new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/chat");
req.setHeader(Names.HOST, "server.example.com");
req.setHeader(Names.UPGRADE, WEBSOCKET.toLowerCase());
req.setHeader(Names.CONNECTION, "Upgrade");
req.setHeader(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.setHeader(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");
req.setHeader(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
req.setHeader(Names.SEC_WEBSOCKET_VERSION, "13");
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.CONNECTION, "Upgrade");
req.headers().set(Names.SEC_WEBSOCKET_KEY, "dGhlIHNhbXBsZSBub25jZQ==");
req.headers().set(Names.SEC_WEBSOCKET_ORIGIN, "http://example.com");
req.headers().set(Names.SEC_WEBSOCKET_PROTOCOL, "chat, superchat");
req.headers().set(Names.SEC_WEBSOCKET_VERSION, "13");
new WebSocketServerHandshaker13(
"ws://example.com/chat", "chat", false, Integer.MAX_VALUE).handshake(ch, req);
@ -55,10 +55,10 @@ public class WebSocketServerHandshaker13Test {
EmbeddedByteChannel ch2 = new EmbeddedByteChannel(new HttpResponseDecoder());
ch2.writeInbound(resBuf);
HttpResponseHeader res = (HttpResponseHeader) ch2.readInbound();
HttpResponse res = (HttpResponse) ch2.readInbound();
Assert.assertEquals(
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.getHeader(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.getHeader(Names.SEC_WEBSOCKET_PROTOCOL));
"s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", res.headers().get(Names.SEC_WEBSOCKET_ACCEPT));
Assert.assertEquals("chat", res.headers().get(Names.SEC_WEBSOCKET_PROTOCOL));
}
}

View File

@ -22,13 +22,13 @@ import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelOutboundMessageHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.channel.embedded.EmbeddedMessageChannel;
import io.netty.handler.codec.http.DefaultHttpRequestHeader;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponseEncoder;
import org.junit.Test;
@ -46,7 +46,7 @@ public class WebSocketServerProtocolHandlerTest {
writeUpgradeRequest(ch);
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponseHeader) ch.outboundMessageBuffer().poll()).getStatus());
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).status());
assertNotNull(WebSocketServerProtocolHandler.getHandshaker(handshakerCtx));
}
@ -55,16 +55,16 @@ public class WebSocketServerProtocolHandlerTest {
EmbeddedMessageChannel ch = createChannel(new MockOutboundHandler());
writeUpgradeRequest(ch);
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponseHeader) ch.outboundMessageBuffer().poll()).getStatus());
assertEquals(SWITCHING_PROTOCOLS, ((HttpResponse) ch.outboundMessageBuffer().poll()).status());
ch.writeInbound(new DefaultHttpRequestHeader(HTTP_1_1, HttpMethod.GET, "/test"));
assertEquals(FORBIDDEN, ((HttpResponseHeader) ch.outboundMessageBuffer().poll()).getStatus());
ch.writeInbound(new DefaultHttpRequest(HTTP_1_1, HttpMethod.GET, "/test"));
assertEquals(FORBIDDEN, ((HttpResponse) ch.outboundMessageBuffer().poll()).status());
}
@Test
public void testHttpUpgradeRequestInvalidUpgradeHeader() {
EmbeddedMessageChannel ch = createChannel();
HttpRequest httpRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
FullHttpRequest httpRequestWithEntity = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
.method(HttpMethod.GET)
.uri("/test")
.connection("Upgrade")
@ -72,10 +72,10 @@ public class WebSocketServerProtocolHandlerTest {
.upgrade("BogusSocket")
.build();
ch.writeInbound(httpRequest);
ch.writeInbound(httpRequestWithEntity);
HttpResponse response = getHttpResponse(ch);
assertEquals(BAD_REQUEST, response.getStatus());
FullHttpResponse response = getHttpResponse(ch);
assertEquals(BAD_REQUEST, response.status());
assertEquals("not a WebSocket handshake request: missing upgrade", getResponseMessage(response));
}
@ -83,7 +83,7 @@ public class WebSocketServerProtocolHandlerTest {
@Test
public void testHttpUpgradeRequestMissingWSKeyHeader() {
EmbeddedMessageChannel ch = createChannel();
HttpRequestHeader httpRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
HttpRequest httpRequest = new WebSocketRequestBuilder().httpVersion(HTTP_1_1)
.method(HttpMethod.GET)
.uri("/test")
.key(null)
@ -94,8 +94,8 @@ public class WebSocketServerProtocolHandlerTest {
ch.writeInbound(httpRequest);
HttpResponse response = getHttpResponse(ch);
assertEquals(BAD_REQUEST, response.getStatus());
FullHttpResponse response = getHttpResponse(ch);
assertEquals(BAD_REQUEST, response.status());
assertEquals("not a WebSocket request: missing key", getResponseMessage(response));
}
@ -129,13 +129,13 @@ public class WebSocketServerProtocolHandlerTest {
ch.writeInbound(WebSocketRequestBuilder.sucessful());
}
private static String getResponseMessage(HttpResponse response) {
return new String(response.getContent().array());
private static String getResponseMessage(FullHttpResponse response) {
return new String(response.data().array());
}
private static HttpResponse getHttpResponse(EmbeddedMessageChannel ch) {
private static FullHttpResponse getHttpResponse(EmbeddedMessageChannel ch) {
MessageBuf<Object> outbound = ch.pipeline().context(MockOutboundHandler.class).outboundMessageBuffer();
return (HttpResponse) outbound.poll();
return (FullHttpResponse) outbound.poll();
}
private static class MockOutboundHandler extends ChannelOutboundMessageHandlerAdapter<Object> {

View File

@ -20,10 +20,10 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil;
@ -94,7 +94,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
*
* </pre>
*/
public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAdapter<HttpRequest> {
public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAdapter<FullHttpRequest> {
public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
@ -102,19 +102,19 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
@Override
public void messageReceived(
ChannelHandlerContext ctx, HttpRequest request) throws Exception {
ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
if (!request.getDecoderResult().isSuccess()) {
if (!request.decoderResult().isSuccess()) {
sendError(ctx, BAD_REQUEST);
return;
}
if (request.getMethod() != GET) {
if (request.method() != GET) {
sendError(ctx, METHOD_NOT_ALLOWED);
return;
}
final String uri = request.getUri();
final String uri = request.uri();
final String path = sanitizeUri(uri);
if (path == null) {
sendError(ctx, FORBIDDEN);
@ -142,7 +142,7 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
}
// Cache Validation
String ifModifiedSince = request.getHeader(IF_MODIFIED_SINCE);
String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
@ -166,12 +166,12 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
}
long fileLength = raf.length();
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
setContentLength(response, fileLength);
setContentTypeHeader(response, file);
setDateAndCacheHeaders(response, file);
if (isKeepAlive(request)) {
response.setHeader(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
// Write the initial line and the header.
@ -232,8 +232,8 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*");
private static void sendListing(ChannelHandlerContext ctx, File dir) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
response.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
StringBuilder buf = new StringBuilder();
String dirPath = dir.getPath();
@ -270,26 +270,24 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
buf.append("</ul></body></html>\r\n");
response.setContent(Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8));
response.data().writeBytes(Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8));
// Close the connection as soon as the error message is sent.
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
private static void sendRedirect(ChannelHandlerContext ctx, String newUri) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, FOUND);
response.setHeader(LOCATION, newUri);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND);
response.headers().set(LOCATION, newUri);
// Close the connection as soon as the error message is sent.
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
}
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
response.setContent(Unpooled.copiedBuffer(
"Failure: " + status.toString() + "\r\n",
CharsetUtil.UTF_8));
FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
// Close the connection as soon as the error message is sent.
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
@ -302,7 +300,7 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
* Context
*/
private static void sendNotModified(ChannelHandlerContext ctx) {
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, NOT_MODIFIED);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, NOT_MODIFIED);
setDateHeader(response);
// Close the connection as soon as the error message is sent.
@ -315,12 +313,12 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
* @param response
* HTTP response
*/
private static void setDateHeader(HttpResponse response) {
private static void setDateHeader(FullHttpResponse response) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
Calendar time = new GregorianCalendar();
response.setHeader(DATE, dateFormatter.format(time.getTime()));
response.headers().set(DATE, dateFormatter.format(time.getTime()));
}
/**
@ -331,19 +329,19 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
* @param fileToCache
* file to extract content type
*/
private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) {
private static void setDateAndCacheHeaders(FullHttpResponse response, File fileToCache) {
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));
// Date header
Calendar time = new GregorianCalendar();
response.setHeader(DATE, dateFormatter.format(time.getTime()));
response.headers().set(DATE, dateFormatter.format(time.getTime()));
// Add cache headers
time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
response.setHeader(EXPIRES, dateFormatter.format(time.getTime()));
response.setHeader(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
response.setHeader(
response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));
response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
response.headers().set(
LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
}
@ -355,9 +353,9 @@ public class HttpStaticFileServerHandler extends ChannelInboundMessageHandlerAda
* @param file
* file to extract content type
*/
private static void setContentTypeHeader(HttpResponse response, File file) {
private static void setContentTypeHeader(FullHttpResponse response, File file) {
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
response.setHeader(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath()));
}
}

View File

@ -21,10 +21,10 @@ import io.netty.channel.socket.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.ClientCookieEncoder;
import io.netty.handler.codec.http.DefaultCookie;
import io.netty.handler.codec.http.DefaultHttpRequestHeader;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import java.net.InetSocketAddress;
@ -73,14 +73,14 @@ public class HttpSnoopClient {
Channel ch = b.connect().sync().channel();
// Prepare the HTTP request.
HttpRequestHeader request = new DefaultHttpRequestHeader(
HttpRequest request = new DefaultHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.GET, uri.getRawPath());
request.setHeader(HttpHeaders.Names.HOST, host);
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
request.headers().set(HttpHeaders.Names.HOST, host);
request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP);
// Set some example cookies.
request.setHeader(
request.headers().set(
HttpHeaders.Names.COOKIE,
ClientCookieEncoder.encode(
new DefaultCookie("my-cookie", "foo"),

View File

@ -19,7 +19,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.util.CharsetUtil;
@ -27,16 +27,16 @@ public class HttpSnoopClientHandler extends ChannelInboundMessageHandlerAdapter<
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponseHeader) {
HttpResponseHeader response = (HttpResponseHeader) msg;
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
System.out.println("STATUS: " + response.getStatus());
System.out.println("VERSION: " + response.getProtocolVersion());
System.out.println("STATUS: " + response.status());
System.out.println("VERSION: " + response.protocolVersion());
System.out.println();
if (!response.getHeaderNames().isEmpty()) {
for (String name: response.getHeaderNames()) {
for (String value: response.getHeaders(name)) {
if (!response.headers().isEmpty()) {
for (String name: response.headers().names()) {
for (String value: response.headers().getAll(name)) {
System.out.println("HEADER: " + name + " = " + value);
}
}
@ -52,7 +52,7 @@ public class HttpSnoopClientHandler extends ChannelInboundMessageHandlerAdapter<
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
System.out.print(content.getContent().toString(CharsetUtil.UTF_8));
System.out.print(content.data().toString(CharsetUtil.UTF_8));
System.out.flush();
if (content instanceof LastHttpContent) {

View File

@ -24,15 +24,15 @@ import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.Cookie;
import io.netty.handler.codec.http.CookieDecoder;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponseHeader;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.ServerCookieEncoder;
import io.netty.util.CharsetUtil;
@ -49,15 +49,14 @@ import static io.netty.handler.codec.http.HttpVersion.*;
public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<Object> {
private HttpRequestHeader request;
private boolean readingChunks;
private HttpRequest request;
/** Buffer that stores the response content */
private final StringBuilder buf = new StringBuilder();
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequestHeader) {
HttpRequestHeader request = this.request = (HttpRequestHeader) msg;
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
if (is100ContinueExpected(request)) {
send100Continue(ctx);
@ -67,13 +66,13 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
buf.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
buf.append("===================================\r\n");
buf.append("VERSION: ").append(request.getProtocolVersion()).append("\r\n");
buf.append("VERSION: ").append(request.protocolVersion()).append("\r\n");
buf.append("HOSTNAME: ").append(getHost(request, "unknown")).append("\r\n");
buf.append("REQUEST_URI: ").append(request.getUri()).append("\r\n\r\n");
buf.append("REQUEST_URI: ").append(request.uri()).append("\r\n\r\n");
List<Map.Entry<String, String>> headers = request.getHeaders();
List<Map.Entry<String, String>> headers = request.headers().entries();
if (!headers.isEmpty()) {
for (Map.Entry<String, String> h: request.getHeaders()) {
for (Map.Entry<String, String> h: request.headers().entries()) {
String key = h.getKey();
String value = h.getValue();
buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n");
@ -81,7 +80,7 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
buf.append("\r\n");
}
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.getUri());
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri());
Map<String, List<String>> params = queryStringDecoder.getParameters();
if (!params.isEmpty()) {
for (Entry<String, List<String>> p: params.entrySet()) {
@ -94,40 +93,28 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
buf.append("\r\n");
}
if (isTransferEncodingChunked(request)) {
readingChunks = true;
} else {
appendDecoderResult(buf, request);
}
appendDecoderResult(buf, request);
}
if (msg instanceof HttpContent) {
HttpContent httpContent = (HttpContent) msg;
ByteBuf content = httpContent.getContent();
ByteBuf content = httpContent.data();
if (content.readable()) {
buf.append("CONTENT: ");
buf.append(content.toString(CharsetUtil.UTF_8));
buf.append("\r\n");
appendDecoderResult(buf, request);
}
appendDecoderResult(buf, request);
writeResponse(ctx, request);
if (msg instanceof LastHttpContent) {
if (readingChunks) {
buf.append("CHUNK: ");
} else {
buf.append("CONTENT: ");
}
buf.append(content.toString(CharsetUtil.UTF_8)).append("\r\n");
readingChunks = false;
buf.append("END OF CONTENT\r\n");
LastHttpContent trailer = (LastHttpContent) msg;
if (!trailer.getHeaderNames().isEmpty()) {
if (!trailer.trailingHeaders().isEmpty()) {
buf.append("\r\n");
for (String name: trailer.getHeaderNames()) {
for (String value: trailer.getHeaders(name)) {
for (String name: trailer.trailingHeaders().names()) {
for (String value: trailer.trailingHeaders().getAll(name)) {
buf.append("TRAILING HEADER: ");
buf.append(name).append(" = ").append(value).append("\r\n");
}
@ -135,20 +122,13 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
buf.append("\r\n");
}
appendDecoderResult(buf, trailer);
writeResponse(ctx, trailer);
} else {
if (readingChunks) {
buf.append("CHUNK: ");
}
buf.append(content.toString(CharsetUtil.UTF_8)).append("\r\n");
appendDecoderResult(buf, httpContent);
}
}
}
private static void appendDecoderResult(StringBuilder buf, HttpObject o) {
DecoderResult result = o.getDecoderResult();
DecoderResult result = o.decoderResult();
if (result.isSuccess()) {
return;
}
@ -167,34 +147,34 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
boolean keepAlive = isKeepAlive(request);
// Build the response object.
HttpResponse response = new DefaultHttpResponse(
HTTP_1_1, currentObj.getDecoderResult().isSuccess()? OK : BAD_REQUEST);
FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, currentObj.decoderResult().isSuccess()? OK : BAD_REQUEST,
Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
response.setContent(Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
if (keepAlive) {
// Add 'Content-Length' header only for a keep-alive connection.
response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
response.headers().set(CONTENT_LENGTH, response.data().readableBytes());
// Add keep alive header as per:
// - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
response.setHeader(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
// Encode the cookie.
String cookieString = request.getHeader(COOKIE);
String cookieString = request.headers().get(COOKIE);
if (cookieString != null) {
Set<Cookie> cookies = CookieDecoder.decode(cookieString);
if (!cookies.isEmpty()) {
// Reset the cookies if necessary.
for (Cookie cookie: cookies) {
response.addHeader(SET_COOKIE, ServerCookieEncoder.encode(cookie));
response.headers().add(SET_COOKIE, ServerCookieEncoder.encode(cookie));
}
}
} else {
// Browser sent no cookie. Add some.
response.addHeader(SET_COOKIE, ServerCookieEncoder.encode("key1", "value1"));
response.addHeader(SET_COOKIE, ServerCookieEncoder.encode("key2", "value2"));
response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key1", "value1"));
response.headers().add(SET_COOKIE, ServerCookieEncoder.encode("key2", "value2"));
}
// Write the response.
@ -207,7 +187,7 @@ public class HttpSnoopServerHandler extends ChannelInboundMessageHandlerAdapter<
}
private static void send100Continue(ChannelHandlerContext ctx) {
HttpResponseHeader response = new DefaultHttpResponseHeader(HTTP_1_1, CONTINUE);
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, CONTINUE);
ctx.write(response);
}

View File

@ -18,7 +18,6 @@ package io.netty.example.http.snoop;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpContentCompressor;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
@ -38,7 +37,7 @@ public class HttpSnoopServerInitializer extends ChannelInitializer<SocketChannel
//pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
p.addLast("encoder", new HttpResponseEncoder());
// Remove the following line if you don't want automatic content compression.
p.addLast("deflater", new HttpContentCompressor());
//p.addLast("deflater", new HttpContentCompressor());
p.addLast("handler", new HttpSnoopServerHandler());
}
}

View File

@ -21,10 +21,10 @@ import io.netty.channel.socket.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.ClientCookieEncoder;
import io.netty.handler.codec.http.DefaultCookie;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringEncoder;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
@ -178,33 +178,31 @@ public class HttpUploadClient {
return null;
}
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
request.setHeader(HttpHeaders.Names.HOST, host);
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP + ','
FullHttpRequest request =
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
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);
request.setHeader(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
request.setHeader(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
request.setHeader(HttpHeaders.Names.REFERER, uriSimple.toString());
request.setHeader(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
request.setHeader(HttpHeaders.Names.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
headers.set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
headers.set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr");
headers.set(HttpHeaders.Names.REFERER, uriSimple.toString());
headers.set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side");
headers.set(HttpHeaders.Names.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
// connection will not close but needed
// request.setHeader("Connection","keep-alive");
// request.setHeader("Keep-Alive","300");
request.setHeader(HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode(new DefaultCookie("my-cookie", "foo"),
headers.set(HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode(new DefaultCookie("my-cookie", "foo"),
new DefaultCookie("another-cookie", "bar")));
// send request
List<Entry<String, String>> headers = request.getHeaders();
channel.write(request);
List<Entry<String, String>> entries = headers.entries();
channel.write(request).sync();
// Wait for the server to close the connection.
channel.closeFuture().sync();
return headers;
return entries;
}
/**
@ -220,7 +218,8 @@ public class HttpUploadClient {
Channel channel = bootstrap.connect().sync().channel();
// Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
FullHttpRequest request =
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriSimple.toASCIIString());
// Use the PostBody encoder
HttpPostRequestEncoder bodyRequestEncoder = null;
@ -236,7 +235,7 @@ public class HttpUploadClient {
// it is legal to add directly header or cookie into the request until finalize
for (Entry<String, String> entry : headers) {
request.setHeader(entry.getKey(), entry.getValue());
request.headers().set(entry.getKey(), entry.getValue());
}
// add Form attribute
@ -304,7 +303,8 @@ public class HttpUploadClient {
Channel channel = bootstrap.connect().sync().channel();
// Prepare the HTTP request.
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
FullHttpRequest request =
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uriFile.toASCIIString());
// Use the PostBody encoder
HttpPostRequestEncoder bodyRequestEncoder = null;
@ -320,7 +320,7 @@ public class HttpUploadClient {
// it is legal to add directly header or cookie into the request until finalize
for (Entry<String, String> entry : headers) {
request.setHeader(entry.getKey(), entry.getValue());
request.headers().set(entry.getKey(), entry.getValue());
}
// add Form attribute from previous request in formpost()

View File

@ -19,7 +19,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponseHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
@ -36,21 +36,21 @@ public class HttpUploadClientHandler extends ChannelInboundMessageHandlerAdapter
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpResponseHeader) {
HttpResponseHeader response = (HttpResponseHeader) msg;
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
logger.info("STATUS: " + response.getStatus());
logger.info("VERSION: " + response.getProtocolVersion());
logger.info("STATUS: " + response.status());
logger.info("VERSION: " + response.protocolVersion());
if (!response.getHeaderNames().isEmpty()) {
for (String name : response.getHeaderNames()) {
for (String value : response.getHeaders(name)) {
if (!response.headers().isEmpty()) {
for (String name : response.headers().names()) {
for (String value : response.headers().getAll(name)) {
logger.info("HEADER: " + name + " = " + value);
}
}
}
if (response.getStatus().getCode() == 200 && HttpHeaders.isTransferEncodingChunked(response)) {
if (response.status().code() == 200 && HttpHeaders.isTransferEncodingChunked(response)) {
readingChunks = true;
logger.info("CHUNKED CONTENT {");
} else {
@ -59,7 +59,7 @@ public class HttpUploadClientHandler extends ChannelInboundMessageHandlerAdapter
}
if (msg instanceof HttpContent) {
HttpContent chunk = (HttpContent) msg;
logger.info(chunk.getContent().toString(CharsetUtil.UTF_8));
logger.info(chunk.data().toString(CharsetUtil.UTF_8));
if (chunk instanceof LastHttpContent) {
if (readingChunks) {
@ -69,7 +69,7 @@ public class HttpUploadClientHandler extends ChannelInboundMessageHandlerAdapter
}
readingChunks = false;
} else {
logger.info(chunk.getContent().toString(CharsetUtil.UTF_8));
logger.info(chunk.data().toString(CharsetUtil.UTF_8));
}
}
}

View File

@ -23,11 +23,11 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.Cookie;
import io.netty.handler.codec.http.CookieDecoder;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequestHeader;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringDecoder;
@ -64,7 +64,7 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
private static final InternalLogger logger = InternalLoggerFactory.getInstance(HttpUploadServerHandler.class);
private HttpRequestHeader request;
private HttpRequest request;
private boolean readingChunks;
@ -95,15 +95,15 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequestHeader) {
if (msg instanceof HttpRequest) {
// clean previous FileUpload if Any
if (decoder != null) {
decoder.cleanFiles();
decoder = null;
}
HttpRequestHeader request = this.request = (HttpRequestHeader) msg;
URI uri = new URI(request.getUri());
HttpRequest request = this.request = (HttpRequest) msg;
URI uri = new URI(request.uri());
if (!uri.getPath().startsWith("/form")) {
// Write Menu
writeMenu(ctx);
@ -113,13 +113,13 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
responseContent.append("WELCOME TO THE WILD WILD WEB SERVER\r\n");
responseContent.append("===================================\r\n");
responseContent.append("VERSION: " + request.getProtocolVersion().getText() + "\r\n");
responseContent.append("VERSION: " + request.protocolVersion().getText() + "\r\n");
responseContent.append("REQUEST_URI: " + request.getUri() + "\r\n\r\n");
responseContent.append("REQUEST_URI: " + request.uri() + "\r\n\r\n");
responseContent.append("\r\n\r\n");
// new method
List<Entry<String, String>> headers = request.getHeaders();
List<Entry<String, String>> headers = request.headers().entries();
for (Entry<String, String> entry : headers) {
responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n");
}
@ -127,7 +127,7 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
// new method
Set<Cookie> cookies;
String value = request.getHeader(COOKIE);
String value = request.headers().get(COOKIE);
if (value == null) {
cookies = Collections.emptySet();
} else {
@ -138,7 +138,7 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
}
responseContent.append("\r\n\r\n");
QueryStringDecoder decoderQuery = new QueryStringDecoder(request.getUri());
QueryStringDecoder decoderQuery = new QueryStringDecoder(request.uri());
Map<String, List<String>> uriAttributes = decoderQuery.getParameters();
for (Entry<String, List<String>> attr: uriAttributes.entrySet()) {
for (String attrVal: attr.getValue()) {
@ -300,23 +300,23 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
responseContent.setLength(0);
// Decide whether to close the connection or not.
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.getHeader(CONNECTION))
|| request.getProtocolVersion().equals(HttpVersion.HTTP_1_0)
&& !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.getHeader(CONNECTION));
boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.headers().get(CONNECTION))
|| request.protocolVersion().equals(HttpVersion.HTTP_1_0)
&& !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.headers().get(CONNECTION));
// Build the response object.
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.setContent(buf);
response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
if (!close) {
// There's no need to add 'Content-Length' header
// if this is the last response.
response.setHeader(CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
response.headers().set(CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
}
Set<Cookie> cookies;
String value = request.getHeader(COOKIE);
String value = request.headers().get(COOKIE);
if (value == null) {
cookies = Collections.emptySet();
} else {
@ -325,7 +325,7 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
if (!cookies.isEmpty()) {
// Reset the cookies if necessary.
for (Cookie cookie : cookies) {
response.addHeader(SET_COOKIE, ServerCookieEncoder.encode(cookie));
response.headers().add(SET_COOKIE, ServerCookieEncoder.encode(cookie));
}
}
// Write the response.
@ -410,10 +410,12 @@ public class HttpUploadServerHandler extends ChannelInboundMessageHandlerAdapter
ByteBuf buf = copiedBuffer(responseContent.toString(), CharsetUtil.UTF_8);
// Build the response object.
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.setContent(buf);
response.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
response.setHeader(CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
response.headers().set(CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
// Write the response.
ctx.channel().write(response);
}

View File

@ -20,10 +20,10 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame;
@ -52,23 +52,23 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter<O
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
// Handle a bad request.
if (!req.getDecoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST));
if (!req.decoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
@ -112,16 +112,17 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter<O
}
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
private static void sendHttpResponse(
ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
if (res.status().code() != 200) {
res.data().writeBytes(Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.data().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
if (!isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@ -132,7 +133,7 @@ public class AutobahnServerHandler extends ChannelInboundMessageHandlerAdapter<O
ctx.close();
}
private static String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.getHeader(HttpHeaders.Names.HOST);
private static String getWebSocketLocation(FullHttpRequest req) {
return "ws://" + req.headers().get(HttpHeaders.Names.HOST);
}
}

View File

@ -44,6 +44,7 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestEncoder;
import io.netty.handler.codec.http.HttpResponseDecoder;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
@ -91,6 +92,7 @@ public class WebSocketClient {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder());
pipeline.addLast("aggregator", new HttpObjectAggregator(8192));
pipeline.addLast("ws-handler", handler);
}
});
@ -101,7 +103,7 @@ public class WebSocketClient {
// Send 10 messages and wait for responses
System.out.println("WebSocket Client sending message");
for (int i = 0; i < 1; i++) {
for (int i = 0; i < 10; i++) {
ch.write(new TextWebSocketFrame("Message #" + i));
}

View File

@ -42,7 +42,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
@ -82,16 +82,16 @@ public class WebSocketClientHandler extends ChannelInboundMessageHandlerAdapter<
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(ch, (HttpResponse) msg);
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
System.out.println("WebSocket Client connected!");
handshakeFuture.setSuccess();
return;
}
if (msg instanceof HttpResponse) {
HttpResponse response = (HttpResponse) msg;
throw new Exception("Unexpected HttpResponse (status=" + response.getStatus() + ", content="
+ response.getContent().toString(CharsetUtil.UTF_8) + ')');
if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new Exception("Unexpected FullHttpResponse (status=" + response.status() + ", content="
+ response.data().toString(CharsetUtil.UTF_8) + ')');
}
WebSocketFrame frame = (WebSocketFrame) msg;

View File

@ -21,9 +21,9 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
@ -53,41 +53,39 @@ public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter<
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
// Handle a bad request.
if (!req.getDecoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST));
if (!req.decoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the demo page and favicon.ico
if ("/".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
if ("/".equals(req.uri())) {
ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
setContentLength(res, content.readableBytes());
res.setContent(content);
sendHttpResponse(ctx, req, res);
return;
}
if ("/favicon.ico".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
if ("/favicon.ico".equals(req.uri())) {
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
sendHttpResponse(ctx, req, res);
return;
}
@ -127,16 +125,17 @@ public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter<
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
private static void sendHttpResponse(
ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
if (res.status().code() != 200) {
res.data().writeBytes(Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.data().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
if (!isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@ -147,7 +146,7 @@ public class WebSocketServerHandler extends ChannelInboundMessageHandlerAdapter<
ctx.close();
}
private static String getWebSocketLocation(HttpRequest req) {
return "ws://" + req.getHeader(HOST) + WEBSOCKET_PATH;
private static String getWebSocketLocation(FullHttpRequest req) {
return "ws://" + req.headers().get(HOST) + WEBSOCKET_PATH;
}
}

View File

@ -22,9 +22,9 @@ import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.example.http.websocketx.server.WebSocketServerIndexPage;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
@ -54,42 +54,40 @@ public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapt
@Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
handleHttpRequest(ctx, (HttpRequest) msg);
if (msg instanceof FullHttpRequest) {
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
}
private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
// Handle a bad request.
if (!req.getDecoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, BAD_REQUEST));
if (!req.decoderResult().isSuccess()) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));
return;
}
// Allow only GET methods.
if (req.getMethod() != GET) {
sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
if (req.method() != GET) {
sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));
return;
}
// Send the demo page and favicon.ico
if ("/".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
if ("/".equals(req.uri())) {
ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
setContentLength(res, content.readableBytes());
res.setContent(content);
sendHttpResponse(ctx, req, res);
return;
}
if ("/favicon.ico".equals(req.getUri())) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
if ("/favicon.ico".equals(req.uri())) {
FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
sendHttpResponse(ctx, req, res);
return;
}
@ -129,16 +127,17 @@ public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapt
ctx.channel().write(new TextWebSocketFrame(request.toUpperCase()));
}
private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
private static void sendHttpResponse(
ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {
// Generate an error page if response status code is not OK (200).
if (res.getStatus().getCode() != 200) {
res.setContent(Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.getContent().readableBytes());
if (res.status().code() != 200) {
res.data().writeBytes(Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8));
setContentLength(res, res.data().readableBytes());
}
// Send the response and close the connection if necessary.
ChannelFuture f = ctx.channel().write(res);
if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
if (!isKeepAlive(req) || res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
}
@ -149,7 +148,7 @@ public class WebSocketSslServerHandler extends ChannelInboundMessageHandlerAdapt
ctx.close();
}
private static String getWebSocketLocation(HttpRequest req) {
return "wss://" + req.getHeader(HOST) + WEBSOCKET_PATH;
private static String getWebSocketLocation(FullHttpRequest req) {
return "wss://" + req.headers().get(HOST) + WEBSOCKET_PATH;
}
}