Search in sources :

Example 96 with Frame

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());
    }
}
Also used : MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) Parser(org.eclipse.jetty.http2.parser.Parser) WindowUpdateGenerator(org.eclipse.jetty.http2.generator.WindowUpdateGenerator) HeaderGenerator(org.eclipse.jetty.http2.generator.HeaderGenerator) Test(org.junit.Test)

Example 97 with Frame

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());
}
Also used : MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) Parser(org.eclipse.jetty.http2.parser.Parser) WindowUpdateGenerator(org.eclipse.jetty.http2.generator.WindowUpdateGenerator) HeaderGenerator(org.eclipse.jetty.http2.generator.HeaderGenerator) Test(org.junit.Test)

Example 98 with Frame

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();
}
Also used : BadMessageException(org.eclipse.jetty.http.BadMessageException) Entry(org.eclipse.jetty.http2.hpack.HpackContext.Entry) HttpHeader(org.eclipse.jetty.http.HttpHeader) HttpField(org.eclipse.jetty.http.HttpField)

Example 99 with Frame

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"));
    }
}
Also used : ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) HashMap(java.util.HashMap) OutputStream(java.io.OutputStream) Matchers.containsString(org.hamcrest.Matchers.containsString) HeadersFrame(org.eclipse.jetty.http2.frames.HeadersFrame) SettingsFrame(org.eclipse.jetty.http2.frames.SettingsFrame) MetaData(org.eclipse.jetty.http.MetaData) HttpFields(org.eclipse.jetty.http.HttpFields) HostPortHttpField(org.eclipse.jetty.http.HostPortHttpField) AtomicReference(java.util.concurrent.atomic.AtomicReference) DataFrame(org.eclipse.jetty.http2.frames.DataFrame) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBuffer(java.nio.ByteBuffer) Parser(org.eclipse.jetty.http2.parser.Parser) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) PrefaceFrame(org.eclipse.jetty.http2.frames.PrefaceFrame) Socket(java.net.Socket) Generator(org.eclipse.jetty.http2.generator.Generator) Test(org.junit.Test)

Example 100 with Frame

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"));
    }
}
Also used : ByteBufferPool(org.eclipse.jetty.io.ByteBufferPool) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) HashMap(java.util.HashMap) OutputStream(java.io.OutputStream) Matchers.containsString(org.hamcrest.Matchers.containsString) HeadersFrame(org.eclipse.jetty.http2.frames.HeadersFrame) SettingsFrame(org.eclipse.jetty.http2.frames.SettingsFrame) MetaData(org.eclipse.jetty.http.MetaData) HttpFields(org.eclipse.jetty.http.HttpFields) HostPortHttpField(org.eclipse.jetty.http.HostPortHttpField) InputStream(java.io.InputStream) Utf8StringBuilder(org.eclipse.jetty.util.Utf8StringBuilder) AtomicReference(java.util.concurrent.atomic.AtomicReference) DataFrame(org.eclipse.jetty.http2.frames.DataFrame) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBuffer(java.nio.ByteBuffer) EndPoint(org.eclipse.jetty.io.EndPoint) Parser(org.eclipse.jetty.http2.parser.Parser) MappedByteBufferPool(org.eclipse.jetty.io.MappedByteBufferPool) PrefaceFrame(org.eclipse.jetty.http2.frames.PrefaceFrame) Socket(java.net.Socket) Generator(org.eclipse.jetty.http2.generator.Generator) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)124 HttpFields (org.eclipse.jetty.http.HttpFields)107 MetaData (org.eclipse.jetty.http.MetaData)107 HeadersFrame (org.eclipse.jetty.http2.frames.HeadersFrame)107 CountDownLatch (java.util.concurrent.CountDownLatch)104 Stream (org.eclipse.jetty.http2.api.Stream)99 Session (org.eclipse.jetty.http2.api.Session)94 ServerSessionListener (org.eclipse.jetty.http2.api.server.ServerSessionListener)85 FuturePromise (org.eclipse.jetty.util.FuturePromise)69 DataFrame (org.eclipse.jetty.http2.frames.DataFrame)60 ByteBuffer (java.nio.ByteBuffer)59 Callback (org.eclipse.jetty.util.Callback)53 HttpServletResponse (javax.servlet.http.HttpServletResponse)51 Promise (org.eclipse.jetty.util.Promise)49 ByteBufferPool (org.eclipse.jetty.io.ByteBufferPool)43 HTTP2Session (org.eclipse.jetty.http2.HTTP2Session)39 IOException (java.io.IOException)38 HttpServletRequest (javax.servlet.http.HttpServletRequest)38 ServletException (javax.servlet.ServletException)35 HashMap (java.util.HashMap)34