// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.http2.hpack; import java.nio.ByteBuffer; import java.util.Iterator; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; public class HpackDecoderTest { @Test public void testDecodeD_3() { HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828684410f7777772e6578616d706c652e636f6d"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); // Second request encoded="828684be58086e6f2d6361636865"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); assertFalse(iterator.hasNext()); // Third request encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET",request.getMethod()); assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); assertEquals("/index.html",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("custom-key","custom-value"),iterator.next()); assertFalse(iterator.hasNext()); } @Test public void testDecodeD_4() { HpackDecoder decoder = new HpackDecoder(4096,8192); // First request String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); // Second request encoded="828684be5886a8eb10649cbf"; buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); Iterator<HttpField> iterator=request.iterator(); assertTrue(iterator.hasNext()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); assertFalse(iterator.hasNext()); } @Test public void testDecodeWithArrayOffset() { String value = "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; HpackDecoder decoder = new HpackDecoder(4096,8192); String encoded = "8682418cF1E3C2E5F23a6bA0Ab90F4Ff841f0822426173696320515778685a475270626a70766347567549484e6c633246745a513d3d"; byte[] bytes = TypeUtil.fromHexString(encoded); byte[] array = new byte[bytes.length + 1]; System.arraycopy(bytes, 0, array, 1, bytes.length); ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice(); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); assertEquals(1,request.getFields().size()); HttpField field = request.iterator().next(); assertEquals(HttpHeader.AUTHORIZATION, field.getHeader()); assertEquals(value, field.getValue()); } @Test public void testDecodeHuffmanWithArrayOffset() { HpackDecoder decoder = new HpackDecoder(4096,8192); String encoded="8286418cf1e3c2e5f23a6ba0ab90f4ff84"; byte[] bytes = TypeUtil.fromHexString(encoded); byte[] array = new byte[bytes.length + 1]; System.arraycopy(bytes, 0, array, 1, bytes.length); ByteBuffer buffer = ByteBuffer.wrap(array, 1, bytes.length).slice(); MetaData.Request request = (MetaData.Request)decoder.decode(buffer); assertEquals("GET", request.getMethod()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals("/",request.getURI().getPath()); assertEquals("www.example.com",request.getURI().getHost()); assertFalse(request.iterator().hasNext()); } @Test public void testNghttpx() { // Response encoded by nghttpx String encoded="886196C361Be940b6a65B6850400B8A00571972e080a62D1Bf5f87497cA589D34d1f9a0f0d0234327690Aa69D29aFcA954D3A5358980Ae112e0f7c880aE152A9A74a6bF3"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); HpackDecoder decoder = new HpackDecoder(4096,8192); MetaData.Response response = (MetaData.Response)decoder.decode(buffer); assertThat(response.getStatus(),is(200)); assertThat(response.getFields().size(),is(6)); assertTrue(response.getFields().contains(new HttpField(HttpHeader.DATE,"Fri, 15 Jul 2016 02:36:20 GMT"))); assertTrue(response.getFields().contains(new HttpField(HttpHeader.CONTENT_TYPE,"text/html"))); assertTrue(response.getFields().contains(new HttpField(HttpHeader.CONTENT_ENCODING,""))); assertTrue(response.getFields().contains(new HttpField(HttpHeader.CONTENT_LENGTH,"42"))); assertTrue(response.getFields().contains(new HttpField(HttpHeader.SERVER,"nghttpx nghttp2/1.12.0"))); assertTrue(response.getFields().contains(new HttpField(HttpHeader.VIA,"1.1 nghttpx"))); } @Test public void testTooBigToIndex() { String encoded = "44FfEc02Df3990A190A0D4Ee5b3d2940Ec98Aa4a62D127D29e273a0aA20dEcAa190a503b262d8a2671D4A2672a927aA874988a2471D05510750c951139EdA2452a3a548cAa1aA90bE4B228342864A9E0D450A5474a92992a1aA513395448E3A0Aa17B96cFe3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f14E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F3E7Cf9f3e7cF9F353F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F54f"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); HpackDecoder decoder = new HpackDecoder(128,8192); try { decoder.decode(buffer); Assert.fail(); } catch (BadMessageException e) { assertThat(e.getCode(),equalTo(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431)); assertThat(e.getReason(),Matchers.startsWith("Indexed field value too large")); } } @Test public void testUnknownIndex() { String encoded = "BE"; ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); HpackDecoder decoder = new HpackDecoder(128,8192); try { decoder.decode(buffer); Assert.fail(); } catch (BadMessageException e) { assertThat(e.getCode(),equalTo(HttpStatus.BAD_REQUEST_400)); assertThat(e.getReason(),Matchers.startsWith("Unknown index")); } } }