Fix application protocol to make it work with utf8

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2021-09-28 16:25:48 +02:00 committed by Simone Bordet
parent 2e98931654
commit b09191d2f8
3 changed files with 42 additions and 19 deletions

View File

@ -17,6 +17,7 @@ import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.ArrayList; import java.util.ArrayList;
@ -45,6 +46,7 @@ public class QuicheConnection
{ {
private static final Logger LOG = LoggerFactory.getLogger(QuicheConnection.class); private static final Logger LOG = LoggerFactory.getLogger(QuicheConnection.class);
private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final Charset APPLICATION_PROTOCOL_CHARSET = StandardCharsets.UTF_8;
static static
{ {
@ -103,9 +105,9 @@ public class QuicheConnection
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (String proto : applicationProtos) for (String proto : applicationProtos)
sb.append((char)proto.length()).append(proto); sb.append((char)proto.getBytes(APPLICATION_PROTOCOL_CHARSET).length).append(proto);
String theProtos = sb.toString(); String theProtos = sb.toString();
LibQuiche.INSTANCE.quiche_config_set_application_protos(quicheConfig, theProtos, new size_t(theProtos.length())); LibQuiche.INSTANCE.quiche_config_set_application_protos(quicheConfig, theProtos, new size_t(theProtos.getBytes(APPLICATION_PROTOCOL_CHARSET).length));
} }
QuicheConfig.CongestionControl cc = config.getCongestionControl(); QuicheConfig.CongestionControl cc = config.getCongestionControl();
@ -473,7 +475,7 @@ public class QuicheConnection
char_pointer out = new char_pointer(); char_pointer out = new char_pointer();
size_t_pointer outLen = new size_t_pointer(); size_t_pointer outLen = new size_t_pointer();
LibQuiche.INSTANCE.quiche_conn_application_proto(quicheConn, out, outLen); LibQuiche.INSTANCE.quiche_conn_application_proto(quicheConn, out, outLen);
return out.getValueAsString((int)outLen.getValue(), StandardCharsets.UTF_8); return out.getValueAsString((int)outLen.getValue(), APPLICATION_PROTOCOL_CHARSET);
} }
} }

View File

@ -1,6 +1,6 @@
git clone --recursive https://github.com/cloudflare/quiche git clone --recursive https://github.com/cloudflare/quiche
cd quiche cd quiche
git checkout -b tag-0.9.0 tags/0.9.0 git checkout -b tag-0.10.0 tags/0.10.0
cargo build --features ffi cargo build --features ffi
ls ./target/debug/libquiche.so ls ./target/debug/libquiche.so

View File

@ -17,6 +17,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
@ -41,7 +42,7 @@ public class LowLevelQuicheTest
private InetSocketAddress clientSocketAddress; private InetSocketAddress clientSocketAddress;
private InetSocketAddress serverSocketAddress; private InetSocketAddress serverSocketAddress;
private QuicheConfig quicheClientConfig; private QuicheConfig clientQuicheConfig;
private QuicheConfig serverQuicheConfig; private QuicheConfig serverQuicheConfig;
private QuicheConnection.TokenMinter tokenMinter; private QuicheConnection.TokenMinter tokenMinter;
private QuicheConnection.TokenValidator tokenValidator; private QuicheConnection.TokenValidator tokenValidator;
@ -52,18 +53,18 @@ public class LowLevelQuicheTest
clientSocketAddress = new InetSocketAddress("localhost", 9999); clientSocketAddress = new InetSocketAddress("localhost", 9999);
serverSocketAddress = new InetSocketAddress("localhost", 8888); serverSocketAddress = new InetSocketAddress("localhost", 8888);
quicheClientConfig = new QuicheConfig(); clientQuicheConfig = new QuicheConfig();
quicheClientConfig.setApplicationProtos("http/0.9"); clientQuicheConfig.setApplicationProtos("http/0.9");
quicheClientConfig.setDisableActiveMigration(true); clientQuicheConfig.setDisableActiveMigration(true);
quicheClientConfig.setVerifyPeer(false); clientQuicheConfig.setVerifyPeer(false);
quicheClientConfig.setMaxIdleTimeout(1_000L); clientQuicheConfig.setMaxIdleTimeout(1_000L);
quicheClientConfig.setInitialMaxData(10_000_000L); clientQuicheConfig.setInitialMaxData(10_000_000L);
quicheClientConfig.setInitialMaxStreamDataBidiLocal(10_000_000L); clientQuicheConfig.setInitialMaxStreamDataBidiLocal(10_000_000L);
quicheClientConfig.setInitialMaxStreamDataBidiRemote(10_000_000L); clientQuicheConfig.setInitialMaxStreamDataBidiRemote(10_000_000L);
quicheClientConfig.setInitialMaxStreamDataUni(10_000_000L); clientQuicheConfig.setInitialMaxStreamDataUni(10_000_000L);
quicheClientConfig.setInitialMaxStreamsUni(100L); clientQuicheConfig.setInitialMaxStreamsUni(100L);
quicheClientConfig.setInitialMaxStreamsBidi(100L); clientQuicheConfig.setInitialMaxStreamsBidi(100L);
quicheClientConfig.setCongestionControl(QuicheConfig.CongestionControl.RENO); clientQuicheConfig.setCongestionControl(QuicheConfig.CongestionControl.RENO);
SSLKeyPair serverKeyPair = new SSLKeyPair(Paths.get(Objects.requireNonNull(getClass().getResource("/keystore.p12")).toURI()).toFile(), "PKCS12", "storepwd".toCharArray(), "mykey", "storepwd".toCharArray()); SSLKeyPair serverKeyPair = new SSLKeyPair(Paths.get(Objects.requireNonNull(getClass().getResource("/keystore.p12")).toURI()).toFile(), "PKCS12", "storepwd".toCharArray(), "mykey", "storepwd".toCharArray());
File[] pemFiles = serverKeyPair.export(new File(System.getProperty("java.io.tmpdir"))); File[] pemFiles = serverKeyPair.export(new File(System.getProperty("java.io.tmpdir")));
@ -165,6 +166,21 @@ public class LowLevelQuicheTest
assertThat(serverQuicheConnection.isStreamFinished(0), is(true)); assertThat(serverQuicheConnection.isStreamFinished(0), is(true));
} }
@Test
public void testApplicationProtocol() throws Exception
{
serverQuicheConfig.setApplicationProtos("");
clientQuicheConfig.setApplicationProtos("");
// establish connection
Map.Entry<QuicheConnection, QuicheConnection> entry = connectClientToServer();
QuicheConnection clientQuicheConnection = entry.getKey();
QuicheConnection serverQuicheConnection = entry.getValue();
assertThat(clientQuicheConnection.getNegotiatedProtocol(), is(""));
assertThat(serverQuicheConnection.getNegotiatedProtocol(), is(""));
}
private void drainServerToFeedClient(Map.Entry<QuicheConnection, QuicheConnection> entry, int expectedSize) throws IOException private void drainServerToFeedClient(Map.Entry<QuicheConnection, QuicheConnection> entry, int expectedSize) throws IOException
{ {
QuicheConnection clientQuicheConnection = entry.getKey(); QuicheConnection clientQuicheConnection = entry.getKey();
@ -196,7 +212,7 @@ public class LowLevelQuicheTest
ByteBuffer buffer = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN); ByteBuffer buffer = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
ByteBuffer buffer2 = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN); ByteBuffer buffer2 = ByteBuffer.allocate(LibQuiche.QUICHE_MIN_CLIENT_INITIAL_LEN);
QuicheConnection clientQuicheConnection = QuicheConnection.connect(quicheClientConfig, serverSocketAddress); QuicheConnection clientQuicheConnection = QuicheConnection.connect(clientQuicheConfig, serverSocketAddress);
connectionsToDisposeOf.add(clientQuicheConnection); connectionsToDisposeOf.add(clientQuicheConnection);
int drained = clientQuicheConnection.drainCipherText(buffer); int drained = clientQuicheConnection.drainCipherText(buffer);
@ -234,7 +250,12 @@ public class LowLevelQuicheTest
AbstractMap.SimpleImmutableEntry<QuicheConnection, QuicheConnection> entry = new AbstractMap.SimpleImmutableEntry<>(clientQuicheConnection, serverQuicheConnection); AbstractMap.SimpleImmutableEntry<QuicheConnection, QuicheConnection> entry = new AbstractMap.SimpleImmutableEntry<>(clientQuicheConnection, serverQuicheConnection);
drainServerToFeedClient(entry, 309); StringBuilder sb = new StringBuilder();
for (String proto : clientQuicheConfig.getApplicationProtos())
sb.append((char)proto.getBytes(StandardCharsets.UTF_8).length).append(proto);
int protosLen = sb.toString().getBytes(StandardCharsets.UTF_8).length;
drainServerToFeedClient(entry, 300 + protosLen);
assertThat(serverQuicheConnection.isConnectionEstablished(), is(false)); assertThat(serverQuicheConnection.isConnectionEstablished(), is(false));
assertThat(clientQuicheConnection.isConnectionEstablished(), is(true)); assertThat(clientQuicheConnection.isConnectionEstablished(), is(true));