480260 - HPack decode error for buffers with offset.

Fixed calculations to advance the ByteBuffer.
This commit is contained in:
Simone Bordet 2015-10-20 23:19:10 +02:00
parent a01565fbc4
commit cbb7be040f
3 changed files with 98 additions and 54 deletions

View File

@ -31,11 +31,9 @@ import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/**
* Hpack Decoder
* <p>This is not thread safe and may only be called by 1 thread at a time
* <p>This is not thread safe and may only be called by 1 thread at a time.</p>
*/
public class HpackDecoder
{
@ -47,7 +45,6 @@ public class HpackDecoder
private final MetaDataBuilder _builder;
private int _localMaxDynamicTableSize;
/* ------------------------------------------------------------ */
/**
* @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table.
* @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters.
@ -85,7 +82,9 @@ public class HpackDecoder
{
int l=Math.min(buffer.remaining(),16);
// TODO: not guaranteed the buffer has a backing array !
LOG.debug("decode "+TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l)+(l<buffer.remaining()?"...":""));
LOG.debug("decode {}{}",
TypeUtil.toHexString(buffer.array(),buffer.arrayOffset()+buffer.position(),l),
l<buffer.remaining()?"...":"");
}
byte b = buffer.get();
@ -236,7 +235,13 @@ public class HpackDecoder
}
if (LOG.isDebugEnabled())
LOG.debug("decoded '"+field+"' by Lit"+(name_index>0?"IdxName":(huffmanName?"HuffName":"LitName"))+(huffmanValue?"HuffVal":"LitVal")+(indexed?"Idx":""));
{
LOG.debug("decoded '{}' by {}/{}/{}",
field,
name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"),
huffmanValue ? "HuffVal" : "LitVal",
indexed ? "Idx" : "");
}
// emit the field
_builder.emit(field);
@ -257,9 +262,10 @@ public class HpackDecoder
public static String toASCIIString(ByteBuffer buffer,int length)
{
StringBuilder builder = new StringBuilder(length);
int start=buffer.arrayOffset()+buffer.position();
int position=buffer.position();
int start=buffer.arrayOffset()+ position;
int end=start+length;
buffer.position(end);
buffer.position(position+length);
byte[] array=buffer.array();
for (int i=start;i<end;i++)
builder.append((char)(0x7f&array[i]));

View File

@ -357,9 +357,10 @@ public class Huffman
int bits = 0;
byte[] array = buffer.array();
int start=buffer.arrayOffset()+buffer.position();
int position=buffer.position();
int start=buffer.arrayOffset()+position;
int end=start+length;
buffer.position(end);
buffer.position(position+length);
for (int i=start; i<end; i++)
{

View File

@ -19,23 +19,20 @@
package org.eclipse.jetty.http2.hpack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.nio.ByteBuffer;
import java.util.Iterator;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.util.TypeUtil;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/* ------------------------------------------------------------ */
/**
*/
public class HpackDecoderTest
{
@Test
@ -55,7 +52,6 @@ public class HpackDecoderTest
assertEquals("www.example.com",request.getURI().getHost());
assertFalse(request.iterator().hasNext());
// Second request
encoded="828684be58086e6f2d6361636865";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
@ -71,7 +67,6 @@ public class HpackDecoderTest
assertEquals(new HttpField("cache-control","no-cache"),iterator.next());
assertFalse(iterator.hasNext());
// Third request
encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
@ -119,7 +114,49 @@ public class HpackDecoderTest
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());
}
}