459845 - Support upgrade from http1 to http2

Parse setting frame.
This commit is contained in:
Greg Wilkins 2015-03-13 00:54:33 +11:00
parent e9658c0aef
commit b7d719be5f
3 changed files with 135 additions and 17 deletions

View File

@ -43,7 +43,7 @@ public class SettingsBodyParser extends BodyParser
super(headerParser, listener);
}
private void reset()
protected void reset()
{
state = State.PREPARE;
cursor = 0;
@ -157,7 +157,7 @@ public class SettingsBodyParser extends BodyParser
return false;
}
private boolean onSettings(Map<Integer, Integer> settings)
protected boolean onSettings(Map<Integer, Integer> settings)
{
SettingsFrame frame = new SettingsFrame(settings, hasFlag(Flags.ACK));
reset();

View File

@ -24,6 +24,7 @@ import java.util.Map;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.Flags;
import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.IStream;
import org.eclipse.jetty.http2.api.Session;
@ -34,12 +35,14 @@ import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.parser.SettingsBodyParser;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.NegotiatingServerConnection.CipherDiscriminator;
import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.annotation.Name;
@ -76,26 +79,52 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
@Override
public Connection newConnection(Connector connector, EndPoint endPoint, Object attachment)
{
Connection connection = super.newConnection(connector,endPoint,attachment);
HTTP2ServerConnection connection = (HTTP2ServerConnection)super.newConnection(connector,endPoint,attachment);
if (attachment instanceof MetaData.Request)
{
MetaData.Request request = (MetaData.Request) attachment;
if (LOG.isDebugEnabled())
LOG.debug("{} upgraded {}",this,request.toString()+request.getFields());
// TODO work out why _ needs replacing?
byte[] settings = B64Code.decode(request.getFields().getField(HttpHeader.HTTP2_SETTINGS).getValue().replace('_', '='));
final byte[] settings = B64Code.decodeRFC4648URL(request.getFields().getField(HttpHeader.HTTP2_SETTINGS).getValue());
if (LOG.isDebugEnabled())
LOG.debug("{} settings {}",this, TypeUtil.toHexString(settings));
// TODO process the settings frame
LOG.debug("{} settings {}",this,TypeUtil.toHexString(settings));
SettingsBodyParser parser = new SettingsBodyParser(null,null)
{
@Override
protected int getStreamId()
{
return 0;
}
@Override
protected int getBodyLength()
{
return settings.length;
}
@Override
protected boolean onSettings(Map<Integer, Integer> settings)
{
SettingsFrame frame = new SettingsFrame(settings, false);
// TODO something with this frame?
reset();
return true;
}
};
parser.parse(BufferUtil.toBuffer(settings));
// TODO use the metadata to push a response
}
return connection;
}
private class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener
{
@ -170,4 +199,5 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
session.close(ErrorCode.PROTOCOL_ERROR.code, reason, Callback.Adapter.INSTANCE);
}
}
}

View File

@ -35,12 +35,12 @@ public class B64Code
{
private static final char __pad='=';
private static final char[] __rfc1421alphabet=
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
private static final byte[] __rfc1421nibbles;
static
@ -52,6 +52,25 @@ public class B64Code
__rfc1421nibbles[(byte)__rfc1421alphabet[b]]=b;
__rfc1421nibbles[(byte)__pad]=0;
}
private static final char[] __rfc4648urlAlphabet=
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_'
};
private static final byte[] __rfc4648urlNibbles;
static
{
__rfc4648urlNibbles=new byte[256];
for (int i=0;i<256;i++)
__rfc4648urlNibbles[i]=-1;
for (byte b=0;b<64;b++)
__rfc4648urlNibbles[(byte)__rfc4648urlAlphabet[b]]=b;
__rfc4648urlNibbles[(byte)__pad]=0;
}
private B64Code()
{
@ -430,6 +449,75 @@ public class B64Code
return;
}
/* ------------------------------------------------------------ */
public static byte[] decodeRFC4648URL(String encoded)
{
if (encoded==null)
return null;
ByteArrayOutputStream bout = new ByteArrayOutputStream(4*encoded.length()/3);
decodeRFC4648URL(encoded, bout);
return bout.toByteArray();
}
/* ------------------------------------------------------------ */
/**
* Base 64 decode as described in RFC 4648 URL.
* <p>Unlike {@link #decode(char[])}, extra whitespace is ignored.
* @param encoded String to decode.
* @param bout stream for decoded bytes
* @throws IllegalArgumentException if the input is not a valid
* B64 encoding.
*/
static public void decodeRFC4648URL (String encoded, ByteArrayOutputStream bout)
{
if (encoded==null)
return;
if (bout == null)
throw new IllegalArgumentException("No outputstream for decoded bytes");
int ci=0;
byte nibbles[] = new byte[4];
int s=0;
while (ci<encoded.length())
{
char c=encoded.charAt(ci++);
if (c==__pad)
break;
if (Character.isWhitespace(c))
continue;
byte nibble=__rfc4648urlNibbles[c];
if (nibble<0)
throw new IllegalArgumentException("Not B64 encoded");
nibbles[s++]=__rfc4648urlNibbles[c];
switch(s)
{
case 1:
break;
case 2:
bout.write(nibbles[0]<<2|nibbles[1]>>>4);
break;
case 3:
bout.write(nibbles[1]<<4|nibbles[2]>>>2);
break;
case 4:
bout.write(nibbles[2]<<6|nibbles[3]);
s=0;
break;
}
}
return;
}
public static void encode(int value,Appendable buf) throws IOException
{