use of org.eclipse.jetty.http2.frames.Frame in project jetty.project by eclipse.
the class WindowUpdateGenerateParseTest method testGenerateParseOneByteAtATime.
@Test
public void testGenerateParseOneByteAtATime() throws Exception {
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
final List<WindowUpdateFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() {
@Override
public void onWindowUpdate(WindowUpdateFrame frame) {
frames.add(frame);
}
}, 4096, 8192);
int streamId = 13;
int windowUpdate = 17;
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i) {
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateWindowUpdate(lease, streamId, windowUpdate);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers()) {
while (buffer.hasRemaining()) {
parser.parse(ByteBuffer.wrap(new byte[] { buffer.get() }));
}
}
Assert.assertEquals(1, frames.size());
WindowUpdateFrame frame = frames.get(0);
Assert.assertEquals(streamId, frame.getStreamId());
Assert.assertEquals(windowUpdate, frame.getWindowDelta());
}
}
use of org.eclipse.jetty.http2.frames.Frame in project jetty.project by eclipse.
the class WindowUpdateGenerateParseTest method testGenerateParse.
@Test
public void testGenerateParse() throws Exception {
WindowUpdateGenerator generator = new WindowUpdateGenerator(new HeaderGenerator());
final List<WindowUpdateFrame> frames = new ArrayList<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() {
@Override
public void onWindowUpdate(WindowUpdateFrame frame) {
frames.add(frame);
}
}, 4096, 8192);
int streamId = 13;
int windowUpdate = 17;
// Iterate a few times to be sure generator and parser are properly reset.
for (int i = 0; i < 2; ++i) {
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.generateWindowUpdate(lease, streamId, windowUpdate);
frames.clear();
for (ByteBuffer buffer : lease.getByteBuffers()) {
while (buffer.hasRemaining()) {
parser.parse(buffer);
}
}
}
Assert.assertEquals(1, frames.size());
WindowUpdateFrame frame = frames.get(0);
Assert.assertEquals(streamId, frame.getStreamId());
Assert.assertEquals(windowUpdate, frame.getWindowDelta());
}
use of org.eclipse.jetty.http2.frames.Frame in project jetty.project by eclipse.
the class HpackDecoder method decode.
public MetaData decode(ByteBuffer buffer) {
if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining()));
// If the buffer is big, don't even think about decoding it
if (buffer.remaining() > _builder.getMaxSize())
throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Header frame size " + buffer.remaining() + ">" + _builder.getMaxSize());
while (buffer.hasRemaining()) {
if (LOG.isDebugEnabled() && buffer.hasArray()) {
int l = Math.min(buffer.remaining(), 32);
LOG.debug("decode {}{}", TypeUtil.toHexString(buffer.array(), buffer.arrayOffset() + buffer.position(), l), l < buffer.remaining() ? "..." : "");
}
byte b = buffer.get();
if (b < 0) {
// 7.1 indexed if the high bit is set
int index = NBitInteger.decode(buffer, 7);
Entry entry = _context.get(index);
if (entry == null) {
throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Unknown index " + index);
} else if (entry.isStatic()) {
if (LOG.isDebugEnabled())
LOG.debug("decode IdxStatic {}", entry);
// emit field
_builder.emit(entry.getHttpField());
// TODO copy and add to reference set if there is room
// _context.add(entry.getHttpField());
} else {
if (LOG.isDebugEnabled())
LOG.debug("decode Idx {}", entry);
// emit
_builder.emit(entry.getHttpField());
}
} else {
// look at the first nibble in detail
byte f = (byte) ((b & 0xF0) >> 4);
String name;
HttpHeader header;
String value;
boolean indexed;
int name_index;
switch(f) {
// 7.3
case 2:
case // 7.3
3:
// change table size
int size = NBitInteger.decode(buffer, 5);
if (LOG.isDebugEnabled())
LOG.debug("decode resize=" + size);
if (size > _localMaxDynamicTableSize)
throw new IllegalArgumentException();
_context.resize(size);
continue;
// 7.2.2
case 0:
case // 7.2.3
1:
indexed = false;
name_index = NBitInteger.decode(buffer, 4);
break;
// 7.2.1
case 4:
// 7.2.1
case 5:
// 7.2.1
case 6:
case // 7.2.1
7:
indexed = true;
name_index = NBitInteger.decode(buffer, 6);
break;
default:
throw new IllegalStateException();
}
boolean huffmanName = false;
// decode the name
if (name_index > 0) {
Entry name_entry = _context.get(name_index);
name = name_entry.getHttpField().getName();
header = name_entry.getHttpField().getHeader();
} else {
huffmanName = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
_builder.checkSize(length, huffmanName);
if (huffmanName)
name = Huffman.decode(buffer, length);
else
name = toASCIIString(buffer, length);
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
if (c >= 'A' && c <= 'Z') {
throw new BadMessageException(400, "Uppercase header name");
}
}
header = HttpHeader.CACHE.get(name);
}
// decode the value
boolean huffmanValue = (buffer.get() & 0x80) == 0x80;
int length = NBitInteger.decode(buffer, 7);
_builder.checkSize(length, huffmanValue);
if (huffmanValue)
value = Huffman.decode(buffer, length);
else
value = toASCIIString(buffer, length);
// Make the new field
HttpField field;
if (header == null) {
// just make a normal field and bypass header name lookup
field = new HttpField(null, name, value);
} else {
// and/or of a type that may be looked up multiple times.
switch(header) {
case C_STATUS:
if (indexed)
field = new HttpField.IntValueHttpField(header, name, value);
else
field = new HttpField(header, name, value);
break;
case C_AUTHORITY:
field = new AuthorityHttpField(value);
break;
case CONTENT_LENGTH:
if ("0".equals(value))
field = CONTENT_LENGTH_0;
else
field = new HttpField.LongValueHttpField(header, name, value);
break;
default:
field = new HttpField(header, name, value);
break;
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("decoded '{}' by {}/{}/{}", field, name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"), huffmanValue ? "HuffVal" : "LitVal", indexed ? "Idx" : "");
}
// emit the field
_builder.emit(field);
// if indexed
if (indexed) {
// add to dynamic table
if (_context.add(field) == null)
throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Indexed field value too large");
}
}
}
return _builder.build();
}
use of org.eclipse.jetty.http2.frames.Frame in project jetty.project by eclipse.
the class HTTP2CServerTest method testHTTP_2_0_Direct.
@Test
public void testHTTP_2_0_Direct() throws Exception {
final CountDownLatch latch = new CountDownLatch(3);
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), "/test", HttpVersion.HTTP_2, new HttpFields());
generator.control(lease, new HeadersFrame(1, metaData, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort())) {
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers()) {
output.write(BufferUtil.toArray(buffer));
}
final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() {
@Override
public void onSettings(SettingsFrame frame) {
latch.countDown();
}
@Override
public void onHeaders(HeadersFrame frame) {
headersRef.set(frame);
latch.countDown();
}
@Override
public void onData(DataFrame frame) {
dataRef.set(frame);
latch.countDown();
}
}, 4096, 8192);
parseResponse(client, parser);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
HeadersFrame response = headersRef.get();
Assert.assertNotNull(response);
MetaData.Response responseMetaData = (MetaData.Response) response.getMetaData();
Assert.assertEquals(200, responseMetaData.getStatus());
DataFrame responseData = dataRef.get();
Assert.assertNotNull(responseData);
String s = BufferUtil.toString(responseData.getData());
assertThat(s, containsString("Hello from Jetty using HTTP/2.0"));
assertThat(s, containsString("uri=/test"));
}
}
use of org.eclipse.jetty.http2.frames.Frame in project jetty.project by eclipse.
the class HTTP2CServerTest method testHTTP_1_1_Upgrade.
@Test
public void testHTTP_1_1_Upgrade() throws Exception {
try (Socket client = new Socket("localhost", connector.getLocalPort())) {
OutputStream output = client.getOutputStream();
output.write(("" + "GET /one HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: something, else, upgrade, HTTP2-Settings\r\n" + "Upgrade: h2c\r\n" + "HTTP2-Settings: \r\n" + "\r\n").getBytes(StandardCharsets.ISO_8859_1));
output.flush();
InputStream input = client.getInputStream();
Utf8StringBuilder upgrade = new Utf8StringBuilder();
int crlfs = 0;
while (true) {
int read = input.read();
if (read == '\r' || read == '\n')
++crlfs;
else
crlfs = 0;
upgrade.append((byte) read);
if (crlfs == 4)
break;
}
assertTrue(upgrade.toString().startsWith("HTTP/1.1 101 "));
byteBufferPool = new MappedByteBufferPool();
generator = new Generator(byteBufferPool);
final AtomicReference<HeadersFrame> headersRef = new AtomicReference<>();
final AtomicReference<DataFrame> dataRef = new AtomicReference<>();
final AtomicReference<CountDownLatch> latchRef = new AtomicReference<>(new CountDownLatch(2));
Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter() {
@Override
public void onHeaders(HeadersFrame frame) {
headersRef.set(frame);
latchRef.get().countDown();
}
@Override
public void onData(DataFrame frame) {
dataRef.set(frame);
latchRef.get().countDown();
}
}, 4096, 8192);
parseResponse(client, parser);
Assert.assertTrue(latchRef.get().await(5, TimeUnit.SECONDS));
HeadersFrame response = headersRef.get();
Assert.assertNotNull(response);
MetaData.Response responseMetaData = (MetaData.Response) response.getMetaData();
Assert.assertEquals(200, responseMetaData.getStatus());
DataFrame responseData = dataRef.get();
Assert.assertNotNull(responseData);
String content = BufferUtil.toString(responseData.getData());
// The upgrade request is seen as HTTP/1.1.
assertThat(content, containsString("Hello from Jetty using HTTP/1.1"));
assertThat(content, containsString("uri=/one"));
// Send a HTTP/2 request.
headersRef.set(null);
dataRef.set(null);
latchRef.set(new CountDownLatch(2));
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
MetaData.Request metaData = new MetaData.Request("GET", HttpScheme.HTTP, new HostPortHttpField("localhost:" + connector.getLocalPort()), "/two", HttpVersion.HTTP_2, new HttpFields());
generator.control(lease, new HeadersFrame(3, metaData, null, true));
for (ByteBuffer buffer : lease.getByteBuffers()) output.write(BufferUtil.toArray(buffer));
output.flush();
parseResponse(client, parser);
Assert.assertTrue(latchRef.get().await(5, TimeUnit.SECONDS));
response = headersRef.get();
Assert.assertNotNull(response);
responseMetaData = (MetaData.Response) response.getMetaData();
Assert.assertEquals(200, responseMetaData.getStatus());
responseData = dataRef.get();
Assert.assertNotNull(responseData);
content = BufferUtil.toString(responseData.getData());
assertThat(content, containsString("Hello from Jetty using HTTP/2.0"));
assertThat(content, containsString("uri=/two"));
}
}
Aggregations