Backport header improvements from 5.0
Motivation: The header class hierarchy and algorithm was improved on the master branch for versions 5.x. These improvments should be backported to the 4.1 baseline. Modifications: - cherry-pick the following commits from the master branch:2374e17
,36b4157
,222d258
Result: Header improvements in master branch are available in 4.1 branch.
This commit is contained in:
parent
f2678a31ff
commit
50e06442c3
@ -17,7 +17,9 @@ package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.DefaultHeaders.NameConverter;
|
||||
import io.netty.handler.codec.DefaultTextHeaders;
|
||||
import io.netty.handler.codec.DefaultTextHeaders.DefaultTextValueTypeConverter;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
import java.util.Calendar;
|
||||
@ -27,20 +29,228 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link HttpHeaders}.
|
||||
*/
|
||||
public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
private static final int HIGHEST_INVALID_NAME_CHAR_MASK = ~63;
|
||||
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~15;
|
||||
|
||||
/**
|
||||
* A look-up table used for checking if a character in a header name is prohibited.
|
||||
*/
|
||||
private static final byte[] LOOKUP_TABLE = new byte[~HIGHEST_INVALID_NAME_CHAR_MASK + 1];
|
||||
|
||||
static {
|
||||
LOOKUP_TABLE['\t'] = -1;
|
||||
LOOKUP_TABLE['\n'] = -1;
|
||||
LOOKUP_TABLE[0x0b] = -1;
|
||||
LOOKUP_TABLE['\f'] = -1;
|
||||
LOOKUP_TABLE[' '] = -1;
|
||||
LOOKUP_TABLE[','] = -1;
|
||||
LOOKUP_TABLE[':'] = -1;
|
||||
LOOKUP_TABLE[';'] = -1;
|
||||
LOOKUP_TABLE['='] = -1;
|
||||
}
|
||||
|
||||
private final TextHeaders headers;
|
||||
private static final class HttpHeadersValidationConverter extends DefaultTextValueTypeConverter {
|
||||
private final boolean validate;
|
||||
|
||||
HttpHeadersValidationConverter(boolean validate) {
|
||||
this.validate = validate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence convertObject(Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
CharSequence seq;
|
||||
if (value instanceof CharSequence) {
|
||||
seq = (CharSequence) value;
|
||||
} else if (value instanceof Number) {
|
||||
seq = value.toString();
|
||||
} else if (value instanceof Date) {
|
||||
seq = HttpHeaderDateFormat.get().format((Date) value);
|
||||
} else if (value instanceof Calendar) {
|
||||
seq = HttpHeaderDateFormat.get().format(((Calendar) value).getTime());
|
||||
} else {
|
||||
seq = value.toString();
|
||||
}
|
||||
|
||||
if (validate) {
|
||||
if (value instanceof AsciiString) {
|
||||
validateValue((AsciiString) seq);
|
||||
} else {
|
||||
validateValue(seq);
|
||||
}
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
private static void validateValue(AsciiString seq) {
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
final int start = seq.arrayOffset();
|
||||
final int end = start + seq.length();
|
||||
final byte[] array = seq.array();
|
||||
for (int index = start; index < end; index++) {
|
||||
state = validateValueChar(seq, state, (char) (array[index] & 0xFF));
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateValue(CharSequence seq) {
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
for (int index = 0; index < seq.length(); index++) {
|
||||
state = validateValueChar(seq, state, seq.charAt(index));
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
|
||||
}
|
||||
}
|
||||
|
||||
private static int validateValueChar(CharSequence seq, int state, char character) {
|
||||
/*
|
||||
* State:
|
||||
* 0: Previous character was neither CR nor LF
|
||||
* 1: The previous character was CR
|
||||
* 2: The previous character was LF
|
||||
*/
|
||||
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
|
||||
// Check the absolutely prohibited characters.
|
||||
switch (character) {
|
||||
case 0x0b: // Vertical tab
|
||||
throw new IllegalArgumentException("a header value contains a prohibited character '\\v': " + seq);
|
||||
case '\f':
|
||||
throw new IllegalArgumentException("a header value contains a prohibited character '\\f': " + seq);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the CRLF (HT | SP) pattern
|
||||
switch (state) {
|
||||
case 0:
|
||||
switch (character) {
|
||||
case '\r':
|
||||
state = 1;
|
||||
break;
|
||||
case '\n':
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (character) {
|
||||
case '\n':
|
||||
state = 2;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (character) {
|
||||
case '\t':
|
||||
case ' ':
|
||||
state = 0;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("only ' ' and '\\t' are allowed after '\\n': " + seq);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
static class HttpHeadersNameConverter implements NameConverter<CharSequence> {
|
||||
protected final boolean validate;
|
||||
|
||||
HttpHeadersNameConverter(boolean validate) {
|
||||
this.validate = validate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence convertName(CharSequence name) {
|
||||
if (validate) {
|
||||
if (name instanceof AsciiString) {
|
||||
validateName((AsciiString) name);
|
||||
} else {
|
||||
validateName(name);
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static void validateName(AsciiString name) {
|
||||
// Go through each characters in the name
|
||||
final int start = name.arrayOffset();
|
||||
final int end = start + name.length();
|
||||
final byte[] array = name.array();
|
||||
for (int index = start; index < end; index ++) {
|
||||
byte b = array[index];
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (b < 0) {
|
||||
throw new IllegalArgumentException("a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters.
|
||||
validateNameChar(name, b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateName(CharSequence name) {
|
||||
// Go through each characters in the name
|
||||
for (int index = 0; index < name.length(); index++) {
|
||||
char character = name.charAt(index);
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (character > 127) {
|
||||
throw new IllegalArgumentException("a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters
|
||||
validateNameChar(name, character);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateNameChar(CharSequence name, int character) {
|
||||
if ((character & HIGHEST_INVALID_NAME_CHAR_MASK) == 0 && LOOKUP_TABLE[character] != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header name cannot contain the following prohibited characters: =,;: \\t\\r\\n\\v\\f: " +
|
||||
name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final HttpHeadersValidationConverter
|
||||
VALIDATE_OBJECT_CONVERTER = new HttpHeadersValidationConverter(true);
|
||||
private static final HttpHeadersValidationConverter
|
||||
NO_VALIDATE_OBJECT_CONVERTER = new HttpHeadersValidationConverter(false);
|
||||
private static final HttpHeadersNameConverter VALIDATE_NAME_CONVERTER = new HttpHeadersNameConverter(true);
|
||||
private static final HttpHeadersNameConverter NO_VALIDATE_NAME_CONVERTER = new HttpHeadersNameConverter(false);
|
||||
|
||||
public DefaultHttpHeaders() {
|
||||
this(true);
|
||||
}
|
||||
|
||||
public DefaultHttpHeaders(boolean validate) {
|
||||
headers = validate? new ValidatingTextHeaders() : new NonValidatingTextHeaders();
|
||||
this(true, validate? VALIDATE_NAME_CONVERTER : NO_VALIDATE_NAME_CONVERTER);
|
||||
}
|
||||
|
||||
DefaultHttpHeaders(TextHeaders headers) {
|
||||
this.headers = headers;
|
||||
protected DefaultHttpHeaders(boolean validate, NameConverter<CharSequence> nameConverter) {
|
||||
headers = new DefaultTextHeaders(true,
|
||||
validate ? VALIDATE_OBJECT_CONVERTER : NO_VALIDATE_OBJECT_CONVERTER, nameConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,25 +275,25 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(String name, Object value) {
|
||||
headers.add(name, value);
|
||||
headers.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(CharSequence name, Object value) {
|
||||
headers.add(name, value);
|
||||
headers.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(String name, Iterable<?> values) {
|
||||
headers.add(name, values);
|
||||
headers.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders add(CharSequence name, Iterable<?> values) {
|
||||
headers.add(name, values);
|
||||
headers.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -101,25 +311,25 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(String name, Object value) {
|
||||
headers.set(name, value);
|
||||
headers.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(CharSequence name, Object value) {
|
||||
headers.set(name, value);
|
||||
headers.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(String name, Iterable<?> values) {
|
||||
headers.set(name, values);
|
||||
headers.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders set(CharSequence name, Iterable<?> values) {
|
||||
headers.set(name, values);
|
||||
headers.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -131,32 +341,32 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
@Override
|
||||
public String get(String name) {
|
||||
return headers.get(name);
|
||||
return headers.getAndConvert(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(CharSequence name) {
|
||||
return headers.get(name);
|
||||
return headers.getAndConvert(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(String name) {
|
||||
return headers.getAll(name);
|
||||
return headers.getAllAndConvert(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(CharSequence name) {
|
||||
return headers.getAll(name);
|
||||
return headers.getAllAndConvert(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
return headers.entries();
|
||||
return headers.entriesConverted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return headers.iterator();
|
||||
return headers.iteratorConverted();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -186,207 +396,10 @@ public class DefaultHttpHeaders extends HttpHeaders {
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
return headers.names();
|
||||
return headers.namesAndConvert(String.CASE_INSENSITIVE_ORDER);
|
||||
}
|
||||
|
||||
void encode(ByteBuf buf) {
|
||||
void encode(ByteBuf buf) throws Exception {
|
||||
headers.forEachEntry(new HttpHeadersEncoder(buf));
|
||||
}
|
||||
|
||||
static class NonValidatingTextHeaders extends DefaultTextHeaders {
|
||||
@Override
|
||||
protected CharSequence convertValue(Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
CharSequence seq;
|
||||
if (value instanceof CharSequence) {
|
||||
seq = (CharSequence) value;
|
||||
} else if (value instanceof Number) {
|
||||
seq = value.toString();
|
||||
} else if (value instanceof Date) {
|
||||
seq = HttpHeaderDateFormat.get().format((Date) value);
|
||||
} else if (value instanceof Calendar) {
|
||||
seq = HttpHeaderDateFormat.get().format(((Calendar) value).getTime());
|
||||
} else {
|
||||
seq = value.toString();
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
||||
static class ValidatingTextHeaders extends NonValidatingTextHeaders {
|
||||
private static final int HIGHEST_INVALID_NAME_CHAR_MASK = ~63;
|
||||
private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~15;
|
||||
|
||||
/**
|
||||
* A look-up table used for checking if a character in a header name is prohibited.
|
||||
*/
|
||||
private static final byte[] LOOKUP_TABLE = new byte[~HIGHEST_INVALID_NAME_CHAR_MASK + 1];
|
||||
|
||||
static {
|
||||
LOOKUP_TABLE['\t'] = -1;
|
||||
LOOKUP_TABLE['\n'] = -1;
|
||||
LOOKUP_TABLE[0x0b] = -1;
|
||||
LOOKUP_TABLE['\f'] = -1;
|
||||
LOOKUP_TABLE[' '] = -1;
|
||||
LOOKUP_TABLE[','] = -1;
|
||||
LOOKUP_TABLE[':'] = -1;
|
||||
LOOKUP_TABLE[';'] = -1;
|
||||
LOOKUP_TABLE['='] = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence convertName(CharSequence name) {
|
||||
name = super.convertName(name);
|
||||
if (name instanceof AsciiString) {
|
||||
validateName((AsciiString) name);
|
||||
} else {
|
||||
validateName(name);
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static void validateName(AsciiString name) {
|
||||
// Go through each characters in the name
|
||||
final int start = name.arrayOffset();
|
||||
final int end = start + name.length();
|
||||
final byte[] array = name.array();
|
||||
for (int index = start; index < end; index ++) {
|
||||
byte b = array[index];
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (b < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters.
|
||||
validateNameChar(name, b);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateName(CharSequence name) {
|
||||
// Go through each characters in the name
|
||||
for (int index = 0; index < name.length(); index ++) {
|
||||
char character = name.charAt(index);
|
||||
|
||||
// Check to see if the character is not an ASCII character
|
||||
if (character > 127) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header name cannot contain non-ASCII characters: " + name);
|
||||
}
|
||||
|
||||
// Check for prohibited characters.
|
||||
validateNameChar(name, character);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateNameChar(CharSequence name, int character) {
|
||||
if ((character & HIGHEST_INVALID_NAME_CHAR_MASK) == 0 && LOOKUP_TABLE[character] != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header name cannot contain the following prohibited characters: " +
|
||||
"=,;: \\t\\r\\n\\v\\f: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence convertValue(Object value) {
|
||||
CharSequence seq = super.convertValue(value);
|
||||
if (value instanceof AsciiString) {
|
||||
validateValue((AsciiString) seq);
|
||||
} else {
|
||||
validateValue(seq);
|
||||
}
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
private static void validateValue(AsciiString seq) {
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
final int start = seq.arrayOffset();
|
||||
final int end = start + seq.length();
|
||||
final byte[] array = seq.array();
|
||||
for (int index = start; index < end; index ++) {
|
||||
state = validateValueChar(seq, state, (char) (array[index] & 0xFF));
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header value must not end with '\\r' or '\\n':" + seq);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateValue(CharSequence seq) {
|
||||
int state = 0;
|
||||
// Start looping through each of the character
|
||||
for (int index = 0; index < seq.length(); index ++) {
|
||||
state = validateValueChar(seq, state, seq.charAt(index));
|
||||
}
|
||||
|
||||
if (state != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"a header value must not end with '\\r' or '\\n':" + seq);
|
||||
}
|
||||
}
|
||||
|
||||
private static int validateValueChar(CharSequence seq, int state, char character) {
|
||||
/*
|
||||
* State:
|
||||
*
|
||||
* 0: Previous character was neither CR nor LF
|
||||
* 1: The previous character was CR
|
||||
* 2: The previous character was LF
|
||||
*/
|
||||
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
|
||||
// Check the absolutely prohibited characters.
|
||||
switch (character) {
|
||||
case 0x0b: // Vertical tab
|
||||
throw new IllegalArgumentException(
|
||||
"a header value contains a prohibited character '\\v': " + seq);
|
||||
case '\f':
|
||||
throw new IllegalArgumentException(
|
||||
"a header value contains a prohibited character '\\f': " + seq);
|
||||
}
|
||||
}
|
||||
|
||||
// Check the CRLF (HT | SP) pattern
|
||||
switch (state) {
|
||||
case 0:
|
||||
switch (character) {
|
||||
case '\r':
|
||||
state = 1;
|
||||
break;
|
||||
case '\n':
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (character) {
|
||||
case '\n':
|
||||
state = 2;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"only '\\n' is allowed after '\\r': " + seq);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch (character) {
|
||||
case '\t': case ' ':
|
||||
state = 0;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"only ' ' and '\\t' are allowed after '\\n': " + seq);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* The default {@link HttpMessage} implementation.
|
||||
@ -88,7 +88,11 @@ public abstract class DefaultHttpMessage extends DefaultHttpObject implements Ht
|
||||
}
|
||||
|
||||
void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: headers()) {
|
||||
appendHeaders(buf, headers());
|
||||
}
|
||||
|
||||
void appendHeaders(StringBuilder buf, HttpHeaders headers) {
|
||||
for (Entry<String, String> e: headers) {
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
buf.append(e.getValue());
|
||||
|
@ -18,11 +18,11 @@ package io.netty.handler.codec.http;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders.NonValidatingTextHeaders;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders.ValidatingTextHeaders;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||
|
||||
/**
|
||||
* The default {@link LastHttpContent} implementation.
|
||||
@ -42,8 +42,7 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
|
||||
|
||||
public DefaultLastHttpContent(ByteBuf content, boolean validateHeaders) {
|
||||
super(content);
|
||||
trailingHeaders = new DefaultHttpHeaders(
|
||||
validateHeaders? new ValidatingTrailingTextHeaders() : new NonValidatingTextHeaders());
|
||||
trailingHeaders = new TrailingHttpHeaders(validateHeaders);
|
||||
this.validateHeaders = validateHeaders;
|
||||
}
|
||||
|
||||
@ -102,7 +101,7 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
|
||||
}
|
||||
|
||||
private void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: trailingHeaders()) {
|
||||
for (Entry<String, String> e : trailingHeaders()) {
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
buf.append(e.getValue());
|
||||
@ -110,17 +109,33 @@ public class DefaultLastHttpContent extends DefaultHttpContent implements LastHt
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ValidatingTrailingTextHeaders extends ValidatingTextHeaders {
|
||||
@Override
|
||||
protected CharSequence convertName(CharSequence name) {
|
||||
name = super.convertName(name);
|
||||
if (AsciiString.equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH, name) ||
|
||||
AsciiString.equalsIgnoreCase(HttpHeaders.Names.TRANSFER_ENCODING, name) ||
|
||||
AsciiString.equalsIgnoreCase(HttpHeaders.Names.TRAILER, name)) {
|
||||
throw new IllegalArgumentException(
|
||||
"prohibited trailing header: " + name);
|
||||
private static final class TrailingHttpHeaders extends DefaultHttpHeaders {
|
||||
private static final class TrailingHttpHeadersNameConverter extends HttpHeadersNameConverter {
|
||||
TrailingHttpHeadersNameConverter(boolean validate) {
|
||||
super(validate);
|
||||
}
|
||||
return name;
|
||||
|
||||
@Override
|
||||
public CharSequence convertName(CharSequence name) {
|
||||
name = super.convertName(name);
|
||||
if (validate) {
|
||||
if (AsciiString.equalsIgnoreCase(CONTENT_LENGTH, name)
|
||||
|| AsciiString.equalsIgnoreCase(TRANSFER_ENCODING, name)
|
||||
|| AsciiString.equalsIgnoreCase(TRAILER, name)) {
|
||||
throw new IllegalArgumentException("prohibited trailing header: " + name);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private static final TrailingHttpHeadersNameConverter
|
||||
VALIDATE_NAME_CONVERTER = new TrailingHttpHeadersNameConverter(true);
|
||||
private static final TrailingHttpHeadersNameConverter
|
||||
NO_VALIDATE_NAME_CONVERTER = new TrailingHttpHeadersNameConverter(false);
|
||||
|
||||
TrailingHttpHeaders(boolean validate) {
|
||||
super(validate, validate ? VALIDATE_NAME_CONVERTER : NO_VALIDATE_NAME_CONVERTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright 2014 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.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Values;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public final class HttpHeaderUtil {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if the connection can remain open and
|
||||
* thus 'kept alive'. This methods respects the value of the
|
||||
* {@code "Connection"} header first and then the return value of
|
||||
* {@link HttpVersion#isKeepAliveDefault()}.
|
||||
*/
|
||||
public static boolean isKeepAlive(HttpMessage message) {
|
||||
CharSequence connection = message.headers().get(Names.CONNECTION);
|
||||
if (connection != null && AsciiString.equalsIgnoreCase(Values.CLOSE, connection)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (message.protocolVersion().isKeepAliveDefault()) {
|
||||
return !AsciiString.equalsIgnoreCase(Values.CLOSE, connection);
|
||||
} else {
|
||||
return AsciiString.equalsIgnoreCase(Values.KEEP_ALIVE, connection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the {@code "Connection"} header depending on the
|
||||
* protocol version of the specified message. This getMethod sets or removes
|
||||
* the {@code "Connection"} header depending on what the default keep alive
|
||||
* mode of the message's protocol version is, as specified by
|
||||
* {@link HttpVersion#isKeepAliveDefault()}.
|
||||
* <ul>
|
||||
* <li>If the connection is kept alive by default:
|
||||
* <ul>
|
||||
* <li>set to {@code "close"} if {@code keepAlive} is {@code false}.</li>
|
||||
* <li>remove otherwise.</li>
|
||||
* </ul></li>
|
||||
* <li>If the connection is closed by default:
|
||||
* <ul>
|
||||
* <li>set to {@code "keep-alive"} if {@code keepAlive} is {@code true}.</li>
|
||||
* <li>remove otherwise.</li>
|
||||
* </ul></li>
|
||||
* </ul>
|
||||
*/
|
||||
public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
|
||||
HttpHeaders h = message.headers();
|
||||
if (message.protocolVersion().isKeepAliveDefault()) {
|
||||
if (keepAlive) {
|
||||
h.remove(Names.CONNECTION);
|
||||
} else {
|
||||
h.set(Names.CONNECTION, Values.CLOSE);
|
||||
}
|
||||
} else {
|
||||
if (keepAlive) {
|
||||
h.set(Names.CONNECTION, Values.KEEP_ALIVE);
|
||||
} else {
|
||||
h.remove(Names.CONNECTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link HttpContent#content()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length
|
||||
*
|
||||
* @throws NumberFormatException
|
||||
* if the message does not have the {@code "Content-Length"} header
|
||||
* or its value is not a number
|
||||
*/
|
||||
public static long getContentLength(HttpMessage message) {
|
||||
String value = message.headers().get(Names.CONTENT_LENGTH);
|
||||
if (value != null) {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
// We know the content length if it's a Web Socket message even if
|
||||
// Content-Length header is missing.
|
||||
long webSocketContentLength = getWebSocketContentLength(message);
|
||||
if (webSocketContentLength >= 0) {
|
||||
return webSocketContentLength;
|
||||
}
|
||||
|
||||
// Otherwise we don't.
|
||||
throw new NumberFormatException("header not found: " + Names.CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the content. Please note that this value is
|
||||
* not retrieved from {@link HttpContent#content()} but from the
|
||||
* {@code "Content-Length"} header, and thus they are independent from each
|
||||
* other.
|
||||
*
|
||||
* @return the content length or {@code defaultValue} if this message does
|
||||
* not have the {@code "Content-Length"} header or its value is not
|
||||
* a number
|
||||
*/
|
||||
public static long getContentLength(HttpMessage message, long defaultValue) {
|
||||
String value = message.headers().get(Names.CONTENT_LENGTH);
|
||||
if (value != null) {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
// We know the content length if it's a Web Socket message even if
|
||||
// Content-Length header is missing.
|
||||
long webSocketContentLength = getWebSocketContentLength(message);
|
||||
if (webSocketContentLength >= 0) {
|
||||
return webSocketContentLength;
|
||||
}
|
||||
|
||||
// Otherwise we don't.
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(HttpMessage message) {
|
||||
// WebSockset messages have constant content-lengths.
|
||||
HttpHeaders h = message.headers();
|
||||
if (message instanceof HttpRequest) {
|
||||
HttpRequest req = (HttpRequest) message;
|
||||
if (HttpMethod.GET.equals(req.method()) &&
|
||||
h.contains(Names.SEC_WEBSOCKET_KEY1) &&
|
||||
h.contains(Names.SEC_WEBSOCKET_KEY2)) {
|
||||
return 8;
|
||||
}
|
||||
} else if (message instanceof HttpResponse) {
|
||||
HttpResponse res = (HttpResponse) message;
|
||||
if (res.status().code() == 101 &&
|
||||
h.contains(Names.SEC_WEBSOCKET_ORIGIN) &&
|
||||
h.contains(Names.SEC_WEBSOCKET_LOCATION)) {
|
||||
return 16;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a web socket message
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@code "Content-Length"} header.
|
||||
*/
|
||||
public static void setContentLength(HttpMessage message, long length) {
|
||||
message.headers().set(Names.CONTENT_LENGTH, length);
|
||||
}
|
||||
|
||||
public static boolean isContentLengthSet(HttpMessage m) {
|
||||
return m.headers().contains(Names.CONTENT_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if the specified message contains the
|
||||
* {@code "Expect: 100-continue"} header.
|
||||
*/
|
||||
public static boolean is100ContinueExpected(HttpMessage message) {
|
||||
// Expect: 100-continue is for requests only.
|
||||
if (!(message instanceof HttpRequest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It works only on HTTP/1.1 or later.
|
||||
if (message.protocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// In most cases, there will be one or zero 'Expect' header.
|
||||
CharSequence value = message.headers().get(Names.EXPECT);
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
if (AsciiString.equalsIgnoreCase(Values.CONTINUE, value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Multiple 'Expect' headers. Search through them.
|
||||
return message.headers().contains(Names.EXPECT, Values.CONTINUE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or removes the {@code "Expect: 100-continue"} header to / from the
|
||||
* specified message. If the specified {@code value} is {@code true},
|
||||
* the {@code "Expect: 100-continue"} header is set and all other previous
|
||||
* {@code "Expect"} headers are removed. Otherwise, all {@code "Expect"}
|
||||
* headers are removed completely.
|
||||
*/
|
||||
public static void set100ContinueExpected(HttpMessage message, boolean expected) {
|
||||
if (expected) {
|
||||
message.headers().set(Names.EXPECT, Values.CONTINUE);
|
||||
} else {
|
||||
message.headers().remove(Names.EXPECT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(HttpMessage message) {
|
||||
return message.headers().contains(Names.TRANSFER_ENCODING, Values.CHUNKED, true);
|
||||
}
|
||||
|
||||
public static void setTransferEncodingChunked(HttpMessage m, boolean chunked) {
|
||||
if (chunked) {
|
||||
m.headers().add(Names.TRANSFER_ENCODING, Values.CHUNKED);
|
||||
m.headers().remove(Names.CONTENT_LENGTH);
|
||||
} else {
|
||||
List<String> values = m.headers().getAll(Names.TRANSFER_ENCODING);
|
||||
if (values.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Iterator<String> valuesIt = values.iterator();
|
||||
while (valuesIt.hasNext()) {
|
||||
CharSequence value = valuesIt.next();
|
||||
if (AsciiString.equalsIgnoreCase(value, Values.CHUNKED)) {
|
||||
valuesIt.remove();
|
||||
}
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
m.headers().remove(Names.TRANSFER_ENCODING);
|
||||
} else {
|
||||
m.headers().set(Names.TRANSFER_ENCODING, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void encodeAscii0(CharSequence seq, ByteBuf buf) {
|
||||
int length = seq.length();
|
||||
for (int i = 0 ; i < length; i++) {
|
||||
buf.writeByte((byte) seq.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
private HttpHeaderUtil() { }
|
||||
}
|
@ -15,6 +15,10 @@
|
||||
*/
|
||||
package io.netty.handler.codec.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.COLON;
|
||||
import static io.netty.handler.codec.http.HttpConstants.CR;
|
||||
import static io.netty.handler.codec.http.HttpConstants.LF;
|
||||
import static io.netty.handler.codec.http.HttpConstants.SP;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
|
||||
@ -28,8 +32,6 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpConstants.*;
|
||||
|
||||
/**
|
||||
* Provides the constants for the standard HTTP header names and values and
|
||||
* commonly used utility methods that accesses an {@link HttpMessage}.
|
||||
@ -38,20 +40,20 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
|
||||
private static final byte[] HEADER_SEPERATOR = { COLON, SP };
|
||||
private static final byte[] CRLF = { CR, LF };
|
||||
private static final CharSequence CONTENT_LENGTH_ENTITY = newEntity(Names.CONTENT_LENGTH);
|
||||
private static final CharSequence CONNECTION_ENTITY = newEntity(Names.CONNECTION);
|
||||
private static final CharSequence CLOSE_ENTITY = newEntity(Values.CLOSE);
|
||||
private static final CharSequence KEEP_ALIVE_ENTITY = newEntity(Values.KEEP_ALIVE);
|
||||
private static final CharSequence HOST_ENTITY = newEntity(Names.HOST);
|
||||
private static final CharSequence DATE_ENTITY = newEntity(Names.DATE);
|
||||
private static final CharSequence EXPECT_ENTITY = newEntity(Names.EXPECT);
|
||||
private static final CharSequence CONTINUE_ENTITY = newEntity(Values.CONTINUE);
|
||||
private static final CharSequence TRANSFER_ENCODING_ENTITY = newEntity(Names.TRANSFER_ENCODING);
|
||||
private static final CharSequence CHUNKED_ENTITY = newEntity(Values.CHUNKED);
|
||||
private static final CharSequence SEC_WEBSOCKET_KEY1_ENTITY = newEntity(Names.SEC_WEBSOCKET_KEY1);
|
||||
private static final CharSequence SEC_WEBSOCKET_KEY2_ENTITY = newEntity(Names.SEC_WEBSOCKET_KEY2);
|
||||
private static final CharSequence SEC_WEBSOCKET_ORIGIN_ENTITY = newEntity(Names.SEC_WEBSOCKET_ORIGIN);
|
||||
private static final CharSequence SEC_WEBSOCKET_LOCATION_ENTITY = newEntity(Names.SEC_WEBSOCKET_LOCATION);
|
||||
private static final CharSequence CONTENT_LENGTH_ENTITY = Names.CONTENT_LENGTH;
|
||||
private static final CharSequence CONNECTION_ENTITY = Names.CONNECTION;
|
||||
private static final CharSequence CLOSE_ENTITY = Values.CLOSE;
|
||||
private static final CharSequence KEEP_ALIVE_ENTITY = Values.KEEP_ALIVE;
|
||||
private static final CharSequence HOST_ENTITY = Names.HOST;
|
||||
private static final CharSequence DATE_ENTITY = Names.DATE;
|
||||
private static final CharSequence EXPECT_ENTITY = Names.EXPECT;
|
||||
private static final CharSequence CONTINUE_ENTITY = Values.CONTINUE;
|
||||
private static final CharSequence TRANSFER_ENCODING_ENTITY = Names.TRANSFER_ENCODING;
|
||||
private static final CharSequence CHUNKED_ENTITY = Values.CHUNKED;
|
||||
private static final CharSequence SEC_WEBSOCKET_KEY1_ENTITY = Names.SEC_WEBSOCKET_KEY1;
|
||||
private static final CharSequence SEC_WEBSOCKET_KEY2_ENTITY = Names.SEC_WEBSOCKET_KEY2;
|
||||
private static final CharSequence SEC_WEBSOCKET_ORIGIN_ENTITY = Names.SEC_WEBSOCKET_ORIGIN;
|
||||
private static final CharSequence SEC_WEBSOCKET_LOCATION_ENTITY = Names.SEC_WEBSOCKET_LOCATION;
|
||||
|
||||
public static final HttpHeaders EMPTY_HEADERS = new HttpHeaders() {
|
||||
@Override
|
||||
@ -122,300 +124,330 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
|
||||
/**
|
||||
* Standard HTTP header names.
|
||||
* <p>
|
||||
* These are all defined as lowercase to support HTTP/2 requirements while also not
|
||||
* violating HTTP/1.x requirements. New header names should always be lowercase.
|
||||
*/
|
||||
public static final class Names {
|
||||
/**
|
||||
* {@code "Accept"}
|
||||
* {@code "accept"}
|
||||
*/
|
||||
public static final String ACCEPT = "Accept";
|
||||
public static final AsciiString ACCEPT = new AsciiString("accept");
|
||||
/**
|
||||
* {@code "Accept-Charset"}
|
||||
* {@code "accept-charset"}
|
||||
*/
|
||||
public static final String ACCEPT_CHARSET = "Accept-Charset";
|
||||
public static final AsciiString ACCEPT_CHARSET = new AsciiString("accept-charset");
|
||||
/**
|
||||
* {@code "Accept-Encoding"}
|
||||
* {@code "accept-encoding"}
|
||||
*/
|
||||
public static final String ACCEPT_ENCODING = "Accept-Encoding";
|
||||
public static final AsciiString ACCEPT_ENCODING = new AsciiString("accept-encoding");
|
||||
/**
|
||||
* {@code "Accept-Language"}
|
||||
* {@code "accept-language"}
|
||||
*/
|
||||
public static final String ACCEPT_LANGUAGE = "Accept-Language";
|
||||
public static final AsciiString ACCEPT_LANGUAGE = new AsciiString("accept-language");
|
||||
/**
|
||||
* {@code "Accept-Ranges"}
|
||||
* {@code "accept-ranges"}
|
||||
*/
|
||||
public static final String ACCEPT_RANGES = "Accept-Ranges";
|
||||
public static final AsciiString ACCEPT_RANGES = new AsciiString("accept-ranges");
|
||||
/**
|
||||
* {@code "Accept-Patch"}
|
||||
* {@code "accept-patch"}
|
||||
*/
|
||||
public static final String ACCEPT_PATCH = "Accept-Patch";
|
||||
public static final AsciiString ACCEPT_PATCH = new AsciiString("accept-patch");
|
||||
/**
|
||||
* {@code "Access-Control-Allow-Credentials"}
|
||||
* {@code "access-control-allow-credentials"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
|
||||
public static final AsciiString ACCESS_CONTROL_ALLOW_CREDENTIALS =
|
||||
new AsciiString("access-control-allow-credentials");
|
||||
/**
|
||||
* {@code "Access-Control-Allow-Headers"}
|
||||
* {@code "access-control-allow-headers"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
|
||||
public static final AsciiString ACCESS_CONTROL_ALLOW_HEADERS =
|
||||
new AsciiString("access-control-allow-headers");
|
||||
/**
|
||||
* {@code "Access-Control-Allow-Methods"}
|
||||
* {@code "access-control-allow-methods"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
|
||||
public static final AsciiString ACCESS_CONTROL_ALLOW_METHODS =
|
||||
new AsciiString("access-control-allow-methods");
|
||||
/**
|
||||
* {@code "Access-Control-Allow-Origin"}
|
||||
* {@code "access-control-allow-origin"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
||||
public static final AsciiString ACCESS_CONTROL_ALLOW_ORIGIN =
|
||||
new AsciiString("access-control-allow-origin");
|
||||
/**
|
||||
* {@code "Access-Control-Expose-Headers"}
|
||||
* {@code "access-control-expose-headers"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
|
||||
public static final AsciiString ACCESS_CONTROL_EXPOSE_HEADERS =
|
||||
new AsciiString("access-control-expose-headers");
|
||||
/**
|
||||
* {@code "Access-Control-Max-Age"}
|
||||
* {@code "access-control-max-age"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
|
||||
public static final AsciiString ACCESS_CONTROL_MAX_AGE = new AsciiString("access-control-max-age");
|
||||
/**
|
||||
* {@code "Access-Control-Request-Headers"}
|
||||
* {@code "access-control-request-headers"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
|
||||
public static final AsciiString ACCESS_CONTROL_REQUEST_HEADERS =
|
||||
new AsciiString("access-control-request-headers");
|
||||
/**
|
||||
* {@code "Access-Control-Request-Method"}
|
||||
* {@code "access-control-request-method"}
|
||||
*/
|
||||
public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
|
||||
public static final AsciiString ACCESS_CONTROL_REQUEST_METHOD =
|
||||
new AsciiString("access-control-request-method");
|
||||
/**
|
||||
* {@code "Age"}
|
||||
* {@code "age"}
|
||||
*/
|
||||
public static final String AGE = "Age";
|
||||
public static final AsciiString AGE = new AsciiString("age");
|
||||
/**
|
||||
* {@code "Allow"}
|
||||
* {@code "allow"}
|
||||
*/
|
||||
public static final String ALLOW = "Allow";
|
||||
public static final AsciiString ALLOW = new AsciiString("allow");
|
||||
/**
|
||||
* {@code "Authorization"}
|
||||
* {@code "authorization"}
|
||||
*/
|
||||
public static final String AUTHORIZATION = "Authorization";
|
||||
public static final AsciiString AUTHORIZATION = new AsciiString("authorization");
|
||||
/**
|
||||
* {@code "Cache-Control"}
|
||||
* {@code "cache-control"}
|
||||
*/
|
||||
public static final String CACHE_CONTROL = "Cache-Control";
|
||||
public static final AsciiString CACHE_CONTROL = new AsciiString("cache-control");
|
||||
/**
|
||||
* {@code "Connection"}
|
||||
* {@code "connection"}
|
||||
*/
|
||||
public static final String CONNECTION = "Connection";
|
||||
public static final AsciiString CONNECTION = new AsciiString("connection");
|
||||
/**
|
||||
* {@code "Content-Base"}
|
||||
* {@code "content-base"}
|
||||
*/
|
||||
public static final String CONTENT_BASE = "Content-Base";
|
||||
public static final AsciiString CONTENT_BASE = new AsciiString("content-base");
|
||||
/**
|
||||
* {@code "Content-Encoding"}
|
||||
* {@code "content-encoding"}
|
||||
*/
|
||||
public static final String CONTENT_ENCODING = "Content-Encoding";
|
||||
public static final AsciiString CONTENT_ENCODING = new AsciiString("content-encoding");
|
||||
/**
|
||||
* {@code "Content-Language"}
|
||||
* {@code "content-language"}
|
||||
*/
|
||||
public static final String CONTENT_LANGUAGE = "Content-Language";
|
||||
public static final AsciiString CONTENT_LANGUAGE = new AsciiString("content-language");
|
||||
/**
|
||||
* {@code "Content-Length"}
|
||||
* {@code "content-length"}
|
||||
*/
|
||||
public static final String CONTENT_LENGTH = "Content-Length";
|
||||
public static final AsciiString CONTENT_LENGTH = new AsciiString("content-length");
|
||||
/**
|
||||
* {@code "Content-Location"}
|
||||
* {@code "content-location"}
|
||||
*/
|
||||
public static final String CONTENT_LOCATION = "Content-Location";
|
||||
public static final AsciiString CONTENT_LOCATION = new AsciiString("content-location");
|
||||
/**
|
||||
* {@code "Content-Transfer-Encoding"}
|
||||
* {@code "content-transfer-encoding"}
|
||||
*/
|
||||
public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
|
||||
public static final AsciiString CONTENT_TRANSFER_ENCODING = new AsciiString("content-transfer-encoding");
|
||||
/**
|
||||
* {@code "Content-MD5"}
|
||||
* {@code "content-disposition"}
|
||||
*/
|
||||
public static final String CONTENT_MD5 = "Content-MD5";
|
||||
public static final AsciiString CONTENT_DISPOSITION = new AsciiString("content-disposition");
|
||||
/**
|
||||
* {@code "Content-Range"}
|
||||
* {@code "content-md5"}
|
||||
*/
|
||||
public static final String CONTENT_RANGE = "Content-Range";
|
||||
public static final AsciiString CONTENT_MD5 = new AsciiString("content-md5");
|
||||
/**
|
||||
* {@code "Content-Type"}
|
||||
* {@code "content-range"}
|
||||
*/
|
||||
public static final String CONTENT_TYPE = "Content-Type";
|
||||
public static final AsciiString CONTENT_RANGE = new AsciiString("content-range");
|
||||
/**
|
||||
* {@code "Cookie"}
|
||||
* {@code "content-type"}
|
||||
*/
|
||||
public static final String COOKIE = "Cookie";
|
||||
public static final AsciiString CONTENT_TYPE = new AsciiString("content-type");
|
||||
/**
|
||||
* {@code "Date"}
|
||||
* {@code "cookie"}
|
||||
*/
|
||||
public static final String DATE = "Date";
|
||||
public static final AsciiString COOKIE = new AsciiString("cookie");
|
||||
/**
|
||||
* {@code "ETag"}
|
||||
* {@code "date"}
|
||||
*/
|
||||
public static final String ETAG = "ETag";
|
||||
public static final AsciiString DATE = new AsciiString("date");
|
||||
/**
|
||||
* {@code "Expect"}
|
||||
* {@code "etag"}
|
||||
*/
|
||||
public static final String EXPECT = "Expect";
|
||||
public static final AsciiString ETAG = new AsciiString("etag");
|
||||
/**
|
||||
* {@code "Expires"}
|
||||
* {@code "expect"}
|
||||
*/
|
||||
public static final String EXPIRES = "Expires";
|
||||
public static final AsciiString EXPECT = new AsciiString("expect");
|
||||
/**
|
||||
* {@code "From"}
|
||||
* {@code "expires"}
|
||||
*/
|
||||
public static final String FROM = "From";
|
||||
public static final AsciiString EXPIRES = new AsciiString("expires");
|
||||
/**
|
||||
* {@code "Host"}
|
||||
* {@code "from"}
|
||||
*/
|
||||
public static final String HOST = "Host";
|
||||
public static final AsciiString FROM = new AsciiString("from");
|
||||
/**
|
||||
* {@code "If-Match"}
|
||||
* {@code "host"}
|
||||
*/
|
||||
public static final String IF_MATCH = "If-Match";
|
||||
public static final AsciiString HOST = new AsciiString("host");
|
||||
/**
|
||||
* {@code "If-Modified-Since"}
|
||||
* {@code "if-match"}
|
||||
*/
|
||||
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
|
||||
public static final AsciiString IF_MATCH = new AsciiString("if-match");
|
||||
/**
|
||||
* {@code "If-None-Match"}
|
||||
* {@code "if-modified-since"}
|
||||
*/
|
||||
public static final String IF_NONE_MATCH = "If-None-Match";
|
||||
public static final AsciiString IF_MODIFIED_SINCE = new AsciiString("if-modified-since");
|
||||
/**
|
||||
* {@code "If-Range"}
|
||||
* {@code "if-none-match"}
|
||||
*/
|
||||
public static final String IF_RANGE = "If-Range";
|
||||
public static final AsciiString IF_NONE_MATCH = new AsciiString("if-none-match");
|
||||
/**
|
||||
* {@code "If-Unmodified-Since"}
|
||||
* {@code "if-range"}
|
||||
*/
|
||||
public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
|
||||
public static final AsciiString IF_RANGE = new AsciiString("if-range");
|
||||
/**
|
||||
* {@code "Last-Modified"}
|
||||
* {@code "if-unmodified-since"}
|
||||
*/
|
||||
public static final String LAST_MODIFIED = "Last-Modified";
|
||||
public static final AsciiString IF_UNMODIFIED_SINCE = new AsciiString("if-unmodified-since");
|
||||
/**
|
||||
* {@code "Location"}
|
||||
* {@code "last-modified"}
|
||||
*/
|
||||
public static final String LOCATION = "Location";
|
||||
public static final AsciiString LAST_MODIFIED = new AsciiString("last-modified");
|
||||
/**
|
||||
* {@code "Max-Forwards"}
|
||||
* {@code "location"}
|
||||
*/
|
||||
public static final String MAX_FORWARDS = "Max-Forwards";
|
||||
public static final AsciiString LOCATION = new AsciiString("location");
|
||||
/**
|
||||
* {@code "Origin"}
|
||||
* {@code "max-forwards"}
|
||||
*/
|
||||
public static final String ORIGIN = "Origin";
|
||||
public static final AsciiString MAX_FORWARDS = new AsciiString("max-forwards");
|
||||
/**
|
||||
* {@code "Pragma"}
|
||||
* {@code "origin"}
|
||||
*/
|
||||
public static final String PRAGMA = "Pragma";
|
||||
public static final AsciiString ORIGIN = new AsciiString("origin");
|
||||
/**
|
||||
* {@code "Proxy-Authenticate"}
|
||||
* {@code "pragma"}
|
||||
*/
|
||||
public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
|
||||
public static final AsciiString PRAGMA = new AsciiString("pragma");
|
||||
/**
|
||||
* {@code "Proxy-Authorization"}
|
||||
* {@code "proxy-authenticate"}
|
||||
*/
|
||||
public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
|
||||
public static final AsciiString PROXY_AUTHENTICATE = new AsciiString("proxy-authenticate");
|
||||
/**
|
||||
* {@code "Range"}
|
||||
* {@code "proxy-authorization"}
|
||||
*/
|
||||
public static final String RANGE = "Range";
|
||||
public static final AsciiString PROXY_AUTHORIZATION = new AsciiString("proxy-authorization");
|
||||
/**
|
||||
* {@code "Referer"}
|
||||
* {@code "range"}
|
||||
*/
|
||||
public static final String REFERER = "Referer";
|
||||
public static final AsciiString RANGE = new AsciiString("range");
|
||||
/**
|
||||
* {@code "Retry-After"}
|
||||
* {@code "referer"}
|
||||
*/
|
||||
public static final String RETRY_AFTER = "Retry-After";
|
||||
public static final AsciiString REFERER = new AsciiString("referer");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Key1"}
|
||||
* {@code "retry-after"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1";
|
||||
public static final AsciiString RETRY_AFTER = new AsciiString("retry-after");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Key2"}
|
||||
* {@code "sec-websocket-key1"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2";
|
||||
public static final AsciiString SEC_WEBSOCKET_KEY1 = new AsciiString("sec-websocket-key1");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Location"}
|
||||
* {@code "sec-websocket-key2"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location";
|
||||
public static final AsciiString SEC_WEBSOCKET_KEY2 = new AsciiString("sec-websocket-key2");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Origin"}
|
||||
* {@code "sec-websocket-location"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin";
|
||||
public static final AsciiString SEC_WEBSOCKET_LOCATION = new AsciiString("sec-websocket-location");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Protocol"}
|
||||
* {@code "sec-websocket-origin"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
|
||||
public static final AsciiString SEC_WEBSOCKET_ORIGIN = new AsciiString("sec-websocket-origin");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Version"}
|
||||
* {@code "sec-websocket-protocol"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
|
||||
public static final AsciiString SEC_WEBSOCKET_PROTOCOL = new AsciiString("sec-websocket-protocol");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Key"}
|
||||
* {@code "sec-websocket-version"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
|
||||
public static final AsciiString SEC_WEBSOCKET_VERSION = new AsciiString("sec-websocket-version");
|
||||
/**
|
||||
* {@code "Sec-WebSocket-Accept"}
|
||||
* {@code "sec-websocket-key"}
|
||||
*/
|
||||
public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
|
||||
public static final AsciiString SEC_WEBSOCKET_KEY = new AsciiString("sec-websocket-key");
|
||||
/**
|
||||
* {@code "Server"}
|
||||
* {@code "sec-websocket-accept"}
|
||||
*/
|
||||
public static final String SERVER = "Server";
|
||||
public static final AsciiString SEC_WEBSOCKET_ACCEPT = new AsciiString("sec-websocket-accept");
|
||||
/**
|
||||
* {@code "Set-Cookie"}
|
||||
* {@code "sec-websocket-protocol"}
|
||||
*/
|
||||
public static final String SET_COOKIE = "Set-Cookie";
|
||||
public static final AsciiString SEC_WEBSOCKET_EXTENSIONS = new AsciiString("sec-websocket-extensions");
|
||||
/**
|
||||
* {@code "Set-Cookie2"}
|
||||
* {@code "server"}
|
||||
*/
|
||||
public static final String SET_COOKIE2 = "Set-Cookie2";
|
||||
public static final AsciiString SERVER = new AsciiString("server");
|
||||
/**
|
||||
* {@code "TE"}
|
||||
* {@code "set-cookie"}
|
||||
*/
|
||||
public static final String TE = "TE";
|
||||
public static final AsciiString SET_COOKIE = new AsciiString("set-cookie");
|
||||
/**
|
||||
* {@code "Trailer"}
|
||||
* {@code "set-cookie2"}
|
||||
*/
|
||||
public static final String TRAILER = "Trailer";
|
||||
public static final AsciiString SET_COOKIE2 = new AsciiString("set-cookie2");
|
||||
/**
|
||||
* {@code "Transfer-Encoding"}
|
||||
* {@code "te"}
|
||||
*/
|
||||
public static final String TRANSFER_ENCODING = "Transfer-Encoding";
|
||||
public static final AsciiString TE = new AsciiString("te");
|
||||
/**
|
||||
* {@code "Upgrade"}
|
||||
* {@code "trailer"}
|
||||
*/
|
||||
public static final String UPGRADE = "Upgrade";
|
||||
public static final AsciiString TRAILER = new AsciiString("trailer");
|
||||
/**
|
||||
* {@code "User-Agent"}
|
||||
* {@code "transfer-encoding"}
|
||||
*/
|
||||
public static final String USER_AGENT = "User-Agent";
|
||||
public static final AsciiString TRANSFER_ENCODING = new AsciiString("transfer-encoding");
|
||||
/**
|
||||
* {@code "Vary"}
|
||||
* {@code "upgrade"}
|
||||
*/
|
||||
public static final String VARY = "Vary";
|
||||
public static final AsciiString UPGRADE = new AsciiString("upgrade");
|
||||
/**
|
||||
* {@code "Via"}
|
||||
* {@code "user-agent"}
|
||||
*/
|
||||
public static final String VIA = "Via";
|
||||
public static final AsciiString USER_AGENT = new AsciiString("user-agent");
|
||||
/**
|
||||
* {@code "Warning"}
|
||||
* {@code "vary"}
|
||||
*/
|
||||
public static final String WARNING = "Warning";
|
||||
public static final AsciiString VARY = new AsciiString("vary");
|
||||
/**
|
||||
* {@code "WebSocket-Location"}
|
||||
* {@code "via"}
|
||||
*/
|
||||
public static final String WEBSOCKET_LOCATION = "WebSocket-Location";
|
||||
public static final AsciiString VIA = new AsciiString("via");
|
||||
/**
|
||||
* {@code "WebSocket-Origin"}
|
||||
* {@code "warning"}
|
||||
*/
|
||||
public static final String WEBSOCKET_ORIGIN = "WebSocket-Origin";
|
||||
public static final AsciiString WARNING = new AsciiString("warning");
|
||||
/**
|
||||
* {@code "WebSocket-Protocol"}
|
||||
* {@code "websocket-location"}
|
||||
*/
|
||||
public static final String WEBSOCKET_PROTOCOL = "WebSocket-Protocol";
|
||||
public static final AsciiString WEBSOCKET_LOCATION = new AsciiString("websocket-location");
|
||||
/**
|
||||
* {@code "WWW-Authenticate"}
|
||||
* {@code "websocket-origin"}
|
||||
*/
|
||||
public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
|
||||
public static final AsciiString WEBSOCKET_ORIGIN = new AsciiString("websocket-origin");
|
||||
/**
|
||||
* {@code "websocket-protocol"}
|
||||
*/
|
||||
public static final AsciiString WEBSOCKET_PROTOCOL = new AsciiString("websocket-protocol");
|
||||
/**
|
||||
* {@code "www-authenticate"}
|
||||
*/
|
||||
public static final AsciiString WWW_AUTHENTICATE = new AsciiString("www-authenticate");
|
||||
/**
|
||||
* {@code "keep-alive"}
|
||||
* @deprecated use {@link #CONNECTION}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final AsciiString KEEP_ALIVE = new AsciiString("keep-alive");
|
||||
/**
|
||||
* {@code "proxy-connection"}
|
||||
* @deprecated use {@link #CONNECTION}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final AsciiString PROXY_CONNECTION = new AsciiString("proxy-connection");
|
||||
|
||||
private Names() {
|
||||
}
|
||||
@ -428,8 +460,16 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
/**
|
||||
* {@code "application/x-www-form-urlencoded"}
|
||||
*/
|
||||
public static final String APPLICATION_X_WWW_FORM_URLENCODED =
|
||||
"application/x-www-form-urlencoded";
|
||||
public static final AsciiString APPLICATION_X_WWW_FORM_URLENCODED =
|
||||
new AsciiString("application/x-www-form-urlencoded");
|
||||
/**
|
||||
* {@code "application/octet-stream"}
|
||||
*/
|
||||
public static final AsciiString APPLICATION_OCTET_STREAM = new AsciiString("application/octet-stream");
|
||||
/**
|
||||
* {@code "text/plain"}
|
||||
*/
|
||||
public static final AsciiString TEXT_PLAIN = new AsciiString("text/plain");
|
||||
/**
|
||||
* {@code "base64"}
|
||||
*/
|
||||
@ -498,6 +538,10 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
* {@code "multipart/form-data"}
|
||||
*/
|
||||
public static final String MULTIPART_FORM_DATA = "multipart/form-data";
|
||||
/**
|
||||
* {@code "multipart/mixed"}
|
||||
*/
|
||||
public static final AsciiString MULTIPART_MIXED = new AsciiString("multipart/mixed");
|
||||
/**
|
||||
* {@code "must-revalidate"}
|
||||
*/
|
||||
@ -553,7 +597,32 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
/**
|
||||
* {@code "WebSocket"}
|
||||
*/
|
||||
public static final String WEBSOCKET = "WebSocket";
|
||||
public static final AsciiString WEBSOCKET = new AsciiString("WebSocket");
|
||||
/**
|
||||
* {@code "name"}
|
||||
* See {@link Names#CONTENT_DISPOSITION}
|
||||
*/
|
||||
public static final AsciiString NAME = new AsciiString("name");
|
||||
/**
|
||||
* {@code "filename"}
|
||||
* See {@link Names#CONTENT_DISPOSITION}
|
||||
*/
|
||||
public static final AsciiString FILENAME = new AsciiString("filename");
|
||||
/**
|
||||
* {@code "form-data"}
|
||||
* See {@link Names#CONTENT_DISPOSITION}
|
||||
*/
|
||||
public static final AsciiString FORM_DATA = new AsciiString("form-data");
|
||||
/**
|
||||
* {@code "attachment"}
|
||||
* See {@link Names#CONTENT_DISPOSITION}
|
||||
*/
|
||||
public static final AsciiString ATTACHMENT = new AsciiString("attachment");
|
||||
/**
|
||||
* {@code "file"}
|
||||
* See {@link Names#CONTENT_DISPOSITION}
|
||||
*/
|
||||
public static final AsciiString FILE = new AsciiString("file");
|
||||
|
||||
private Values() {
|
||||
}
|
||||
@ -1193,7 +1262,7 @@ public abstract class HttpHeaders implements Iterable<Map.Entry<String, String>>
|
||||
return AsciiString.equalsIgnoreCase(name1, name2);
|
||||
}
|
||||
|
||||
static void encode(HttpHeaders headers, ByteBuf buf) {
|
||||
static void encode(HttpHeaders headers, ByteBuf buf) throws Exception {
|
||||
if (headers instanceof DefaultHttpHeaders) {
|
||||
((DefaultHttpHeaders) headers).encode(buf);
|
||||
} else {
|
||||
|
@ -18,9 +18,11 @@ package io.netty.handler.codec.http;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaderProcessor;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
|
||||
final class HttpHeadersEncoder implements TextHeaderProcessor {
|
||||
import java.util.Map.Entry;
|
||||
|
||||
final class HttpHeadersEncoder implements EntryVisitor {
|
||||
|
||||
private final ByteBuf buf;
|
||||
|
||||
@ -29,7 +31,9 @@ final class HttpHeadersEncoder implements TextHeaderProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(CharSequence name, CharSequence value) throws Exception {
|
||||
public boolean visit(Entry<CharSequence, CharSequence> entry) throws Exception {
|
||||
final CharSequence name = entry.getKey();
|
||||
final CharSequence value = entry.getValue();
|
||||
final ByteBuf buf = this.buf;
|
||||
final int nameLen = name.length();
|
||||
final int valueLen = value.length();
|
||||
|
@ -559,8 +559,12 @@ public abstract class HttpObjectDecoder extends ReplayingDecoder<State> {
|
||||
List<String> current = trailer.trailingHeaders().getAll(lastHeader);
|
||||
if (!current.isEmpty()) {
|
||||
int lastPos = current.size() - 1;
|
||||
String newString = current.get(lastPos) + line.toString().trim();
|
||||
current.set(lastPos, newString);
|
||||
String lineTrimmed = line.toString().trim();
|
||||
CharSequence currentLastPos = current.get(lastPos);
|
||||
StringBuilder b = new StringBuilder(currentLastPos.length() + lineTrimmed.length());
|
||||
b.append(currentLastPos);
|
||||
b.append(lineTrimmed);
|
||||
current.set(lastPos, b.toString());
|
||||
} else {
|
||||
// Content-Length, Transfer-Encoding, or Trailer
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.FileRegion;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
@ -150,7 +151,13 @@ public abstract class HttpObjectEncoder<H extends HttpMessage> extends MessageTo
|
||||
} else {
|
||||
ByteBuf buf = ctx.alloc().buffer();
|
||||
buf.writeBytes(ZERO_CRLF);
|
||||
HttpHeaders.encode(headers, buf);
|
||||
|
||||
try {
|
||||
HttpHeaders.encode(headers, buf);
|
||||
} catch (Exception ex) {
|
||||
buf.release();
|
||||
PlatformDependent.throwException(ex);
|
||||
}
|
||||
buf.writeBytes(CRLF);
|
||||
out.add(buf);
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public class CorsHandler extends ChannelDuplexHandler {
|
||||
}
|
||||
|
||||
private boolean setOrigin(final HttpResponse response) {
|
||||
final String origin = request.headers().get(ORIGIN);
|
||||
final CharSequence origin = request.headers().get(ORIGIN);
|
||||
if (origin != null) {
|
||||
if ("null".equals(origin) && config.isNullOriginAllowed()) {
|
||||
setAnyOrigin(response);
|
||||
@ -118,7 +118,7 @@ public class CorsHandler extends ChannelDuplexHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String origin = request.headers().get(ORIGIN);
|
||||
final CharSequence origin = request.headers().get(ORIGIN);
|
||||
if (origin == null) {
|
||||
// Not a CORS request so we cannot validate it. It may be a non CORS request.
|
||||
return true;
|
||||
@ -143,7 +143,7 @@ public class CorsHandler extends ChannelDuplexHandler {
|
||||
setOrigin(response, "*");
|
||||
}
|
||||
|
||||
private static void setOrigin(final HttpResponse response, final String origin) {
|
||||
private static void setOrigin(final HttpResponse response, final CharSequence origin) {
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
package io.netty.handler.codec.http.multipart;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
@ -29,31 +30,31 @@ final class HttpPostBodyUtil {
|
||||
/**
|
||||
* HTTP content disposition header name.
|
||||
*/
|
||||
public static final String CONTENT_DISPOSITION = "Content-Disposition";
|
||||
public static final String CONTENT_DISPOSITION = HttpHeaders.Names.CONTENT_DISPOSITION.toString();
|
||||
|
||||
public static final String NAME = "name";
|
||||
public static final String NAME = HttpHeaders.Values.NAME.toString();
|
||||
|
||||
public static final String FILENAME = "filename";
|
||||
public static final String FILENAME = HttpHeaders.Values.FILENAME.toString();
|
||||
|
||||
/**
|
||||
* Content-disposition value for form data.
|
||||
*/
|
||||
public static final String FORM_DATA = "form-data";
|
||||
public static final String FORM_DATA = HttpHeaders.Values.FORM_DATA.toString();
|
||||
|
||||
/**
|
||||
* Content-disposition value for file attachment.
|
||||
*/
|
||||
public static final String ATTACHMENT = "attachment";
|
||||
public static final String ATTACHMENT = HttpHeaders.Values.ATTACHMENT.toString();
|
||||
|
||||
/**
|
||||
* Content-disposition value for file attachment.
|
||||
*/
|
||||
public static final String FILE = "file";
|
||||
public static final String FILE = HttpHeaders.Values.FILE.toString();
|
||||
|
||||
/**
|
||||
* HTTP content type body attribute for multiple uploads.
|
||||
*/
|
||||
public static final String MULTIPART_MIXED = "multipart/mixed";
|
||||
public static final String MULTIPART_MIXED = HttpHeaders.Values.MULTIPART_MIXED.toString();
|
||||
|
||||
/**
|
||||
* Charset for 8BIT
|
||||
@ -68,12 +69,12 @@ final class HttpPostBodyUtil {
|
||||
/**
|
||||
* Default Content-Type in binary form
|
||||
*/
|
||||
public static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream";
|
||||
public static final String DEFAULT_BINARY_CONTENT_TYPE = HttpHeaders.Values.APPLICATION_OCTET_STREAM.toString();
|
||||
|
||||
/**
|
||||
* Default Content-Type in Text form
|
||||
*/
|
||||
public static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain";
|
||||
public static final String DEFAULT_TEXT_CONTENT_TYPE = HttpHeaders.Values.TEXT_PLAIN.toString();
|
||||
|
||||
/**
|
||||
* Allowed mechanism for multipart
|
||||
|
@ -16,6 +16,7 @@
|
||||
package io.netty.handler.codec.http.multipart;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpConstants;
|
||||
import io.netty.handler.codec.http.HttpContent;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
@ -695,10 +696,10 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
currentFieldAttributes.put(attribute.getName(), attribute);
|
||||
}
|
||||
}
|
||||
} else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING)) {
|
||||
} else if (AsciiString.equalsIgnoreCase(contents[0], HttpHeaders.Names.CONTENT_TRANSFER_ENCODING)) {
|
||||
Attribute attribute;
|
||||
try {
|
||||
attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_TRANSFER_ENCODING,
|
||||
attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_TRANSFER_ENCODING.toString(),
|
||||
cleanString(contents[1]));
|
||||
} catch (NullPointerException e) {
|
||||
throw new ErrorDataDecoderException(e);
|
||||
@ -706,10 +707,10 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
throw new ErrorDataDecoderException(e);
|
||||
}
|
||||
currentFieldAttributes.put(HttpHeaders.Names.CONTENT_TRANSFER_ENCODING, attribute);
|
||||
} else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
} else if (AsciiString.equalsIgnoreCase(contents[0], HttpHeaders.Names.CONTENT_LENGTH)) {
|
||||
Attribute attribute;
|
||||
try {
|
||||
attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_LENGTH,
|
||||
attribute = factory.createAttribute(request, HttpHeaders.Names.CONTENT_LENGTH.toString(),
|
||||
cleanString(contents[1]));
|
||||
} catch (NullPointerException e) {
|
||||
throw new ErrorDataDecoderException(e);
|
||||
@ -717,7 +718,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
throw new ErrorDataDecoderException(e);
|
||||
}
|
||||
currentFieldAttributes.put(HttpHeaders.Names.CONTENT_LENGTH, attribute);
|
||||
} else if (contents[0].equalsIgnoreCase(HttpHeaders.Names.CONTENT_TYPE)) {
|
||||
} else if (AsciiString.equalsIgnoreCase(contents[0], HttpHeaders.Names.CONTENT_TYPE)) {
|
||||
// Take care of possible "multipart/mixed"
|
||||
if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) {
|
||||
if (currentStatus == MultiPartStatus.DISPOSITION) {
|
||||
|
@ -716,7 +716,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
|
||||
// "multipart/form-data; boundary=--89421926422648"
|
||||
String lowercased = contentType.toLowerCase();
|
||||
if (lowercased.startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA) ||
|
||||
lowercased.startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
|
||||
lowercased.startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED.toString())) {
|
||||
// ignore
|
||||
} else {
|
||||
headers.add(HttpHeaders.Names.CONTENT_TYPE, contentType);
|
||||
@ -744,7 +744,7 @@ public class HttpPostRequestEncoder implements ChunkedInput<HttpContent> {
|
||||
isChunked = true;
|
||||
if (transferEncoding != null) {
|
||||
headers.remove(HttpHeaders.Names.TRANSFER_ENCODING);
|
||||
for (String v : transferEncoding) {
|
||||
for (CharSequence v : transferEncoding) {
|
||||
if (AsciiString.equalsIgnoreCase(v, HttpHeaders.Values.CHUNKED)) {
|
||||
// ignore
|
||||
} else {
|
||||
|
@ -198,13 +198,13 @@ public class WebSocketClientHandshaker00 extends WebSocketClientHandshaker {
|
||||
|
||||
HttpHeaders headers = response.headers();
|
||||
|
||||
String upgrade = headers.get(Names.UPGRADE);
|
||||
CharSequence upgrade = headers.get(Names.UPGRADE);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: "
|
||||
+ upgrade);
|
||||
}
|
||||
|
||||
String connection = headers.get(Names.CONNECTION);
|
||||
CharSequence connection = headers.get(Names.CONNECTION);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: "
|
||||
+ connection);
|
||||
|
@ -41,7 +41,7 @@ import java.net.URI;
|
||||
public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker07.class);
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
private String expectedChallengeResponseString;
|
||||
@ -207,17 +207,17 @@ public class WebSocketClientHandshaker07 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response getStatus: " + response.status());
|
||||
}
|
||||
|
||||
String upgrade = headers.get(Names.UPGRADE);
|
||||
CharSequence upgrade = headers.get(Names.UPGRADE);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||
}
|
||||
|
||||
String connection = headers.get(Names.CONNECTION);
|
||||
CharSequence connection = headers.get(Names.CONNECTION);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||
}
|
||||
|
||||
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
CharSequence accept = 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));
|
||||
|
@ -41,7 +41,7 @@ import java.net.URI;
|
||||
public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker08.class);
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
|
||||
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@ -208,17 +208,17 @@ public class WebSocketClientHandshaker08 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response getStatus: " + response.status());
|
||||
}
|
||||
|
||||
String upgrade = headers.get(Names.UPGRADE);
|
||||
CharSequence upgrade = headers.get(Names.UPGRADE);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||
}
|
||||
|
||||
String connection = headers.get(Names.CONNECTION);
|
||||
CharSequence connection = headers.get(Names.CONNECTION);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||
}
|
||||
|
||||
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
CharSequence accept = 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));
|
||||
|
@ -41,7 +41,7 @@ import java.net.URI;
|
||||
public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClientHandshaker13.class);
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
|
||||
public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@ -218,17 +218,17 @@ public class WebSocketClientHandshaker13 extends WebSocketClientHandshaker {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response getStatus: " + response.status());
|
||||
}
|
||||
|
||||
String upgrade = headers.get(Names.UPGRADE);
|
||||
CharSequence upgrade = headers.get(Names.UPGRADE);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.WEBSOCKET, upgrade)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response upgrade: " + upgrade);
|
||||
}
|
||||
|
||||
String connection = headers.get(Names.CONNECTION);
|
||||
CharSequence connection = headers.get(Names.CONNECTION);
|
||||
if (!AsciiString.equalsIgnoreCase(Values.UPGRADE, connection)) {
|
||||
throw new WebSocketHandshakeException("Invalid handshake response connection: " + connection);
|
||||
}
|
||||
|
||||
String accept = headers.get(Names.SEC_WEBSOCKET_ACCEPT);
|
||||
CharSequence accept = 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));
|
||||
|
@ -35,7 +35,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
*/
|
||||
public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
|
||||
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
|
||||
public static final String WEBSOCKET_07_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@ -129,7 +129,7 @@ public class WebSocketServerHandshaker07 extends WebSocketServerHandshaker {
|
||||
res.headers().add(headers);
|
||||
}
|
||||
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
CharSequence key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
*/
|
||||
public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
|
||||
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
|
||||
public static final String WEBSOCKET_08_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@ -128,7 +128,7 @@ public class WebSocketServerHandshaker08 extends WebSocketServerHandshaker {
|
||||
res.headers().add(headers);
|
||||
}
|
||||
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
CharSequence key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ import static io.netty.handler.codec.http.HttpVersion.*;
|
||||
*/
|
||||
public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
|
||||
|
||||
private static final CharSequence WEBSOCKET = HttpHeaders.newEntity(Values.WEBSOCKET.toLowerCase());
|
||||
private static final CharSequence WEBSOCKET = Values.WEBSOCKET.toLowerCase();
|
||||
|
||||
public static final String WEBSOCKET_13_ACCEPT_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@ -126,7 +126,7 @@ public class WebSocketServerHandshaker13 extends WebSocketServerHandshaker {
|
||||
res.headers().add(headers);
|
||||
}
|
||||
|
||||
String key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
CharSequence key = req.headers().get(Names.SEC_WEBSOCKET_KEY);
|
||||
if (key == null) {
|
||||
throw new WebSocketHandshakeException("not a WebSocket request: missing key");
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ public class WebSocketServerHandshakerFactory {
|
||||
*/
|
||||
public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
|
||||
|
||||
String version = req.headers().get(Names.SEC_WEBSOCKET_VERSION);
|
||||
CharSequence 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).
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package io.netty.handler.codec.rtsp;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
|
||||
|
||||
@ -30,179 +31,179 @@ public final class RtspHeaders {
|
||||
/**
|
||||
* {@code "Accept"}
|
||||
*/
|
||||
public static final String ACCEPT = HttpHeaders.Names.ACCEPT;
|
||||
public static final AsciiString ACCEPT = HttpHeaders.Names.ACCEPT;
|
||||
/**
|
||||
* {@code "Accept-Encoding"}
|
||||
*/
|
||||
public static final String ACCEPT_ENCODING = HttpHeaders.Names.ACCEPT_ENCODING;
|
||||
public static final AsciiString ACCEPT_ENCODING = HttpHeaders.Names.ACCEPT_ENCODING;
|
||||
/**
|
||||
* {@code "Accept-Lanugage"}
|
||||
*/
|
||||
public static final String ACCEPT_LANGUAGE = HttpHeaders.Names.ACCEPT_LANGUAGE;
|
||||
public static final AsciiString ACCEPT_LANGUAGE = HttpHeaders.Names.ACCEPT_LANGUAGE;
|
||||
/**
|
||||
* {@code "Allow"}
|
||||
*/
|
||||
public static final String ALLOW = "Allow";
|
||||
public static final AsciiString ALLOW = new AsciiString("Allow");
|
||||
/**
|
||||
* {@code "Authorization"}
|
||||
*/
|
||||
public static final String AUTHORIZATION = HttpHeaders.Names.AUTHORIZATION;
|
||||
public static final AsciiString AUTHORIZATION = HttpHeaders.Names.AUTHORIZATION;
|
||||
/**
|
||||
* {@code "Bandwidth"}
|
||||
*/
|
||||
public static final String BANDWIDTH = "Bandwidth";
|
||||
public static final AsciiString BANDWIDTH = new AsciiString("Bandwidth");
|
||||
/**
|
||||
* {@code "Blocksize"}
|
||||
*/
|
||||
public static final String BLOCKSIZE = "Blocksize";
|
||||
public static final AsciiString BLOCKSIZE = new AsciiString("Blocksize");
|
||||
/**
|
||||
* {@code "Cache-Control"}
|
||||
*/
|
||||
public static final String CACHE_CONTROL = HttpHeaders.Names.CACHE_CONTROL;
|
||||
public static final AsciiString CACHE_CONTROL = HttpHeaders.Names.CACHE_CONTROL;
|
||||
/**
|
||||
* {@code "Conference"}
|
||||
*/
|
||||
public static final String CONFERENCE = "Conference";
|
||||
public static final AsciiString CONFERENCE = new AsciiString("Conference");
|
||||
/**
|
||||
* {@code "Connection"}
|
||||
*/
|
||||
public static final String CONNECTION = HttpHeaders.Names.CONNECTION;
|
||||
public static final AsciiString CONNECTION = HttpHeaders.Names.CONNECTION;
|
||||
/**
|
||||
* {@code "Content-Base"}
|
||||
*/
|
||||
public static final String CONTENT_BASE = HttpHeaders.Names.CONTENT_BASE;
|
||||
public static final AsciiString CONTENT_BASE = HttpHeaders.Names.CONTENT_BASE;
|
||||
/**
|
||||
* {@code "Content-Encoding"}
|
||||
*/
|
||||
public static final String CONTENT_ENCODING = HttpHeaders.Names.CONTENT_ENCODING;
|
||||
public static final AsciiString CONTENT_ENCODING = HttpHeaders.Names.CONTENT_ENCODING;
|
||||
/**
|
||||
* {@code "Content-Language"}
|
||||
*/
|
||||
public static final String CONTENT_LANGUAGE = HttpHeaders.Names.CONTENT_LANGUAGE;
|
||||
public static final AsciiString CONTENT_LANGUAGE = HttpHeaders.Names.CONTENT_LANGUAGE;
|
||||
/**
|
||||
* {@code "Content-Length"}
|
||||
*/
|
||||
public static final String CONTENT_LENGTH = HttpHeaders.Names.CONTENT_LENGTH;
|
||||
public static final AsciiString CONTENT_LENGTH = HttpHeaders.Names.CONTENT_LENGTH;
|
||||
/**
|
||||
* {@code "Content-Location"}
|
||||
*/
|
||||
public static final String CONTENT_LOCATION = HttpHeaders.Names.CONTENT_LOCATION;
|
||||
public static final AsciiString CONTENT_LOCATION = HttpHeaders.Names.CONTENT_LOCATION;
|
||||
/**
|
||||
* {@code "Content-Type"}
|
||||
*/
|
||||
public static final String CONTENT_TYPE = HttpHeaders.Names.CONTENT_TYPE;
|
||||
public static final AsciiString CONTENT_TYPE = HttpHeaders.Names.CONTENT_TYPE;
|
||||
/**
|
||||
* {@code "CSeq"}
|
||||
*/
|
||||
public static final String CSEQ = "CSeq";
|
||||
public static final AsciiString CSEQ = new AsciiString("CSeq");
|
||||
/**
|
||||
* {@code "Date"}
|
||||
*/
|
||||
public static final String DATE = HttpHeaders.Names.DATE;
|
||||
public static final AsciiString DATE = HttpHeaders.Names.DATE;
|
||||
/**
|
||||
* {@code "Expires"}
|
||||
*/
|
||||
public static final String EXPIRES = HttpHeaders.Names.EXPIRES;
|
||||
public static final AsciiString EXPIRES = HttpHeaders.Names.EXPIRES;
|
||||
/**
|
||||
* {@code "From"}
|
||||
*/
|
||||
public static final String FROM = HttpHeaders.Names.FROM;
|
||||
public static final AsciiString FROM = HttpHeaders.Names.FROM;
|
||||
/**
|
||||
* {@code "Host"}
|
||||
*/
|
||||
public static final String HOST = HttpHeaders.Names.HOST;
|
||||
public static final AsciiString HOST = HttpHeaders.Names.HOST;
|
||||
/**
|
||||
* {@code "If-Match"}
|
||||
*/
|
||||
public static final String IF_MATCH = HttpHeaders.Names.IF_MATCH;
|
||||
public static final AsciiString IF_MATCH = HttpHeaders.Names.IF_MATCH;
|
||||
/**
|
||||
* {@code "If-Modified-Since"}
|
||||
*/
|
||||
public static final String IF_MODIFIED_SINCE = HttpHeaders.Names.IF_MODIFIED_SINCE;
|
||||
public static final AsciiString IF_MODIFIED_SINCE = HttpHeaders.Names.IF_MODIFIED_SINCE;
|
||||
/**
|
||||
* {@code "KeyMgmt"}
|
||||
*/
|
||||
public static final String KEYMGMT = "KeyMgmt";
|
||||
public static final AsciiString KEYMGMT = new AsciiString("KeyMgmt");
|
||||
/**
|
||||
* {@code "Last-Modified"}
|
||||
*/
|
||||
public static final String LAST_MODIFIED = HttpHeaders.Names.LAST_MODIFIED;
|
||||
public static final AsciiString LAST_MODIFIED = HttpHeaders.Names.LAST_MODIFIED;
|
||||
/**
|
||||
* {@code "Proxy-Authenticate"}
|
||||
*/
|
||||
public static final String PROXY_AUTHENTICATE = HttpHeaders.Names.PROXY_AUTHENTICATE;
|
||||
public static final AsciiString PROXY_AUTHENTICATE = HttpHeaders.Names.PROXY_AUTHENTICATE;
|
||||
/**
|
||||
* {@code "Proxy-Require"}
|
||||
*/
|
||||
public static final String PROXY_REQUIRE = "Proxy-Require";
|
||||
public static final AsciiString PROXY_REQUIRE = new AsciiString("Proxy-Require");
|
||||
/**
|
||||
* {@code "Public"}
|
||||
*/
|
||||
public static final String PUBLIC = "Public";
|
||||
public static final AsciiString PUBLIC = new AsciiString("Public");
|
||||
/**
|
||||
* {@code "Range"}
|
||||
*/
|
||||
public static final String RANGE = HttpHeaders.Names.RANGE;
|
||||
public static final AsciiString RANGE = HttpHeaders.Names.RANGE;
|
||||
/**
|
||||
* {@code "Referer"}
|
||||
*/
|
||||
public static final String REFERER = HttpHeaders.Names.REFERER;
|
||||
public static final AsciiString REFERER = HttpHeaders.Names.REFERER;
|
||||
/**
|
||||
* {@code "Require"}
|
||||
*/
|
||||
public static final String REQUIRE = "Require";
|
||||
public static final AsciiString REQUIRE = new AsciiString("Require");
|
||||
/**
|
||||
* {@code "Retry-After"}
|
||||
*/
|
||||
public static final String RETRT_AFTER = HttpHeaders.Names.RETRY_AFTER;
|
||||
public static final AsciiString RETRT_AFTER = HttpHeaders.Names.RETRY_AFTER;
|
||||
/**
|
||||
* {@code "RTP-Info"}
|
||||
*/
|
||||
public static final String RTP_INFO = "RTP-Info";
|
||||
public static final AsciiString RTP_INFO = new AsciiString("RTP-Info");
|
||||
/**
|
||||
* {@code "Scale"}
|
||||
*/
|
||||
public static final String SCALE = "Scale";
|
||||
public static final AsciiString SCALE = new AsciiString("Scale");
|
||||
/**
|
||||
* {@code "Session"}
|
||||
*/
|
||||
public static final String SESSION = "Session";
|
||||
public static final AsciiString SESSION = new AsciiString("Session");
|
||||
/**
|
||||
* {@code "Server"}
|
||||
*/
|
||||
public static final String SERVER = HttpHeaders.Names.SERVER;
|
||||
public static final AsciiString SERVER = HttpHeaders.Names.SERVER;
|
||||
/**
|
||||
* {@code "Speed"}
|
||||
*/
|
||||
public static final String SPEED = "Speed";
|
||||
public static final AsciiString SPEED = new AsciiString("Speed");
|
||||
/**
|
||||
* {@code "Timestamp"}
|
||||
*/
|
||||
public static final String TIMESTAMP = "Timestamp";
|
||||
public static final AsciiString TIMESTAMP = new AsciiString("Timestamp");
|
||||
/**
|
||||
* {@code "Transport"}
|
||||
*/
|
||||
public static final String TRANSPORT = "Transport";
|
||||
public static final AsciiString TRANSPORT = new AsciiString("Transport");
|
||||
/**
|
||||
* {@code "Unsupported"}
|
||||
*/
|
||||
public static final String UNSUPPORTED = "Unsupported";
|
||||
public static final AsciiString UNSUPPORTED = new AsciiString("Unsupported");
|
||||
/**
|
||||
* {@code "User-Agent"}
|
||||
*/
|
||||
public static final String USER_AGENT = HttpHeaders.Names.USER_AGENT;
|
||||
public static final AsciiString USER_AGENT = HttpHeaders.Names.USER_AGENT;
|
||||
/**
|
||||
* {@code "Vary"}
|
||||
*/
|
||||
public static final String VARY = HttpHeaders.Names.VARY;
|
||||
public static final AsciiString VARY = HttpHeaders.Names.VARY;
|
||||
/**
|
||||
* {@code "Via"}
|
||||
*/
|
||||
public static final String VIA = HttpHeaders.Names.VIA;
|
||||
public static final AsciiString VIA = HttpHeaders.Names.VIA;
|
||||
/**
|
||||
* {@code "WWW-Authenticate"}
|
||||
*/
|
||||
public static final String WWW_AUTHENTICATE = HttpHeaders.Names.WWW_AUTHENTICATE;
|
||||
public static final AsciiString WWW_AUTHENTICATE = HttpHeaders.Names.WWW_AUTHENTICATE;
|
||||
|
||||
private Names() {
|
||||
}
|
||||
|
@ -17,60 +17,129 @@ package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.DefaultTextHeaders;
|
||||
import io.netty.handler.codec.TextHeaderProcessor;
|
||||
import io.netty.handler.codec.Headers;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class DefaultSpdyHeaders extends DefaultTextHeaders implements SpdyHeaders {
|
||||
@Override
|
||||
protected CharSequence convertName(CharSequence name) {
|
||||
name = super.convertName(name);
|
||||
if (name instanceof AsciiString) {
|
||||
name = ((AsciiString) name).toLowerCase();
|
||||
} else {
|
||||
name = name.toString().toLowerCase(Locale.US);
|
||||
private static final Headers.ValueConverter<CharSequence> SPDY_VALUE_CONVERTER =
|
||||
new DefaultTextValueTypeConverter() {
|
||||
@Override
|
||||
public CharSequence convertObject(Object value) {
|
||||
CharSequence seq;
|
||||
if (value instanceof CharSequence) {
|
||||
seq = (CharSequence) value;
|
||||
} else {
|
||||
seq = value.toString();
|
||||
}
|
||||
|
||||
SpdyCodecUtil.validateHeaderValue(seq);
|
||||
return seq;
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderName(name);
|
||||
return name;
|
||||
};
|
||||
|
||||
private static final NameConverter<CharSequence> SPDY_NAME_CONVERTER = new NameConverter<CharSequence>() {
|
||||
@Override
|
||||
public CharSequence convertName(CharSequence name) {
|
||||
if (name instanceof AsciiString) {
|
||||
name = ((AsciiString) name).toLowerCase();
|
||||
} else {
|
||||
name = name.toString().toLowerCase(Locale.US);
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderName(name);
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
public DefaultSpdyHeaders() {
|
||||
super(true, SPDY_VALUE_CONVERTER, SPDY_NAME_CONVERTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence convertValue(Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
CharSequence seq;
|
||||
if (value instanceof CharSequence) {
|
||||
seq = (CharSequence) value;
|
||||
} else {
|
||||
seq = value.toString();
|
||||
}
|
||||
|
||||
SpdyCodecUtil.validateHeaderValue(seq);
|
||||
return seq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(CharSequence name, Object value) {
|
||||
public SpdyHeaders add(CharSequence name, CharSequence value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(CharSequence name, Iterable<?> values) {
|
||||
public SpdyHeaders add(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(CharSequence name, Object... values) {
|
||||
public SpdyHeaders add(CharSequence name, CharSequence... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addObject(CharSequence name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addObject(CharSequence name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addObject(CharSequence name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addBoolean(CharSequence name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addChar(CharSequence name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addByte(CharSequence name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addShort(CharSequence name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addInt(CharSequence name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addLong(CharSequence name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addFloat(CharSequence name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders addDouble(CharSequence name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(TextHeaders headers) {
|
||||
super.add(headers);
|
||||
@ -78,23 +147,89 @@ public class DefaultSpdyHeaders extends DefaultTextHeaders implements SpdyHeader
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(CharSequence name, Object value) {
|
||||
public SpdyHeaders set(CharSequence name, CharSequence value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(CharSequence name, Object... values) {
|
||||
public SpdyHeaders set(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(CharSequence name, Iterable<?> values) {
|
||||
public SpdyHeaders set(CharSequence name, CharSequence... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setObject(CharSequence name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setObject(CharSequence name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setObject(CharSequence name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setBoolean(CharSequence name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setChar(CharSequence name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setByte(CharSequence name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setShort(CharSequence name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setInt(CharSequence name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setLong(CharSequence name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setFloat(CharSequence name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders setDouble(CharSequence name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(TextHeaders headers) {
|
||||
super.set(headers);
|
||||
@ -102,14 +237,14 @@ public class DefaultSpdyHeaders extends DefaultTextHeaders implements SpdyHeader
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders clear() {
|
||||
super.clear();
|
||||
public SpdyHeaders setAll(TextHeaders headers) {
|
||||
super.setAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders forEachEntry(TextHeaderProcessor processor) {
|
||||
super.forEachEntry(processor);
|
||||
public SpdyHeaders clear() {
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyStreamFrame
|
||||
}
|
||||
|
||||
protected void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: headers()) {
|
||||
for (Map.Entry<CharSequence, CharSequence> e: headers()) {
|
||||
buf.append(" ");
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
|
@ -15,14 +15,15 @@
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import static io.netty.handler.codec.spdy.SpdyCodecUtil.SPDY_MAX_NV_LENGTH;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static io.netty.handler.codec.spdy.SpdyCodecUtil.*;
|
||||
|
||||
public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
|
||||
private final int version;
|
||||
@ -44,7 +45,7 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
|
||||
@Override
|
||||
public ByteBuf encode(ByteBufAllocator alloc, SpdyHeadersFrame frame) throws Exception {
|
||||
Set<String> names = frame.headers().names();
|
||||
Set<CharSequence> names = frame.headers().names();
|
||||
int numHeaders = names.size();
|
||||
if (numHeaders == 0) {
|
||||
return Unpooled.EMPTY_BUFFER;
|
||||
@ -55,15 +56,15 @@ public class SpdyHeaderBlockRawEncoder extends SpdyHeaderBlockEncoder {
|
||||
}
|
||||
ByteBuf headerBlock = alloc.heapBuffer();
|
||||
writeLengthField(headerBlock, numHeaders);
|
||||
for (String name: names) {
|
||||
byte[] nameBytes = name.getBytes("UTF-8");
|
||||
for (CharSequence name: names) {
|
||||
byte[] nameBytes = AsciiString.getBytes(name, CharsetUtil.UTF_8);
|
||||
writeLengthField(headerBlock, nameBytes.length);
|
||||
headerBlock.writeBytes(nameBytes);
|
||||
int savedIndex = headerBlock.writerIndex();
|
||||
int valueLength = 0;
|
||||
writeLengthField(headerBlock, valueLength);
|
||||
for (String value: frame.headers().getAll(name)) {
|
||||
byte[] valueBytes = value.getBytes("UTF-8");
|
||||
for (CharSequence value: frame.headers().getAll(name)) {
|
||||
byte[] valueBytes = AsciiString.getBytes(value, CharsetUtil.UTF_8);
|
||||
if (valueBytes.length > 0) {
|
||||
headerBlock.writeBytes(valueBytes);
|
||||
headerBlock.writeByte(0);
|
||||
|
@ -16,7 +16,6 @@
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaderProcessor;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
/**
|
||||
@ -58,32 +57,98 @@ public interface SpdyHeaders extends TextHeaders {
|
||||
}
|
||||
|
||||
@Override
|
||||
SpdyHeaders add(CharSequence name, Object value);
|
||||
SpdyHeaders add(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders add(CharSequence name, Iterable<?> values);
|
||||
SpdyHeaders add(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders add(CharSequence name, Object... values);
|
||||
SpdyHeaders add(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders addDouble(CharSequence name, double value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders add(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
SpdyHeaders set(CharSequence name, Object value);
|
||||
SpdyHeaders set(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders set(CharSequence name, Iterable<?> values);
|
||||
SpdyHeaders set(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders set(CharSequence name, Object... values);
|
||||
SpdyHeaders set(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setDouble(CharSequence name, double value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders setObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
SpdyHeaders set(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
SpdyHeaders clear();
|
||||
SpdyHeaders setAll(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
SpdyHeaders forEachEntry(TextHeaderProcessor processor);
|
||||
SpdyHeaders clear();
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
return;
|
||||
}
|
||||
|
||||
String URL = spdySynStreamFrame.headers().get(PATH);
|
||||
CharSequence URL = spdySynStreamFrame.headers().get(PATH);
|
||||
spdySynStreamFrame.headers().remove(PATH);
|
||||
|
||||
// If a client receives a SYN_STREAM without a 'url' header
|
||||
@ -197,8 +197,8 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||
spdySynReplyFrame.setLast(true);
|
||||
SpdyHeaders frameHeaders = spdySynReplyFrame.headers();
|
||||
frameHeaders.set(STATUS, HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE);
|
||||
frameHeaders.set(VERSION, HttpVersion.HTTP_1_0);
|
||||
frameHeaders.setInt(STATUS, HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE.code());
|
||||
frameHeaders.setObject(VERSION, HttpVersion.HTTP_1_0);
|
||||
ctx.writeAndFlush(spdySynReplyFrame);
|
||||
return;
|
||||
}
|
||||
@ -222,8 +222,8 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||
spdySynReplyFrame.setLast(true);
|
||||
SpdyHeaders frameHeaders = spdySynReplyFrame.headers();
|
||||
frameHeaders.set(STATUS, HttpResponseStatus.BAD_REQUEST);
|
||||
frameHeaders.set(VERSION, HttpVersion.HTTP_1_0);
|
||||
frameHeaders.setInt(STATUS, HttpResponseStatus.BAD_REQUEST.code());
|
||||
frameHeaders.setObject(VERSION, HttpVersion.HTTP_1_0);
|
||||
ctx.writeAndFlush(spdySynReplyFrame);
|
||||
}
|
||||
}
|
||||
@ -276,7 +276,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
|
||||
// Ignore trailers in a truncated HEADERS frame.
|
||||
if (!spdyHeadersFrame.isTruncated()) {
|
||||
for (Map.Entry<String, String> e: spdyHeadersFrame.headers()) {
|
||||
for (Map.Entry<CharSequence, CharSequence> e: spdyHeadersFrame.headers()) {
|
||||
fullHttpMessage.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
@ -327,9 +327,9 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
throws Exception {
|
||||
// Create the first line of the request from the name/value pairs
|
||||
SpdyHeaders headers = requestFrame.headers();
|
||||
HttpMethod method = HttpMethod.valueOf(headers.get(METHOD));
|
||||
String url = headers.get(PATH);
|
||||
HttpVersion httpVersion = HttpVersion.valueOf(headers.get(VERSION));
|
||||
HttpMethod method = HttpMethod.valueOf(headers.getAndConvert(METHOD));
|
||||
String url = headers.getAndConvert(PATH);
|
||||
HttpVersion httpVersion = HttpVersion.valueOf(headers.getAndConvert(VERSION));
|
||||
headers.remove(METHOD);
|
||||
headers.remove(PATH);
|
||||
headers.remove(VERSION);
|
||||
@ -340,11 +340,11 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
headers.remove(SCHEME);
|
||||
|
||||
// Replace the SPDY host header with the HTTP host header
|
||||
String host = headers.get(HOST);
|
||||
CharSequence host = headers.get(HOST);
|
||||
headers.remove(HOST);
|
||||
req.headers().set(HttpHeaders.Names.HOST, host);
|
||||
|
||||
for (Map.Entry<String, String> e: requestFrame.headers()) {
|
||||
for (Map.Entry<CharSequence, CharSequence> e: requestFrame.headers()) {
|
||||
req.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@ -363,12 +363,12 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
||||
// Create the first line of the response from the name/value pairs
|
||||
SpdyHeaders headers = responseFrame.headers();
|
||||
HttpResponseStatus status = HttpResponseStatus.parseLine(headers.get(STATUS));
|
||||
HttpVersion version = HttpVersion.valueOf(headers.get(VERSION));
|
||||
HttpVersion version = HttpVersion.valueOf(headers.getAndConvert(VERSION));
|
||||
headers.remove(STATUS);
|
||||
headers.remove(VERSION);
|
||||
|
||||
FullHttpResponse res = new DefaultFullHttpResponse(version, status, ctx.alloc().buffer(), validateHeaders);
|
||||
for (Map.Entry<String, String> e: responseFrame.headers()) {
|
||||
for (Map.Entry<CharSequence, CharSequence> e: responseFrame.headers()) {
|
||||
res.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
|
@ -234,15 +234,15 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
|
||||
SpdyHeaders frameHeaders = spdySynStreamFrame.headers();
|
||||
if (httpMessage instanceof FullHttpRequest) {
|
||||
HttpRequest httpRequest = (HttpRequest) httpMessage;
|
||||
frameHeaders.set(METHOD, httpRequest.method());
|
||||
frameHeaders.setObject(METHOD, httpRequest.method());
|
||||
frameHeaders.set(PATH, httpRequest.uri());
|
||||
frameHeaders.set(VERSION, httpMessage.protocolVersion());
|
||||
frameHeaders.setObject(VERSION, httpMessage.protocolVersion());
|
||||
}
|
||||
if (httpMessage instanceof HttpResponse) {
|
||||
HttpResponse httpResponse = (HttpResponse) httpMessage;
|
||||
frameHeaders.set(STATUS, httpResponse.status());
|
||||
frameHeaders.setInt(STATUS, httpResponse.status().code());
|
||||
frameHeaders.set(PATH, URL);
|
||||
frameHeaders.set(VERSION, httpMessage.protocolVersion());
|
||||
frameHeaders.setObject(VERSION, httpMessage.protocolVersion());
|
||||
spdySynStreamFrame.setUnidirectional(true);
|
||||
}
|
||||
|
||||
@ -286,8 +286,8 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<HttpObject> {
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
|
||||
SpdyHeaders frameHeaders = spdySynReplyFrame.headers();
|
||||
// Unfold the first line of the response into name/value pairs
|
||||
frameHeaders.set(STATUS, httpResponse.status());
|
||||
frameHeaders.set(VERSION, httpResponse.protocolVersion());
|
||||
frameHeaders.setInt(STATUS, httpResponse.status().code());
|
||||
frameHeaders.setObject(VERSION, httpResponse.protocolVersion());
|
||||
|
||||
// Transfer the remaining HTTP headers
|
||||
for (Map.Entry<String, String> entry: httpHeaders) {
|
||||
|
@ -41,7 +41,8 @@ public class HttpResponseEncoderTest {
|
||||
|
||||
ByteBuf buffer = channel.readOutbound();
|
||||
|
||||
assertEquals("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n", buffer.toString(CharsetUtil.US_ASCII));
|
||||
assertEquals("HTTP/1.1 200 OK\r\n" + HttpHeaders.Names.TRANSFER_ENCODING + ": " +
|
||||
HttpHeaders.Values.CHUNKED + "\r\n\r\n", buffer.toString(CharsetUtil.US_ASCII));
|
||||
buffer.release();
|
||||
assertTrue(channel.writeOutbound(FILE_REGION));
|
||||
buffer = channel.readOutbound();
|
||||
|
@ -108,7 +108,8 @@ public class HttpServerCodecTest {
|
||||
|
||||
// Ensure the encoder handles the response after handling 100 Continue.
|
||||
ByteBuf encodedRes = ch.readOutbound();
|
||||
assertThat(encodedRes.toString(CharsetUtil.UTF_8), is("HTTP/1.1 201 Created\r\nContent-Length: 2\r\n\r\nOK"));
|
||||
assertThat(encodedRes.toString(CharsetUtil.UTF_8), is("HTTP/1.1 201 Created\r\n" +
|
||||
CONTENT_LENGTH + ": 2\r\n\r\nOK"));
|
||||
encodedRes.release();
|
||||
|
||||
ch.finish();
|
||||
|
@ -83,7 +83,7 @@ public class CorsHandlerTest {
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is("http://localhost:8888"));
|
||||
assertThat(response.headers().getAll(ACCESS_CONTROL_ALLOW_METHODS), hasItems("GET", "DELETE"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -96,7 +96,7 @@ public class CorsHandlerTest {
|
||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), is("http://localhost:8888"));
|
||||
assertThat(response.headers().getAll(ACCESS_CONTROL_ALLOW_METHODS), hasItems("OPTIONS", "GET"));
|
||||
assertThat(response.headers().getAll(ACCESS_CONTROL_ALLOW_HEADERS), hasItems("content-type", "xheader1"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -105,7 +105,7 @@ public class CorsHandlerTest {
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().get(CONTENT_LENGTH), is("0"));
|
||||
assertThat(response.headers().get(DATE), is(notNullValue()));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -115,7 +115,7 @@ public class CorsHandlerTest {
|
||||
.build();
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().get("CustomHeader"), equalTo("somevalue"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -125,7 +125,7 @@ public class CorsHandlerTest {
|
||||
.build();
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().getAll("CustomHeader"), hasItems("value1", "value2"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -135,7 +135,7 @@ public class CorsHandlerTest {
|
||||
.build();
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().getAll("CustomHeader"), hasItems("value1", "value2"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -149,7 +149,7 @@ public class CorsHandlerTest {
|
||||
}).build();
|
||||
final HttpResponse response = preflightRequest(config, "http://localhost:8888", "content-type, xheader1");
|
||||
assertThat(response.headers().get("GenHeader"), equalTo("generatedValue"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -204,7 +204,7 @@ public class CorsHandlerTest {
|
||||
final HttpResponse response = simpleRequest(config, "http://localhost:7777");
|
||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_CREDENTIALS), equalTo("true"));
|
||||
assertThat(response.headers().get(ACCESS_CONTROL_ALLOW_ORIGIN), equalTo("http://localhost:7777"));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN));
|
||||
assertThat(response.headers().get(VARY), equalTo(ORIGIN.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -18,11 +18,13 @@ package io.netty.handler.codec.http.multipart;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder.EncoderMode;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
@ -47,15 +49,15 @@ public class HttpPostRequestEncoderTest {
|
||||
String content = getRequestBody(encoder);
|
||||
|
||||
String expected = "--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"foo\"" + "\r\n" +
|
||||
"Content-Type: text/plain; charset=UTF-8" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"foo\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain; charset=UTF-8" + "\r\n" +
|
||||
"\r\n" +
|
||||
"bar" +
|
||||
"\r\n" +
|
||||
"--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 01" + StringUtil.NEWLINE +
|
||||
"\r\n" +
|
||||
@ -83,25 +85,25 @@ public class HttpPostRequestEncoderTest {
|
||||
String content = getRequestBody(encoder);
|
||||
|
||||
String expected = "--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"foo\"" + "\r\n" +
|
||||
"Content-Type: text/plain; charset=UTF-8" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"foo\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain; charset=UTF-8" + "\r\n" +
|
||||
"\r\n" +
|
||||
"bar" + "\r\n" +
|
||||
"--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"quux\"" + "\r\n" +
|
||||
"Content-Type: multipart/mixed; boundary=" + multipartMixedBoundary + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"quux\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": multipart/mixed; boundary=" + multipartMixedBoundary + "\r\n" +
|
||||
"\r\n" +
|
||||
"--" + multipartMixedBoundary + "\r\n" +
|
||||
"Content-Disposition: attachment; filename=\"file-02.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": attachment; filename=\"file-02.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 01" + StringUtil.NEWLINE +
|
||||
"\r\n" +
|
||||
"--" + multipartMixedBoundary + "\r\n" +
|
||||
"Content-Disposition: attachment; filename=\"file-02.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": attachment; filename=\"file-02.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 02" + StringUtil.NEWLINE +
|
||||
"\r\n" +
|
||||
@ -130,20 +132,20 @@ public class HttpPostRequestEncoderTest {
|
||||
String content = getRequestBody(encoder);
|
||||
|
||||
String expected = "--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"foo\"" + "\r\n" +
|
||||
"Content-Type: text/plain; charset=UTF-8" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"foo\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain; charset=UTF-8" + "\r\n" +
|
||||
"\r\n" +
|
||||
"bar" + "\r\n" +
|
||||
"--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 01" + StringUtil.NEWLINE + "\r\n" +
|
||||
"--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"quux\"; filename=\"file-02.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"quux\"; filename=\"file-02.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 02" + StringUtil.NEWLINE +
|
||||
"\r\n" +
|
||||
@ -169,15 +171,15 @@ public class HttpPostRequestEncoderTest {
|
||||
String content = getRequestBody(encoder);
|
||||
|
||||
String expected = "--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"foo\"" + "\r\n" +
|
||||
"Content-Type: text/plain; charset=UTF-8" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"foo\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain; charset=UTF-8" + "\r\n" +
|
||||
"\r\n" +
|
||||
"bar" +
|
||||
"\r\n" +
|
||||
"--" + multipartDataBoundary + "\r\n" +
|
||||
"Content-Disposition: form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
"Content-Type: text/plain" + "\r\n" +
|
||||
"Content-Transfer-Encoding: binary" + "\r\n" +
|
||||
CONTENT_DISPOSITION + ": form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" +
|
||||
CONTENT_TYPE + ": text/plain" + "\r\n" +
|
||||
CONTENT_TRANSFER_ENCODING + ": binary" + "\r\n" +
|
||||
"\r\n" +
|
||||
"File 01" + StringUtil.NEWLINE +
|
||||
"\r\n" +
|
||||
|
@ -127,7 +127,7 @@ public class WebSocketRequestBuilder {
|
||||
.method(HttpMethod.GET)
|
||||
.uri("/test")
|
||||
.host("server.example.com")
|
||||
.upgrade(WEBSOCKET.toLowerCase())
|
||||
.upgrade(WEBSOCKET.toLowerCase().toString())
|
||||
.key("dGhlIHNhbXBsZSBub25jZQ==")
|
||||
.origin("http://example.com")
|
||||
.version13()
|
||||
|
@ -95,7 +95,7 @@ public class WebSocketServerProtocolHandlerTest {
|
||||
.uri("/test")
|
||||
.key(null)
|
||||
.connection("Upgrade")
|
||||
.upgrade(WEBSOCKET.toLowerCase())
|
||||
.upgrade(WEBSOCKET.toLowerCase().toString())
|
||||
.version13()
|
||||
.build();
|
||||
|
||||
|
@ -81,9 +81,9 @@ public class SpdySessionHandlerTest {
|
||||
SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
|
||||
assertEquals(streamId, spdyHeadersFrame.streamId());
|
||||
assertEquals(last, spdyHeadersFrame.isLast());
|
||||
for (String name: headers.names()) {
|
||||
List<String> expectedValues = headers.getAll(name);
|
||||
List<String> receivedValues = spdyHeadersFrame.headers().getAll(name);
|
||||
for (CharSequence name: headers.names()) {
|
||||
List<CharSequence> expectedValues = headers.getAll(name);
|
||||
List<CharSequence> receivedValues = spdyHeadersFrame.headers().getAll(name);
|
||||
assertTrue(receivedValues.containsAll(expectedValues));
|
||||
receivedValues.removeAll(expectedValues);
|
||||
assertTrue(receivedValues.isEmpty());
|
||||
@ -357,7 +357,7 @@ public class SpdySessionHandlerTest {
|
||||
int streamId = spdySynStreamFrame.streamId();
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||
spdySynReplyFrame.setLast(spdySynStreamFrame.isLast());
|
||||
for (Map.Entry<String, String> entry: spdySynStreamFrame.headers()) {
|
||||
for (Map.Entry<CharSequence, CharSequence> entry: spdySynStreamFrame.headers()) {
|
||||
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
|
@ -17,29 +17,94 @@
|
||||
package io.netty.handler.codec.stomp;
|
||||
|
||||
import io.netty.handler.codec.DefaultTextHeaders;
|
||||
import io.netty.handler.codec.TextHeaderProcessor;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
public class DefaultStompHeaders extends DefaultTextHeaders implements StompHeaders {
|
||||
|
||||
@Override
|
||||
public StompHeaders add(CharSequence name, Object value) {
|
||||
public StompHeaders add(CharSequence name, CharSequence value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders add(CharSequence name, Iterable<?> values) {
|
||||
public StompHeaders add(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders add(CharSequence name, Object... values) {
|
||||
public StompHeaders add(CharSequence name, CharSequence... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addObject(CharSequence name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addObject(CharSequence name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addObject(CharSequence name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addBoolean(CharSequence name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addChar(CharSequence name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addByte(CharSequence name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addShort(CharSequence name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addInt(CharSequence name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addLong(CharSequence name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addFloat(CharSequence name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders addDouble(CharSequence name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders add(TextHeaders headers) {
|
||||
super.add(headers);
|
||||
@ -47,23 +112,89 @@ public class DefaultStompHeaders extends DefaultTextHeaders implements StompHead
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders set(CharSequence name, Object value) {
|
||||
public StompHeaders set(CharSequence name, CharSequence value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders set(CharSequence name, Object... values) {
|
||||
public StompHeaders set(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders set(CharSequence name, Iterable<?> values) {
|
||||
public StompHeaders set(CharSequence name, CharSequence... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setObject(CharSequence name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setObject(CharSequence name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setObject(CharSequence name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setBoolean(CharSequence name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setChar(CharSequence name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setByte(CharSequence name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setShort(CharSequence name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setInt(CharSequence name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setLong(CharSequence name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setFloat(CharSequence name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders setDouble(CharSequence name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders set(TextHeaders headers) {
|
||||
super.set(headers);
|
||||
@ -71,14 +202,14 @@ public class DefaultStompHeaders extends DefaultTextHeaders implements StompHead
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders clear() {
|
||||
super.clear();
|
||||
public StompHeaders setAll(TextHeaders headers) {
|
||||
super.setAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StompHeaders forEachEntry(TextHeaderProcessor processor) {
|
||||
super.forEachEntry(processor);
|
||||
public StompHeaders clear() {
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package io.netty.handler.codec.stomp;
|
||||
|
||||
import io.netty.handler.codec.AsciiString;
|
||||
import io.netty.handler.codec.TextHeaderProcessor;
|
||||
import io.netty.handler.codec.TextHeaders;
|
||||
|
||||
/**
|
||||
@ -46,32 +45,98 @@ public interface StompHeaders extends TextHeaders {
|
||||
AsciiString CONTENT_TYPE = new AsciiString("content-type");
|
||||
|
||||
@Override
|
||||
StompHeaders add(CharSequence name, Object value);
|
||||
StompHeaders add(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
StompHeaders add(CharSequence name, Iterable<?> values);
|
||||
StompHeaders add(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
StompHeaders add(CharSequence name, Object... values);
|
||||
StompHeaders add(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
StompHeaders addObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
StompHeaders addObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
StompHeaders addObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
StompHeaders addBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
StompHeaders addByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
StompHeaders addChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
StompHeaders addShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
StompHeaders addInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
StompHeaders addLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
StompHeaders addFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
StompHeaders addDouble(CharSequence name, double value);
|
||||
|
||||
@Override
|
||||
StompHeaders add(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
StompHeaders set(CharSequence name, Object value);
|
||||
StompHeaders set(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
StompHeaders set(CharSequence name, Iterable<?> values);
|
||||
StompHeaders set(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
StompHeaders set(CharSequence name, Object... values);
|
||||
StompHeaders set(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
StompHeaders setObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
StompHeaders setObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
StompHeaders setObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
StompHeaders setBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
StompHeaders setByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
StompHeaders setChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
StompHeaders setShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
StompHeaders setInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
StompHeaders setLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
StompHeaders setFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
StompHeaders setDouble(CharSequence name, double value);
|
||||
|
||||
@Override
|
||||
StompHeaders set(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
StompHeaders clear();
|
||||
StompHeaders setAll(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
StompHeaders forEachEntry(TextHeaderProcessor processor);
|
||||
StompHeaders clear();
|
||||
}
|
||||
|
@ -69,8 +69,7 @@ public class StompSubframeAggregator
|
||||
|
||||
@Override
|
||||
protected long contentLength(StompHeadersSubframe start) throws Exception {
|
||||
String value = start.headers().get(StompHeaders.CONTENT_LENGTH);
|
||||
return Long.parseLong(value);
|
||||
return start.headers().getLong(StompHeaders.CONTENT_LENGTH, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -219,15 +219,7 @@ public class StompSubframeDecoder extends ReplayingDecoder<State> {
|
||||
}
|
||||
|
||||
private static long getContentLength(StompHeaders headers, long defaultValue) {
|
||||
String contentLength = headers.get(StompHeaders.CONTENT_LENGTH);
|
||||
if (contentLength != null) {
|
||||
try {
|
||||
return Long.parseLong(contentLength);
|
||||
} catch (NumberFormatException ignored) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
return headers.getLong(StompHeaders.CONTENT_LENGTH, defaultValue);
|
||||
}
|
||||
|
||||
private static void skipNullCharacter(ByteBuf buffer) {
|
||||
|
@ -22,6 +22,7 @@ import io.netty.handler.codec.AsciiHeadersEncoder.NewlineType;
|
||||
import io.netty.handler.codec.AsciiHeadersEncoder.SeparatorType;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -65,7 +66,12 @@ public class StompSubframeEncoder extends MessageToMessageEncoder<StompSubframe>
|
||||
|
||||
buf.writeBytes(frame.command().toString().getBytes(CharsetUtil.US_ASCII));
|
||||
buf.writeByte(StompConstants.LF);
|
||||
frame.headers().forEachEntry(new AsciiHeadersEncoder(buf, SeparatorType.COLON, NewlineType.LF));
|
||||
try {
|
||||
frame.headers().forEachEntry(new AsciiHeadersEncoder(buf, SeparatorType.COLON, NewlineType.LF));
|
||||
} catch (Exception ex) {
|
||||
buf.release();
|
||||
PlatformDependent.throwException(ex);
|
||||
}
|
||||
buf.writeByte(StompConstants.LF);
|
||||
return buf;
|
||||
}
|
||||
|
@ -17,9 +17,12 @@
|
||||
package io.netty.handler.codec;
|
||||
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public final class AsciiHeadersEncoder implements TextHeaderProcessor {
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.TextHeaders.EntryVisitor;
|
||||
|
||||
public final class AsciiHeadersEncoder implements EntryVisitor {
|
||||
|
||||
/**
|
||||
* The separator characters to insert between a header name and a header value.
|
||||
@ -74,7 +77,9 @@ public final class AsciiHeadersEncoder implements TextHeaderProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(CharSequence name, CharSequence value) throws Exception {
|
||||
public boolean visit(Entry<CharSequence, CharSequence> entry) throws Exception {
|
||||
final CharSequence name = entry.getKey();
|
||||
final CharSequence value = entry.getValue();
|
||||
final ByteBuf buf = this.buf;
|
||||
final int nameLen = name.length();
|
||||
final int valueLen = value.length();
|
||||
|
File diff suppressed because it is too large
Load Diff
138
codec/src/main/java/io/netty/handler/codec/BinaryHeaders.java
Normal file
138
codec/src/main/java/io/netty/handler/codec/BinaryHeaders.java
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
/**
|
||||
* A typical {@code AsciiString} multimap used by protocols that use binary headers (such as HTTP/2) for the
|
||||
* representation of arbitrary key-value data. {@link AsciiString} is just a wrapper around a byte array but provides
|
||||
* some additional utility when handling text data.
|
||||
*/
|
||||
public interface BinaryHeaders extends Headers<AsciiString> {
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
*/
|
||||
interface EntryVisitor extends Headers.EntryVisitor<AsciiString> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
*/
|
||||
interface NameVisitor extends Headers.NameVisitor<AsciiString> {
|
||||
}
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, AsciiString value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders add(AsciiString name, AsciiString... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Object value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addObject(AsciiString name, Object... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addBoolean(AsciiString name, boolean value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addByte(AsciiString name, byte value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addChar(AsciiString name, char value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addShort(AsciiString name, short value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addInt(AsciiString name, int value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addLong(AsciiString name, long value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addFloat(AsciiString name, float value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders addDouble(AsciiString name, double value);
|
||||
|
||||
/**
|
||||
* See {@link Headers#add(Headers)}
|
||||
*/
|
||||
BinaryHeaders add(BinaryHeaders headers);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, AsciiString value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders set(AsciiString name, AsciiString... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Object value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setObject(AsciiString name, Object... values);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setBoolean(AsciiString name, boolean value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setByte(AsciiString name, byte value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setChar(AsciiString name, char value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setShort(AsciiString name, short value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setInt(AsciiString name, int value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setLong(AsciiString name, long value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setFloat(AsciiString name, float value);
|
||||
|
||||
@Override
|
||||
BinaryHeaders setDouble(AsciiString name, double value);
|
||||
|
||||
/**
|
||||
* See {@link Headers#set(Headers)}
|
||||
*/
|
||||
BinaryHeaders set(BinaryHeaders headers);
|
||||
|
||||
/**
|
||||
* See {@link Headers#setAll(Headers)}
|
||||
*/
|
||||
BinaryHeaders setAll(BinaryHeaders headers);
|
||||
|
||||
@Override
|
||||
BinaryHeaders clear();
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Extension to the {@link Headers} interface to provide methods which convert the
|
||||
* native {@code UnconvertedType} to the not-native {@code ConvertedType}
|
||||
*/
|
||||
public interface ConvertibleHeaders<UnconvertedType, ConvertedType> extends Headers<UnconvertedType> {
|
||||
|
||||
/**
|
||||
* Interface to do conversions to and from the two generic type parameters
|
||||
*/
|
||||
interface TypeConverter<UnconvertedType, ConvertedType> {
|
||||
/**
|
||||
* Convert a native value
|
||||
* @param value The value to be converted
|
||||
* @return The conversion results
|
||||
*/
|
||||
ConvertedType toConvertedType(UnconvertedType value);
|
||||
|
||||
/**
|
||||
* Undo a conversion and restore the original native type
|
||||
* @param value The converted value
|
||||
* @return The original native type
|
||||
*/
|
||||
UnconvertedType toUnconvertedType(ConvertedType value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#get(Object)} and does a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The value corresponding to {@code name} and then converted
|
||||
*/
|
||||
ConvertedType getAndConvert(UnconvertedType name);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#get(Object, Object)} and does a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The value corresponding to {@code name} and then converted
|
||||
*/
|
||||
ConvertedType getAndConvert(UnconvertedType name, ConvertedType defaultValue);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#getAndRemove(Object)} and does a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The value corresponding to {@code name} and then converted
|
||||
*/
|
||||
ConvertedType getAndRemoveAndConvert(UnconvertedType name);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#getAndRemove(Object, Object)} and does
|
||||
* a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The value corresponding to {@code name} and then converted
|
||||
*/
|
||||
ConvertedType getAndRemoveAndConvert(UnconvertedType name, ConvertedType defaultValue);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#getAll(Object)} and does a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The values corresponding to {@code name} and then converted
|
||||
*/
|
||||
List<ConvertedType> getAllAndConvert(UnconvertedType name);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#getAllAndRemove(Object)} and does a conversion on the results if not {@code null}
|
||||
* @param name The name of entry to get
|
||||
* @return The values corresponding to {@code name} and then converted
|
||||
*/
|
||||
List<ConvertedType> getAllAndRemoveAndConvert(UnconvertedType name);
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#entries()} and lazily does a conversion on the results as they are accessed
|
||||
*
|
||||
* @return The values corresponding to {@code name} and then lazily converted
|
||||
*/
|
||||
List<Map.Entry<ConvertedType, ConvertedType>> entriesConverted();
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#iterator()} and lazily does a conversion on the results as they are accessed
|
||||
*
|
||||
* @return Iterator which will provide converted values corresponding to {@code name}
|
||||
*/
|
||||
Iterator<Entry<ConvertedType, ConvertedType>> iteratorConverted();
|
||||
|
||||
/**
|
||||
* Invokes {@link Headers#names()} and does a conversion on the results
|
||||
*
|
||||
* @return The values corresponding to {@code name} and then converted
|
||||
*/
|
||||
Set<ConvertedType> namesAndConvert(Comparator<ConvertedType> comparator);
|
||||
}
|
@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import static io.netty.handler.codec.AsciiString.*;
|
||||
|
||||
public class DefaultBinaryHeaders extends DefaultHeaders<AsciiString> implements BinaryHeaders {
|
||||
private static final HashCodeGenerator<AsciiString> ASCII_HASH_CODE_GENERATOR =
|
||||
new HashCodeGenerator<AsciiString>() {
|
||||
@Override
|
||||
public int generateHashCode(AsciiString name) {
|
||||
return AsciiString.caseInsensitiveHashCode(name);
|
||||
}
|
||||
};
|
||||
|
||||
private static final ValueConverter<AsciiString> OBJECT_TO_ASCII = new ValueConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertObject(Object value) {
|
||||
if (value instanceof AsciiString) {
|
||||
return (AsciiString) value;
|
||||
}
|
||||
if (value instanceof CharSequence) {
|
||||
return new AsciiString((CharSequence) value);
|
||||
}
|
||||
return new AsciiString(value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertInt(int value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertLong(long value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertDouble(double value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertChar(char value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertBoolean(boolean value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertFloat(float value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convertToInt(AsciiString value) {
|
||||
return value.parseInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long convertToLong(AsciiString value) {
|
||||
return value.parseLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long convertToTimeMillis(AsciiString value) {
|
||||
try {
|
||||
return HeaderDateFormat.get().parse(value.toString());
|
||||
} catch (ParseException e) {
|
||||
PlatformDependent.throwException(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double convertToDouble(AsciiString value) {
|
||||
return value.parseDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char convertToChar(AsciiString value) {
|
||||
return value.charAt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean convertToBoolean(AsciiString value) {
|
||||
return value.byteAt(0) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float convertToFloat(AsciiString value) {
|
||||
return value.parseFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertShort(short value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public short convertToShort(AsciiString value) {
|
||||
return value.parseShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsciiString convertByte(byte value) {
|
||||
return new AsciiString(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte convertToByte(AsciiString value) {
|
||||
return value.byteAt(0);
|
||||
}
|
||||
};
|
||||
|
||||
private static final NameConverter<AsciiString> ASCII_TO_LOWER_CONVERTER = new NameConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertName(AsciiString name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
private static final NameConverter<AsciiString> ASCII_IDENTITY_CONVERTER = new NameConverter<AsciiString>() {
|
||||
@Override
|
||||
public AsciiString convertName(AsciiString name) {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
public DefaultBinaryHeaders() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public DefaultBinaryHeaders(boolean forceKeyToLower) {
|
||||
super(CASE_INSENSITIVE_ORDER, CASE_INSENSITIVE_ORDER, ASCII_HASH_CODE_GENERATOR, OBJECT_TO_ASCII,
|
||||
forceKeyToLower ? ASCII_TO_LOWER_CONVERTER : ASCII_IDENTITY_CONVERTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addBoolean(AsciiString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addChar(AsciiString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addByte(AsciiString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addShort(AsciiString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addInt(AsciiString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addLong(AsciiString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addFloat(AsciiString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addDouble(AsciiString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(BinaryHeaders headers) {
|
||||
super.add(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setBoolean(AsciiString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setChar(AsciiString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setByte(AsciiString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setShort(AsciiString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setInt(AsciiString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setLong(AsciiString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setFloat(AsciiString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setDouble(AsciiString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(BinaryHeaders headers) {
|
||||
super.set(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setAll(BinaryHeaders headers) {
|
||||
super.setAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders clear() {
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class DefaultConvertibleHeaders<UnconvertedType, ConvertedType> extends DefaultHeaders<UnconvertedType>
|
||||
implements ConvertibleHeaders<UnconvertedType, ConvertedType> {
|
||||
|
||||
private final TypeConverter<UnconvertedType, ConvertedType> typeConverter;
|
||||
|
||||
public DefaultConvertibleHeaders(Comparator<? super UnconvertedType> keyComparator,
|
||||
Comparator<? super UnconvertedType> valueComparator,
|
||||
HashCodeGenerator<UnconvertedType> hashCodeGenerator,
|
||||
ValueConverter<UnconvertedType> valueConverter,
|
||||
TypeConverter<UnconvertedType, ConvertedType> typeConverter) {
|
||||
super(keyComparator, valueComparator, hashCodeGenerator, valueConverter);
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
public DefaultConvertibleHeaders(Comparator<? super UnconvertedType> keyComparator,
|
||||
Comparator<? super UnconvertedType> valueComparator,
|
||||
HashCodeGenerator<UnconvertedType> hashCodeGenerator,
|
||||
ValueConverter<UnconvertedType> valueConverter,
|
||||
TypeConverter<UnconvertedType, ConvertedType> typeConverter,
|
||||
NameConverter<UnconvertedType> nameConverter) {
|
||||
super(keyComparator, valueComparator, hashCodeGenerator, valueConverter, nameConverter);
|
||||
this.typeConverter = typeConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndConvert(UnconvertedType name) {
|
||||
return getAndConvert(name, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndConvert(UnconvertedType name, ConvertedType defaultValue) {
|
||||
UnconvertedType v = get(name);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return typeConverter.toConvertedType(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndRemoveAndConvert(UnconvertedType name) {
|
||||
return getAndRemoveAndConvert(name, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndRemoveAndConvert(UnconvertedType name, ConvertedType defaultValue) {
|
||||
UnconvertedType v = getAndRemove(name);
|
||||
if (v == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return typeConverter.toConvertedType(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConvertedType> getAllAndConvert(UnconvertedType name) {
|
||||
List<UnconvertedType> all = getAll(name);
|
||||
List<ConvertedType> allConverted = new ArrayList<ConvertedType>(all.size());
|
||||
for (int i = 0; i < all.size(); ++i) {
|
||||
allConverted.add(typeConverter.toConvertedType(all.get(i)));
|
||||
}
|
||||
return allConverted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConvertedType> getAllAndRemoveAndConvert(UnconvertedType name) {
|
||||
List<UnconvertedType> all = getAllAndRemove(name);
|
||||
List<ConvertedType> allConverted = new ArrayList<ConvertedType>(all.size());
|
||||
for (int i = 0; i < all.size(); ++i) {
|
||||
allConverted.add(typeConverter.toConvertedType(all.get(i)));
|
||||
}
|
||||
return allConverted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entry<ConvertedType, ConvertedType>> entriesConverted() {
|
||||
List<Entry<UnconvertedType, UnconvertedType>> entries = entries();
|
||||
List<Entry<ConvertedType, ConvertedType>> entriesConverted = new ArrayList<Entry<ConvertedType, ConvertedType>>(
|
||||
entries.size());
|
||||
for (int i = 0; i < entries.size(); ++i) {
|
||||
entriesConverted.add(new ConvertedEntry(entries.get(i)));
|
||||
}
|
||||
return entriesConverted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<ConvertedType, ConvertedType>> iteratorConverted() {
|
||||
return new ConvertedIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConvertedType> namesAndConvert(Comparator<ConvertedType> comparator) {
|
||||
Set<UnconvertedType> names = names();
|
||||
Set<ConvertedType> namesConverted = new TreeSet<ConvertedType>(comparator);
|
||||
for (UnconvertedType unconverted : names) {
|
||||
namesConverted.add(typeConverter.toConvertedType(unconverted));
|
||||
}
|
||||
return namesConverted;
|
||||
}
|
||||
|
||||
private final class ConvertedIterator implements Iterator<Entry<ConvertedType, ConvertedType>> {
|
||||
private final Iterator<Entry<UnconvertedType, UnconvertedType>> iter = iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iter.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<ConvertedType, ConvertedType> next() {
|
||||
Entry<UnconvertedType, UnconvertedType> next = iter.next();
|
||||
|
||||
return new ConvertedEntry(next);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private final class ConvertedEntry implements Entry<ConvertedType, ConvertedType> {
|
||||
private final Entry<UnconvertedType, UnconvertedType> entry;
|
||||
private ConvertedType name;
|
||||
private ConvertedType value;
|
||||
|
||||
ConvertedEntry(Entry<UnconvertedType, UnconvertedType> entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getKey() {
|
||||
if (name == null) {
|
||||
name = typeConverter.toConvertedType(entry.getKey());
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getValue() {
|
||||
if (value == null) {
|
||||
value = typeConverter.toConvertedType(entry.getValue());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType setValue(ConvertedType value) {
|
||||
ConvertedType old = getValue();
|
||||
entry.setValue(typeConverter.toUnconvertedType(value));
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return entry.toString();
|
||||
}
|
||||
}
|
||||
}
|
1461
codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java
Normal file
1461
codec/src/main/java/io/netty/handler/codec/DefaultHeaders.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
public class EmptyBinaryHeaders extends EmptyHeaders<AsciiString> implements BinaryHeaders {
|
||||
protected EmptyBinaryHeaders() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(AsciiString name, AsciiString... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addObject(AsciiString name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addBoolean(AsciiString name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addChar(AsciiString name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addByte(AsciiString name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addShort(AsciiString name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addInt(AsciiString name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addLong(AsciiString name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addFloat(AsciiString name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders addDouble(AsciiString name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders add(BinaryHeaders headers) {
|
||||
super.add(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, Iterable<? extends AsciiString> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(AsciiString name, AsciiString... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setObject(AsciiString name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setBoolean(AsciiString name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setChar(AsciiString name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setByte(AsciiString name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setShort(AsciiString name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setInt(AsciiString name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setLong(AsciiString name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setFloat(AsciiString name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setDouble(AsciiString name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders set(BinaryHeaders headers) {
|
||||
super.set(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders setAll(BinaryHeaders headers) {
|
||||
super.setAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BinaryHeaders clear() {
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class EmptyConvertibleHeaders<UnconvertedType, ConvertedType> extends
|
||||
EmptyHeaders<UnconvertedType> implements ConvertibleHeaders<UnconvertedType, ConvertedType> {
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndConvert(UnconvertedType name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndConvert(UnconvertedType name, ConvertedType defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndRemoveAndConvert(UnconvertedType name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConvertedType getAndRemoveAndConvert(UnconvertedType name, ConvertedType defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConvertedType> getAllAndConvert(UnconvertedType name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConvertedType> getAllAndRemoveAndConvert(UnconvertedType name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entry<ConvertedType, ConvertedType>> entriesConverted() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<ConvertedType, ConvertedType>> iteratorConverted() {
|
||||
return entriesConverted().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ConvertedType> namesAndConvert(Comparator<ConvertedType> comparator) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
536
codec/src/main/java/io/netty/handler/codec/EmptyHeaders.java
Normal file
536
codec/src/main/java/io/netty/handler/codec/EmptyHeaders.java
Normal file
@ -0,0 +1,536 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class EmptyHeaders<T> implements Headers<T> {
|
||||
@Override
|
||||
public T get(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(T name, T defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getAndRemove(T name, T defaultValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getAll(T name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getAllAndRemove(T name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(T name, boolean defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte getByte(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(T name, byte defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Character getChar(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(T name, char defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getShort(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getInt(T name, short defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(T name, int defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(T name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFloat(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(T name, float defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDouble(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(T name, double defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeMillis(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeMillis(T name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBooleanAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBooleanAndRemove(T name, boolean defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte getByteAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByteAndRemove(T name, byte defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Character getCharAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getCharAndRemove(T name, char defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short getShortAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShortAndRemove(T name, short defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIntAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntAndRemove(T name, int defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLongAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongAndRemove(T name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float getFloatAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloatAndRemove(T name, float defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double getDoubleAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleAndRemove(T name, double defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeMillisAndRemove(T name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeMillisAndRemove(T name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entry<T, T>> entries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T name, T value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsObject(T name, Object value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsBoolean(T name, boolean value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsByte(T name, byte value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsChar(T name, char value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsShort(T name, short value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsInt(T name, int value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsLong(T name, long value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsFloat(T name, float value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsDouble(T name, double value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T name, T value, Comparator<? super T> comparator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T name, T value,
|
||||
Comparator<? super T> keyComparator, Comparator<? super T> valueComparator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsObject(T name, Object value, Comparator<? super T> comparator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsObject(T name, Object value, Comparator<? super T> keyComparator,
|
||||
Comparator<? super T> valueComparator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<T> names() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> namesList() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> add(T name, T value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> add(T name, Iterable<? extends T> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> add(T name, T... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addObject(T name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addObject(T name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addObject(T name, Object... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addBoolean(T name, boolean value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addByte(T name, byte value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addChar(T name, char value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addShort(T name, short value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addInt(T name, int value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addLong(T name, long value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addFloat(T name, float value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> addDouble(T name, double value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> add(Headers<T> headers) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> set(T name, T value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> set(T name, Iterable<? extends T> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> set(T name, T... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setObject(T name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setObject(T name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setObject(T name, Object... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setBoolean(T name, boolean value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setByte(T name, byte value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setChar(T name, char value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setShort(T name, short value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setInt(T name, int value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setLong(T name, long value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setFloat(T name, float value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setDouble(T name, double value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> set(Headers<T> headers) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> setAll(Headers<T> headers) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(T name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers<T> clear() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<T, T>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<T, T> forEachEntry(Headers.EntryVisitor<T> visitor) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T forEachName(Headers.NameVisitor<T> visitor) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Headers)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Headers<?> rhs = (Headers<?>) o;
|
||||
return isEmpty() && rhs.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(getClass().getSimpleName()).append('[').append(']').toString();
|
||||
}
|
||||
}
|
@ -16,233 +16,209 @@
|
||||
|
||||
package io.netty.handler.codec;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
public class EmptyTextHeaders implements TextHeaders {
|
||||
|
||||
protected EmptyTextHeaders() { }
|
||||
|
||||
@Override
|
||||
public String get(CharSequence name) {
|
||||
return null;
|
||||
public class EmptyTextHeaders extends EmptyConvertibleHeaders<CharSequence, String> implements TextHeaders {
|
||||
protected EmptyTextHeaders() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(CharSequence name, String defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(CharSequence name, int defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(CharSequence name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeMillis(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeMillis(CharSequence name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAndRemove(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAndRemove(CharSequence name, String defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getIntAndRemove(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntAndRemove(CharSequence name, int defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLongAndRemove(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongAndRemove(CharSequence name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimeMillisAndRemove(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeMillisAndRemove(CharSequence name, long defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getUnconverted(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getUnconvertedAndRemove(CharSequence name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(CharSequence name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CharSequence> getAllUnconverted(CharSequence name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAllAndRemove(CharSequence name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CharSequence> getAllUnconvertedAndRemove(CharSequence name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entry<String, String>> entries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Entry<CharSequence, CharSequence>> unconvertedEntries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name) {
|
||||
public boolean contains(CharSequence name, CharSequence value, boolean ignoreCase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
public boolean containsObject(CharSequence name, Object value, boolean ignoreCase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
public TextHeaders add(CharSequence name, CharSequence value) {
|
||||
super.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
return Collections.emptySet();
|
||||
public TextHeaders add(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CharSequence> unconvertedNames() {
|
||||
return Collections.emptySet();
|
||||
public TextHeaders add(CharSequence name, CharSequence... values) {
|
||||
super.add(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders add(CharSequence name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders addObject(CharSequence name, Object value) {
|
||||
super.addObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders add(CharSequence name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders addObject(CharSequence name, Iterable<?> values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders add(CharSequence name, Object... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders addObject(CharSequence name, Object... values) {
|
||||
super.addObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addBoolean(CharSequence name, boolean value) {
|
||||
super.addBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addChar(CharSequence name, char value) {
|
||||
super.addChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addByte(CharSequence name, byte value) {
|
||||
super.addByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addShort(CharSequence name, short value) {
|
||||
super.addShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addInt(CharSequence name, int value) {
|
||||
super.addInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addLong(CharSequence name, long value) {
|
||||
super.addLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addFloat(CharSequence name, float value) {
|
||||
super.addFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders addDouble(CharSequence name, double value) {
|
||||
super.addDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders add(TextHeaders headers) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
super.add(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders set(CharSequence name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders set(CharSequence name, CharSequence value) {
|
||||
super.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders set(CharSequence name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders set(CharSequence name, Iterable<? extends CharSequence> values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders set(CharSequence name, Object... values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
public TextHeaders set(CharSequence name, CharSequence... values) {
|
||||
super.set(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setObject(CharSequence name, Object value) {
|
||||
super.setObject(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setObject(CharSequence name, Iterable<?> values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setObject(CharSequence name, Object... values) {
|
||||
super.setObject(name, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setBoolean(CharSequence name, boolean value) {
|
||||
super.setBoolean(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setChar(CharSequence name, char value) {
|
||||
super.setChar(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setByte(CharSequence name, byte value) {
|
||||
super.setByte(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setShort(CharSequence name, short value) {
|
||||
super.setShort(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setInt(CharSequence name, int value) {
|
||||
super.setInt(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setLong(CharSequence name, long value) {
|
||||
super.setLong(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setFloat(CharSequence name, float value) {
|
||||
super.setFloat(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders setDouble(CharSequence name, double value) {
|
||||
super.setDouble(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders set(TextHeaders headers) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
super.set(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(CharSequence name) {
|
||||
return false;
|
||||
public TextHeaders setAll(TextHeaders headers) {
|
||||
super.setAll(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders clear() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name, Object value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(CharSequence name, Object value, boolean ignoreCase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<String, String>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<CharSequence, CharSequence>> unconvertedIterator() {
|
||||
return unconvertedEntries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextHeaders forEachEntry(TextHeaderProcessor processor) {
|
||||
super.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
1085
codec/src/main/java/io/netty/handler/codec/Headers.java
Normal file
1085
codec/src/main/java/io/netty/handler/codec/Headers.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
public interface TextHeaderProcessor {
|
||||
boolean process(CharSequence name, CharSequence value) throws Exception;
|
||||
}
|
@ -16,444 +16,142 @@
|
||||
|
||||
package io.netty.handler.codec;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A typical string multimap used by text protocols such as HTTP for the representation of arbitrary key-value data.
|
||||
* One thing to note is that it uses {@link CharSequence} as its primary key and value type rather than {@link String}.
|
||||
* When you invoke the operations that produce {@link String}s such as {@link #get(CharSequence)},
|
||||
* a {@link CharSequence} is implicitly converted to a {@link String}. This is particularly useful for speed
|
||||
* optimization because this multimap can hold a special {@link CharSequence} implementation that a codec can
|
||||
* treat specially, such as {@link AsciiString}.
|
||||
* A typical string multimap used by text protocols such as HTTP for the representation of arbitrary key-value data. One
|
||||
* thing to note is that it uses {@link CharSequence} as its primary key and value type rather than {@link String}. When
|
||||
* you invoke the operations that produce {@link String}s such as {@link #get(Object)}, a {@link CharSequence} is
|
||||
* implicitly converted to a {@link String}. This is particularly useful for speed optimization because this multimap
|
||||
* can hold a special {@link CharSequence} implementation that a codec can treat specially, such as {@link CharSequence}
|
||||
* .
|
||||
*/
|
||||
public interface TextHeaders extends Iterable<Map.Entry<String, String>> {
|
||||
public interface TextHeaders extends ConvertibleHeaders<CharSequence, String> {
|
||||
/**
|
||||
* 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 if the header is found.
|
||||
* {@code null} if there's no such header.
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
*/
|
||||
String get(CharSequence name);
|
||||
interface EntryVisitor extends Headers.EntryVisitor<CharSequence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value if the header is found.
|
||||
* {@code defaultValue} if there's no such header.
|
||||
* A visitor that helps reduce GC pressure while iterating over a collection of {@link Headers}.
|
||||
*/
|
||||
String get(CharSequence name, String defaultValue);
|
||||
interface NameVisitor extends Headers.NameVisitor<CharSequence> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the integer 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 if the header is found and its value is an integer.
|
||||
* {@code null} if there's no such header or its value is not an integer.
|
||||
* Returns {@code true} if a header with the name and value exists.
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return {@code true} if it contains it {@code false} otherwise
|
||||
*/
|
||||
Integer getInt(CharSequence name);
|
||||
boolean contains(CharSequence name, CharSequence value, boolean ignoreCase);
|
||||
|
||||
/**
|
||||
* Returns the integer 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value if the header is found and its value is an integer.
|
||||
* {@code defaultValue} if there's no such header or its value is not an integer.
|
||||
* Returns {@code true} if a header with the name and value exists.
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return {@code true} if it contains it {@code false} otherwise
|
||||
*/
|
||||
int getInt(CharSequence name, int defaultValue);
|
||||
boolean containsObject(CharSequence name, Object value, boolean ignoreCase);
|
||||
|
||||
@Override
|
||||
TextHeaders add(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
TextHeaders add(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
TextHeaders add(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
TextHeaders addObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
TextHeaders addObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
TextHeaders addObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
TextHeaders addBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
TextHeaders addByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
TextHeaders addChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
TextHeaders addShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
TextHeaders addInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
TextHeaders addLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
TextHeaders addFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
TextHeaders addDouble(CharSequence name, double value);
|
||||
|
||||
/**
|
||||
* Returns the long integer 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 if the header is found and its value is a long integer.
|
||||
* {@code null} if there's no such header or its value is not a long integer.
|
||||
*/
|
||||
Long getLong(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns the long integer 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value if the header is found and its value is a long integer.
|
||||
* {@code defaultValue} if there's no such header or its value is not a long integer.
|
||||
*/
|
||||
long getLong(CharSequence name, long defaultValue);
|
||||
|
||||
/**
|
||||
* Returns the date value of a header with the specified name as milliseconds. 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 in milliseconds if the header is found and its value is a date.
|
||||
* {@code null} if there's no such header or its value is not a date.
|
||||
*/
|
||||
Long getTimeMillis(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns the date value of a header with the specified name as milliseconds. 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
|
||||
* @param defaultValue default value
|
||||
* @return the first header value in milliseconds if the header is found and its value is a date.
|
||||
* {@code defaultValue} if there's no such header or its value is not a date.
|
||||
*/
|
||||
long getTimeMillis(CharSequence name, long defaultValue);
|
||||
|
||||
/**
|
||||
* Returns and removes 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 getAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and removes 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value or {@code defaultValue} if there is no such header
|
||||
*/
|
||||
String getAndRemove(CharSequence name, String defaultValue);
|
||||
|
||||
/**
|
||||
* Returns and removes the integer 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 if the header is found and its value is an integer.
|
||||
* {@code null} if there's no such header or its value is not an integer.
|
||||
*/
|
||||
Integer getIntAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and removes the integer 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value if the header is found and its value is an integer.
|
||||
* {@code defaultValue} if there is no such header or its value of header is not an integer.
|
||||
*/
|
||||
int getIntAndRemove(CharSequence name, int defaultValue);
|
||||
|
||||
/**
|
||||
* Returns and removes the long 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 if the header is found and its value is an integer.
|
||||
* {@code null} if there's no such header or its value is not an integer.
|
||||
*/
|
||||
Long getLongAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and removes the long 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
|
||||
* @param defaultValue the default value
|
||||
* @return the first header value if the header is found and its value is an integer.
|
||||
* {@code defaultValue} if there's no such header or its value is not an integer.
|
||||
*/
|
||||
long getLongAndRemove(CharSequence name, long defaultValue);
|
||||
|
||||
/**
|
||||
* Returns and removes the date value of a header with the specified name as milliseconds. 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 in milliseconds if the header is found and its value is a date.
|
||||
* {@code null} if there's no such header or its value is not a date.
|
||||
*/
|
||||
Long getTimeMillisAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and removes the date value of a header with the specified name as milliseconds. 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
|
||||
* @param defaultValue default value
|
||||
* @return the first header value in milliseconds if the header is found and its value is a date.
|
||||
* {@code defaultValue} if there's no such header or its value is not a date.
|
||||
*/
|
||||
long getTimeMillisAndRemove(CharSequence name, long defaultValue);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
CharSequence getUnconverted(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and Removes 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
|
||||
*/
|
||||
CharSequence getUnconvertedAndRemove(CharSequence 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> getAll(CharSequence 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<CharSequence> getAllUnconverted(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and Removes 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> getAllAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns and Removes 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<CharSequence> getAllUnconvertedAndRemove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns a new {@link List} that contains all headers in this object. Note that modifying the
|
||||
* returned {@link List} will not affect the state of this object. If you intend to enumerate over the header
|
||||
* entries only, use {@link #iterator()} instead, which has much less overhead.
|
||||
*/
|
||||
List<Entry<String, String>> entries();
|
||||
|
||||
/**
|
||||
* Returns a new {@link List} that contains all headers in this object. Note that modifying the
|
||||
* returned {@link List} will not affect the state of this object. If you intend to enumerate over the header
|
||||
* entries only, use {@link #iterator()} instead, which has much less overhead.
|
||||
*/
|
||||
List<Entry<CharSequence, CharSequence>> unconvertedEntries();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if this collection contains the header with the specified name.
|
||||
*
|
||||
* @param name The name of the header to search for
|
||||
* @return {@code true} if at least one header is found
|
||||
*/
|
||||
boolean contains(CharSequence name);
|
||||
|
||||
/**
|
||||
* Returns the number of header entries in this collection.
|
||||
*/
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if this collection contains no header entries.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Returns a new {@link Set} that contains the names of all headers in this object. Note that modifying the
|
||||
* returned {@link Set} will not affect the state of this object. If you intend to enumerate over the header
|
||||
* entries only, use {@link #iterator()} instead, which has much less overhead.
|
||||
*/
|
||||
Set<String> names();
|
||||
|
||||
/**
|
||||
* Returns a new {@link Set} that contains the names of all headers in this object. Note that modifying the
|
||||
* returned {@link Set} will not affect the state of this object. If you intend to enumerate over the header
|
||||
* entries only, use {@link #iterator()} instead, which has much less overhead.
|
||||
*/
|
||||
Set<CharSequence> unconvertedNames();
|
||||
|
||||
/**
|
||||
* 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 java.util.Date} and {@link java.util.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
|
||||
*
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders add(CharSequence name, Object value);
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and values.
|
||||
*
|
||||
* This getMethod 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 headepublic abstract rs being set
|
||||
* @param values the values of the headers being set
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders add(CharSequence name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and values.
|
||||
*
|
||||
* This getMethod 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 headepublic abstract rs being set
|
||||
* @param values the values of the headers being set
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders add(CharSequence name, Object... values);
|
||||
|
||||
/**
|
||||
* Adds all header entries of the specified {@code headers}.
|
||||
*
|
||||
* @return {@code this}
|
||||
* See {@link Headers#add(Headers)}
|
||||
*/
|
||||
TextHeaders add(TextHeaders headers);
|
||||
|
||||
/**
|
||||
* 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 java.util.Date}
|
||||
* and {@link java.util.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
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders set(CharSequence name, Object value);
|
||||
@Override
|
||||
TextHeaders set(CharSequence name, CharSequence value);
|
||||
|
||||
@Override
|
||||
TextHeaders set(CharSequence name, Iterable<? extends CharSequence> values);
|
||||
|
||||
@Override
|
||||
TextHeaders set(CharSequence name, CharSequence... values);
|
||||
|
||||
@Override
|
||||
TextHeaders setObject(CharSequence name, Object value);
|
||||
|
||||
@Override
|
||||
TextHeaders setObject(CharSequence name, Iterable<?> values);
|
||||
|
||||
@Override
|
||||
TextHeaders setObject(CharSequence name, Object... values);
|
||||
|
||||
@Override
|
||||
TextHeaders setBoolean(CharSequence name, boolean value);
|
||||
|
||||
@Override
|
||||
TextHeaders setByte(CharSequence name, byte value);
|
||||
|
||||
@Override
|
||||
TextHeaders setChar(CharSequence name, char value);
|
||||
|
||||
@Override
|
||||
TextHeaders setShort(CharSequence name, short value);
|
||||
|
||||
@Override
|
||||
TextHeaders setInt(CharSequence name, int value);
|
||||
|
||||
@Override
|
||||
TextHeaders setLong(CharSequence name, long value);
|
||||
|
||||
@Override
|
||||
TextHeaders setFloat(CharSequence name, float value);
|
||||
|
||||
@Override
|
||||
TextHeaders setDouble(CharSequence name, double value);
|
||||
|
||||
/**
|
||||
* Sets a header with the specified name and values.
|
||||
*
|
||||
* If there is an existing header with the same name, it is removed.
|
||||
* This getMethod 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
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders set(CharSequence name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Sets a header with the specified name and values.
|
||||
*
|
||||
* If there is an existing header with the same name, it is removed.
|
||||
* This getMethod 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
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders set(CharSequence name, Object... values);
|
||||
|
||||
/**
|
||||
* Cleans the current header entries and copies all header entries of the specified {@code headers}.
|
||||
*
|
||||
* @return {@code this}
|
||||
* See {@link Headers#set(Headers)}
|
||||
*/
|
||||
TextHeaders set(TextHeaders headers);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
*
|
||||
* @param name The name of the header to remove
|
||||
* @return {@code true} if and only if at least one entry has been removed
|
||||
* See {@link Headers#setAll(Headers)}
|
||||
*/
|
||||
boolean remove(CharSequence name);
|
||||
|
||||
/**
|
||||
* Removes all headers.
|
||||
*
|
||||
* @return {@code this}
|
||||
*/
|
||||
TextHeaders clear();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a header with the name and value exists.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return {@code true} if it contains it {@code false} otherwise
|
||||
*/
|
||||
boolean contains(CharSequence name, Object value);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a header with the name and value exists.
|
||||
*
|
||||
* @param name the header name
|
||||
* @param value the header value
|
||||
* @return {@code true} if it contains it {@code false} otherwise
|
||||
*/
|
||||
boolean contains(CharSequence name, Object value, boolean ignoreCase);
|
||||
TextHeaders setAll(TextHeaders headers);
|
||||
|
||||
@Override
|
||||
Iterator<Entry<String, String>> iterator();
|
||||
|
||||
Iterator<Entry<CharSequence, CharSequence>> unconvertedIterator();
|
||||
|
||||
TextHeaders forEachEntry(TextHeaderProcessor processor);
|
||||
TextHeaders clear();
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test for the {@link AsciiString} class
|
||||
*/
|
||||
public class AsciiStringTest {
|
||||
|
||||
@Test
|
||||
public void testGetBytesStringBuilder() {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
for (int i = 0; i < 1 << 16; ++i) {
|
||||
b.append("eéaà");
|
||||
}
|
||||
final String bString = b.toString();
|
||||
final Charset[] charsets = CharsetUtil.values();
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] expected = getBytesWithEncoder(bString, charset);
|
||||
byte[] actual = AsciiString.getBytes(b, charset);
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBytesString() {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
for (int i = 0; i < 1 << 16; ++i) {
|
||||
b.append("eéaà");
|
||||
}
|
||||
final String bString = b.toString();
|
||||
final Charset[] charsets = CharsetUtil.values();
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] expected = bString.getBytes(charset);
|
||||
byte[] actual = AsciiString.getBytes(bString, charset);
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBytesAsciiString() {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
for (int i = 0; i < 1 << 16; ++i) {
|
||||
b.append("eéaà");
|
||||
}
|
||||
final String bString = b.toString();
|
||||
// The AsciiString class actually limits the Charset to ISO_8859_1
|
||||
byte[] expected = bString.getBytes(CharsetUtil.ISO_8859_1);
|
||||
final Charset[] charsets = CharsetUtil.values();
|
||||
for (int i = 0; i < charsets.length; ++i) {
|
||||
final Charset charset = charsets[i];
|
||||
byte[] actual = AsciiString.getBytes(new AsciiString(bString), charset);
|
||||
assertArrayEquals("failure for " + charset, expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getBytesWithEncoder(CharSequence value, Charset charset) {
|
||||
final CharsetEncoder encoder = CharsetUtil.getEncoder(charset);
|
||||
final ByteBuffer nativeBuffer = ByteBuffer.allocate((int) (encoder.maxBytesPerChar() * value.length()));
|
||||
encoder.encode(CharBuffer.wrap(value), nativeBuffer, true);
|
||||
return nativeBuffer.array();
|
||||
}
|
||||
}
|
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright 2014 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link DefaultBinaryHeaders}.
|
||||
*/
|
||||
public class DefaultBinaryHeadersTest {
|
||||
|
||||
@Test
|
||||
public void binaryHeadersWithSameValuesShouldBeEquivalent() {
|
||||
byte[] key1 = randomBytes();
|
||||
byte[] value1 = randomBytes();
|
||||
byte[] key2 = randomBytes();
|
||||
byte[] value2 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
h1.set(as(key1), as(value1));
|
||||
h1.set(as(key2), as(value2));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
h2.set(as(key1), as(value1));
|
||||
h2.set(as(key2), as(value2));
|
||||
|
||||
assertTrue(h1.equals(h2));
|
||||
assertTrue(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binaryHeadersWithSameDuplicateValuesShouldBeEquivalent() {
|
||||
byte[] k1 = randomBytes();
|
||||
byte[] k2 = randomBytes();
|
||||
byte[] v1 = randomBytes();
|
||||
byte[] v2 = randomBytes();
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
h2.add(as(k2), as(v3));
|
||||
|
||||
assertTrue(h1.equals(h2));
|
||||
assertTrue(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binaryHeadersWithDifferentValuesShouldNotBeEquivalent() {
|
||||
byte[] k1 = randomBytes();
|
||||
byte[] k2 = randomBytes();
|
||||
byte[] v1 = randomBytes();
|
||||
byte[] v2 = randomBytes();
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
|
||||
assertFalse(h1.equals(h2));
|
||||
assertFalse(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binarySetAllShouldMergeHeaders() {
|
||||
byte[] k1 = randomBytes();
|
||||
byte[] k2 = randomBytes();
|
||||
byte[] v1 = randomBytes();
|
||||
byte[] v2 = randomBytes();
|
||||
byte[] v3 = randomBytes();
|
||||
byte[] v4 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
h1.set(as(k1), as(v1));
|
||||
h1.set(as(k2), as(v2));
|
||||
h1.add(as(k2), as(v3));
|
||||
h1.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders(false);
|
||||
h2.set(as(k1), as(v1));
|
||||
h2.set(as(k2), as(v2));
|
||||
h2.add(as(k1), as(v4));
|
||||
|
||||
DefaultBinaryHeaders expected = new DefaultBinaryHeaders(false);
|
||||
expected.set(as(k1), as(v1));
|
||||
expected.set(as(k2), as(v2));
|
||||
expected.add(as(k2), as(v3));
|
||||
expected.add(as(k1), as(v4));
|
||||
expected.set(as(k1), as(v1));
|
||||
expected.set(as(k2), as(v2));
|
||||
expected.set(as(k1), as(v4));
|
||||
|
||||
h1.setAll(h2);
|
||||
|
||||
assertEquals(expected, h1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binarySetShouldReplacePreviousValues() {
|
||||
byte[] k1 = randomBytes();
|
||||
byte[] v1 = randomBytes();
|
||||
byte[] v2 = randomBytes();
|
||||
byte[] v3 = randomBytes();
|
||||
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders(false);
|
||||
h1.add(as(k1), as(v1));
|
||||
h1.add(as(k1), as(v2));
|
||||
assertEquals(2, h1.size());
|
||||
|
||||
h1.set(as(k1), as(v3));
|
||||
assertEquals(1, h1.size());
|
||||
List<AsciiString> list = h1.getAll(as(k1));
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(as(v3), list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWithSameValuesShouldBeEquivalent() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as("foo"), as("goo"));
|
||||
h1.set(as("foo2"), as("goo2"));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as("foo"), as("goo"));
|
||||
h2.set(as("foo2"), as("goo2"));
|
||||
|
||||
assertTrue(h1.equals(h2));
|
||||
assertTrue(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWithSameDuplicateValuesShouldBeEquivalent() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as("foo"), as("goo"));
|
||||
h1.set(as("foo2"), as("goo2"));
|
||||
h1.add(as("foo2"), as("goo3"));
|
||||
h1.add(as("foo"), as("goo4"));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as("foo"), as("goo"));
|
||||
h2.set(as("foo2"), as("goo2"));
|
||||
h2.add(as("foo"), as("goo4"));
|
||||
h2.add(as("foo2"), as("goo3"));
|
||||
|
||||
assertTrue(h1.equals(h2));
|
||||
assertTrue(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headersWithDifferentValuesShouldNotBeEquivalent() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as("foo"), as("goo"));
|
||||
h1.set(as("foo2"), as("goo2"));
|
||||
h1.add(as("foo2"), as("goo3"));
|
||||
h1.add(as("foo"), as("goo4"));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as("foo"), as("goo"));
|
||||
h2.set(as("foo2"), as("goo2"));
|
||||
h2.add(as("foo"), as("goo4"));
|
||||
|
||||
assertFalse(h1.equals(h2));
|
||||
assertFalse(h2.equals(h1));
|
||||
assertTrue(h2.equals(h2));
|
||||
assertTrue(h1.equals(h1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAllShouldMergeHeaders() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.set(as("foo"), as("goo"));
|
||||
h1.set(as("foo2"), as("goo2"));
|
||||
h1.add(as("foo2"), as("goo3"));
|
||||
h1.add(as("foo"), as("goo4"));
|
||||
|
||||
DefaultBinaryHeaders h2 = new DefaultBinaryHeaders();
|
||||
h2.set(as("foo"), as("goo"));
|
||||
h2.set(as("foo2"), as("goo2"));
|
||||
h2.add(as("foo"), as("goo4"));
|
||||
|
||||
DefaultBinaryHeaders expected = new DefaultBinaryHeaders();
|
||||
expected.set(as("foo"), as("goo"));
|
||||
expected.set(as("foo2"), as("goo2"));
|
||||
expected.add(as("foo2"), as("goo3"));
|
||||
expected.add(as("foo"), as("goo4"));
|
||||
expected.set(as("foo"), as("goo"));
|
||||
expected.set(as("foo2"), as("goo2"));
|
||||
expected.set(as("foo"), as("goo4"));
|
||||
|
||||
h1.setAll(h2);
|
||||
|
||||
assertEquals(expected, h1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setShouldReplacePreviousValues() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.add(as("foo"), as("goo"));
|
||||
h1.add(as("foo"), as("goo2"));
|
||||
assertEquals(2, h1.size());
|
||||
|
||||
h1.set(as("foo"), as("goo3"));
|
||||
assertEquals(1, h1.size());
|
||||
List<AsciiString> list = h1.getAll(as("foo"));
|
||||
assertEquals(1, list.size());
|
||||
assertEquals(as("goo3"), list.get(0));
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchElementException.class)
|
||||
public void iterateEmptyHeadersShouldThrow() {
|
||||
Iterator<Map.Entry<AsciiString, AsciiString>> iterator = new DefaultBinaryHeaders().iterator();
|
||||
assertFalse(iterator.hasNext());
|
||||
iterator.next();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void iterateHeadersShouldReturnAllValues() {
|
||||
Set<String> headers = new HashSet<String>();
|
||||
headers.add("a:1");
|
||||
headers.add("a:2");
|
||||
headers.add("a:3");
|
||||
headers.add("b:1");
|
||||
headers.add("b:2");
|
||||
headers.add("c:1");
|
||||
|
||||
// Build the headers from the input set.
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
for (String header : headers) {
|
||||
String[] parts = header.split(":");
|
||||
h1.add(as(parts[0]), as(parts[1]));
|
||||
}
|
||||
|
||||
// Now iterate through the headers, removing them from the original set.
|
||||
for (Map.Entry<AsciiString, AsciiString> entry : h1) {
|
||||
assertTrue(headers.remove(entry.getKey().toString() + ':' + entry.getValue().toString()));
|
||||
}
|
||||
|
||||
// Make sure we removed them all.
|
||||
assertTrue(headers.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAndRemoveShouldReturnFirstEntry() {
|
||||
DefaultBinaryHeaders h1 = new DefaultBinaryHeaders();
|
||||
h1.add(as("foo"), as("goo"));
|
||||
h1.add(as("foo"), as("goo2"));
|
||||
assertEquals(as("goo"), h1.getAndRemove(as("foo")));
|
||||
assertEquals(0, h1.size());
|
||||
List<AsciiString> values = h1.getAll(as("foo"));
|
||||
assertEquals(0, values.size());
|
||||
}
|
||||
|
||||
private static byte[] randomBytes() {
|
||||
byte[] data = new byte[100];
|
||||
new Random().nextBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private AsciiString as(byte[] bytes) {
|
||||
return new AsciiString(bytes);
|
||||
}
|
||||
|
||||
private AsciiString as(String value) {
|
||||
return new AsciiString(value);
|
||||
}
|
||||
}
|
@ -61,6 +61,11 @@ public final class CharsetUtil {
|
||||
*/
|
||||
public static final Charset US_ASCII = Charset.forName("US-ASCII");
|
||||
|
||||
private static final Charset[] CHARSETS = new Charset[]
|
||||
{ UTF_16, UTF_16BE, UTF_16LE, UTF_8, ISO_8859_1, US_ASCII };
|
||||
|
||||
public static Charset[] values() { return CHARSETS; }
|
||||
|
||||
/**
|
||||
* Returns a cached thread-local {@link CharsetEncoder} for the specified
|
||||
* <tt>charset</tt>.
|
||||
@ -111,7 +116,5 @@ public final class CharsetUtil {
|
||||
return d;
|
||||
}
|
||||
|
||||
private CharsetUtil() {
|
||||
// Unused
|
||||
}
|
||||
private CharsetUtil() { }
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2014 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.util.collection;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides utilities for the primitive collection types that are not supplied by the JDK
|
||||
*/
|
||||
public final class CollectionUtils {
|
||||
|
||||
private CollectionUtils() { }
|
||||
|
||||
/**
|
||||
* Compare two lists using the {@code comparator} for all comparisons (not using the equals() operator)
|
||||
* @param lhs Left hand side
|
||||
* @param rhs Right hand side
|
||||
* @param comparator Comparator which will be used for all comparisons (equals() on objects will not be used)
|
||||
* @return True if {@code lhs} == {@code rhs} according to {@code comparator}. False otherwise.
|
||||
*/
|
||||
public static <T> boolean equals(List<T> lhs, List<T> rhs, Comparator<? super T> comparator) {
|
||||
final int lhsSize = lhs.size();
|
||||
if (lhsSize != rhs.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't use a TreeSet to do the comparison. We want to force the comparator
|
||||
// to be used instead of the object's equals()
|
||||
Collections.sort(lhs, comparator);
|
||||
Collections.sort(rhs, comparator);
|
||||
for (int i = 0; i < lhsSize; ++i) {
|
||||
if (comparator.compare(lhs.get(i), rhs.get(i)) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -149,7 +149,7 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
}
|
||||
|
||||
// Cache Validation
|
||||
String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
|
||||
String ifModifiedSince = request.headers().getAndConvert(IF_MODIFIED_SINCE);
|
||||
if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
|
||||
Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince);
|
||||
|
@ -52,7 +52,7 @@ public class HttpHelloWorldServerHandler extends ChannelInboundHandlerAdapter {
|
||||
boolean keepAlive = HttpHeaders.isKeepAlive(req);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT));
|
||||
response.headers().set(CONTENT_TYPE, "text/plain");
|
||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
@ -36,8 +36,8 @@ public class HttpSnoopClientHandler extends SimpleChannelInboundHandler<HttpObje
|
||||
System.err.println();
|
||||
|
||||
if (!response.headers().isEmpty()) {
|
||||
for (String name: response.headers().names()) {
|
||||
for (String value: response.headers().getAll(name)) {
|
||||
for (CharSequence name: response.headers().names()) {
|
||||
for (CharSequence value: response.headers().getAll(name)) {
|
||||
System.err.println("HEADER: " + name + " = " + value);
|
||||
}
|
||||
}
|
||||
|
@ -73,9 +73,9 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
|
||||
|
||||
HttpHeaders headers = request.headers();
|
||||
if (!headers.isEmpty()) {
|
||||
for (Map.Entry<String, String> h: headers) {
|
||||
String key = h.getKey();
|
||||
String value = h.getValue();
|
||||
for (Map.Entry<CharSequence, CharSequence> h: headers) {
|
||||
CharSequence key = h.getKey();
|
||||
CharSequence value = h.getValue();
|
||||
buf.append("HEADER: ").append(key).append(" = ").append(value).append("\r\n");
|
||||
}
|
||||
buf.append("\r\n");
|
||||
@ -114,8 +114,8 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
|
||||
LastHttpContent trailer = (LastHttpContent) msg;
|
||||
if (!trailer.trailingHeaders().isEmpty()) {
|
||||
buf.append("\r\n");
|
||||
for (String name: trailer.trailingHeaders().names()) {
|
||||
for (String value: trailer.trailingHeaders().getAll(name)) {
|
||||
for (CharSequence name: trailer.trailingHeaders().names()) {
|
||||
for (CharSequence value: trailer.trailingHeaders().getAll(name)) {
|
||||
buf.append("TRAILING HEADER: ");
|
||||
buf.append(name).append(" = ").append(value).append("\r\n");
|
||||
}
|
||||
@ -154,14 +154,14 @@ public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object>
|
||||
|
||||
if (keepAlive) {
|
||||
// Add 'Content-Length' header only for a keep-alive connection.
|
||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
// Add keep alive header as per:
|
||||
// - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
|
||||
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Encode the cookie.
|
||||
String cookieString = request.headers().get(COOKIE);
|
||||
String cookieString = request.headers().getAndConvert(COOKIE);
|
||||
if (cookieString != null) {
|
||||
Set<Cookie> cookies = CookieDecoder.decode(cookieString);
|
||||
if (!cookies.isEmpty()) {
|
||||
|
@ -183,7 +183,7 @@ public final class HttpUploadClient {
|
||||
);
|
||||
|
||||
// send request
|
||||
List<Entry<String, String>> entries = headers.entries();
|
||||
List<Entry<String, String>> entries = headers.entriesConverted();
|
||||
channel.writeAndFlush(request);
|
||||
|
||||
// Wait for the server to close the connection.
|
||||
|
@ -40,8 +40,8 @@ public class HttpUploadClientHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
System.err.println("VERSION: " + response.protocolVersion());
|
||||
|
||||
if (!response.headers().isEmpty()) {
|
||||
for (String name : response.headers().names()) {
|
||||
for (String value : response.headers().getAll(name)) {
|
||||
for (CharSequence name : response.headers().names()) {
|
||||
for (CharSequence value : response.headers().getAll(name)) {
|
||||
System.err.println("HEADER: " + name + " = " + value);
|
||||
}
|
||||
}
|
||||
|
@ -113,14 +113,14 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
responseContent.append("\r\n\r\n");
|
||||
|
||||
// new getMethod
|
||||
for (Entry<String, String> entry : request.headers()) {
|
||||
for (Entry<CharSequence, CharSequence> entry : request.headers()) {
|
||||
responseContent.append("HEADER: " + entry.getKey() + '=' + entry.getValue() + "\r\n");
|
||||
}
|
||||
responseContent.append("\r\n\r\n");
|
||||
|
||||
// new getMethod
|
||||
Set<Cookie> cookies;
|
||||
String value = request.headers().get(COOKIE);
|
||||
String value = request.headers().getAndConvert(COOKIE);
|
||||
if (value == null) {
|
||||
cookies = Collections.emptySet();
|
||||
} else {
|
||||
@ -299,11 +299,11 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
if (!close) {
|
||||
// There's no need to add 'Content-Length' header
|
||||
// if this is the last response.
|
||||
response.headers().set(CONTENT_LENGTH, buf.readableBytes());
|
||||
response.headers().setInt(CONTENT_LENGTH, buf.readableBytes());
|
||||
}
|
||||
|
||||
Set<Cookie> cookies;
|
||||
String value = request.headers().get(COOKIE);
|
||||
String value = request.headers().getAndConvert(COOKIE);
|
||||
if (value == null) {
|
||||
cookies = Collections.emptySet();
|
||||
} else {
|
||||
@ -401,7 +401,7 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
|
||||
|
||||
response.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8");
|
||||
response.headers().set(CONTENT_LENGTH, buf.readableBytes());
|
||||
response.headers().setInt(CONTENT_LENGTH, buf.readableBytes());
|
||||
|
||||
// Write the response.
|
||||
ctx.channel().writeAndFlush(response);
|
||||
|
@ -47,8 +47,8 @@ public class HttpResponseClientHandler extends SimpleChannelInboundHandler<HttpO
|
||||
System.out.println();
|
||||
|
||||
if (!response.headers().isEmpty()) {
|
||||
for (String name : response.headers().names()) {
|
||||
for (String value : response.headers().getAll(name)) {
|
||||
for (CharSequence name : response.headers().names()) {
|
||||
for (CharSequence value : response.headers().getAll(name)) {
|
||||
System.out.println("HEADER: " + name + " = " + value);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class SpdyServerHandler extends SimpleChannelInboundHandler<Object> {
|
||||
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, content);
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
|
||||
|
||||
if (!keepAlive) {
|
||||
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
@ -62,7 +62,7 @@ public class StompClientHandler extends SimpleChannelInboundHandler<StompFrame>
|
||||
ctx.writeAndFlush(subscribeFrame);
|
||||
break;
|
||||
case RECEIPT:
|
||||
String receiptHeader = frame.headers().get(StompHeaders.RECEIPT_ID);
|
||||
String receiptHeader = frame.headers().getAndConvert(StompHeaders.RECEIPT_ID);
|
||||
if (state == ClientState.AUTHENTICATED && receiptHeader.equals(subscrReceiptId)) {
|
||||
StompFrame msgFrame = new DefaultStompFrame(StompCommand.SEND);
|
||||
msgFrame.headers().set(StompHeaders.DESTINATION, StompClient.TOPIC);
|
||||
|
@ -86,7 +86,7 @@ final class HttpProxyServer extends ProxyServer {
|
||||
|
||||
boolean authzSuccess = false;
|
||||
if (username != null) {
|
||||
String authz = req.headers().get(Names.AUTHORIZATION);
|
||||
CharSequence authz = req.headers().get(Names.AUTHORIZATION);
|
||||
if (authz != null) {
|
||||
ByteBuf authzBuf64 = Unpooled.copiedBuffer(authz, CharsetUtil.US_ASCII);
|
||||
ByteBuf authzBuf = Base64.decode(authzBuf64);
|
||||
|
Loading…
Reference in New Issue
Block a user