@Override public boolean parsedHeader(HttpField field) { if (field.getHeader() == HttpHeader.HOST) headers.put(HTTPSPDYHeader.HOST.name(version), field.getValue()); else headers.put(field.getName(), field.getValue()); return false; }
@Test public void testSYNThenREPLYAndDATA() throws Exception { final byte[] data = "0123456789ABCDEF".getBytes("UTF-8"); final String header = "foo"; InetSocketAddress proxyAddress = startProxy( startServer( new ServerSessionFrameListener.Adapter() { @Override public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) { Fields requestHeaders = synInfo.getHeaders(); Assert.assertNotNull(requestHeaders.get("via")); Assert.assertNotNull(requestHeaders.get(header)); Fields responseHeaders = new Fields(); responseHeaders.put(header, "baz"); stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); return null; } })); proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); Session client = factory.newSPDYClient(version).connect(proxyAddress, null).get(5, TimeUnit.SECONDS); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); Fields headers = new Fields(); headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); headers.put(header, "bar"); client.syn( new SynInfo(headers, true), new StreamFrameListener.Adapter() { private final ByteArrayOutputStream result = new ByteArrayOutputStream(); @Override public void onReply(Stream stream, ReplyInfo replyInfo) { Fields headers = replyInfo.getHeaders(); Assert.assertNotNull(headers.get(header)); replyLatch.countDown(); } @Override public void onData(Stream stream, DataInfo dataInfo) { result.write(dataInfo.asBytes(true), 0, dataInfo.length()); if (dataInfo.isClose()) { Assert.assertArrayEquals(data, result.toByteArray()); dataLatch.countDown(); } } }); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); }
@Test public void testSYNThenReset() throws Exception { InetSocketAddress proxyAddress = startProxy( startServer( new ServerSessionFrameListener.Adapter() { @Override public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) { Assert.assertTrue(synInfo.isClose()); Fields requestHeaders = synInfo.getHeaders(); Assert.assertNotNull(requestHeaders.get("via")); stream .getSession() .rst( new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter()); return null; } })); proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); final CountDownLatch resetLatch = new CountDownLatch(1); Session client = factory .newSPDYClient(version) .connect( proxyAddress, new SessionFrameListener.Adapter() { @Override public void onRst(Session session, RstInfo rstInfo) { resetLatch.countDown(); } }) .get(5, TimeUnit.SECONDS); Fields headers = new Fields(); headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); client.syn(new SynInfo(headers, true), null); Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS)); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); }
@Test public void testSYNThenREPLY() throws Exception { final String header = "foo"; InetSocketAddress proxyAddress = startProxy( startServer( new ServerSessionFrameListener.Adapter() { @Override public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) { Fields requestHeaders = synInfo.getHeaders(); Assert.assertNotNull(requestHeaders.get("via")); Assert.assertNotNull(requestHeaders.get(header)); Fields responseHeaders = new Fields(); responseHeaders.put(header, "baz"); stream.reply(new ReplyInfo(responseHeaders, true), new Callback.Adapter()); return null; } })); proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); Session client = factory.newSPDYClient(version).connect(proxyAddress, null).get(5, TimeUnit.SECONDS); final CountDownLatch replyLatch = new CountDownLatch(1); Fields headers = new Fields(); headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); headers.put(header, "bar"); client.syn( new SynInfo(headers, true), new StreamFrameListener.Adapter() { @Override public void onReply(Stream stream, ReplyInfo replyInfo) { Fields headers = replyInfo.getHeaders(); Assert.assertNotNull(headers.get(header)); replyLatch.countDown(); } }); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); }
@Override public void reply(ReplyInfo replyInfo, Callback handler) { try { Fields headers = new Fields(replyInfo.getHeaders(), false); headers.remove(HTTPSPDYHeader.SCHEME.name(version)); String status = headers.remove(HTTPSPDYHeader.STATUS.name(version)).value(); Matcher matcher = statusRegexp.matcher(status); matcher.matches(); int code = Integer.parseInt(matcher.group(1)); String reason = matcher.group(2).trim(); HttpVersion httpVersion = HttpVersion.fromString(headers.remove(HTTPSPDYHeader.VERSION.name(version)).value()); // Convert the Host header from a SPDY special header to a normal header Fields.Field host = headers.remove(HTTPSPDYHeader.HOST.name(version)); if (host != null) headers.put("host", host.value()); HttpFields fields = new HttpFields(); for (Fields.Field header : headers) { String name = camelize(header.name()); fields.put(name, header.value()); } // TODO: handle better the HEAD last parameter HttpGenerator.ResponseInfo info = new HttpGenerator.ResponseInfo(httpVersion, fields, -1, code, reason, false); send(info, null, replyInfo.isClose()); if (replyInfo.isClose()) completed(); handler.succeeded(); } catch (IOException x) { handler.failed(x); } }
@Test public void testSYNThenSPDYNestedPushIsReceived() throws Exception { final byte[] data = "0123456789ABCDEF".getBytes("UTF-8"); InetSocketAddress proxyAddress = startProxy( startServer( new ServerSessionFrameListener.Adapter() { @Override public StreamFrameListener onSyn(Stream stream, SynInfo synInfo) { Fields responseHeaders = new Fields(); responseHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1"); responseHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200 OK"); stream.reply(new ReplyInfo(responseHeaders, false), new Callback.Adapter()); final Fields pushHeaders = new Fields(); pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/push"); stream.push( new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Promise.Adapter<Stream>() { @Override public void succeeded(Stream pushStream) { pushHeaders.put(HTTPSPDYHeader.URI.name(version), "/nestedpush"); pushStream.push( new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>() { @Override public void succeeded(Stream pushStream) { pushHeaders.put( HTTPSPDYHeader.URI.name(version), "/anothernestedpush"); pushStream.push( new PushInfo(5, TimeUnit.SECONDS, pushHeaders, false), new Adapter<Stream>() { @Override public void succeeded(Stream pushStream) { pushStream.data( new BytesDataInfo(data, true), new Callback.Adapter()); } }); pushStream.data( new BytesDataInfo(data, true), new Callback.Adapter()); } }); pushStream.data(new BytesDataInfo(data, true), new Callback.Adapter()); } }); stream.data(new BytesDataInfo(data, true), new Callback.Adapter()); return null; } })); proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version)); final CountDownLatch pushSynLatch = new CountDownLatch(3); final CountDownLatch pushDataLatch = new CountDownLatch(3); Session client = factory.newSPDYClient(version).connect(proxyAddress, null).get(5, TimeUnit.SECONDS); Fields headers = new Fields(); headers.put(HTTPSPDYHeader.HOST.name(version), "localhost:" + proxyAddress.getPort()); final CountDownLatch replyLatch = new CountDownLatch(1); final CountDownLatch dataLatch = new CountDownLatch(1); client.syn( new SynInfo(headers, true), new StreamFrameListener.Adapter() { // onPush for 1st push stream @Override public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) { pushSynLatch.countDown(); return new StreamFrameListener.Adapter() { // onPush for 2nd nested push stream @Override public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) { pushSynLatch.countDown(); return new Adapter() { // onPush for 3rd nested push stream @Override public StreamFrameListener onPush(Stream stream, PushInfo pushInfo) { pushSynLatch.countDown(); return new Adapter() { @Override public void onData(Stream stream, DataInfo dataInfo) { dataInfo.consume(dataInfo.length()); if (dataInfo.isClose()) pushDataLatch.countDown(); } }; } @Override public void onData(Stream stream, DataInfo dataInfo) { dataInfo.consume(dataInfo.length()); if (dataInfo.isClose()) pushDataLatch.countDown(); } }; } @Override public void onData(Stream stream, DataInfo dataInfo) { dataInfo.consume(dataInfo.length()); if (dataInfo.isClose()) pushDataLatch.countDown(); } }; } @Override public void onReply(Stream stream, ReplyInfo replyInfo) { replyLatch.countDown(); } @Override public void onData(Stream stream, DataInfo dataInfo) { dataInfo.consume(dataInfo.length()); if (dataInfo.isClose()) dataLatch.countDown(); } }); Assert.assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(pushSynLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(pushDataLatch.await(5, TimeUnit.SECONDS)); Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS)); }