| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.spdy.server.http; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.nio.ByteBuffer; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Arrays; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import javax.servlet.AsyncContext; |
| import javax.servlet.AsyncEvent; |
| import javax.servlet.AsyncListener; |
| import javax.servlet.ServletException; |
| import javax.servlet.ServletOutputStream; |
| import javax.servlet.http.Cookie; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.eclipse.jetty.http.HttpHeader; |
| import org.eclipse.jetty.server.HttpChannel; |
| import org.eclipse.jetty.server.Request; |
| import org.eclipse.jetty.server.handler.AbstractHandler; |
| import org.eclipse.jetty.spdy.api.BytesDataInfo; |
| import org.eclipse.jetty.spdy.api.DataInfo; |
| import org.eclipse.jetty.spdy.api.ReplyInfo; |
| import org.eclipse.jetty.spdy.api.Session; |
| import org.eclipse.jetty.spdy.api.Stream; |
| import org.eclipse.jetty.spdy.api.StreamFrameListener; |
| import org.eclipse.jetty.spdy.api.StringDataInfo; |
| import org.eclipse.jetty.spdy.api.SynInfo; |
| import org.eclipse.jetty.spdy.http.HTTPSPDYHeader; |
| import org.eclipse.jetty.util.Fields; |
| import org.eclipse.jetty.util.log.StdErrLog; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| import static org.hamcrest.CoreMatchers.containsString; |
| import static org.hamcrest.CoreMatchers.is; |
| import static org.hamcrest.CoreMatchers.notNullValue; |
| import static org.hamcrest.core.IsInstanceOf.instanceOf; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest |
| { |
| public static final String SUSPENDED_ATTRIBUTE = ServerHTTPSPDYTest.class.getName() + ".SUSPENDED"; |
| |
| public ServerHTTPSPDYTest(short version) |
| { |
| super(version); |
| } |
| |
| @Test |
| public void testSimpleGET() throws Exception |
| { |
| final String path = "/foo"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("GET", httpRequest.getMethod()); |
| assertEquals(path, target); |
| assertEquals(path, httpRequest.getRequestURI()); |
| assertThat("accept-encoding is set to gzip, even if client didn't set it", |
| httpRequest.getHeader("accept-encoding"), containsString("gzip")); |
| assertThat(httpRequest.getHeader("host"), is("localhost:" + connector.getLocalPort())); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getLocalPort(), version, "GET", path); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertThat(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200"), is(true)); |
| assertThat(replyHeaders.get(HttpHeader.SERVER.asString()), is(notNullValue())); |
| assertThat(replyHeaders.get(HttpHeader.X_POWERED_BY.asString()), is(notNullValue())); |
| replyLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithQueryString() throws Exception |
| { |
| final String path = "/foo"; |
| final String query = "p=1"; |
| final String uri = path + "?" + query; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("GET", httpRequest.getMethod()); |
| assertEquals(path, target); |
| assertEquals(path, httpRequest.getRequestURI()); |
| assertEquals(query, httpRequest.getQueryString()); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithCookies() throws Exception |
| { |
| final String path = "/foo"; |
| final String uri = path; |
| final String cookie1 = "cookie1"; |
| final String cookie2 = "cookie2"; |
| final String cookie1Value = "cookie 1 value"; |
| final String cookie2Value = "cookie 2 value"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.addCookie(new Cookie(cookie1, cookie1Value)); |
| httpResponse.addCookie(new Cookie(cookie2, cookie2Value)); |
| assertThat("method is GET", httpRequest.getMethod(), is("GET")); |
| assertThat("target is /foo", target, is(path)); |
| assertThat("requestUri is /foo", httpRequest.getRequestURI(), is(path)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", uri); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertThat("isClose is true", replyInfo.isClose(), is(true)); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertThat("response code is 200 OK", replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue() |
| .contains("200"), is(true)); |
| assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(0), is(cookie1 + "=\"" + cookie1Value + |
| "\";Version=1")); |
| assertThat(replyInfo.getHeaders().get("Set-Cookie").getValues().get(1), is(cookie2 + "=\"" + cookie2Value + |
| "\";Version=1")); |
| replyLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testHEAD() throws Exception |
| { |
| final String path = "/foo"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("HEAD", httpRequest.getMethod()); |
| assertEquals(path, target); |
| assertEquals(path, httpRequest.getRequestURI()); |
| httpResponse.getWriter().write("body that shouldn't be sent on a HEAD request"); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "HEAD", path); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| fail("HEAD request shouldn't send any data"); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTWithDelayedContentBody() throws Exception |
| { |
| final String path = "/foo"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| // don't read the request body, reply immediately |
| request.setHandled(true); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); |
| headers.put("content-type", "application/x-www-form-urlencoded"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| stream.data(new StringDataInfo("a", false)); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| stream.data(new StringDataInfo("b", true)); |
| } |
| |
| @Test |
| public void testPOSTWithParameters() throws Exception |
| { |
| final String path = "/foo"; |
| final String data = "a=1&b=2"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("POST", httpRequest.getMethod()); |
| assertEquals("1", httpRequest.getParameter("a")); |
| assertEquals("2", httpRequest.getParameter("b")); |
| assertNotNull(httpRequest.getRemoteHost()); |
| assertNotNull(httpRequest.getRemotePort()); |
| assertNotNull(httpRequest.getRemoteAddr()); |
| assertNotNull(httpRequest.getLocalPort()); |
| assertNotNull(httpRequest.getLocalName()); |
| assertNotNull(httpRequest.getLocalAddr()); |
| assertNotNull(httpRequest.getServerPort()); |
| assertNotNull(httpRequest.getServerName()); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); |
| headers.put("content-type", "application/x-www-form-urlencoded"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| stream.data(new StringDataInfo(data, true)); |
| |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTWithParametersInTwoFramesTwoReads() throws Exception |
| { |
| final String path = "/foo"; |
| final String data1 = "a=1&"; |
| final String data2 = "b=2"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("POST", httpRequest.getMethod()); |
| assertEquals("1", httpRequest.getParameter("a")); |
| assertEquals("2", httpRequest.getParameter("b")); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); |
| headers.put("content-type", "application/x-www-form-urlencoded"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| // Sleep between the data frames so that they will be read in 2 reads |
| stream.data(new StringDataInfo(data1, false)); |
| Thread.sleep(1000); |
| stream.data(new StringDataInfo(data2, true)); |
| |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTWithParametersInTwoFramesOneRead() throws Exception |
| { |
| final String path = "/foo"; |
| final String data1 = "a=1&"; |
| final String data2 = "b=2"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| assertEquals("POST", httpRequest.getMethod()); |
| assertEquals("1", httpRequest.getParameter("a")); |
| assertEquals("2", httpRequest.getParameter("b")); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", path); |
| headers.put("content-type", "application/x-www-form-urlencoded"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.toString(), replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| |
| // Send the data frames consecutively, so the server reads both frames in one read |
| stream.data(new StringDataInfo(data1, false)); |
| stream.data(new StringDataInfo(data2, true)); |
| |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithSmallResponseContent() throws Exception |
| { |
| final String data = "0123456789ABCDEF"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data.getBytes(StandardCharsets.UTF_8)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| assertTrue(dataInfo.isClose()); |
| assertEquals(data, dataInfo.asString(StandardCharsets.UTF_8, true)); |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithOneByteResponseContent() throws Exception |
| { |
| final char data = 'x'; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| assertTrue(dataInfo.isClose()); |
| byte[] bytes = dataInfo.asBytes(true); |
| assertEquals(1, bytes.length); |
| assertEquals(data, bytes[0]); |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithSmallResponseContentInTwoChunks() throws Exception |
| { |
| final String data1 = "0123456789ABCDEF"; |
| final String data2 = "FEDCBA9876543210"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data1.getBytes(StandardCharsets.UTF_8)); |
| output.flush(); |
| output.write(data2.getBytes(StandardCharsets.UTF_8)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(2); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replyFrames = new AtomicInteger(); |
| private final AtomicInteger dataFrames = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replyFrames.incrementAndGet()); |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| int data = dataFrames.incrementAndGet(); |
| assertTrue(data >= 1 && data <= 2); |
| if (data == 1) |
| assertEquals(data1, dataInfo.asString(StandardCharsets.UTF_8, true)); |
| else |
| assertEquals(data2, dataInfo.asString(StandardCharsets.UTF_8, true)); |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithBigResponseContentInOneWrite() throws Exception |
| { |
| final byte[] data = new byte[128 * 1024]; |
| Arrays.fill(data, (byte)'x'); |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger contentBytes = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); |
| if (dataInfo.isClose()) |
| { |
| assertEquals(data.length, contentBytes.get()); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithBigResponseContentInMultipleWrites() throws Exception |
| { |
| final byte[] data = new byte[4 * 1024]; |
| Arrays.fill(data, (byte)'x'); |
| final int writeTimes = 16; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| for (int i = 0; i < writeTimes; i++) |
| { |
| output.write(data); |
| } |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger contentBytes = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); |
| if (dataInfo.isClose()) |
| { |
| assertEquals(data.length * writeTimes, contentBytes.get()); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithBigResponseContentInTwoWrites() throws Exception |
| { |
| final byte[] data = new byte[128 * 1024]; |
| Arrays.fill(data, (byte)'y'); |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data); |
| output.write(data); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger contentBytes = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining()); |
| if (dataInfo.isClose()) |
| { |
| assertEquals(2 * data.length, contentBytes.get()); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithOutputStreamFlushedAndClosed() throws Exception |
| { |
| final String data = "0123456789ABCDEF"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(data.getBytes(StandardCharsets.UTF_8)); |
| output.flush(); |
| output.close(); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| ByteBuffer byteBuffer = dataInfo.asByteBuffer(true); |
| while (byteBuffer.hasRemaining()) |
| buffer.write(byteBuffer.get()); |
| if (dataInfo.isClose()) |
| { |
| assertEquals(data, new String(buffer.toByteArray(), StandardCharsets.UTF_8)); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithResponseResetBuffer() throws Exception |
| { |
| final String data1 = "0123456789ABCDEF"; |
| final String data2 = "FEDCBA9876543210"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setStatus(HttpServletResponse.SC_OK); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| // Write some |
| output.write(data1.getBytes(StandardCharsets.UTF_8)); |
| // But then change your mind and reset the buffer |
| httpResponse.resetBuffer(); |
| output.write(data2.getBytes(StandardCharsets.UTF_8)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| ByteBuffer byteBuffer = dataInfo.asByteBuffer(true); |
| while (byteBuffer.hasRemaining()) |
| buffer.write(byteBuffer.get()); |
| if (dataInfo.isClose()) |
| { |
| assertEquals(data2, new String(buffer.toByteArray(), StandardCharsets.UTF_8)); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithRedirect() throws Exception |
| { |
| final String suffix = "/redirect"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| String location = httpResponse.encodeRedirectURL(String.format("%s://%s:%d%s", |
| request.getScheme(), request.getLocalAddr(), request.getLocalPort(), target + suffix)); |
| httpResponse.sendRedirect(location); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replies = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replies.incrementAndGet()); |
| assertTrue(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("302")); |
| assertTrue(replyHeaders.get("location").getValue().endsWith(suffix)); |
| replyLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithSendError() throws Exception |
| { |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replies = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replies.incrementAndGet()); |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("404")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| if (dataInfo.isClose()) |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithException() throws Exception |
| { |
| StdErrLog log = StdErrLog.getLogger(HttpChannel.class); |
| log.setHideStacks(true); |
| |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| throw new NullPointerException("thrown_explicitly_by_the_test"); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch latch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replies = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replies.incrementAndGet()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("500")); |
| replyLatch.countDown(); |
| if (replyInfo.isClose()) |
| latch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| if (dataInfo.isClose()) |
| latch.countDown(); |
| } |
| }); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| |
| log.setHideStacks(false); |
| } |
| |
| @Test |
| public void testGETWithSmallResponseContentChunked() throws Exception |
| { |
| final String pangram1 = "the quick brown fox jumps over the lazy dog"; |
| final String pangram2 = "qualche vago ione tipo zolfo, bromo, sodio"; |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| httpResponse.setHeader("Transfer-Encoding", "chunked"); |
| ServletOutputStream output = httpResponse.getOutputStream(); |
| output.write(pangram1.getBytes(StandardCharsets.UTF_8)); |
| httpResponse.setHeader("EXTRA", "X"); |
| output.flush(); |
| output.write(pangram2.getBytes(StandardCharsets.UTF_8)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(2); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replyFrames = new AtomicInteger(); |
| private final AtomicInteger dataFrames = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replyFrames.incrementAndGet()); |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| assertTrue(replyHeaders.get("extra").getValue().contains("X")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| int count = dataFrames.incrementAndGet(); |
| if (count == 1) |
| { |
| Assert.assertFalse(dataInfo.isClose()); |
| assertEquals(pangram1, dataInfo.asString(StandardCharsets.UTF_8, true)); |
| } |
| else if (count == 2) |
| { |
| assertTrue(dataInfo.isClose()); |
| assertEquals(pangram2, dataInfo.asString(StandardCharsets.UTF_8, true)); |
| } |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithMediumContentAsBufferByPassed() throws Exception |
| { |
| final byte[] data = new byte[2048]; |
| |
| final CountDownLatch handlerLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| request.getResponse().getHttpOutput().sendContent(ByteBuffer.wrap(data)); |
| handlerLatch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| private final AtomicInteger replyFrames = new AtomicInteger(); |
| private final AtomicInteger contentLength = new AtomicInteger(); |
| |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| assertEquals(1, replyFrames.incrementAndGet()); |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| contentLength.addAndGet(dataInfo.asBytes(true).length); |
| if (dataInfo.isClose()) |
| { |
| Assert.assertEquals(data.length, contentLength.get()); |
| dataLatch.countDown(); |
| } |
| } |
| }); |
| assertTrue(handlerLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testGETWithMultipleMediumContentByPassed() throws Exception |
| { |
| final byte[] data = new byte[2048]; |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| // The sequence of write/flush/write/write below triggers a condition where |
| // HttpGenerator._bypass is set to true on the second write(), and the |
| // third write causes an infinite spin loop on the third write(). |
| request.setHandled(true); |
| OutputStream output = httpResponse.getOutputStream(); |
| output.write(data); |
| output.flush(); |
| output.write(data); |
| output.write(data); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| final CountDownLatch dataLatch = new CountDownLatch(1); |
| final AtomicInteger contentLength = new AtomicInteger(); |
| session.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Assert.assertFalse(replyInfo.isClose()); |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| dataInfo.consume(dataInfo.available()); |
| contentLength.addAndGet(dataInfo.length()); |
| if (dataInfo.isClose()) |
| dataLatch.countDown(); |
| } |
| }); |
| assertTrue(dataLatch.await(5, TimeUnit.SECONDS)); |
| assertEquals(3 * data.length, contentLength.get()); |
| } |
| |
| @Test |
| public void testPOSTThenSuspendRequestThenReadOneChunkThenComplete() throws Exception |
| { |
| final byte[] data = new byte[2000]; |
| final CountDownLatch latch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| final AsyncContext asyncContext = request.startAsync(); |
| new Thread() |
| { |
| @Override |
| public void run() |
| { |
| try |
| { |
| readRequestData(request, data.length); |
| asyncContext.complete(); |
| latch.countDown(); |
| } |
| catch (IOException x) |
| { |
| x.printStackTrace(); |
| } |
| } |
| }.start(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| stream.data(new BytesDataInfo(data, true)); |
| |
| assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTThenSuspendExpire() throws Exception |
| { |
| final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) |
| { |
| dispatchedAgainAfterExpire.countDown(); |
| } |
| else |
| { |
| AsyncContext asyncContext = request.startAsync(); |
| asyncContext.setTimeout(1000); |
| asyncContext.addListener(new AsyncListenerAdapter()); |
| request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); |
| } |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| |
| assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, |
| TimeUnit.SECONDS)); |
| assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTThenSuspendExpireWithRequestData() throws Exception |
| { |
| final byte[] data = new byte[2000]; |
| final CountDownLatch dispatchedAgainAfterExpire = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) |
| { |
| dispatchedAgainAfterExpire.countDown(); |
| } |
| else |
| { |
| readRequestData(request, data.length); |
| AsyncContext asyncContext = request.startAsync(); |
| asyncContext.setTimeout(1000); |
| asyncContext.addListener(new AsyncListenerAdapter()); |
| request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); |
| } |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| stream.data(new BytesDataInfo(data, true)); |
| |
| assertTrue("Not dispatched again after expire", dispatchedAgainAfterExpire.await(5, |
| TimeUnit.SECONDS)); |
| assertTrue("Reply not sent", replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| private void readRequestData(Request request, int expectedDataLength) throws IOException |
| { |
| InputStream input = request.getInputStream(); |
| byte[] buffer = new byte[512]; |
| int read = 0; |
| while (read < expectedDataLength) |
| read += input.read(buffer); |
| } |
| |
| @Test |
| public void testPOSTThenSuspendRequestThenReadTwoChunksThenComplete() throws Exception |
| { |
| final byte[] data = new byte[2000]; |
| final CountDownLatch latch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| final AsyncContext asyncContext = request.startAsync(); |
| new Thread() |
| { |
| @Override |
| public void run() |
| { |
| try |
| { |
| InputStream input = request.getInputStream(); |
| byte[] buffer = new byte[512]; |
| int read = 0; |
| while (read < 2 * data.length) |
| read += input.read(buffer); |
| asyncContext.complete(); |
| latch.countDown(); |
| } |
| catch (IOException x) |
| { |
| x.printStackTrace(); |
| } |
| } |
| }.start(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch replyLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| replyLatch.countDown(); |
| } |
| }); |
| stream.data(new BytesDataInfo(data, false)); |
| stream.data(new BytesDataInfo(data, true)); |
| |
| assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| assertTrue(replyLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTThenSuspendRequestThenResumeThenRespond() throws Exception |
| { |
| final byte[] data = new byte[1000]; |
| final CountDownLatch latch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| if (request.getAttribute(SUSPENDED_ATTRIBUTE) == Boolean.TRUE) |
| { |
| OutputStream output = httpResponse.getOutputStream(); |
| output.write(data); |
| } |
| else |
| { |
| final AsyncContext asyncContext = request.startAsync(); |
| request.setAttribute(SUSPENDED_ATTRIBUTE, Boolean.TRUE); |
| InputStream input = request.getInputStream(); |
| byte[] buffer = new byte[256]; |
| int read = 0; |
| while (read < data.length) |
| read += input.read(buffer); |
| new Thread() |
| { |
| @Override |
| public void run() |
| { |
| try |
| { |
| TimeUnit.SECONDS.sleep(1); |
| asyncContext.dispatch(); |
| latch.countDown(); |
| } |
| catch (InterruptedException x) |
| { |
| x.printStackTrace(); |
| } |
| } |
| }.start(); |
| } |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch responseLatch = new CountDownLatch(2); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| responseLatch.countDown(); |
| } |
| |
| @Override |
| public void onData(Stream stream, DataInfo dataInfo) |
| { |
| if (dataInfo.isClose()) |
| responseLatch.countDown(); |
| } |
| }); |
| stream.data(new BytesDataInfo(data, true)); |
| |
| assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testPOSTThenResponseWithoutReadingContent() throws Exception |
| { |
| final byte[] data = new byte[1000]; |
| final CountDownLatch latch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| request.setHandled(true); |
| latch.countDown(); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "POST", "/foo"); |
| final CountDownLatch responseLatch = new CountDownLatch(1); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, false, (byte)0), new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| Fields replyHeaders = replyInfo.getHeaders(); |
| assertTrue(replyHeaders.get(HTTPSPDYHeader.STATUS.name(version)).getValue().contains("200")); |
| responseLatch.countDown(); |
| } |
| }); |
| stream.data(new BytesDataInfo(data, false)); |
| stream.data(new BytesDataInfo(5, TimeUnit.SECONDS, data, true)); |
| |
| assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| assertTrue(responseLatch.await(5, TimeUnit.SECONDS)); |
| } |
| |
| @Test |
| public void testIdleTimeout() throws Exception |
| { |
| final int idleTimeout = 500; |
| final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); |
| |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| try |
| { |
| Thread.sleep(2 * idleTimeout); |
| } |
| catch (InterruptedException e) |
| { |
| throw new RuntimeException(e); |
| } |
| request.setHandled(true); |
| } |
| }, 30000), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); |
| Stream stream = session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onFailure(Stream stream, Throwable x) |
| { |
| assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); |
| timeoutReceivedLatch.countDown(); |
| } |
| }); |
| stream.setIdleTimeout(idleTimeout); |
| |
| assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); |
| } |
| |
| @Test |
| public void testIdleTimeoutSetOnConnectionOnly() throws Exception |
| { |
| final int idleTimeout = 500; |
| final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| try |
| { |
| Thread.sleep(2 * idleTimeout); |
| } |
| catch (InterruptedException e) |
| { |
| throw new RuntimeException(e); |
| } |
| request.setHandled(true); |
| } |
| }, idleTimeout), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); |
| session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onFailure(Stream stream, Throwable x) |
| { |
| assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); |
| timeoutReceivedLatch.countDown(); |
| } |
| }); |
| |
| assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); |
| } |
| |
| @Test |
| public void testSingleStreamIdleTimeout() throws Exception |
| { |
| final int idleTimeout = 500; |
| final CountDownLatch timeoutReceivedLatch = new CountDownLatch(1); |
| final CountDownLatch replyReceivedLatch = new CountDownLatch(3); |
| Session session = startClient(version, startHTTPServer(version, new AbstractHandler() |
| { |
| @Override |
| public void handle(String target, final Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) |
| throws IOException, ServletException |
| { |
| if ("true".equals(request.getHeader("slow"))) |
| { |
| try |
| { |
| Thread.sleep(2 * idleTimeout); |
| } |
| catch (InterruptedException e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| request.setHandled(true); |
| } |
| }, idleTimeout), null); |
| |
| Fields headers = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); |
| Fields slowHeaders = SPDYTestUtils.createHeaders("localhost", connector.getPort(), version, "GET", "/"); |
| slowHeaders.add("slow", "true"); |
| sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); |
| session.syn(new SynInfo(5, TimeUnit.SECONDS, slowHeaders, true, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onFailure(Stream stream, Throwable x) |
| { |
| assertThat("we got a TimeoutException", x, instanceOf(TimeoutException.class)); |
| timeoutReceivedLatch.countDown(); |
| } |
| }); |
| Thread.sleep(idleTimeout / 2); |
| sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); |
| Thread.sleep(idleTimeout / 2); |
| sendSingleRequestThatIsNotExpectedToTimeout(replyReceivedLatch, session, headers); |
| assertThat("idle timeout hit", timeoutReceivedLatch.await(5, TimeUnit.SECONDS), is(true)); |
| assertThat("received replies on 3 non idle requests", replyReceivedLatch.await(5, TimeUnit.SECONDS), |
| is(true)); |
| } |
| |
| private void sendSingleRequestThatIsNotExpectedToTimeout(final CountDownLatch replyReceivedLatch, Session session, Fields headers) throws ExecutionException, InterruptedException, TimeoutException |
| { |
| session.syn(new SynInfo(5, TimeUnit.SECONDS, headers, true, (byte)0), |
| new StreamFrameListener.Adapter() |
| { |
| @Override |
| public void onReply(Stream stream, ReplyInfo replyInfo) |
| { |
| replyReceivedLatch.countDown(); |
| } |
| }); |
| } |
| |
| private class AsyncListenerAdapter implements AsyncListener |
| { |
| @Override |
| public void onStartAsync(AsyncEvent event) throws IOException |
| { |
| } |
| |
| @Override |
| public void onComplete(AsyncEvent event) throws IOException |
| { |
| } |
| |
| @Override |
| public void onTimeout(AsyncEvent event) throws IOException |
| { |
| event.getAsyncContext().dispatch(); |
| } |
| |
| @Override |
| public void onError(AsyncEvent event) throws IOException |
| { |
| } |
| } |
| } |