Javadocs.

This commit is contained in:
Simone Bordet 2012-02-22 23:47:45 +01:00
parent 111ae7fa1a
commit 726fda5593
37 changed files with 520 additions and 86 deletions

View File

@ -34,7 +34,14 @@ public class Promise<T> implements Handler<T>, Future<T>
@Override @Override
public void completed(T result) public void completed(T result)
{ {
fulfilled(result); this.promise = result;
latch.countDown();
}
public void failed(Throwable x, T context)
{
this.failure = x;
latch.countDown();
} }
@Override @Override
@ -78,16 +85,4 @@ public class Promise<T> implements Handler<T>, Future<T>
throw new ExecutionException(failure); throw new ExecutionException(failure);
return promise; return promise;
} }
public void failed(Throwable x)
{
this.failure = x;
latch.countDown();
}
public void fulfilled(T promise)
{
this.promise = promise;
latch.countDown();
}
} }

View File

@ -140,7 +140,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
catch (StreamException x) catch (StreamException x)
{ {
removeStream(stream); removeStream(stream);
handler.failed(x); handler.failed(x, stream);
} }
} }
} }
@ -174,7 +174,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
catch (StreamException x) catch (StreamException x)
{ {
logger.info("Could not send reset on stream " + rstInfo.getStreamId(), x); logger.info("Could not send reset on stream " + rstInfo.getStreamId(), x);
handler.failed(x); handler.failed(x, null);
} }
} }
@ -197,7 +197,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
} }
catch (StreamException x) catch (StreamException x)
{ {
handler.failed(x); handler.failed(x, null);
} }
} }
@ -212,17 +212,17 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override @Override
public void ping(final Handler<PingInfo> handler) public void ping(final Handler<PingInfo> handler)
{ {
int pingId = pingIds.getAndAdd(2);
PingInfo pingInfo = new PingInfo(pingId);
try try
{ {
int pingId = pingIds.getAndAdd(2);
final PingInfo pingInfo = new PingInfo(pingId);
PingFrame frame = new PingFrame(version, pingId); PingFrame frame = new PingFrame(version, pingId);
control(null, frame, handler, pingInfo); control(null, frame, handler, pingInfo);
flush(); flush();
} }
catch (StreamException x) catch (StreamException x)
{ {
handler.failed(x); handler.failed(x, pingInfo);
} }
} }
@ -250,7 +250,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
} }
catch (StreamException x) catch (StreamException x)
{ {
handler.failed(x); handler.failed(x, null);
} }
} }
} }
@ -730,7 +730,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
} }
@Override @Override
public void failed(Throwable x) public void failed(Throwable x, FrameBytes frameBytes)
{ {
throw new SPDYException(x); throw new SPDYException(x);
} }

View File

@ -286,7 +286,7 @@ public class StandardStream implements IStream
catch (StreamException x) catch (StreamException x)
{ {
logger.debug("Could not send reply on stream " + this, x); logger.debug("Could not send reply on stream " + this, x);
handler.failed(x); handler.failed(x, null);
session.rst(new RstInfo(getId(), x.getStreamStatus())); session.rst(new RstInfo(getId(), x.getStreamStatus()));
} }
} }
@ -327,7 +327,7 @@ public class StandardStream implements IStream
catch (StreamException x) catch (StreamException x)
{ {
logger.debug("Could not send headers on stream " + this, x); logger.debug("Could not send headers on stream " + this, x);
handler.failed(x); handler.failed(x, null);
session.rst(new RstInfo(getId(), x.getStreamStatus())); session.rst(new RstInfo(getId(), x.getStreamStatus()));
} }
} }

View File

@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/**
* <p>Specialized {@link DataInfo} for {@link ByteBuffer} content.</p>
*/
public class ByteBufferDataInfo extends DataInfo public class ByteBufferDataInfo extends DataInfo
{ {
private ByteBuffer buffer; private ByteBuffer buffer;
@ -34,13 +37,13 @@ public class ByteBufferDataInfo extends DataInfo
} }
@Override @Override
public int getBytesCount() public int getContentLength()
{ {
return buffer.remaining(); return buffer.remaining();
} }
@Override @Override
public int getBytes(ByteBuffer output) public int getContent(ByteBuffer output)
{ {
int length = output.remaining(); int length = output.remaining();
if (buffer.remaining() > length) if (buffer.remaining() > length)

View File

@ -18,6 +18,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/**
* <p>Specialized {@link DataInfo} for byte array content.</p>
*/
public class BytesDataInfo extends DataInfo public class BytesDataInfo extends DataInfo
{ {
private byte[] bytes; private byte[] bytes;
@ -35,13 +38,13 @@ public class BytesDataInfo extends DataInfo
} }
@Override @Override
public int getBytesCount() public int getContentLength()
{ {
return bytes.length - offset; return bytes.length - offset;
} }
@Override @Override
public int getBytes(ByteBuffer output) public int getContent(ByteBuffer output)
{ {
int remaining = output.remaining(); int remaining = output.remaining();
int length = Math.min(bytes.length - offset, remaining); int length = Math.min(bytes.length - offset, remaining);

View File

@ -19,88 +19,171 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/**
* <p>A container for DATA frames metadata and content bytes.</p>
* <p>Specialized subclasses (like {@link StringDataInfo}) may be used by applications
* to send specific types of content.</p>
* <p>Applications may send multiple instances of {@link DataInfo}, usually of the same
* type, via {@link Stream#data(DataInfo)}. The last instance must have the
* {@link #isClose() close flag} set, so that the client knows that no more content is
* expected.</p>
*/
public abstract class DataInfo public abstract class DataInfo
{ {
public final static byte FLAG_FIN = 1; /**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public final static byte FLAG_CLOSE = 1;
/**
* <p>Flag that indicates that this {@link DataInfo}'s data is compressed.</p>
*
* @see #isCompress()
* @see #getFlags()
*/
public final static byte FLAG_COMPRESS = 2; public final static byte FLAG_COMPRESS = 2;
private boolean close; private boolean close;
private boolean compress; private boolean compress;
private boolean consumed; private boolean consumed;
/**
* <p>Creates a new {@link DataInfo} with the given close flag and no compression flag.</p>
*
* @param close the value of the close flag
*/
public DataInfo(boolean close) public DataInfo(boolean close)
{ {
setClose(close); setClose(close);
} }
/**
* <p>Creates a new {@link DataInfo} with the given close flag and given compression flag.</p>
*
* @param close the close flag
* @param compress the compress flag
*/
public DataInfo(boolean close, boolean compress) public DataInfo(boolean close, boolean compress)
{ {
setClose(close); setClose(close);
setCompress(compress); setCompress(compress);
} }
/**
* @return the value of the compress flag
* @see #setCompress(boolean)
*/
public boolean isCompress() public boolean isCompress()
{ {
return compress; return compress;
} }
/**
* @param compress the value of the compress flag
* @see #isCompress()
*/
public void setCompress(boolean compress) public void setCompress(boolean compress)
{ {
this.compress = compress; this.compress = compress;
} }
/**
* @return the value of the close flag
* @see #setClose(boolean)
*/
public boolean isClose() public boolean isClose()
{ {
return close; return close;
} }
/**
* @param close the value of the close flag
* @see #isClose()
*/
public void setClose(boolean close) public void setClose(boolean close)
{ {
this.close = close; this.close = close;
} }
/**
* @return the close and compress flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_COMPRESS
*/
public byte getFlags() public byte getFlags()
{ {
byte flags = isClose() ? FLAG_FIN : 0; byte flags = isClose() ? FLAG_CLOSE : 0;
flags |= isCompress() ? FLAG_COMPRESS : 0; flags |= isCompress() ? FLAG_COMPRESS : 0;
return flags; return flags;
} }
public abstract int getBytesCount(); /**
* @return the length of the content bytes
* @see #getContent(ByteBuffer)
*/
public abstract int getContentLength();
public abstract int getBytes(ByteBuffer output); /**
* <p>Copies the content bytes of this {@link DataInfo} into the given {@link ByteBuffer}.</p>
* <p>If the given {@link ByteBuffer} cannot contain the whole content of this {@link DataInfo}
* then this {@link DataInfo} will not be {@link #isConsumed() consumed}, and further content
* may be retrieved by invoking again this method.</p>
*
* @param output the {@link ByteBuffer} to copy to bytes into
* @return the number of bytes copied
* @see #getContentLength()
*/
public abstract int getContent(ByteBuffer output);
/**
* @param charset the charset used to convert the bytes
* @return a String with the content of this {@link DataInfo}
*/
public String asString(String charset) public String asString(String charset)
{ {
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount()); ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getBytes(buffer); getContent(buffer);
buffer.flip(); buffer.flip();
return Charset.forName(charset).decode(buffer).toString(); return Charset.forName(charset).decode(buffer).toString();
} }
/**
* @return a byte array with the content of this {@link DataInfo}
*/
public byte[] asBytes() public byte[] asBytes()
{ {
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount()); ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getBytes(buffer); getContent(buffer);
buffer.flip(); buffer.flip();
byte[] result = new byte[buffer.remaining()]; byte[] result = new byte[buffer.remaining()];
buffer.get(result); buffer.get(result);
return result; return result;
} }
/**
* @return a {@link ByteBuffer} with the content of this {@link DataInfo}
*/
public ByteBuffer asByteBuffer() public ByteBuffer asByteBuffer()
{ {
ByteBuffer buffer = ByteBuffer.allocate(getBytesCount()); ByteBuffer buffer = ByteBuffer.allocate(getContentLength());
getBytes(buffer); getContent(buffer);
buffer.flip(); buffer.flip();
return buffer; return buffer;
} }
/**
* @return whether this {@link DataInfo}'s content has been consumed
*/
public boolean isConsumed() public boolean isConsumed()
{ {
return consumed; return consumed;
} }
/**
* @param consumed whether this {@link DataInfo}'s content has been consumed
*/
protected void setConsumed(boolean consumed) protected void setConsumed(boolean consumed)
{ {
this.consumed = consumed; this.consumed = consumed;
@ -109,6 +192,6 @@ public abstract class DataInfo
@Override @Override
public String toString() public String toString()
{ {
return String.format("DATA @%x length=%d close=%b compress=%b", hashCode(), getBytesCount(), isClose(), isCompress()); return String.format("DATA @%x length=%d close=%b compress=%b", hashCode(), getContentLength(), isClose(), isCompress());
} }
} }

View File

@ -16,22 +16,38 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for GOAWAY frames metadata: the last good stream id and
* the session status.</p>
*/
public class GoAwayInfo public class GoAwayInfo
{ {
private final int lastStreamId; private final int lastStreamId;
private final SessionStatus sessionStatus; private final SessionStatus sessionStatus;
/**
* <p>Creates a new {@link GoAwayInfo} with the given last good stream id and session status</p>
*
* @param lastStreamId the last good stream id
* @param sessionStatus the session status
*/
public GoAwayInfo(int lastStreamId, SessionStatus sessionStatus) public GoAwayInfo(int lastStreamId, SessionStatus sessionStatus)
{ {
this.lastStreamId = lastStreamId; this.lastStreamId = lastStreamId;
this.sessionStatus = sessionStatus; this.sessionStatus = sessionStatus;
} }
/**
* @return the last good stream id
*/
public int getLastStreamId() public int getLastStreamId()
{ {
return lastStreamId; return lastStreamId;
} }
/**
* @return the session status
*/
public SessionStatus getSessionStatus() public SessionStatus getSessionStatus()
{ {
return sessionStatus; return sessionStatus;

View File

@ -16,12 +16,36 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A callback abstraction that handles completed/failed events of asynchronous operations.</p>
* <p>Instances of this class capture a context that is made available on completion
* and failure callbacks.</p>
*
* @param <C> the type of the context object
*/
public interface Handler<C> public interface Handler<C>
{ {
/**
* <p>Callback invoked when the operation completes.</p>
*
* @param context the context
* @see #failed(Throwable, Object)
*/
public abstract void completed(C context); public abstract void completed(C context);
public void failed(Throwable x); /**
* <p>Callback invoked when the operation fails.</p>
*
* @param x the reason for the operation failure
* @param context the context
*/
public void failed(Throwable x, C context);
/**
* <p>Empty implementation of {@link Handler}</p>
*
* @param <C> the type of the context object
*/
public static class Adapter<C> implements Handler<C> public static class Adapter<C> implements Handler<C>
{ {
@Override @Override
@ -30,7 +54,7 @@ public interface Handler<C>
} }
@Override @Override
public void failed(Throwable x) public void failed(Throwable x, C context)
{ {
throw new SPDYException(x); throw new SPDYException(x);
} }

View File

@ -24,15 +24,32 @@ import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/**
* <p>A container for name/value pairs, known as headers.</p>
* <p>A {@link Header} is composed of a case-insensitive name string and
* of a case-sensitive set of value strings.</p>
* <p>The implementation of this class is not thread safe.</p>
*/
public class Headers implements Iterable<Headers.Header> public class Headers implements Iterable<Headers.Header>
{ {
private final Map<String, Header> headers; private final Map<String, Header> headers;
/**
* <p>Creates an empty modifiable {@link Headers} instance.</p>
* @see #Headers(Headers, boolean)
*/
public Headers() public Headers()
{ {
headers = new LinkedHashMap<>(); headers = new LinkedHashMap<>();
} }
/**
* <p>Creates a {@link Headers} instance by copying the headers from the given
* {@link Headers} and making it (im)mutable depending on the given {@code immutable} parameter</p>
*
* @param original the {@link Headers} to copy headers from
* @param immutable whether this instance is immutable
*/
public Headers(Headers original, boolean immutable) public Headers(Headers original, boolean immutable)
{ {
Map<String, Header> copy = new LinkedHashMap<>(); Map<String, Header> copy = new LinkedHashMap<>();
@ -57,19 +74,32 @@ public class Headers implements Iterable<Headers.Header>
return headers.hashCode(); return headers.hashCode();
} }
/**
* @return a set of header names
*/
public Set<String> names() public Set<String> names()
{ {
Set<String> result = new LinkedHashSet<String>(); Set<String> result = new LinkedHashSet<>();
for (Header header : headers.values()) for (Header header : headers.values())
result.add(header.name); result.add(header.name);
return result; return result;
} }
/**
* @param name the header name
* @return the {@link Header} with the given name, or null if no such header exists
*/
public Header get(String name) public Header get(String name)
{ {
return headers.get(name.trim().toLowerCase()); return headers.get(name.trim().toLowerCase());
} }
/**
* <p>Inserts or replaces the given name/value pair as a single-valued {@link Header}.</p>
*
* @param name the header name
* @param value the header value
*/
public void put(String name, String value) public void put(String name, String value)
{ {
name = name.trim(); name = name.trim();
@ -77,12 +107,23 @@ public class Headers implements Iterable<Headers.Header>
headers.put(name.toLowerCase(), header); headers.put(name.toLowerCase(), header);
} }
public void put(String name, Header header) /**
* <p>Inserts or replaces the given {@link Header}, mapped to the {@link Header#name() header's name}</p>
*
* @param header the header to add
*/
public void put(Header header)
{ {
name = name.trim(); headers.put(header.name().toLowerCase(), header);
headers.put(name.toLowerCase(), header);
} }
/**
* <p>Adds the given value to a header with the given name, creating a {@link Header} is none exists
* for the given name.</p>
*
* @param name the header name
* @param value the header value to add
*/
public void add(String name, String value) public void add(String name, String value)
{ {
name = name.trim(); name = name.trim();
@ -99,27 +140,46 @@ public class Headers implements Iterable<Headers.Header>
} }
} }
/**
* <p>Removes the {@link Header} with the given name</p>
*
* @param name the name of the header to remove
* @return the removed header, or null if no such header existed
*/
public Header remove(String name) public Header remove(String name)
{ {
name = name.trim(); name = name.trim();
return headers.remove(name.toLowerCase()); return headers.remove(name.toLowerCase());
} }
/**
* <p>Empties this {@link Headers} instance from all headers</p>
* @see #isEmpty()
*/
public void clear() public void clear()
{ {
headers.clear(); headers.clear();
} }
/**
* @return whether this {@link Headers} instance is empty
*/
public boolean isEmpty() public boolean isEmpty()
{ {
return headers.isEmpty(); return headers.isEmpty();
} }
public int getSize() /**
* @return the number of headers
*/
public int size()
{ {
return headers.size(); return headers.size();
} }
/**
* @return an iterator over the {@link Header} present in this instance
*/
@Override @Override
public Iterator<Header> iterator() public Iterator<Header> iterator()
{ {
@ -132,6 +192,10 @@ public class Headers implements Iterable<Headers.Header>
return headers.toString(); return headers.toString();
} }
/**
* <p>A named list of string values.</p>
* <p>The name is case-sensitive and there must be at least one value.</p>
*/
public static class Header public static class Header
{ {
private final String name; private final String name;
@ -165,11 +229,17 @@ public class Headers implements Iterable<Headers.Header>
return result; return result;
} }
/**
* @return the header's name
*/
public String name() public String name()
{ {
return name; return name;
} }
/**
* @return the first header's value
*/
public String value() public String value()
{ {
return values[0]; return values[0];
@ -189,11 +259,17 @@ public class Headers implements Iterable<Headers.Header>
return value == null ? null : Integer.valueOf(value); return value == null ? null : Integer.valueOf(value);
} }
/**
* @return the header's values
*/
public String[] values() public String[] values()
{ {
return values; return values;
} }
/**
* @return whether the header has multiple values
*/
public boolean hasMultipleValues() public boolean hasMultipleValues()
{ {
return values.length > 1; return values.length > 1;

View File

@ -16,20 +16,50 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for HEADERS frame metadata and headers.</p>
*/
public class HeadersInfo public class HeadersInfo
{ {
public static final byte FLAG_FIN = 1; /**
* <p>Flag that indicates that this {@link HeadersInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
/**
* <p>Flag that indicates that the compression of the stream must be reset.</p>
*
* @see #isResetCompression()
* @see #getFlags()
*/
public static final byte FLAG_RESET_COMPRESSION = 2; public static final byte FLAG_RESET_COMPRESSION = 2;
private final boolean close; private final boolean close;
private final boolean resetCompression; private final boolean resetCompression;
private final Headers headers; private final Headers headers;
/**
* <p>Creates a new {@link HeadersInfo} instance with the given headers,
* the given close flag and no reset compression flag</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public HeadersInfo(Headers headers, boolean close) public HeadersInfo(Headers headers, boolean close)
{ {
this(headers, close, false); this(headers, close, false);
} }
/**
* <p>Creates a new {@link HeadersInfo} instance with the given headers,
* the given close flag and the given reset compression flag</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
* @param resetCompression the value of the reset compression flag
*/
public HeadersInfo(Headers headers, boolean close, boolean resetCompression) public HeadersInfo(Headers headers, boolean close, boolean resetCompression)
{ {
this.headers = headers; this.headers = headers;
@ -37,24 +67,38 @@ public class HeadersInfo
this.resetCompression = resetCompression; this.resetCompression = resetCompression;
} }
/**
* @return the value of the close flag
*/
public boolean isClose() public boolean isClose()
{ {
return close; return close;
} }
/**
* @return the value of the reset compression flag
*/
public boolean isResetCompression() public boolean isResetCompression()
{ {
return resetCompression; return resetCompression;
} }
/**
* @return the {@link Headers}
*/
public Headers getHeaders() public Headers getHeaders()
{ {
return headers; return headers;
} }
/**
* @return the close and reset compression flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_RESET_COMPRESSION
*/
public byte getFlags() public byte getFlags()
{ {
byte flags = isClose() ? FLAG_FIN : 0; byte flags = isClose() ? FLAG_CLOSE : 0;
flags += isResetCompression() ? FLAG_RESET_COMPRESSION : 0; flags += isResetCompression() ? FLAG_RESET_COMPRESSION : 0;
return flags; return flags;
} }

View File

@ -16,15 +16,25 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for PING frames data.</p>
*/
public class PingInfo public class PingInfo
{ {
private final int pingId; private final int pingId;
/**
* <p>Creates a {@link PingInfo} with the given ping id</p>
* @param pingId the ping id
*/
public PingInfo(int pingId) public PingInfo(int pingId)
{ {
this.pingId = pingId; this.pingId = pingId;
} }
/**
* @return the ping id
*/
public int getPingId() public int getPingId()
{ {
return pingId; return pingId;

View File

@ -16,37 +16,67 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for SYN_REPLY frames metadata and headers.</p>
*/
public class ReplyInfo public class ReplyInfo
{ {
public static final byte FLAG_FIN = 1; /**
* <p>Flag that indicates that this {@link ReplyInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
private final Headers headers; private final Headers headers;
private final boolean close; private final boolean close;
/**
* <p>Creates a new {@link ReplyInfo} instance with empty headers and the given close flag.</p>
*
* @param close the value of the close flag
*/
public ReplyInfo(boolean close) public ReplyInfo(boolean close)
{ {
this(new Headers(), close); this(new Headers(), close);
} }
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public ReplyInfo(Headers headers, boolean close) public ReplyInfo(Headers headers, boolean close)
{ {
this.headers = headers; this.headers = headers;
this.close = close; this.close = close;
} }
/**
* @return the {@link Headers}
*/
public Headers getHeaders() public Headers getHeaders()
{ {
return headers; return headers;
} }
/**
* @return the value of the close flag
*/
public boolean isClose() public boolean isClose()
{ {
return close; return close;
} }
/**
* @return the close and reset compression flags as integer
* @see #FLAG_CLOSE
*/
public byte getFlags() public byte getFlags()
{ {
return isClose() ? FLAG_FIN : 0; return isClose() ? FLAG_CLOSE : 0;
} }
@Override @Override

View File

@ -16,22 +16,37 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for RST_STREAM frames data: the stream id and the stream status.</p>
*/
public class RstInfo public class RstInfo
{ {
private final int streamId; private final int streamId;
private final StreamStatus streamStatus; private final StreamStatus streamStatus;
/**
* <p>Creates a new {@link RstInfo} with the given stream id and stream status</p>
*
* @param streamId the stream id
* @param streamStatus the stream status
*/
public RstInfo(int streamId, StreamStatus streamStatus) public RstInfo(int streamId, StreamStatus streamStatus)
{ {
this.streamId = streamId; this.streamId = streamId;
this.streamStatus = streamStatus; this.streamStatus = streamStatus;
} }
/**
* @return the stream id
*/
public int getStreamId() public int getStreamId()
{ {
return streamId; return streamId;
} }
/**
* @return the stream status
*/
public StreamStatus getStreamStatus() public StreamStatus getStreamStatus()
{ {
return streamStatus; return streamStatus;

View File

@ -18,7 +18,7 @@ package org.eclipse.jetty.spdy.api;
/** /**
* <p>An unrecoverable exception that signals to the application that * <p>An unrecoverable exception that signals to the application that
* something wrong happened</p> * something wrong happened.</p>
*/ */
public class SPDYException extends RuntimeException public class SPDYException extends RuntimeException
{ {

View File

@ -19,11 +19,25 @@ package org.eclipse.jetty.spdy.api;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* <p>An enumeration of session statuses.</p>
*/
public enum SessionStatus public enum SessionStatus
{ {
/**
* <p>The session status indicating no errors</p>
*/
OK(0), OK(0),
/**
* <p>The session status indicating a protocol error</p>
*/
PROTOCOL_ERROR(1); PROTOCOL_ERROR(1);
/**
* @param code the session status code
* @return a {@link SessionStatus} from the given code,
* or null if no status exists
*/
public static SessionStatus from(int code) public static SessionStatus from(int code)
{ {
return Mapper.codes.get(code); return Mapper.codes.get(code);
@ -37,6 +51,9 @@ public enum SessionStatus
Mapper.codes.put(code, this); Mapper.codes.put(code, this);
} }
/**
* @return the code of this {@link SessionStatus}
*/
public int getCode() public int getCode()
{ {
return code; return code;

View File

@ -19,18 +19,62 @@ package org.eclipse.jetty.spdy.api;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* <p>An enumeration of stream statuses.</p>
*/
public enum StreamStatus public enum StreamStatus
{ {
/**
* <p>The stream status indicating a protocol error</p>
*/
PROTOCOL_ERROR(1, 1), PROTOCOL_ERROR(1, 1),
/**
* <p>The stream status indicating that the stream is not valid</p>
*/
INVALID_STREAM(2, 2), INVALID_STREAM(2, 2),
/**
* <p>The stream status indicating that the stream has been refused</p>
*/
REFUSED_STREAM(3, 3), REFUSED_STREAM(3, 3),
/**
* <p>The stream status indicating that the implementation does not support the SPDY version of the stream</p>
*/
UNSUPPORTED_VERSION(4, 4), UNSUPPORTED_VERSION(4, 4),
/**
* <p>The stream status indicating that the stream is no longer needed</p>
*/
CANCEL_STREAM(5, 5), CANCEL_STREAM(5, 5),
INTERNAL_ERROR(6, -1), /**
* <p>The stream status indicating an implementation error</p>
*/
INTERNAL_ERROR(6, 11),
/**
* <p>The stream status indicating a flow control error</p>
*/
FLOW_CONTROL_ERROR(7, 6), FLOW_CONTROL_ERROR(7, 6),
/**
* <p>The stream status indicating a stream opened more than once</p>
*/
STREAM_IN_USE(-1, 7), STREAM_IN_USE(-1, 7),
STREAM_ALREADY_CLOSED(-1, 8); /**
* <p>The stream status indicating data on a stream already closed</p>
*/
STREAM_ALREADY_CLOSED(-1, 8),
/**
* <p>The stream status indicating credentials not valid</p>
*/
INVALID_CREDENTIALS(-1, 9),
/**
* <p>The stream status indicating that the implementation could not support a frame too large</p>
*/
FRAME_TOO_LARGE(-1, 10);
/**
* @param version the SPDY protocol version
* @param code the stream status code
* @return a {@link StreamStatus} from the given version and code,
* or null if no such status exists
*/
public static StreamStatus from(short version, int code) public static StreamStatus from(short version, int code)
{ {
switch (version) switch (version)
@ -57,6 +101,10 @@ public enum StreamStatus
Mapper.v3Codes.put(v3Code, this); Mapper.v3Codes.put(v3Code, this);
} }
/**
* @param version the SPDY protocol version
* @return the stream status code
*/
public int getCode(short version) public int getCode(short version)
{ {
switch (version) switch (version)

View File

@ -19,6 +19,9 @@ package org.eclipse.jetty.spdy.api;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/**
* <p>Specialized {@link DataInfo} for {@link String} content.</p>
*/
public class StringDataInfo extends DataInfo public class StringDataInfo extends DataInfo
{ {
private byte[] bytes; private byte[] bytes;
@ -36,13 +39,13 @@ public class StringDataInfo extends DataInfo
} }
@Override @Override
public int getBytesCount() public int getContentLength()
{ {
return bytes.length - offset; return bytes.length - offset;
} }
@Override @Override
public int getBytes(ByteBuffer output) public int getContent(ByteBuffer output)
{ {
int remaining = output.remaining(); int remaining = output.remaining();
int length = Math.min(bytes.length - offset, remaining); int length = Math.min(bytes.length - offset, remaining);

View File

@ -16,9 +16,18 @@
package org.eclipse.jetty.spdy.api; package org.eclipse.jetty.spdy.api;
/**
* <p>A container for SYN_STREAM frames metadata and data.</p>
*/
public class SynInfo public class SynInfo
{ {
public static final byte FLAG_FIN = 1; /**
* <p>Flag that indicates that this {@link DataInfo} is the last frame in the stream.</p>
*
* @see #isClose()
* @see #getFlags()
*/
public static final byte FLAG_CLOSE = 1;
public static final byte FLAG_UNIDIRECTIONAL = 2; public static final byte FLAG_UNIDIRECTIONAL = 2;
private final boolean close; private final boolean close;
@ -27,16 +36,39 @@ public class SynInfo
private final byte priority; private final byte priority;
private final Headers headers; private final Headers headers;
/**
* <p>Creates a new {@link SynInfo} instance with empty headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param close the value of the close flag
*/
public SynInfo(boolean close) public SynInfo(boolean close)
{ {
this(new Headers(), close); this(new Headers(), close);
} }
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag,
* not unidirectional, without associated stream, and with default priority.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
*/
public SynInfo(Headers headers, boolean close) public SynInfo(Headers headers, boolean close)
{ {
this(headers, close, false, 0, (byte)0); this(headers, close, false, 0, (byte)0);
} }
/**
* <p>Creates a {@link ReplyInfo} instance with the given headers and the given close flag,
* the given unidirectional flag, the given associated stream, and with the given priority.</p>
*
* @param headers the {@link Headers}
* @param close the value of the close flag
* @param unidirectional the value of the unidirectional flag
* @param associatedStreamId the associated stream id
* @param priority the priority
*/
public SynInfo(Headers headers, boolean close, boolean unidirectional, int associatedStreamId, byte priority) public SynInfo(Headers headers, boolean close, boolean unidirectional, int associatedStreamId, byte priority)
{ {
this.close = close; this.close = close;
@ -46,34 +78,54 @@ public class SynInfo
this.headers = headers; this.headers = headers;
} }
/**
* @return the value of the close flag
*/
public boolean isClose() public boolean isClose()
{ {
return close; return close;
} }
/**
* @return the value of the unidirectional flag
*/
public boolean isUnidirectional() public boolean isUnidirectional()
{ {
return unidirectional; return unidirectional;
} }
/**
* @return the associated stream id
*/
public int getAssociatedStreamId() public int getAssociatedStreamId()
{ {
return associatedStreamId; return associatedStreamId;
} }
/**
* @return the priority
*/
public byte getPriority() public byte getPriority()
{ {
return priority; return priority;
} }
/**
* @return the {@link Headers}
*/
public Headers getHeaders() public Headers getHeaders()
{ {
return headers; return headers;
} }
/**
* @return the close and unidirectional flags as integer
* @see #FLAG_CLOSE
* @see #FLAG_UNIDIRECTIONAL
*/
public byte getFlags() public byte getFlags()
{ {
byte flags = isClose() ? FLAG_FIN : 0; byte flags = isClose() ? FLAG_CLOSE : 0;
flags += isUnidirectional() ? FLAG_UNIDIRECTIONAL : 0; flags += isUnidirectional() ? FLAG_UNIDIRECTIONAL : 0;
return flags; return flags;
} }

View File

@ -19,10 +19,25 @@ package org.eclipse.jetty.spdy.api.server;
import org.eclipse.jetty.spdy.api.Session; import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener; import org.eclipse.jetty.spdy.api.SessionFrameListener;
/**
* <p>Specific, server-side, {@link SessionFrameListener}.</p>
* <p>In addition to {@link SessionFrameListener}, this listener adds method
* {@link #onConnect(Session)} that is called when a client first connects to the
* server and may be used by a server-side application to send a SETTINGS frame
* to configure the connection before the client can open any stream.</p>
*/
public interface ServerSessionFrameListener extends SessionFrameListener public interface ServerSessionFrameListener extends SessionFrameListener
{ {
/**
* <p>Callback invoked when a client opens a connection.</p>
*
* @param session the session
*/
public void onConnect(Session session); public void onConnect(Session session);
/**
* <p>Empty implementation of {@link ServerSessionFrameListener}</p>
*/
public static class Adapter extends SessionFrameListener.Adapter implements ServerSessionFrameListener public static class Adapter extends SessionFrameListener.Adapter implements ServerSessionFrameListener
{ {
@Override @Override

View File

@ -50,7 +50,7 @@ public class DataFrame
public boolean isClose() public boolean isClose()
{ {
return (flags & DataInfo.FLAG_FIN) == DataInfo.FLAG_FIN; return (flags & DataInfo.FLAG_CLOSE) == DataInfo.FLAG_CLOSE;
} }
public boolean isCompress() public boolean isCompress()

View File

@ -60,7 +60,7 @@ public class HeadersFrame extends ControlFrame
public boolean isClose() public boolean isClose()
{ {
return (getFlags() & HeadersInfo.FLAG_FIN) == HeadersInfo.FLAG_FIN; return (getFlags() & HeadersInfo.FLAG_CLOSE) == HeadersInfo.FLAG_CLOSE;
} }
public boolean isResetCompression() public boolean isResetCompression()

View File

@ -43,7 +43,7 @@ public class SynReplyFrame extends ControlFrame
public boolean isClose() public boolean isClose()
{ {
return (getFlags() & ReplyInfo.FLAG_FIN) == ReplyInfo.FLAG_FIN; return (getFlags() & ReplyInfo.FLAG_CLOSE) == ReplyInfo.FLAG_CLOSE;
} }
@Override @Override

View File

@ -57,7 +57,7 @@ public class SynStreamFrame extends ControlFrame
public boolean isClose() public boolean isClose()
{ {
return (getFlags() & SynInfo.FLAG_FIN) == SynInfo.FLAG_FIN; return (getFlags() & SynInfo.FLAG_CLOSE) == SynInfo.FLAG_CLOSE;
} }
public boolean isUnidirectional() public boolean isUnidirectional()

View File

@ -28,14 +28,14 @@ public class DataFrameGenerator
ByteBuffer buffer = ByteBuffer.allocateDirect(DataFrame.HEADER_LENGTH + windowSize); ByteBuffer buffer = ByteBuffer.allocateDirect(DataFrame.HEADER_LENGTH + windowSize);
buffer.position(DataFrame.HEADER_LENGTH); buffer.position(DataFrame.HEADER_LENGTH);
// Guaranteed to always be >= 0 // Guaranteed to always be >= 0
int read = dataInfo.getBytes(buffer); int read = dataInfo.getContent(buffer);
buffer.putInt(0, streamId & 0x7F_FF_FF_FF); buffer.putInt(0, streamId & 0x7F_FF_FF_FF);
buffer.putInt(4, read & 0x00_FF_FF_FF); buffer.putInt(4, read & 0x00_FF_FF_FF);
// TODO: compression can be done here, as long as we have one DataFrameGenerator per stream // TODO: compression can be done here, as long as we have one DataFrameGenerator per stream
// since the compression context for data is per-stream, without dictionary // since the compression context for data is per-stream, without dictionary
byte flags = dataInfo.isConsumed() && dataInfo.isClose() ? DataInfo.FLAG_FIN : 0; byte flags = dataInfo.isConsumed() && dataInfo.isClose() ? DataInfo.FLAG_CLOSE : 0;
buffer.put(4, flags); buffer.put(4, flags);
buffer.flip(); buffer.flip();

View File

@ -40,8 +40,8 @@ public class HeadersBlockGenerator
{ {
// TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using ByteBuffer ? // TODO: ByteArrayOutputStream is quite inefficient, but grows on demand; optimize using ByteBuffer ?
Charset iso1 = Charset.forName("ISO-8859-1"); Charset iso1 = Charset.forName("ISO-8859-1");
ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.getSize() * 64); ByteArrayOutputStream buffer = new ByteArrayOutputStream(headers.size() * 64);
writeCount(version, buffer, headers.getSize()); writeCount(version, buffer, headers.size());
for (Headers.Header header : headers) for (Headers.Header header : headers)
{ {
String name = header.name(); String name = header.name();

View File

@ -80,7 +80,7 @@ public class HeadersBodyParser extends ControlFrameBodyParser
if (headersBlockParser.parse(version, length, buffer)) if (headersBlockParser.parse(version, length, buffer))
{ {
byte flags = controlFrameParser.getFlags(); byte flags = controlFrameParser.getFlags();
if (flags != 0 && flags != HeadersInfo.FLAG_FIN && flags != HeadersInfo.FLAG_RESET_COMPRESSION) if (flags != 0 && flags != HeadersInfo.FLAG_CLOSE && flags != HeadersInfo.FLAG_RESET_COMPRESSION)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS); throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.HEADERS);
HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Headers(headers, true)); HeadersFrame frame = new HeadersFrame(version, flags, streamId, new Headers(headers, true));

View File

@ -120,7 +120,7 @@ public class SynReplyBodyParser extends ControlFrameBodyParser
if (headersBlockParser.parse(version, length, buffer)) if (headersBlockParser.parse(version, length, buffer))
{ {
byte flags = controlFrameParser.getFlags(); byte flags = controlFrameParser.getFlags();
if (flags != 0 && flags != ReplyInfo.FLAG_FIN) if (flags != 0 && flags != ReplyInfo.FLAG_CLOSE)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY); throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_REPLY);
SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Headers(headers, true)); SynReplyFrame frame = new SynReplyFrame(version, flags, streamId, new Headers(headers, true));

View File

@ -126,7 +126,7 @@ public class SynStreamBodyParser extends ControlFrameBodyParser
{ {
byte flags = controlFrameParser.getFlags(); byte flags = controlFrameParser.getFlags();
// TODO: can it be both FIN and UNIDIRECTIONAL ? // TODO: can it be both FIN and UNIDIRECTIONAL ?
if (flags != 0 && flags != SynInfo.FLAG_FIN && flags != SynInfo.FLAG_UNIDIRECTIONAL) if (flags != 0 && flags != SynInfo.FLAG_CLOSE && flags != SynInfo.FLAG_UNIDIRECTIONAL)
throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_STREAM); throw new IllegalArgumentException("Invalid flag " + flags + " for frame " + ControlFrameType.SYN_STREAM);
SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, priority, new Headers(headers, true)); SynStreamFrame frame = new SynStreamFrame(version, flags, streamId, associatedStreamId, priority, new Headers(headers, true));

View File

@ -37,7 +37,7 @@ public class ServerUsageTest
// Get the http response, fill headers and data // Get the http response, fill headers and data
Headers replyHeaders = new Headers(); Headers replyHeaders = new Headers();
replyHeaders.put("host", synHeaders.get("host")); replyHeaders.put(synHeaders.get("host"));
// Sends a reply // Sends a reply
stream.reply(new ReplyInfo(replyHeaders, false)); stream.reply(new ReplyInfo(replyHeaders, false));

View File

@ -58,7 +58,7 @@ public class DataGenerateParseTest
Assert.assertNotNull(frame2); Assert.assertNotNull(frame2);
Assert.assertEquals(streamId, frame2.getStreamId()); Assert.assertEquals(streamId, frame2.getStreamId());
Assert.assertEquals(DataInfo.FLAG_FIN, frame2.getFlags()); Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags());
Assert.assertEquals(length, frame2.getLength()); Assert.assertEquals(length, frame2.getLength());
Assert.assertEquals(length, listener.getData().remaining()); Assert.assertEquals(length, listener.getData().remaining());
} }
@ -84,7 +84,7 @@ public class DataGenerateParseTest
Assert.assertNotNull(frame2); Assert.assertNotNull(frame2);
Assert.assertEquals(streamId, frame2.getStreamId()); Assert.assertEquals(streamId, frame2.getStreamId());
Assert.assertEquals(DataInfo.FLAG_FIN, frame2.getFlags()); Assert.assertEquals(DataInfo.FLAG_CLOSE, frame2.getFlags());
Assert.assertEquals(length, frame2.getLength()); Assert.assertEquals(length, frame2.getLength());
Assert.assertEquals(length, listener.getData().remaining()); Assert.assertEquals(length, listener.getData().remaining());
} }

View File

@ -32,7 +32,7 @@ public class SynReplyGenerateParseTest
@Test @Test
public void testGenerateParse() throws Exception public void testGenerateParse() throws Exception
{ {
byte flags = ReplyInfo.FLAG_FIN; byte flags = ReplyInfo.FLAG_CLOSE;
int streamId = 13; int streamId = 13;
Headers headers = new Headers(); Headers headers = new Headers();
headers.put("a", "b"); headers.put("a", "b");
@ -60,7 +60,7 @@ public class SynReplyGenerateParseTest
@Test @Test
public void testGenerateParseOneByteAtATime() throws Exception public void testGenerateParseOneByteAtATime() throws Exception
{ {
byte flags = ReplyInfo.FLAG_FIN; byte flags = ReplyInfo.FLAG_CLOSE;
int streamId = 13; int streamId = 13;
Headers headers = new Headers(); Headers headers = new Headers();
headers.put("a", "b"); headers.put("a", "b");

View File

@ -32,7 +32,7 @@ public class SynStreamGenerateParseTest
@Test @Test
public void testGenerateParse() throws Exception public void testGenerateParse() throws Exception
{ {
byte flags = SynInfo.FLAG_FIN; byte flags = SynInfo.FLAG_CLOSE;
int streamId = 13; int streamId = 13;
int associatedStreamId = 11; int associatedStreamId = 11;
byte priority = 3; byte priority = 3;
@ -65,7 +65,7 @@ public class SynStreamGenerateParseTest
@Test @Test
public void testGenerateParseOneByteAtATime() throws Exception public void testGenerateParseOneByteAtATime() throws Exception
{ {
byte flags = SynInfo.FLAG_FIN; byte flags = SynInfo.FLAG_CLOSE;
int streamId = 13; int streamId = 13;
int associatedStreamId = 11; int associatedStreamId = 11;
byte priority = 3; byte priority = 3;

View File

@ -592,7 +592,7 @@ public class ServerHTTPSPDYTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
contentBytes.addAndGet(dataInfo.getBytesCount()); contentBytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
{ {
Assert.assertEquals(data.length, contentBytes.get()); Assert.assertEquals(data.length, contentBytes.get());
@ -649,7 +649,7 @@ public class ServerHTTPSPDYTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
contentBytes.addAndGet(dataInfo.getBytesCount()); contentBytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
{ {
Assert.assertEquals(2 * data.length, contentBytes.get()); Assert.assertEquals(2 * data.length, contentBytes.get());

View File

@ -134,7 +134,7 @@ public class SPDYAsyncConnection extends AbstractConnection implements AsyncConn
catch (Exception x) catch (Exception x)
{ {
close(false); close(false);
handler.failed(x); handler.failed(x, context);
} }
finally finally
{ {

View File

@ -123,8 +123,8 @@ public class ConcurrentSynDataReplyDataTest extends AbstractTest
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
Assert.assertEquals(1, latch.getCount()); Assert.assertEquals(1, latch.getCount());
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getBytesCount()); ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getContentLength());
dataInfo.getBytes(buffer); dataInfo.getContent(buffer);
Assert.assertTrue(dataInfo.isConsumed()); Assert.assertTrue(dataInfo.isConsumed());
latch.countDown(); latch.countDown();
} }

View File

@ -55,7 +55,7 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
bytes.addAndGet(dataInfo.getBytesCount()); bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
dataLatch.countDown(); dataLatch.countDown();
} }
@ -88,7 +88,7 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
bytes.addAndGet(dataInfo.getBytesCount()); bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
dataLatch.countDown(); dataLatch.countDown();
} }
@ -114,7 +114,7 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
bytes.addAndGet(dataInfo.getBytesCount()); bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
dataLatch.countDown(); dataLatch.countDown();
} }
@ -146,7 +146,7 @@ public class FlowControlTest extends AbstractTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
bytes.addAndGet(dataInfo.getBytesCount()); bytes.addAndGet(dataInfo.getContentLength());
if (dataInfo.isClose()) if (dataInfo.isClose())
dataLatch.countDown(); dataLatch.countDown();
} }

View File

@ -139,7 +139,7 @@ public class SynReplyTest extends AbstractTest
ByteBuffer buffer = ByteBuffer.allocate(2); ByteBuffer buffer = ByteBuffer.allocate(2);
while (!dataInfo.isConsumed()) while (!dataInfo.isConsumed())
{ {
dataInfo.getBytes(buffer); dataInfo.getContent(buffer);
buffer.flip(); buffer.flip();
bytes.write(buffer.array(), buffer.arrayOffset(), buffer.remaining()); bytes.write(buffer.array(), buffer.arrayOffset(), buffer.remaining());
buffer.clear(); buffer.clear();
@ -309,8 +309,8 @@ public class SynReplyTest extends AbstractTest
@Override @Override
public void onData(Stream stream, DataInfo dataInfo) public void onData(Stream stream, DataInfo dataInfo)
{ {
ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getBytesCount()); ByteBuffer buffer = ByteBuffer.allocate(dataInfo.getContentLength());
dataInfo.getBytes(buffer); dataInfo.getContent(buffer);
buffer.flip(); buffer.flip();
String data = Charset.forName("UTF-8").decode(buffer).toString(); String data = Charset.forName("UTF-8").decode(buffer).toString();
Assert.assertEquals(serverData, data); Assert.assertEquals(serverData, data);