// // ======================================================================== // 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 static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import java.nio.ByteBuffer; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; 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.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; /* ------------------------------------------------------------ */ /** */ public class HpackEncoderTest { @Test public void testUnknownFieldsContextManagement() { HpackEncoder encoder = new HpackEncoder(38*5); HttpFields fields = new HttpFields(); HttpField[] field = { new HttpField("fo0","b0r"), new HttpField("fo1","b1r"), new HttpField("fo2","b2r"), new HttpField("fo3","b3r"), new HttpField("fo4","b4r"), new HttpField("fo5","b5r"), new HttpField("fo6","b6r"), new HttpField("fo7","b7r"), new HttpField("fo8","b8r"), new HttpField("fo9","b9r"), new HttpField("foA","bAr"), }; // Add 4 entries for (int i=0;i<=3;i++) fields.add(field[i]); // encode them ByteBuffer buffer = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,pos); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // All are in the dynamic table Assert.assertEquals(4,encoder.getHpackContext().size()); // encode exact same fields again! BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // All are in the dynamic table Assert.assertEquals(4,encoder.getHpackContext().size()); // Add 4 more fields for (int i=4;i<=7;i++) fields.add(field[i]); // encode BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // max dynamic table size reached Assert.assertEquals(5,encoder.getHpackContext().size()); // remove some fields for (int i=0;i<=7;i+=2) fields.remove(field[i].getName()); // encode BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // max dynamic table size reached Assert.assertEquals(5,encoder.getHpackContext().size()); // remove another fields fields.remove(field[1].getName()); // encode BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // max dynamic table size reached Assert.assertEquals(5,encoder.getHpackContext().size()); // re add the field fields.add(field[1]); // encode BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // max dynamic table size reached Assert.assertEquals(5,encoder.getHpackContext().size()); } @Test public void testNeverIndexSetCookie() { HpackEncoder encoder = new HpackEncoder(38*5); ByteBuffer buffer = BufferUtil.allocate(4096); HttpFields fields = new HttpFields(); fields.put("set-cookie","some cookie value"); // encode BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // empty dynamic table Assert.assertEquals(0,encoder.getHpackContext().size()); // encode again BufferUtil.clearToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,0); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // empty dynamic table Assert.assertEquals(0,encoder.getHpackContext().size()); } @Test public void testFieldLargerThanTable() { HttpFields fields = new HttpFields(); HpackEncoder encoder = new HpackEncoder(128); ByteBuffer buffer0 = BufferUtil.allocate(4096); int pos = BufferUtil.flipToFill(buffer0); encoder.encode(buffer0,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer0,pos); encoder = new HpackEncoder(128); fields.add(new HttpField("user-agent","jetty/test")); ByteBuffer buffer1 = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer1); encoder.encode(buffer1,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer1,pos); encoder = new HpackEncoder(128); fields.add(new HttpField(":path", "This is a very large field, whose size is larger than the dynamic table so it should not be indexed as it will not fit in the table ever!"+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "+ "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY "+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ ")); ByteBuffer buffer2 = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer2); encoder.encode(buffer2,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer2,pos); encoder = new HpackEncoder(128); fields.add(new HttpField("host","somehost")); ByteBuffer buffer = BufferUtil.allocate(4096); pos = BufferUtil.flipToFill(buffer); encoder.encode(buffer,new MetaData(HttpVersion.HTTP_2,fields)); BufferUtil.flipToFlush(buffer,pos); //System.err.println(BufferUtil.toHexString(buffer0)); //System.err.println(BufferUtil.toHexString(buffer1)); //System.err.println(BufferUtil.toHexString(buffer2)); //System.err.println(BufferUtil.toHexString(buffer)); // something was encoded! assertThat(buffer.remaining(),Matchers.greaterThan(0)); // check first field is static index name and dynamic index body assertThat((buffer.get(buffer0.remaining())&0xFF)>>6,equalTo(1)); // check first field is static index name and literal body assertThat((buffer.get(buffer1.remaining())&0xFF)>>4,equalTo(0)); // check first field is static index name and dynamic index body assertThat((buffer.get(buffer2.remaining())&0xFF)>>6,equalTo(1)); // Only first and third fields are put in the table HpackContext context = encoder.getHpackContext(); assertThat(context.size(),equalTo(2)); assertThat(context.get(HpackContext.STATIC_SIZE+1).getHttpField().getName(),equalTo("host")); assertThat(context.get(HpackContext.STATIC_SIZE+2).getHttpField().getName(),equalTo("user-agent")); assertThat(context.getDynamicTableSize(),equalTo( context.get(HpackContext.STATIC_SIZE+1).getSize()+context.get(HpackContext.STATIC_SIZE+2).getSize())); } }