Merged branch 'jetty-9.3.x' into 'master'.

This commit is contained in:
Simone Bordet 2015-10-20 23:23:25 +02:00
commit 5c8c590398
6 changed files with 103 additions and 62 deletions

View File

@ -31,23 +31,20 @@ import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** /**
* Hpack Decoder * 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 public class HpackDecoder
{ {
public static final Logger LOG = Log.getLogger(HpackDecoder.class); public static final Logger LOG = Log.getLogger(HpackDecoder.class);
public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 = public final static HttpField.LongValueHttpField CONTENT_LENGTH_0 =
new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L); new HttpField.LongValueHttpField(HttpHeader.CONTENT_LENGTH,0L);
private final HpackContext _context; private final HpackContext _context;
private final MetaDataBuilder _builder; private final MetaDataBuilder _builder;
private int _localMaxDynamicTableSize; private int _localMaxDynamicTableSize;
/* ------------------------------------------------------------ */
/** /**
* @param localMaxDynamicTableSize The maximum allowed size of the local dynamic header field table. * @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. * @param maxHeaderSize The maximum allowed size of a headers block, expressed as total of all name and value characters.
@ -58,36 +55,38 @@ public class HpackDecoder
_localMaxDynamicTableSize=localMaxDynamicTableSize; _localMaxDynamicTableSize=localMaxDynamicTableSize;
_builder = new MetaDataBuilder(maxHeaderSize); _builder = new MetaDataBuilder(maxHeaderSize);
} }
public HpackContext getHpackContext() public HpackContext getHpackContext()
{ {
return _context; return _context;
} }
public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize) public void setLocalMaxDynamicTableSize(int localMaxdynamciTableSize)
{ {
_localMaxDynamicTableSize=localMaxdynamciTableSize; _localMaxDynamicTableSize=localMaxdynamciTableSize;
} }
public MetaData decode(ByteBuffer buffer) public MetaData decode(ByteBuffer buffer)
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug(String.format("CtxTbl[%x] decoding %d octets",_context.hashCode(),buffer.remaining())); 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 the buffer is big, don't even think about decoding it
if (buffer.remaining()>_builder.getMaxSize()) if (buffer.remaining()>_builder.getMaxSize())
throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize()); throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header frame size "+buffer.remaining()+">"+_builder.getMaxSize());
while(buffer.hasRemaining()) while(buffer.hasRemaining())
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
{ {
int l=Math.min(buffer.remaining(),16); int l=Math.min(buffer.remaining(),16);
// TODO: not guaranteed the buffer has a backing array ! // 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(); byte b = buffer.get();
if (b<0) if (b<0)
{ {
@ -104,7 +103,7 @@ public class HpackDecoder
LOG.debug("decode IdxStatic {}",entry); LOG.debug("decode IdxStatic {}",entry);
// emit field // emit field
_builder.emit(entry.getHttpField()); _builder.emit(entry.getHttpField());
// TODO copy and add to reference set if there is room // TODO copy and add to reference set if there is room
// _context.add(entry.getHttpField()); // _context.add(entry.getHttpField());
} }
@ -116,7 +115,7 @@ public class HpackDecoder
_builder.emit(entry.getHttpField()); _builder.emit(entry.getHttpField());
} }
} }
else else
{ {
// look at the first nibble in detail // look at the first nibble in detail
byte f= (byte)((b&0xF0)>>4); byte f= (byte)((b&0xF0)>>4);
@ -126,7 +125,7 @@ public class HpackDecoder
boolean indexed; boolean indexed;
int name_index; int name_index;
switch (f) switch (f)
{ {
case 2: // 7.3 case 2: // 7.3
@ -139,14 +138,14 @@ public class HpackDecoder
throw new IllegalArgumentException(); throw new IllegalArgumentException();
_context.resize(size); _context.resize(size);
continue; continue;
case 0: // 7.2.2 case 0: // 7.2.2
case 1: // 7.2.3 case 1: // 7.2.3
indexed=false; indexed=false;
name_index=NBitInteger.decode(buffer,4); name_index=NBitInteger.decode(buffer,4);
break; break;
case 4: // 7.2.1 case 4: // 7.2.1
case 5: // 7.2.1 case 5: // 7.2.1
case 6: // 7.2.1 case 6: // 7.2.1
@ -154,7 +153,7 @@ public class HpackDecoder
indexed=true; indexed=true;
name_index=NBitInteger.decode(buffer,6); name_index=NBitInteger.decode(buffer,6);
break; break;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -236,7 +235,13 @@ public class HpackDecoder
} }
if (LOG.isDebugEnabled()) 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 // emit the field
_builder.emit(field); _builder.emit(field);
@ -250,22 +255,23 @@ public class HpackDecoder
} }
} }
return _builder.build(); return _builder.build();
} }
public static String toASCIIString(ByteBuffer buffer,int length) public static String toASCIIString(ByteBuffer buffer,int length)
{ {
StringBuilder builder = new StringBuilder(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; int end=start+length;
buffer.position(end); buffer.position(position+length);
byte[] array=buffer.array(); byte[] array=buffer.array();
for (int i=start;i<end;i++) for (int i=start;i<end;i++)
builder.append((char)(0x7f&array[i])); builder.append((char)(0x7f&array[i]));
return builder.toString(); return builder.toString();
} }
@Override @Override
public String toString() public String toString()
{ {

View File

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

View File

@ -19,47 +19,43 @@
package org.eclipse.jetty.http2.hpack; 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.nio.ByteBuffer;
import java.util.Iterator; import java.util.Iterator;
import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.TypeUtil;
import org.junit.Test; 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 public class HpackDecoderTest
{ {
@Test @Test
public void testDecodeD_3() public void testDecodeD_3()
{ {
HpackDecoder decoder = new HpackDecoder(4096,8192); HpackDecoder decoder = new HpackDecoder(4096,8192);
// First request // First request
String encoded="828684410f7777772e6578616d706c652e636f6d"; String encoded="828684410f7777772e6578616d706c652e636f6d";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData.Request request = (MetaData.Request)decoder.decode(buffer); MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod()); assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
assertEquals("/",request.getURI().getPath()); assertEquals("/",request.getURI().getPath());
assertEquals("www.example.com",request.getURI().getHost()); assertEquals("www.example.com",request.getURI().getHost());
assertFalse(request.iterator().hasNext()); assertFalse(request.iterator().hasNext());
// Second request // Second request
encoded="828684be58086e6f2d6361636865"; encoded="828684be58086e6f2d6361636865";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer); request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod()); assertEquals("GET", request.getMethod());
@ -70,14 +66,13 @@ public class HpackDecoderTest
assertTrue(iterator.hasNext()); assertTrue(iterator.hasNext());
assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next());
assertFalse(iterator.hasNext()); assertFalse(iterator.hasNext());
// Third request // Third request
encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565"; encoded="828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer); request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET",request.getMethod()); assertEquals("GET",request.getMethod());
assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme()); assertEquals(HttpScheme.HTTPS.asString(),request.getURI().getScheme());
assertEquals("/index.html",request.getURI().getPath()); assertEquals("/index.html",request.getURI().getPath());
@ -92,23 +87,23 @@ public class HpackDecoderTest
public void testDecodeD_4() public void testDecodeD_4()
{ {
HpackDecoder decoder = new HpackDecoder(4096,8192); HpackDecoder decoder = new HpackDecoder(4096,8192);
// First request // First request
String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff"; String encoded="828684418cf1e3c2e5f23a6ba0ab90f4ff";
ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); ByteBuffer buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
MetaData.Request request = (MetaData.Request)decoder.decode(buffer); MetaData.Request request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod()); assertEquals("GET", request.getMethod());
assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme()); assertEquals(HttpScheme.HTTP.asString(),request.getURI().getScheme());
assertEquals("/",request.getURI().getPath()); assertEquals("/",request.getURI().getPath());
assertEquals("www.example.com",request.getURI().getHost()); assertEquals("www.example.com",request.getURI().getHost());
assertFalse(request.iterator().hasNext()); assertFalse(request.iterator().hasNext());
// Second request // Second request
encoded="828684be5886a8eb10649cbf"; encoded="828684be5886a8eb10649cbf";
buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded)); buffer = ByteBuffer.wrap(TypeUtil.fromHexString(encoded));
request = (MetaData.Request)decoder.decode(buffer); request = (MetaData.Request)decoder.decode(buffer);
assertEquals("GET", request.getMethod()); assertEquals("GET", request.getMethod());
@ -119,7 +114,49 @@ public class HpackDecoderTest
assertTrue(iterator.hasNext()); assertTrue(iterator.hasNext());
assertEquals(new HttpField("cache-control","no-cache"),iterator.next()); assertEquals(new HttpField("cache-control","no-cache"),iterator.next());
assertFalse(iterator.hasNext()); 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());
}
} }

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue; import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.HttpVersion;
@ -129,6 +130,8 @@ class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandl
if (!_metadata.getURI().isAbsolute() && field instanceof HostPortHttpField) if (!_metadata.getURI().isAbsolute() && field instanceof HostPortHttpField)
{ {
HostPortHttpField hp = (HostPortHttpField)field; HostPortHttpField hp = (HostPortHttpField)field;
// Set scheme default value as 'http' (can be overridden later in SecureRequestCustomizer)
_metadata.getURI().setScheme(HttpScheme.HTTP.asString());
_metadata.getURI().setAuthority(hp.getHost(),hp.getPort()); _metadata.getURI().setAuthority(hp.getHost(),hp.getPort());
} }
break; break;

View File

@ -553,7 +553,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
@Override @Override
public String toString() public String toString()
{ {
return String.format("%s[p=%s,g=%s,c=%s][b=%s]", return String.format("%s[p=%s,g=%s,c=%s]",
super.toString(), super.toString(),
_parser, _parser,
_generator, _generator,

View File

@ -68,13 +68,7 @@ public class DebugHandler extends HandlerWrapper implements Connection.Listener
boolean retry=false; boolean retry=false;
String name=(String)request.getAttribute("org.eclipse.jetty.thread.name"); String name=(String)request.getAttribute("org.eclipse.jetty.thread.name");
if (name == null) if (name == null)
{ name = old_name + ":" + baseRequest.getHttpURI();
HttpURI baseUri = baseRequest.getHttpURI();
if (baseUri.getScheme() == null)
name = old_name + ":" + baseRequest.getScheme() + ":" + baseUri.toString();
else
name = old_name + ":" + baseUri.toString();
}
else else
retry=true; retry=true;