[SPDY] Factor out headers into extra class like we did in http and support method chaining where possible
This commit is contained in:
parent
238e03f75b
commit
3843cfd702
@ -62,12 +62,13 @@ public class DefaultSpdyDataFrame extends DefaultByteBufHolder implements SpdyDa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdyDataFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,8 +77,9 @@ public class DefaultSpdyDataFrame extends DefaultByteBufHolder implements SpdyDa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLast(boolean last) {
|
||||
public SpdyDataFrame setLast(boolean last) {
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,12 +61,13 @@ public class DefaultSpdyGoAwayFrame implements SpdyGoAwayFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastGoodStreamId(int lastGoodStreamId) {
|
||||
public SpdyGoAwayFrame setLastGoodStreamId(int lastGoodStreamId) {
|
||||
if (lastGoodStreamId < 0) {
|
||||
throw new IllegalArgumentException("Last-good-stream-ID"
|
||||
+ " cannot be negative: " + lastGoodStreamId);
|
||||
}
|
||||
this.lastGoodStreamId = lastGoodStreamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -75,8 +76,9 @@ public class DefaultSpdyGoAwayFrame implements SpdyGoAwayFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(SpdySessionStatus status) {
|
||||
public SpdyGoAwayFrame setStatus(SpdySessionStatus status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,9 +17,7 @@ package io.netty.handler.codec.spdy;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The default {@link SpdyHeaderBlock} implementation.
|
||||
@ -27,7 +25,7 @@ import java.util.Set;
|
||||
public class DefaultSpdyHeaderBlock implements SpdyHeaderBlock {
|
||||
|
||||
private boolean invalid;
|
||||
private final SpdyHeaders headers = new SpdyHeaders();
|
||||
private final SpdyHeaders headers = new DefaultSpdyHeaders();
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
@ -41,62 +39,18 @@ public class DefaultSpdyHeaderBlock implements SpdyHeaderBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInvalid() {
|
||||
public SpdyHeaderBlock setInvalid() {
|
||||
invalid = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(final String name, final Object value) {
|
||||
headers.addHeader(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(final String name, final Object value) {
|
||||
headers.setHeader(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(final String name, final Iterable<?> values) {
|
||||
headers.setHeader(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeHeader(final String name) {
|
||||
headers.removeHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeaders() {
|
||||
headers.clearHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(final String name) {
|
||||
return headers.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHeaders(final String name) {
|
||||
return headers.getHeaders(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> getHeaders() {
|
||||
return headers.getHeaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsHeader(final String name) {
|
||||
return headers.containsHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getHeaderNames() {
|
||||
return headers.getHeaderNames();
|
||||
public SpdyHeaders headers() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
protected void appendHeaders(StringBuilder buf) {
|
||||
for (Map.Entry<String, String> e: getHeaders()) {
|
||||
for (Map.Entry<String, String> e: headers().entries()) {
|
||||
buf.append(" ");
|
||||
buf.append(e.getKey());
|
||||
buf.append(": ");
|
||||
|
@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
||||
public class DefaultSpdyHeaders extends SpdyHeaders {
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static int hash(String name) {
|
||||
int h = 0;
|
||||
for (int i = name.length() - 1; i >= 0; i --) {
|
||||
char c = name.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 32;
|
||||
}
|
||||
h = 31 * h + c;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
return h;
|
||||
} else if (h == Integer.MIN_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return -h;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean eq(String name1, String name2) {
|
||||
int nameLen = name1.length();
|
||||
if (nameLen != name2.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = nameLen - 1; i >= 0; i --) {
|
||||
char c1 = name1.charAt(i);
|
||||
char c2 = name2.charAt(i);
|
||||
if (c1 != c2) {
|
||||
if (c1 >= 'A' && c1 <= 'Z') {
|
||||
c1 += 32;
|
||||
}
|
||||
if (c2 >= 'A' && c2 <= 'Z') {
|
||||
c2 += 32;
|
||||
}
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int index(int hash) {
|
||||
return hash % BUCKET_SIZE;
|
||||
}
|
||||
|
||||
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
|
||||
private final HeaderEntry head = new HeaderEntry(-1, null, null);
|
||||
|
||||
DefaultSpdyHeaders() {
|
||||
head.before = head.after = head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void add0(int h, int i, final String name, final String value) {
|
||||
// Update the hash table.
|
||||
HeaderEntry e = entries[i];
|
||||
HeaderEntry newEntry;
|
||||
entries[i] = newEntry = new HeaderEntry(h, name, value);
|
||||
newEntry.next = e;
|
||||
|
||||
// Update the linked list.
|
||||
newEntry.addBefore(head);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders remove(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
remove0(h, i, lowerCaseName);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void remove0(int h, int i, String name) {
|
||||
HeaderEntry e = entries[i];
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
e.remove();
|
||||
HeaderEntry next = e.next;
|
||||
if (next != null) {
|
||||
entries[i] = next;
|
||||
e = next;
|
||||
} else {
|
||||
entries[i] = null;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
HeaderEntry next = e.next;
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
if (next.hash == h && eq(name, next.key)) {
|
||||
e.next = next.next;
|
||||
next.remove();
|
||||
} else {
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
remove0(h, i, lowerCaseName);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
|
||||
remove0(h, i, lowerCaseName);
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
String strVal = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
add0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders clear() {
|
||||
for (int i = 0; i < entries.length; i ++) {
|
||||
entries[i] = null;
|
||||
}
|
||||
head.before = head.after = head;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
return e.value;
|
||||
}
|
||||
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAll(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
LinkedList<String> values = new LinkedList<String>();
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
values.addFirst(e.value);
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
List<Map.Entry<String, String>> all =
|
||||
new LinkedList<Map.Entry<String, String>>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
all.add(e);
|
||||
e = e.after;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return get(name) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
Set<String> names = new TreeSet<String>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
names.add(e.key);
|
||||
e = e.after;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Iterable<?> values) {
|
||||
SpdyCodecUtil.validateHeaderValue(name);
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
for (Object v: values) {
|
||||
String vstr = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(vstr);
|
||||
add0(h, i, name, vstr);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return entries().isEmpty();
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static final class HeaderEntry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
String value;
|
||||
HeaderEntry next;
|
||||
HeaderEntry before, after;
|
||||
|
||||
HeaderEntry(int hash, String key, String value) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
before.after = after;
|
||||
after.before = before;
|
||||
}
|
||||
|
||||
void addBefore(HeaderEntry e) {
|
||||
after = e;
|
||||
before = e.before;
|
||||
before.after = this;
|
||||
after.before = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setValue(String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderValue(value);
|
||||
String oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + '=' + value;
|
||||
}
|
||||
}
|
||||
}
|
@ -42,12 +42,13 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdyHeadersFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,8 +57,15 @@ public class DefaultSpdyHeadersFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLast(boolean last) {
|
||||
public SpdyHeadersFrame setLast(boolean last) {
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeadersFrame setInvalid() {
|
||||
super.setInvalid();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,8 +39,9 @@ public class DefaultSpdyPingFrame implements SpdyPingFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(int id) {
|
||||
public SpdyPingFrame setId(int id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,12 +52,13 @@ public class DefaultSpdyRstStreamFrame implements SpdyRstStreamFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdyRstStreamFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,8 +67,9 @@ public class DefaultSpdyRstStreamFrame implements SpdyRstStreamFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(SpdyStreamStatus status) {
|
||||
public SpdyRstStreamFrame setStatus(SpdyStreamStatus status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,12 +51,12 @@ public class DefaultSpdySettingsFrame implements SpdySettingsFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int id, int value) {
|
||||
setValue(id, value, false, false);
|
||||
public SpdySettingsFrame setValue(int id, int value) {
|
||||
return setValue(id, value, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int id, int value, boolean persistValue, boolean persisted) {
|
||||
public SpdySettingsFrame setValue(int id, int value, boolean persistValue, boolean persisted) {
|
||||
if (id <= 0 || id > SpdyCodecUtil.SPDY_SETTINGS_MAX_ID) {
|
||||
throw new IllegalArgumentException("Setting ID is not valid: " + id);
|
||||
}
|
||||
@ -69,14 +69,16 @@ public class DefaultSpdySettingsFrame implements SpdySettingsFrame {
|
||||
} else {
|
||||
settingsMap.put(key, new Setting(value, persistValue, persisted));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(int id) {
|
||||
public SpdySettingsFrame removeValue(int id) {
|
||||
Integer key = Integer.valueOf(id);
|
||||
if (settingsMap.containsKey(key)) {
|
||||
settingsMap.remove(key);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,11 +92,12 @@ public class DefaultSpdySettingsFrame implements SpdySettingsFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPersistValue(int id, boolean persistValue) {
|
||||
public SpdySettingsFrame setPersistValue(int id, boolean persistValue) {
|
||||
Integer key = Integer.valueOf(id);
|
||||
if (settingsMap.containsKey(key)) {
|
||||
settingsMap.get(key).setPersist(persistValue);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -108,11 +111,12 @@ public class DefaultSpdySettingsFrame implements SpdySettingsFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPersisted(int id, boolean persisted) {
|
||||
public SpdySettingsFrame setPersisted(int id, boolean persisted) {
|
||||
Integer key = Integer.valueOf(id);
|
||||
if (settingsMap.containsKey(key)) {
|
||||
settingsMap.get(key).setPersisted(persisted);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -121,8 +125,9 @@ public class DefaultSpdySettingsFrame implements SpdySettingsFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClearPreviouslyPersistedSettings(boolean clear) {
|
||||
public SpdySettingsFrame setClearPreviouslyPersistedSettings(boolean clear) {
|
||||
this.clear = clear;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Set<Map.Entry<Integer, Setting>> getSettings() {
|
||||
|
@ -41,12 +41,13 @@ public class DefaultSpdySynReplyFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdySynReplyFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,8 +56,15 @@ public class DefaultSpdySynReplyFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLast(boolean last) {
|
||||
public SpdySynReplyFrame setLast(boolean last) {
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdySynReplyFrame setInvalid() {
|
||||
super.setInvalid();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,12 +49,13 @@ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdySynStreamFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,13 +64,14 @@ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAssociatedToStreamId(int associatedToStreamId) {
|
||||
public SpdySynStreamFrame setAssociatedToStreamId(int associatedToStreamId) {
|
||||
if (associatedToStreamId < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Associated-To-Stream-ID cannot be negative: " +
|
||||
associatedToStreamId);
|
||||
}
|
||||
this.associatedToStreamId = associatedToStreamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -78,12 +80,13 @@ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPriority(byte priority) {
|
||||
public SpdySynStreamFrame setPriority(byte priority) {
|
||||
if (priority < 0 || priority > 7) {
|
||||
throw new IllegalArgumentException(
|
||||
"Priority must be between 0 and 7 inclusive: " + priority);
|
||||
}
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -92,8 +95,9 @@ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLast(boolean last) {
|
||||
public SpdySynStreamFrame setLast(boolean last) {
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -102,8 +106,15 @@ public class DefaultSpdySynStreamFrame extends DefaultSpdyHeaderBlock
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnidirectional(boolean unidirectional) {
|
||||
public SpdySynStreamFrame setUnidirectional(boolean unidirectional) {
|
||||
this.unidirectional = unidirectional;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdySynStreamFrame setInvalid() {
|
||||
super.setInvalid();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,12 +42,13 @@ public class DefaultSpdyWindowUpdateFrame implements SpdyWindowUpdateFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamId(int streamId) {
|
||||
public SpdyWindowUpdateFrame setStreamId(int streamId) {
|
||||
if (streamId <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Stream-ID must be positive: " + streamId);
|
||||
}
|
||||
this.streamId = streamId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -56,13 +57,14 @@ public class DefaultSpdyWindowUpdateFrame implements SpdyWindowUpdateFrame {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeltaWindowSize(int deltaWindowSize) {
|
||||
public SpdyWindowUpdateFrame setDeltaWindowSize(int deltaWindowSize) {
|
||||
if (deltaWindowSize <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Delta-Window-Size must be positive: " +
|
||||
deltaWindowSize);
|
||||
}
|
||||
this.deltaWindowSize = deltaWindowSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,28 +22,13 @@ import io.netty.buffer.Unpooled;
|
||||
/**
|
||||
* A SPDY Protocol Data Frame
|
||||
*/
|
||||
public interface SpdyDataFrame extends ByteBufHolder {
|
||||
public interface SpdyDataFrame extends ByteBufHolder, SpdyStreamFrame {
|
||||
|
||||
/**
|
||||
* Returns the Stream-ID of this frame.
|
||||
*/
|
||||
int getStreamId();
|
||||
@Override
|
||||
SpdyDataFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this frame is the last frame to be transmitted
|
||||
* on the stream.
|
||||
*/
|
||||
boolean isLast();
|
||||
|
||||
/**
|
||||
* Sets if this frame is the last frame to be transmitted on the stream.
|
||||
*/
|
||||
void setLast(boolean last);
|
||||
@Override
|
||||
SpdyDataFrame setLast(boolean last);
|
||||
|
||||
/**
|
||||
* Returns the data payload of this frame. If there is no data payload
|
||||
|
@ -613,7 +613,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
|
||||
String name = new String(nameBytes, "UTF-8");
|
||||
|
||||
// Check for identically named headers
|
||||
if (spdyHeaderBlock.containsHeader(name)) {
|
||||
if (spdyHeaderBlock.headers().contains(name)) {
|
||||
spdyHeaderBlock.setInvalid();
|
||||
return;
|
||||
}
|
||||
@ -638,7 +638,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
|
||||
spdyHeaderBlock.setInvalid();
|
||||
return;
|
||||
} else {
|
||||
spdyHeaderBlock.addHeader(name, "");
|
||||
spdyHeaderBlock.headers().add(name, "");
|
||||
numHeaders --;
|
||||
this.headerSize = headerSize;
|
||||
continue;
|
||||
@ -676,7 +676,7 @@ public class SpdyFrameDecoder extends ByteToMessageDecoder {
|
||||
String value = new String(valueBytes, offset, index - offset, "UTF-8");
|
||||
|
||||
try {
|
||||
spdyHeaderBlock.addHeader(name, value);
|
||||
spdyHeaderBlock.headers().add(name, value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Name contains NULL or non-ascii characters
|
||||
spdyHeaderBlock.setInvalid();
|
||||
|
@ -289,7 +289,7 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<Object> {
|
||||
|
||||
private static ByteBuf encodeHeaderBlock(int version, SpdyHeaderBlock headerFrame)
|
||||
throws Exception {
|
||||
Set<String> names = headerFrame.getHeaderNames();
|
||||
Set<String> names = headerFrame.headers().names();
|
||||
int numHeaders = names.size();
|
||||
if (numHeaders == 0) {
|
||||
return Unpooled.EMPTY_BUFFER;
|
||||
@ -307,7 +307,7 @@ public class SpdyFrameEncoder extends MessageToByteEncoder<Object> {
|
||||
int savedIndex = headerBlock.writerIndex();
|
||||
int valueLength = 0;
|
||||
writeLengthField(version, headerBlock, valueLength);
|
||||
for (String value: headerFrame.getHeaders(name)) {
|
||||
for (String value: headerFrame.headers().getAll(name)) {
|
||||
byte[] valueBytes = value.getBytes(CharsetUtil.UTF_8);
|
||||
if (valueBytes.length > 0) {
|
||||
headerBlock.writeBytes(valueBytes);
|
||||
|
@ -29,7 +29,7 @@ public interface SpdyGoAwayFrame extends SpdyControlFrame {
|
||||
* Sets the Last-good-stream-ID of this frame. The Last-good-stream-ID
|
||||
* cannot be negative.
|
||||
*/
|
||||
void setLastGoodStreamId(int lastGoodStreamId);
|
||||
SpdyGoAwayFrame setLastGoodStreamId(int lastGoodStreamId);
|
||||
|
||||
/**
|
||||
* Returns the getStatus of this frame.
|
||||
@ -39,5 +39,5 @@ public interface SpdyGoAwayFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets the getStatus of this frame.
|
||||
*/
|
||||
void setStatus(SpdySessionStatus status);
|
||||
SpdyGoAwayFrame setStatus(SpdySessionStatus status);
|
||||
}
|
||||
|
@ -15,9 +15,6 @@
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A SPDY Name/Value Header Block which provides common properties for
|
||||
@ -36,68 +33,10 @@ public interface SpdyHeaderBlock {
|
||||
/**
|
||||
* Marks this header block as invalid.
|
||||
*/
|
||||
void setInvalid();
|
||||
SpdyHeaderBlock setInvalid();
|
||||
|
||||
/**
|
||||
* Returns the header value with the specified header name. If there is
|
||||
* more than one header value for the specified header name, the first
|
||||
* value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
* Returns the {@link SpdyHeaders}.
|
||||
*/
|
||||
String getHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
*/
|
||||
List<String> getHeaders(String name);
|
||||
|
||||
/**
|
||||
* Returns all header names and values that this block contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this message.
|
||||
*/
|
||||
List<Map.Entry<String, String>> getHeaders();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a header with the specified
|
||||
* header name.
|
||||
*/
|
||||
boolean containsHeader(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of all header names that this block contains.
|
||||
*/
|
||||
Set<String> getHeaderNames();
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
void addHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
void setHeader(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
void setHeader(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
*/
|
||||
void removeHeader(String name);
|
||||
|
||||
/**
|
||||
* Removes all headers from this block.
|
||||
*/
|
||||
void clearHeaders();
|
||||
SpdyHeaders headers();
|
||||
}
|
||||
|
@ -19,18 +19,86 @@ import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Provides the constants for the standard SPDY HTTP header names and commonly
|
||||
* used utility methods that access a {@link SpdyHeaderBlock}.
|
||||
* @apiviz.stereotype static
|
||||
*/
|
||||
public class SpdyHeaders {
|
||||
public abstract class SpdyHeaders implements Iterable<Map.Entry<String, String>> {
|
||||
|
||||
public static final SpdyHeaders EMPTY_HEADERS = new SpdyHeaders() {
|
||||
|
||||
@Override
|
||||
public List<String> getAll(String name) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<String, String>> entries() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> names() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders add(String name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(String name, Object value) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders set(String name, Iterable<?> values) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders remove(String name) {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpdyHeaders clear() {
|
||||
throw new UnsupportedOperationException("read only");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String name) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SPDY HTTP header names
|
||||
@ -102,7 +170,7 @@ public class SpdyHeaders {
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
*/
|
||||
public static String getHeader(SpdyHeaderBlock block, String name) {
|
||||
return block.getHeader(name);
|
||||
return block.headers().get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,7 +182,7 @@ public class SpdyHeaders {
|
||||
* header
|
||||
*/
|
||||
public static String getHeader(SpdyHeaderBlock block, String name, String defaultValue) {
|
||||
String value = block.getHeader(name);
|
||||
String value = block.headers().get(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
@ -126,7 +194,7 @@ public class SpdyHeaders {
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public static void setHeader(SpdyHeaderBlock block, String name, Object value) {
|
||||
block.setHeader(name, value);
|
||||
block.headers().set(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,35 +202,35 @@ public class SpdyHeaders {
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public static void setHeader(SpdyHeaderBlock block, String name, Iterable<?> values) {
|
||||
block.setHeader(name, values);
|
||||
block.headers().set(name, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
public static void addHeader(SpdyHeaderBlock block, String name, Object value) {
|
||||
block.addHeader(name, value);
|
||||
block.headers().add(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the SPDY host header.
|
||||
*/
|
||||
public static void removeHost(SpdyHeaderBlock block) {
|
||||
block.removeHeader(HttpNames.HOST);
|
||||
block.headers().remove(HttpNames.HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SPDY host header.
|
||||
*/
|
||||
public static String getHost(SpdyHeaderBlock block) {
|
||||
return block.getHeader(HttpNames.HOST);
|
||||
return block.headers().get(HttpNames.HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SPDY host header.
|
||||
*/
|
||||
public static void setHost(SpdyHeaderBlock block, String host) {
|
||||
block.setHeader(HttpNames.HOST, host);
|
||||
block.headers().set(HttpNames.HOST, host);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,9 +238,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void removeMethod(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
block.removeHeader(Spdy2HttpNames.METHOD);
|
||||
block.headers().remove(Spdy2HttpNames.METHOD);
|
||||
} else {
|
||||
block.removeHeader(HttpNames.METHOD);
|
||||
block.headers().remove(HttpNames.METHOD);
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,9 +250,9 @@ public class SpdyHeaders {
|
||||
public static HttpMethod getMethod(int spdyVersion, SpdyHeaderBlock block) {
|
||||
try {
|
||||
if (spdyVersion < 3) {
|
||||
return HttpMethod.valueOf(block.getHeader(Spdy2HttpNames.METHOD));
|
||||
return HttpMethod.valueOf(block.headers().get(Spdy2HttpNames.METHOD));
|
||||
} else {
|
||||
return HttpMethod.valueOf(block.getHeader(HttpNames.METHOD));
|
||||
return HttpMethod.valueOf(block.headers().get(HttpNames.METHOD));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
@ -196,9 +264,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void setMethod(int spdyVersion, SpdyHeaderBlock block, HttpMethod method) {
|
||||
if (spdyVersion < 3) {
|
||||
block.setHeader(Spdy2HttpNames.METHOD, method.name());
|
||||
block.headers().set(Spdy2HttpNames.METHOD, method.name());
|
||||
} else {
|
||||
block.setHeader(HttpNames.METHOD, method.name());
|
||||
block.headers().set(HttpNames.METHOD, method.name());
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,9 +275,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void removeScheme(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 2) {
|
||||
block.removeHeader(Spdy2HttpNames.SCHEME);
|
||||
block.headers().remove(Spdy2HttpNames.SCHEME);
|
||||
} else {
|
||||
block.removeHeader(HttpNames.SCHEME);
|
||||
block.headers().remove(HttpNames.SCHEME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,9 +286,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static String getScheme(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
return block.getHeader(Spdy2HttpNames.SCHEME);
|
||||
return block.headers().get(Spdy2HttpNames.SCHEME);
|
||||
} else {
|
||||
return block.getHeader(HttpNames.SCHEME);
|
||||
return block.headers().get(HttpNames.SCHEME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,9 +297,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void setScheme(int spdyVersion, SpdyHeaderBlock block, String scheme) {
|
||||
if (spdyVersion < 3) {
|
||||
block.setHeader(Spdy2HttpNames.SCHEME, scheme);
|
||||
block.headers().set(Spdy2HttpNames.SCHEME, scheme);
|
||||
} else {
|
||||
block.setHeader(HttpNames.SCHEME, scheme);
|
||||
block.headers().set(HttpNames.SCHEME, scheme);
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,9 +308,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void removeStatus(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
block.removeHeader(Spdy2HttpNames.STATUS);
|
||||
block.headers().remove(Spdy2HttpNames.STATUS);
|
||||
} else {
|
||||
block.removeHeader(HttpNames.STATUS);
|
||||
block.headers().remove(HttpNames.STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,9 +321,9 @@ public class SpdyHeaders {
|
||||
try {
|
||||
String status;
|
||||
if (spdyVersion < 3) {
|
||||
status = block.getHeader(Spdy2HttpNames.STATUS);
|
||||
status = block.headers().get(Spdy2HttpNames.STATUS);
|
||||
} else {
|
||||
status = block.getHeader(HttpNames.STATUS);
|
||||
status = block.headers().get(HttpNames.STATUS);
|
||||
}
|
||||
int space = status.indexOf(' ');
|
||||
if (space == -1) {
|
||||
@ -280,9 +348,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void setStatus(int spdyVersion, SpdyHeaderBlock block, HttpResponseStatus status) {
|
||||
if (spdyVersion < 3) {
|
||||
block.setHeader(Spdy2HttpNames.STATUS, status.toString());
|
||||
block.headers().set(Spdy2HttpNames.STATUS, status.toString());
|
||||
} else {
|
||||
block.setHeader(HttpNames.STATUS, status.toString());
|
||||
block.headers().set(HttpNames.STATUS, status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,9 +359,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void removeUrl(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
block.removeHeader(Spdy2HttpNames.URL);
|
||||
block.headers().remove(Spdy2HttpNames.URL);
|
||||
} else {
|
||||
block.removeHeader(HttpNames.PATH);
|
||||
block.headers().remove(HttpNames.PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@ -302,9 +370,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static String getUrl(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
return block.getHeader(Spdy2HttpNames.URL);
|
||||
return block.headers().get(Spdy2HttpNames.URL);
|
||||
} else {
|
||||
return block.getHeader(HttpNames.PATH);
|
||||
return block.headers().get(HttpNames.PATH);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,9 +381,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void setUrl(int spdyVersion, SpdyHeaderBlock block, String path) {
|
||||
if (spdyVersion < 3) {
|
||||
block.setHeader(Spdy2HttpNames.URL, path);
|
||||
block.headers().set(Spdy2HttpNames.URL, path);
|
||||
} else {
|
||||
block.setHeader(HttpNames.PATH, path);
|
||||
block.headers().set(HttpNames.PATH, path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,9 +392,9 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void removeVersion(int spdyVersion, SpdyHeaderBlock block) {
|
||||
if (spdyVersion < 3) {
|
||||
block.removeHeader(Spdy2HttpNames.VERSION);
|
||||
block.headers().remove(Spdy2HttpNames.VERSION);
|
||||
} else {
|
||||
block.removeHeader(HttpNames.VERSION);
|
||||
block.headers().remove(HttpNames.VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,9 +404,9 @@ public class SpdyHeaders {
|
||||
public static HttpVersion getVersion(int spdyVersion, SpdyHeaderBlock block) {
|
||||
try {
|
||||
if (spdyVersion < 3) {
|
||||
return HttpVersion.valueOf(block.getHeader(Spdy2HttpNames.VERSION));
|
||||
return HttpVersion.valueOf(block.headers().get(Spdy2HttpNames.VERSION));
|
||||
} else {
|
||||
return HttpVersion.valueOf(block.getHeader(HttpNames.VERSION));
|
||||
return HttpVersion.valueOf(block.headers().get(HttpNames.VERSION));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
@ -350,295 +418,87 @@ public class SpdyHeaders {
|
||||
*/
|
||||
public static void setVersion(int spdyVersion, SpdyHeaderBlock block, HttpVersion httpVersion) {
|
||||
if (spdyVersion < 3) {
|
||||
block.setHeader(Spdy2HttpNames.VERSION, httpVersion.text());
|
||||
block.headers().set(Spdy2HttpNames.VERSION, httpVersion.text());
|
||||
} else {
|
||||
block.setHeader(HttpNames.VERSION, httpVersion.text());
|
||||
block.headers().set(HttpNames.VERSION, httpVersion.text());
|
||||
}
|
||||
}
|
||||
|
||||
private static final int BUCKET_SIZE = 17;
|
||||
|
||||
private static int hash(String name) {
|
||||
int h = 0;
|
||||
for (int i = name.length() - 1; i >= 0; i --) {
|
||||
char c = name.charAt(i);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
c += 32;
|
||||
}
|
||||
h = 31 * h + c;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
return h;
|
||||
} else if (h == Integer.MIN_VALUE) {
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return -h;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean eq(String name1, String name2) {
|
||||
int nameLen = name1.length();
|
||||
if (nameLen != name2.length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = nameLen - 1; i >= 0; i --) {
|
||||
char c1 = name1.charAt(i);
|
||||
char c2 = name2.charAt(i);
|
||||
if (c1 != c2) {
|
||||
if (c1 >= 'A' && c1 <= 'Z') {
|
||||
c1 += 32;
|
||||
}
|
||||
if (c2 >= 'A' && c2 <= 'Z') {
|
||||
c2 += 32;
|
||||
}
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int index(int hash) {
|
||||
return hash % BUCKET_SIZE;
|
||||
}
|
||||
|
||||
private final HeaderEntry[] entries = new HeaderEntry[BUCKET_SIZE];
|
||||
private final HeaderEntry head = new HeaderEntry(-1, null, null);
|
||||
|
||||
SpdyHeaders() {
|
||||
head.before = head.after = head;
|
||||
}
|
||||
|
||||
void addHeader(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
|
||||
private void addHeader0(int h, int i, final String name, final String value) {
|
||||
// Update the hash table.
|
||||
HeaderEntry e = entries[i];
|
||||
HeaderEntry newEntry;
|
||||
entries[i] = newEntry = new HeaderEntry(h, name, value);
|
||||
newEntry.next = e;
|
||||
|
||||
// Update the linked list.
|
||||
newEntry.addBefore(head);
|
||||
}
|
||||
|
||||
void removeHeader(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
}
|
||||
|
||||
private void removeHeader0(int h, int i, String name) {
|
||||
HeaderEntry e = entries[i];
|
||||
if (e == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
e.remove();
|
||||
HeaderEntry next = e.next;
|
||||
if (next != null) {
|
||||
entries[i] = next;
|
||||
e = next;
|
||||
} else {
|
||||
entries[i] = null;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
HeaderEntry next = e.next;
|
||||
if (next == null) {
|
||||
break;
|
||||
}
|
||||
if (next.hash == h && eq(name, next.key)) {
|
||||
e.next = next.next;
|
||||
next.remove();
|
||||
} else {
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setHeader(final String name, final Object value) {
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
String strVal = toString(value);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
|
||||
void setHeader(final String name, final Iterable<?> values) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException("values");
|
||||
}
|
||||
|
||||
String lowerCaseName = name.toLowerCase();
|
||||
SpdyCodecUtil.validateHeaderName(lowerCaseName);
|
||||
|
||||
int h = hash(lowerCaseName);
|
||||
int i = index(h);
|
||||
|
||||
removeHeader0(h, i, lowerCaseName);
|
||||
for (Object v: values) {
|
||||
if (v == null) {
|
||||
break;
|
||||
}
|
||||
String strVal = toString(v);
|
||||
SpdyCodecUtil.validateHeaderValue(strVal);
|
||||
addHeader0(h, i, lowerCaseName, strVal);
|
||||
}
|
||||
}
|
||||
|
||||
void clearHeaders() {
|
||||
for (int i = 0; i < entries.length; i ++) {
|
||||
entries[i] = null;
|
||||
}
|
||||
head.before = head.after = head;
|
||||
}
|
||||
|
||||
String getHeader(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
return e.value;
|
||||
}
|
||||
|
||||
e = e.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> getHeaders(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
|
||||
LinkedList<String> values = new LinkedList<String>();
|
||||
|
||||
int h = hash(name);
|
||||
int i = index(h);
|
||||
HeaderEntry e = entries[i];
|
||||
while (e != null) {
|
||||
if (e.hash == h && eq(name, e.key)) {
|
||||
values.addFirst(e.value);
|
||||
}
|
||||
e = e.next;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
List<Map.Entry<String, String>> getHeaders() {
|
||||
List<Map.Entry<String, String>> all =
|
||||
new LinkedList<Map.Entry<String, String>>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
all.add(e);
|
||||
e = e.after;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
|
||||
boolean containsHeader(String name) {
|
||||
return getHeader(name) != null;
|
||||
}
|
||||
|
||||
Set<String> getHeaderNames() {
|
||||
Set<String> names = new TreeSet<String>();
|
||||
|
||||
HeaderEntry e = head.after;
|
||||
while (e != head) {
|
||||
names.add(e.key);
|
||||
e = e.after;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
private static String toString(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
private static final class HeaderEntry implements Map.Entry<String, String> {
|
||||
final int hash;
|
||||
final String key;
|
||||
String value;
|
||||
HeaderEntry next;
|
||||
HeaderEntry before, after;
|
||||
|
||||
HeaderEntry(int hash, String key, String value) {
|
||||
this.hash = hash;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
before.after = after;
|
||||
after.before = before;
|
||||
}
|
||||
|
||||
void addBefore(HeaderEntry e) {
|
||||
after = e;
|
||||
before = e.before;
|
||||
before.after = this;
|
||||
after.before = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
return entries().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Returns the header value with the specified header name. If there is
|
||||
* more than one header value for the specified header name, the first
|
||||
* value is returned.
|
||||
*
|
||||
* @return the header value or {@code null} if there is no such header
|
||||
*/
|
||||
public abstract String get(String name);
|
||||
|
||||
@Override
|
||||
public String setValue(String value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
SpdyCodecUtil.validateHeaderValue(value);
|
||||
String oldValue = this.value;
|
||||
this.value = value;
|
||||
return oldValue;
|
||||
}
|
||||
/**
|
||||
* Returns the header values with the specified header name.
|
||||
*
|
||||
* @return the {@link List} of header values. An empty list if there is no
|
||||
* such header.
|
||||
*/
|
||||
public abstract List<String> getAll(String name);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return key + '=' + value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns all header names and values that this block contains.
|
||||
*
|
||||
* @return the {@link List} of the header name-value pairs. An empty list
|
||||
* if there is no header in this message.
|
||||
*/
|
||||
public abstract List<Map.Entry<String, String>> entries();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if and only if there is a header with the specified
|
||||
* header name.
|
||||
*/
|
||||
public abstract boolean contains(String name);
|
||||
|
||||
/**
|
||||
* Returns the {@link Set} of all header names that this block contains.
|
||||
*/
|
||||
public abstract Set<String> names();
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and value.
|
||||
*/
|
||||
public abstract SpdyHeaders add(String name, Object value);
|
||||
|
||||
/**
|
||||
* Adds a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders add(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and value. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders set(String name, Object value);
|
||||
|
||||
/**
|
||||
* Sets a new header with the specified name and values. If there is an
|
||||
* existing header with the same name, the existing header is removed.
|
||||
*/
|
||||
public abstract SpdyHeaders set(String name, Iterable<?> values);
|
||||
|
||||
/**
|
||||
* Removes the header with the specified name.
|
||||
*/
|
||||
public abstract SpdyHeaders remove(String name);
|
||||
|
||||
/**
|
||||
* Removes all headers from this block.
|
||||
*/
|
||||
public abstract SpdyHeaders clear();
|
||||
|
||||
/**
|
||||
* Checks if no header exists.
|
||||
*/
|
||||
public abstract boolean isEmpty();
|
||||
}
|
||||
|
@ -18,26 +18,15 @@ package io.netty.handler.codec.spdy;
|
||||
/**
|
||||
* A SPDY Protocol HEADERS Control Frame
|
||||
*/
|
||||
public interface SpdyHeadersFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
public interface SpdyHeadersFrame extends SpdyHeaderBlock, SpdyControlFrame, SpdyStreamFrame {
|
||||
|
||||
/**
|
||||
* Returns the Stream-ID of this frame.
|
||||
*/
|
||||
int getStreamId();
|
||||
@Override
|
||||
SpdyHeadersFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamID);
|
||||
@Override
|
||||
SpdyHeadersFrame setLast(boolean last);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this frame is the last frame to be transmitted
|
||||
* on the stream.
|
||||
*/
|
||||
boolean isLast();
|
||||
@Override
|
||||
SpdyHeadersFrame setInvalid();
|
||||
|
||||
/**
|
||||
* Sets if this frame is the last frame to be transmitted on the stream.
|
||||
*/
|
||||
void setLast(boolean last);
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e: spdyHeadersFrame.getHeaders()) {
|
||||
for (Map.Entry<String, String> e: spdyHeadersFrame.headers().entries()) {
|
||||
httpMessage.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
||||
HttpHeaders.setHost(req, host);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> e: requestFrame.getHeaders()) {
|
||||
for (Map.Entry<String, String> e: requestFrame.headers().entries()) {
|
||||
req.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<Object> {
|
||||
SpdyHeaders.removeVersion(spdyVersion, responseFrame);
|
||||
|
||||
FullHttpResponse res = new DefaultFullHttpResponse(version, status);
|
||||
for (Map.Entry<String, String> e: responseFrame.getHeaders()) {
|
||||
for (Map.Entry<String, String> e: responseFrame.headers().entries()) {
|
||||
res.headers().add(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
|
||||
// Create SPDY HEADERS frame out of trailers
|
||||
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(currentStreamId);
|
||||
for (Map.Entry<String, String> entry: trailers) {
|
||||
spdyHeadersFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
spdyHeadersFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// Write HEADERS frame and append Data Frame
|
||||
@ -246,7 +246,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
|
||||
|
||||
// Transfer the remaining HTTP headers
|
||||
for (Map.Entry<String, String> entry: httpMessage.headers()) {
|
||||
spdySynStreamFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
spdySynStreamFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
currentStreamId = spdySynStreamFrame.getStreamId();
|
||||
|
||||
@ -276,7 +276,7 @@ public class SpdyHttpEncoder extends MessageToMessageEncoder<Object> {
|
||||
|
||||
// Transfer the remaining HTTP headers
|
||||
for (Map.Entry<String, String> entry: httpResponse.headers()) {
|
||||
spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
if (chunked) {
|
||||
|
@ -28,5 +28,5 @@ public interface SpdyPingFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets the ID of this frame.
|
||||
*/
|
||||
void setId(int id);
|
||||
SpdyPingFrame setId(int id);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public interface SpdyRstStreamFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamID);
|
||||
SpdyControlFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Returns the getStatus of this frame.
|
||||
@ -38,5 +38,5 @@ public interface SpdyRstStreamFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets the getStatus of this frame.
|
||||
*/
|
||||
void setStatus(SpdyStreamStatus status);
|
||||
SpdyControlFrame setStatus(SpdyStreamStatus status);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public interface SpdySettingsFrame extends SpdyControlFrame {
|
||||
* Sets the value of the setting ID.
|
||||
* The ID must be positive and cannot exceed 16777215.
|
||||
*/
|
||||
void setValue(int id, int value);
|
||||
SpdySettingsFrame setValue(int id, int value);
|
||||
|
||||
/**
|
||||
* Sets the value of the setting ID.
|
||||
@ -60,13 +60,13 @@ public interface SpdySettingsFrame extends SpdyControlFrame {
|
||||
* Sets if the setting is persisted (should only be set by the client).
|
||||
* The ID must be positive and cannot exceed 16777215.
|
||||
*/
|
||||
void setValue(int id, int value, boolean persistVal, boolean persisted);
|
||||
SpdySettingsFrame setValue(int id, int value, boolean persistVal, boolean persisted);
|
||||
|
||||
/**
|
||||
* Removes the value of the setting ID.
|
||||
* Removes all persistence information for the setting.
|
||||
*/
|
||||
void removeValue(int id);
|
||||
SpdySettingsFrame removeValue(int id);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this setting should be persisted.
|
||||
@ -79,7 +79,7 @@ public interface SpdySettingsFrame extends SpdyControlFrame {
|
||||
* Sets if this setting should be persisted.
|
||||
* Has no effect if the setting ID has no value.
|
||||
*/
|
||||
void setPersistValue(int id, boolean persistValue);
|
||||
SpdySettingsFrame setPersistValue(int id, boolean persistValue);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this setting is persisted.
|
||||
@ -92,7 +92,7 @@ public interface SpdySettingsFrame extends SpdyControlFrame {
|
||||
* Sets if this setting is persisted.
|
||||
* Has no effect if the setting ID has no value.
|
||||
*/
|
||||
void setPersisted(int id, boolean persisted);
|
||||
SpdySettingsFrame setPersisted(int id, boolean persisted);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if previously persisted settings should be cleared.
|
||||
@ -102,5 +102,5 @@ public interface SpdySettingsFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets if previously persisted settings should be cleared.
|
||||
*/
|
||||
void setClearPreviouslyPersistedSettings(boolean clear);
|
||||
SpdySettingsFrame setClearPreviouslyPersistedSettings(boolean clear);
|
||||
}
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package io.netty.handler.codec.spdy;
|
||||
|
||||
/**
|
||||
* A frame which is part of a stream
|
||||
*/
|
||||
public interface SpdyStreamFrame {
|
||||
|
||||
/**
|
||||
* Returns the Stream-ID of this frame.
|
||||
*/
|
||||
int getStreamId();
|
||||
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
SpdyStreamFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this frame is the last frame to be transmitted
|
||||
* on the stream.
|
||||
*/
|
||||
boolean isLast();
|
||||
|
||||
/**
|
||||
* Sets if this frame is the last frame to be transmitted on the stream.
|
||||
*/
|
||||
SpdyStreamFrame setLast(boolean last);
|
||||
}
|
@ -18,26 +18,14 @@ package io.netty.handler.codec.spdy;
|
||||
/**
|
||||
* A SPDY Protocol SYN_REPLY Control Frame
|
||||
*/
|
||||
public interface SpdySynReplyFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
public interface SpdySynReplyFrame extends SpdyHeaderBlock, SpdyControlFrame, SpdyStreamFrame {
|
||||
|
||||
/**
|
||||
* Returns the Stream-ID of this frame.
|
||||
*/
|
||||
int getStreamId();
|
||||
@Override
|
||||
SpdySynReplyFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamID);
|
||||
@Override
|
||||
SpdySynReplyFrame setLast(boolean last);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this frame is the last frame to be transmitted
|
||||
* on the stream.
|
||||
*/
|
||||
boolean isLast();
|
||||
|
||||
/**
|
||||
* Sets if this frame is the last frame to be transmitted on the stream.
|
||||
*/
|
||||
void setLast(boolean last);
|
||||
@Override
|
||||
SpdySynReplyFrame setInvalid();
|
||||
}
|
||||
|
@ -18,17 +18,7 @@ package io.netty.handler.codec.spdy;
|
||||
/**
|
||||
* A SPDY Protocol SYN_STREAM Control Frame
|
||||
*/
|
||||
public interface SpdySynStreamFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
|
||||
/**
|
||||
* Returns the Stream-ID of this frame.
|
||||
*/
|
||||
int getStreamId();
|
||||
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamId);
|
||||
public interface SpdySynStreamFrame extends SpdyHeaderBlock, SpdyControlFrame , SpdyStreamFrame {
|
||||
|
||||
/**
|
||||
* Returns the Associated-To-Stream-ID of this frame.
|
||||
@ -39,7 +29,7 @@ public interface SpdySynStreamFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
* Sets the Associated-To-Stream-ID of this frame.
|
||||
* The Associated-To-Stream-ID cannot be negative.
|
||||
*/
|
||||
void setAssociatedToStreamId(int associatedToStreamId);
|
||||
SpdySynStreamFrame setAssociatedToStreamId(int associatedToStreamId);
|
||||
|
||||
/**
|
||||
* Returns the priority of the stream.
|
||||
@ -50,18 +40,7 @@ public interface SpdySynStreamFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
* Sets the priority of the stream.
|
||||
* The priority must be between 0 and 7 inclusive.
|
||||
*/
|
||||
void setPriority(byte priority);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this frame is the last frame to be transmitted
|
||||
* on the stream.
|
||||
*/
|
||||
boolean isLast();
|
||||
|
||||
/**
|
||||
* Sets if this frame is the last frame to be transmitted on the stream.
|
||||
*/
|
||||
void setLast(boolean last);
|
||||
SpdySynStreamFrame setPriority(byte priority);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the stream created with this frame is to be
|
||||
@ -73,5 +52,14 @@ public interface SpdySynStreamFrame extends SpdyHeaderBlock, SpdyControlFrame {
|
||||
* Sets if the stream created with this frame is to be considered
|
||||
* half-closed to the receiver.
|
||||
*/
|
||||
void setUnidirectional(boolean unidirectional);
|
||||
SpdySynStreamFrame setUnidirectional(boolean unidirectional);
|
||||
|
||||
@Override
|
||||
SpdySynStreamFrame setStreamId(int streamID);
|
||||
|
||||
@Override
|
||||
SpdySynStreamFrame setLast(boolean last);
|
||||
|
||||
@Override
|
||||
SpdySynStreamFrame setInvalid();
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public interface SpdyWindowUpdateFrame extends SpdyControlFrame {
|
||||
/**
|
||||
* Sets the Stream-ID of this frame. The Stream-ID must be positive.
|
||||
*/
|
||||
void setStreamId(int streamID);
|
||||
SpdyWindowUpdateFrame setStreamId(int streamID);
|
||||
|
||||
/**
|
||||
* Returns the Delta-Window-Size of this frame.
|
||||
@ -39,5 +39,5 @@ public interface SpdyWindowUpdateFrame extends SpdyControlFrame {
|
||||
* Sets the Delta-Window-Size of this frame.
|
||||
* The Delta-Window-Size must be positive.
|
||||
*/
|
||||
void setDeltaWindowSize(int deltaWindowSize);
|
||||
SpdyWindowUpdateFrame setDeltaWindowSize(int deltaWindowSize);
|
||||
}
|
||||
|
@ -40,15 +40,15 @@ public class SpdySessionHandlerTest {
|
||||
}
|
||||
|
||||
private static void assertHeaderBlock(SpdyHeaderBlock received, SpdyHeaderBlock expected) {
|
||||
for (String name: expected.getHeaderNames()) {
|
||||
List<String> expectedValues = expected.getHeaders(name);
|
||||
List<String> receivedValues = received.getHeaders(name);
|
||||
for (String name: expected.headers().names()) {
|
||||
List<String> expectedValues = expected.headers().getAll(name);
|
||||
List<String> receivedValues = received.headers().getAll(name);
|
||||
assertTrue(receivedValues.containsAll(expectedValues));
|
||||
receivedValues.removeAll(expectedValues);
|
||||
assertTrue(receivedValues.isEmpty());
|
||||
received.removeHeader(name);
|
||||
received.headers().remove(name);
|
||||
}
|
||||
assertTrue(received.getHeaders().isEmpty());
|
||||
assertTrue(received.headers().entries().isEmpty());
|
||||
}
|
||||
|
||||
private static void assertDataFrame(Object msg, int streamID, boolean last) {
|
||||
@ -114,7 +114,7 @@ public class SpdySessionHandlerTest {
|
||||
|
||||
SpdySynStreamFrame spdySynStreamFrame =
|
||||
new DefaultSpdySynStreamFrame(localStreamID, 0, (byte) 0);
|
||||
spdySynStreamFrame.setHeader("Compression", "test");
|
||||
spdySynStreamFrame.headers().set("Compression", "test");
|
||||
|
||||
SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(localStreamID);
|
||||
spdyDataFrame.setLast(true);
|
||||
@ -146,8 +146,10 @@ public class SpdySessionHandlerTest {
|
||||
assertSynReply(sessionHandler.readOutbound(), localStreamID, false, spdySynStreamFrame);
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(localStreamID);
|
||||
spdyHeadersFrame.addHeader("HEADER","test1");
|
||||
spdyHeadersFrame.addHeader("HEADER","test2");
|
||||
|
||||
spdyHeadersFrame.headers().add("HEADER","test1");
|
||||
spdyHeadersFrame.headers().add("HEADER","test2");
|
||||
|
||||
sessionHandler.writeInbound(spdyHeadersFrame);
|
||||
assertHeaders(sessionHandler.readOutbound(), localStreamID, spdyHeadersFrame);
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
@ -159,6 +161,7 @@ public class SpdySessionHandlerTest {
|
||||
spdySynStreamFrame.setStreamId(localStreamID);
|
||||
spdySynStreamFrame.setLast(true);
|
||||
spdySynStreamFrame.setUnidirectional(true);
|
||||
|
||||
sessionHandler.writeInbound(spdySynStreamFrame);
|
||||
assertRstStream(sessionHandler.readOutbound(), localStreamID, SpdyStreamStatus.REFUSED_STREAM);
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
@ -175,6 +178,7 @@ public class SpdySessionHandlerTest {
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
spdySynStreamFrame.setUnidirectional(false);
|
||||
|
||||
|
||||
// Check if session handler returns PROTOCOL_ERROR if it receives
|
||||
// multiple SYN_STREAM frames for the same active Stream-ID
|
||||
sessionHandler.writeInbound(spdySynStreamFrame);
|
||||
@ -190,6 +194,7 @@ public class SpdySessionHandlerTest {
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
spdySynStreamFrame.setStreamId(localStreamID);
|
||||
|
||||
|
||||
// Check if session handler correctly limits the number of
|
||||
// concurrent streams in the SETTINGS frame
|
||||
SpdySettingsFrame spdySettingsFrame = new DefaultSpdySettingsFrame();
|
||||
@ -212,6 +217,7 @@ public class SpdySessionHandlerTest {
|
||||
assertDataFrame(sessionHandler.readOutbound(), testStreamID, spdyDataFrame.isLast());
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
spdyHeadersFrame.setStreamId(testStreamID);
|
||||
|
||||
sessionHandler.writeInbound(spdyHeadersFrame);
|
||||
assertRstStream(sessionHandler.readOutbound(), testStreamID, SpdyStreamStatus.INVALID_STREAM);
|
||||
assertNull(sessionHandler.readOutbound());
|
||||
@ -219,6 +225,7 @@ public class SpdySessionHandlerTest {
|
||||
// Check if session handler returns PROTOCOL_ERROR if it receives
|
||||
// an invalid HEADERS frame
|
||||
spdyHeadersFrame.setStreamId(localStreamID);
|
||||
|
||||
spdyHeadersFrame.setInvalid();
|
||||
sessionHandler.writeInbound(spdyHeadersFrame);
|
||||
assertRstStream(sessionHandler.readOutbound(), localStreamID, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||
@ -320,8 +327,8 @@ public class SpdySessionHandlerTest {
|
||||
int streamID = spdySynStreamFrame.getStreamId();
|
||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
|
||||
spdySynReplyFrame.setLast(spdySynStreamFrame.isLast());
|
||||
for (Map.Entry<String, String> entry: spdySynStreamFrame.getHeaders()) {
|
||||
spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
|
||||
for (Map.Entry<String, String> entry: spdySynStreamFrame.headers()) {
|
||||
spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
ctx.write(spdySynReplyFrame);
|
||||
|
Loading…
Reference in New Issue
Block a user