blob: 907a9abb2dd90256bc7567beb6b077e72bdf2e9d [file] [log] [blame]
//
// ========================================================================
// 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"));
}
}
}