encoder headers as lowercase
This commit is contained in:
parent
e115dee62f
commit
140e7ed0c5
|
@ -319,7 +319,7 @@ public class HpackContext
|
|||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(String.format("RefSet[%x] remove unused",hashCode(),entry));
|
||||
LOG.debug(String.format("RefSet[%x] remove unused %s",hashCode(),entry));
|
||||
// encode the reference to remove it
|
||||
buffer.put((byte)0x80);
|
||||
NBitInteger.encode(buffer,7,index(entry));
|
||||
|
@ -339,7 +339,7 @@ public class HpackContext
|
|||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(String.format("RefSet[%x] emit unref",hashCode(),entry));
|
||||
LOG.debug(String.format("RefSet[%x] emit unref %s",hashCode(),entry));
|
||||
builder.emit(entry.getHttpField());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.hpack;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.BadMessageException;
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
@ -132,6 +133,14 @@ public class HpackDecoder
|
|||
name=Huffman.decode(buffer,length);
|
||||
else
|
||||
name=toASCIIString(buffer,length);
|
||||
for (int i=0;i<name.length();i++)
|
||||
{
|
||||
char c=name.charAt(i);
|
||||
if (c>='A'&&c<='Z')
|
||||
{
|
||||
throw new BadMessageException(400,"Uppercase header name");
|
||||
}
|
||||
}
|
||||
header=HttpHeader.CACHE.get(name);
|
||||
}
|
||||
|
||||
|
|
|
@ -302,10 +302,10 @@ public class HpackEncoder
|
|||
NBitInteger.encode(buffer,name_bits,_context.index(name_entry));
|
||||
else
|
||||
{
|
||||
// Encode the name always with huffman
|
||||
// Encode the name always with lowercase huffman
|
||||
buffer.put((byte)0x80);
|
||||
NBitInteger.encode(buffer,7,Huffman.octetsNeeded(field.getName()));
|
||||
Huffman.encode(buffer,field.getName());
|
||||
NBitInteger.encode(buffer,7,Huffman.octetsNeededLC(field.getName()));
|
||||
Huffman.encodeLC(buffer,field.getName());
|
||||
}
|
||||
|
||||
// Add the literal value
|
||||
|
@ -339,8 +339,6 @@ public class HpackEncoder
|
|||
if (new_entry!=null)
|
||||
_context.addToRefSet(new_entry);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (p>=0)
|
||||
|
|
|
@ -287,15 +287,21 @@ public class Huffman
|
|||
|
||||
};
|
||||
|
||||
static final int[][] LCCODES = new int[CODES.length][];
|
||||
|
||||
// Huffman decode tree stored in a flattened char array for good
|
||||
// locality of reference.
|
||||
static final char[] tree;
|
||||
static final char[] rowsym;
|
||||
static final byte[] rowbits;
|
||||
|
||||
// Build the Huffman lookup tree
|
||||
// Build the Huffman lookup tree and LC TABLE
|
||||
static
|
||||
{
|
||||
System.arraycopy(CODES,0,LCCODES,0,CODES.length);
|
||||
for (int i='A';i<='Z';i++)
|
||||
LCCODES[i]=LCCODES['a'+i-'A'];
|
||||
|
||||
int r=0;
|
||||
for (int i=0;i<CODES.length;i++)
|
||||
r+=(CODES[i][1]+7)/8;
|
||||
|
@ -339,12 +345,12 @@ public class Huffman
|
|||
}
|
||||
}
|
||||
|
||||
static public String decode(ByteBuffer buffer)
|
||||
public static String decode(ByteBuffer buffer)
|
||||
{
|
||||
return decode(buffer,buffer.remaining());
|
||||
}
|
||||
|
||||
static public String decode(ByteBuffer buffer,int length)
|
||||
public static String decode(ByteBuffer buffer,int length)
|
||||
{
|
||||
StringBuilder out = new StringBuilder(length*2);
|
||||
int node = 0;
|
||||
|
@ -398,7 +404,27 @@ public class Huffman
|
|||
return out.toString();
|
||||
}
|
||||
|
||||
static public int octetsNeeded(String s)
|
||||
public static int octetsNeeded(String s)
|
||||
{
|
||||
return octetsNeeded(CODES,s);
|
||||
}
|
||||
|
||||
public static void encode(ByteBuffer buffer,String s)
|
||||
{
|
||||
encode(CODES,buffer,s);
|
||||
}
|
||||
|
||||
public static int octetsNeededLC(String s)
|
||||
{
|
||||
return octetsNeeded(LCCODES,s);
|
||||
}
|
||||
|
||||
public static void encodeLC(ByteBuffer buffer, String s)
|
||||
{
|
||||
encode(LCCODES,buffer,s);
|
||||
}
|
||||
|
||||
private static int octetsNeeded(final int[][] table,String s)
|
||||
{
|
||||
int needed=0;
|
||||
int len = s.length();
|
||||
|
@ -407,13 +433,13 @@ public class Huffman
|
|||
char c=s.charAt(i);
|
||||
if (c>=128 || c<' ')
|
||||
throw new IllegalArgumentException();
|
||||
needed += CODES[c][1];
|
||||
needed += table[c][1];
|
||||
}
|
||||
|
||||
return (needed+7) / 8;
|
||||
}
|
||||
|
||||
static public void encode(ByteBuffer buffer,String s)
|
||||
private static void encode(final int[][] table,ByteBuffer buffer,String s)
|
||||
{
|
||||
long current = 0;
|
||||
int n = 0;
|
||||
|
@ -427,8 +453,8 @@ public class Huffman
|
|||
char c=s.charAt(i);
|
||||
if (c>=128 || c<' ')
|
||||
throw new IllegalArgumentException();
|
||||
int code = CODES[c][0];
|
||||
int bits = CODES[c][1];
|
||||
int code = table[c][0];
|
||||
int bits = table[c][1];
|
||||
|
||||
current <<= bits;
|
||||
current |= code;
|
||||
|
@ -450,4 +476,5 @@ public class Huffman
|
|||
|
||||
buffer.position(p-buffer.arrayOffset());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class MetaDataBuilder
|
|||
HttpFields _fields = new HttpFields(10);
|
||||
|
||||
public void emit(HttpField field)
|
||||
{
|
||||
{
|
||||
if (field instanceof StaticValueHttpField)
|
||||
{
|
||||
StaticValueHttpField value = (StaticValueHttpField)field;
|
||||
|
|
|
@ -67,7 +67,7 @@ public class HpackTest
|
|||
fields1.add(HttpHeader.CONTENT_TYPE,"text/plain");
|
||||
fields1.add(HttpHeader.CONTENT_LENGTH,"1234");
|
||||
fields1.add(HttpHeader.SERVER,"jetty");
|
||||
fields1.add("custom-key","other-value");
|
||||
fields1.add("Custom-Key","Other-Value");
|
||||
Response original1 = new Response(HttpVersion.HTTP_2,200,fields1);
|
||||
|
||||
// Same again?
|
||||
|
@ -77,7 +77,7 @@ public class HpackTest
|
|||
Response decoded1 = (Response)decoder.decode(buffer);
|
||||
|
||||
Assert.assertEquals(original1,decoded1);
|
||||
|
||||
Assert.assertEquals("custom-key",decoded1.getFields().getField("Custom-Key").getName());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpChannelOverHTTP2.class);
|
||||
private static final HttpField ACCEPT_ENCODING_GZIP = new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip");
|
||||
private static final HttpField SERVER_VERSION=new HttpField(HttpHeader.SERVER,HttpConfiguration.SERVER_VERSION);
|
||||
private static final HttpField POWERED_BY=new HttpField(HttpHeader.X_POWERED_BY,HttpConfiguration.SERVER_VERSION);
|
||||
private final Stream stream;
|
||||
|
||||
public HttpChannelOverHTTP2(Connector connector, HttpConfiguration configuration, EndPoint endPoint, HttpTransport transport, HttpInput input, Stream stream)
|
||||
|
@ -69,6 +71,13 @@ public class HttpChannelOverHTTP2 extends HttpChannel
|
|||
if (!fields.contains(HttpHeader.ACCEPT_ENCODING, "gzip"))
|
||||
fields.add(ACCEPT_ENCODING_GZIP);
|
||||
|
||||
|
||||
// TODO make this a better field for h2 hpack generation
|
||||
if (getHttpConfiguration().getSendServerVersion())
|
||||
getResponse().getHttpFields().add(SERVER_VERSION);
|
||||
if (getHttpConfiguration().getSendXPoweredBy())
|
||||
getResponse().getHttpFields().add(POWERED_BY);
|
||||
|
||||
onRequest(request);
|
||||
|
||||
if (frame.isEndStream())
|
||||
|
|
|
@ -21,8 +21,10 @@ package org.eclipse.jetty.http2.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
@ -116,7 +118,10 @@ public class Http2Server
|
|||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
HttpSession session = request.getSession(true);
|
||||
response.setHeader("custom","value");
|
||||
if (session.isNew())
|
||||
response.addCookie(new Cookie("bigcookie",
|
||||
"This is a test cookies that was created on "+new Date()+" and is used by the jetty http/2 test servlet."));
|
||||
response.setHeader("Custom","Value");
|
||||
response.setContentType("text/plain");
|
||||
String content = "Hello from Jetty using "+request.getProtocol() +"\n";
|
||||
content+="uri="+request.getRequestURI()+"\n";
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.http2.LEVEL=INFO
|
||||
org.eclipse.jetty.http2.hpack.LEVEL=DEBUG
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ public class Jetty
|
|||
pkg.getImplementationVersion() != null)
|
||||
VERSION = pkg.getImplementationVersion();
|
||||
else
|
||||
VERSION = System.getProperty("jetty.version", "9.2.z-SNAPSHOT");
|
||||
VERSION = System.getProperty("jetty.version", "9.3.z-SNAPSHOT");
|
||||
}
|
||||
|
||||
private Jetty()
|
||||
|
|
Loading…
Reference in New Issue