blob: 2ff3f4b51443a383624fb4d23d64d421c4ea7bbb [file] [log] [blame]
//
// ========================================================================
// 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.servlet;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.toolchain.test.TestTracker;
import org.eclipse.jetty.toolchain.test.http.SimpleHttpParser;
import org.eclipse.jetty.toolchain.test.http.SimpleHttpResponse;
import org.junit.After;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
public class AsyncServletLongPollTest
{
@Rule
public TestTracker tracker = new TestTracker();
private Server server;
private ServerConnector connector;
private ServletContextHandler context;
private String uri;
protected void prepare(HttpServlet servlet) throws Exception
{
server = new Server();
connector = new ServerConnector(server);
server.addConnector(connector);
String contextPath = "/context";
context = new ServletContextHandler(server, contextPath, ServletContextHandler.NO_SESSIONS);
ServletHolder servletHolder = new ServletHolder(servlet);
String servletPath = "/path";
context.addServlet(servletHolder, servletPath);
uri = contextPath + servletPath;
server.start();
}
@After
public void destroy() throws Exception
{
server.stop();
}
@Test
public void testSuspendedRequestCompletedByAnotherRequest() throws Exception
{
final CountDownLatch asyncLatch = new CountDownLatch(1);
prepare(new HttpServlet()
{
private volatile AsyncContext asyncContext;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
int suspend = 0;
String param = request.getParameter("suspend");
if (param != null)
suspend = Integer.parseInt(param);
if (suspend > 0)
{
asyncContext = request.startAsync();
asyncLatch.countDown();
}
}
@Override
protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
int error = 0;
String param = request.getParameter("error");
if (param != null)
error = Integer.parseInt(param);
final AsyncContext asyncContext = this.asyncContext;
if (asyncContext != null)
{
HttpServletResponse asyncResponse = (HttpServletResponse)asyncContext.getResponse();
asyncResponse.sendError(error);
asyncContext.complete();
}
else
{
response.sendError(404);
}
}
});
try (Socket socket1 = new Socket("localhost", connector.getLocalPort()))
{
int wait = 1000;
String request1 = "GET " + uri + "?suspend=" + wait + " HTTP/1.1\r\n" +
"Host: localhost:" + connector.getLocalPort() + "\r\n" +
"\r\n";
OutputStream output1 = socket1.getOutputStream();
output1.write(request1.getBytes(StandardCharsets.UTF_8));
output1.flush();
Assert.assertTrue(asyncLatch.await(5, TimeUnit.SECONDS));
String error = "408";
try (Socket socket2 = new Socket("localhost", connector.getLocalPort()))
{
String request2 = "DELETE " + uri + "?error=" + error + " HTTP/1.1\r\n" +
"Host: localhost:" + connector.getLocalPort() + "\r\n" +
"\r\n";
OutputStream output2 = socket2.getOutputStream();
output2.write(request2.getBytes(StandardCharsets.UTF_8));
output2.flush();
SimpleHttpParser parser2 = new SimpleHttpParser();
BufferedReader input2 = new BufferedReader(new InputStreamReader(socket2.getInputStream(), StandardCharsets.UTF_8));
SimpleHttpResponse response2 = parser2.readResponse(input2);
Assert.assertEquals("200", response2.getCode());
}
socket1.setSoTimeout(2 * wait);
SimpleHttpParser parser1 = new SimpleHttpParser();
BufferedReader input1 = new BufferedReader(new InputStreamReader(socket1.getInputStream(), StandardCharsets.UTF_8));
SimpleHttpResponse response1 = parser1.readResponse(input1);
Assert.assertEquals(error, response1.getCode());
// Now try to make another request on the first connection
// to verify that we set correctly the read interest (#409842)
String request3 = "GET " + uri + " HTTP/1.1\r\n" +
"Host: localhost:" + connector.getLocalPort() + "\r\n" +
"\r\n";
output1.write(request3.getBytes(StandardCharsets.UTF_8));
output1.flush();
SimpleHttpResponse response3 = parser1.readResponse(input1);
Assert.assertEquals("200", response3.getCode());
}
}
}