use of javax.servlet.AsyncContext in project jetty.project by eclipse.
the class ServerTimeoutsTest method testAsyncReadIdleTimeoutFires.
@Test
public void testAsyncReadIdleTimeoutFires() throws Exception {
CountDownLatch handlerLatch = new CountDownLatch(1);
start(new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
baseRequest.setHandled(true);
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
ServletInputStream input = request.getInputStream();
input.setReadListener(new ReadListener() {
@Override
public void onDataAvailable() throws IOException {
Assert.assertEquals(0, input.read());
Assert.assertFalse(input.isReady());
}
@Override
public void onAllDataRead() throws IOException {
}
@Override
public void onError(Throwable failure) {
if (failure instanceof TimeoutException) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
asyncContext.complete();
handlerLatch.countDown();
}
}
});
}
});
long idleTimeout = 2500;
setServerIdleTimeout(idleTimeout);
DeferredContentProvider contentProvider = new DeferredContentProvider(ByteBuffer.allocate(1));
CountDownLatch resultLatch = new CountDownLatch(1);
client.POST(newURI()).content(contentProvider).send(result -> {
if (result.getResponse().getStatus() == HttpStatus.INTERNAL_SERVER_ERROR_500)
resultLatch.countDown();
});
// Async read should timeout.
Assert.assertTrue(handlerLatch.await(2 * idleTimeout, TimeUnit.MILLISECONDS));
// Complete the request.
contentProvider.close();
Assert.assertTrue(resultLatch.await(5, TimeUnit.SECONDS));
}
use of javax.servlet.AsyncContext in project jetty.project by eclipse.
the class SuspendHandler method handle.
@Override
public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) {
if (_read > 0) {
byte[] buf = new byte[_read];
request.getInputStream().read(buf);
} else if (_read < 0) {
InputStream in = request.getInputStream();
int b = in.read();
while (b != -1) b = in.read();
}
final AsyncContext asyncContext = baseRequest.startAsync();
asyncContext.addListener(this);
if (_suspendFor > 0)
asyncContext.setTimeout(_suspendFor);
if (_completeAfter > 0) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(_completeAfter);
response.getOutputStream().println("COMPLETED");
response.setStatus(200);
baseRequest.setHandled(true);
asyncContext.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
} else if (_completeAfter == 0) {
response.getOutputStream().println("COMPLETED");
response.setStatus(200);
baseRequest.setHandled(true);
asyncContext.complete();
}
if (_resumeAfter > 0) {
new Thread() {
@Override
public void run() {
try {
Thread.sleep(_resumeAfter);
asyncContext.dispatch();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
} else if (_resumeAfter == 0) {
asyncContext.dispatch();
}
} else if (request.getAttribute("TIMEOUT") != null) {
response.setStatus(200);
response.getOutputStream().print("TIMEOUT");
baseRequest.setHandled(true);
} else {
response.setStatus(200);
response.getOutputStream().print("RESUMED");
baseRequest.setHandled(true);
}
}
use of javax.servlet.AsyncContext in project jetty.project by eclipse.
the class StatisticsHandlerTest method testSuspendExpire.
@Test
public void testSuspendExpire() throws Exception {
final long dispatchTime = 10;
final long timeout = 100;
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
final CyclicBarrier[] barrier = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2) };
_statsHandler.setHandler(new AbstractHandler() {
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException {
request.setHandled(true);
try {
barrier[0].await();
Thread.sleep(dispatchTime);
if (asyncHolder.get() == null) {
AsyncContext async = request.startAsync();
asyncHolder.set(async);
async.setTimeout(timeout);
}
} catch (Exception x) {
throw new ServletException(x);
} finally {
try {
barrier[1].await();
} catch (Exception ignored) {
}
}
}
});
_server.start();
String request = "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n";
_connector.executeRequest(request);
barrier[0].await();
assertEquals(1, _statistics.getConnections());
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(1, _statsHandler.getDispatchedActive());
barrier[1].await();
assertTrue(_latchHandler.await());
assertNotNull(asyncHolder.get());
asyncHolder.get().addListener(new AsyncListener() {
@Override
public void onTimeout(AsyncEvent event) throws IOException {
event.getAsyncContext().complete();
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
}
@Override
public void onError(AsyncEvent event) throws IOException {
}
@Override
public void onComplete(AsyncEvent event) throws IOException {
try {
barrier[2].await();
} catch (Exception ignored) {
}
}
});
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
barrier[2].await();
assertEquals(1, _statsHandler.getRequests());
assertEquals(0, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
assertEquals(1, _statsHandler.getAsyncRequests());
assertEquals(0, _statsHandler.getAsyncDispatches());
assertEquals(1, _statsHandler.getExpires());
assertEquals(1, _statsHandler.getResponses2xx());
assertTrue(_statsHandler.getRequestTimeTotal() >= (timeout + dispatchTime) * 3 / 4);
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
assertThat(_statsHandler.getDispatchedTimeTotal(), greaterThanOrEqualTo(dispatchTime * 3 / 4));
}
use of javax.servlet.AsyncContext in project jetty.project by eclipse.
the class CGI method exec.
/**
* executes the CGI process
*
* @param command the command to execute, this command is prefixed by
* the context parameter "commandPrefix".
* @param pathInfo The PATH_INFO to process,
* see http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPathInfo%28%29. Cannot be null
* @param req the HTTP request
* @param res the HTTP response
* @throws IOException if the execution of the CGI process throws
*/
private void exec(File command, String pathInfo, HttpServletRequest req, HttpServletResponse res) throws IOException {
assert req != null;
assert res != null;
assert pathInfo != null;
assert command != null;
if (LOG.isDebugEnabled()) {
LOG.debug("CGI: script is " + command);
LOG.debug("CGI: pathInfo is " + pathInfo);
}
String bodyFormEncoded = null;
if ((HttpMethod.POST.is(req.getMethod()) || HttpMethod.PUT.is(req.getMethod())) && "application/x-www-form-urlencoded".equals(req.getContentType())) {
MultiMap<String> parameterMap = new MultiMap<>();
Enumeration<String> names = req.getParameterNames();
while (names.hasMoreElements()) {
String parameterName = names.nextElement();
parameterMap.addValues(parameterName, req.getParameterValues(parameterName));
}
bodyFormEncoded = UrlEncoded.encode(parameterMap, Charset.forName(req.getCharacterEncoding()), true);
}
EnvList env = new EnvList(_env);
// these ones are from "The WWW Common Gateway Interface Version 1.1"
// look at :
// http://Web.Golux.Com/coar/cgi/draft-coar-cgi-v11-03-clean.html#6.1.1
env.set("AUTH_TYPE", req.getAuthType());
int contentLen = req.getContentLength();
if (contentLen < 0)
contentLen = 0;
if (bodyFormEncoded != null) {
env.set("CONTENT_LENGTH", Integer.toString(bodyFormEncoded.length()));
} else {
env.set("CONTENT_LENGTH", Integer.toString(contentLen));
}
env.set("CONTENT_TYPE", req.getContentType());
env.set("GATEWAY_INTERFACE", "CGI/1.1");
if (pathInfo.length() > 0) {
env.set("PATH_INFO", pathInfo);
}
String pathTranslated = req.getPathTranslated();
if ((pathTranslated == null) || (pathTranslated.length() == 0))
pathTranslated = pathInfo;
env.set("PATH_TRANSLATED", pathTranslated);
env.set("QUERY_STRING", req.getQueryString());
env.set("REMOTE_ADDR", req.getRemoteAddr());
env.set("REMOTE_HOST", req.getRemoteHost());
// The identity information reported about the connection by a
// RFC 1413 [11] request to the remote agent, if
// available. Servers MAY choose not to support this feature, or
// not to request the data for efficiency reasons.
// "REMOTE_IDENT" => "NYI"
env.set("REMOTE_USER", req.getRemoteUser());
env.set("REQUEST_METHOD", req.getMethod());
String scriptPath;
String scriptName;
// use docRoot for scriptPath, too
if (_cgiBinProvided) {
scriptPath = command.getAbsolutePath();
scriptName = scriptPath.substring(_docRoot.getAbsolutePath().length());
} else {
String requestURI = req.getRequestURI();
scriptName = requestURI.substring(0, requestURI.length() - pathInfo.length());
scriptPath = getServletContext().getRealPath(scriptName);
}
env.set("SCRIPT_FILENAME", scriptPath);
env.set("SCRIPT_NAME", scriptName);
env.set("SERVER_NAME", req.getServerName());
env.set("SERVER_PORT", Integer.toString(req.getServerPort()));
env.set("SERVER_PROTOCOL", req.getProtocol());
env.set("SERVER_SOFTWARE", getServletContext().getServerInfo());
Enumeration<String> enm = req.getHeaderNames();
while (enm.hasMoreElements()) {
String name = enm.nextElement();
if (name.equalsIgnoreCase("Proxy"))
continue;
String value = req.getHeader(name);
env.set("HTTP_" + name.toUpperCase(Locale.ENGLISH).replace('-', '_'), value);
}
// these extra ones were from printenv on www.dev.nomura.co.uk
env.set("HTTPS", (req.isSecure() ? "ON" : "OFF"));
// "DOCUMENT_ROOT" => root + "/docs",
// "SERVER_URL" => "NYI - http://us0245",
// "TZ" => System.getProperty("user.timezone"),
// are we meant to decode args here? or does the script get them
// via PATH_INFO? if we are, they should be decoded and passed
// into exec here...
String absolutePath = command.getAbsolutePath();
String execCmd = absolutePath;
// escape the execCommand
if (execCmd.length() > 0 && execCmd.charAt(0) != '"' && execCmd.contains(" "))
execCmd = "\"" + execCmd + "\"";
if (_cmdPrefix != null)
execCmd = _cmdPrefix + " " + execCmd;
LOG.debug("Environment: " + env.getExportString());
LOG.debug("Command: " + execCmd);
final Process p = Runtime.getRuntime().exec(execCmd, env.getEnvArray(), _docRoot);
// hook processes input to browser's output (async)
if (bodyFormEncoded != null)
writeProcessInput(p, bodyFormEncoded);
else if (contentLen > 0)
writeProcessInput(p, req.getInputStream(), contentLen);
// hook processes output to browser's input (sync)
// if browser closes stream, we should detect it and kill process...
OutputStream os = null;
AsyncContext async = req.startAsync();
try {
async.start(new Runnable() {
@Override
public void run() {
try {
IO.copy(p.getErrorStream(), System.err);
} catch (IOException e) {
LOG.warn(e);
}
}
});
// read any headers off the top of our input stream
// NOTE: Multiline header items not supported!
String line = null;
InputStream inFromCgi = p.getInputStream();
// while ((line=br.readLine())!=null)
while ((line = getTextLineFromStream(inFromCgi)).length() > 0) {
if (!line.startsWith("HTTP")) {
int k = line.indexOf(':');
if (k > 0) {
String key = line.substring(0, k).trim();
String value = line.substring(k + 1).trim();
if ("Location".equals(key)) {
res.sendRedirect(res.encodeRedirectURL(value));
} else if ("Status".equals(key)) {
String[] token = value.split(" ");
int status = Integer.parseInt(token[0]);
res.setStatus(status);
} else {
// add remaining header items to our response header
res.addHeader(key, value);
}
}
}
}
// copy cgi content to response stream...
os = res.getOutputStream();
IO.copy(inFromCgi, os);
p.waitFor();
if (!_ignoreExitState) {
int exitValue = p.exitValue();
if (0 != exitValue) {
LOG.warn("Non-zero exit status (" + exitValue + ") from CGI program: " + absolutePath);
if (!res.isCommitted())
res.sendError(500, "Failed to exec CGI");
}
}
} catch (IOException e) {
// browser has probably closed its input stream - we
// terminate and clean up...
LOG.debug("CGI: Client closed connection!", e);
} catch (InterruptedException ie) {
LOG.debug("CGI: interrupted!");
} finally {
if (os != null) {
try {
os.close();
} catch (Exception e) {
LOG.debug(e);
}
}
p.destroy();
// LOG.debug("CGI: terminated!");
async.complete();
}
}
use of javax.servlet.AsyncContext in project jetty.project by eclipse.
the class SSLAsyncIOServletTest method testAsyncIOWritesWithAggregation.
@Test
public void testAsyncIOWritesWithAggregation() throws Exception {
Random random = new Random();
String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
final byte[] content = new byte[50000];
for (int i = 0; i < content.length; ++i) content[i] = (byte) chars.charAt(random.nextInt(chars.length()));
prepare(new HttpServlet() {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
final AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0);
final int bufferSize = 4096;
response.setBufferSize(bufferSize);
response.getOutputStream().setWriteListener(new WriteListener() {
private int writes;
private int written;
@Override
public void onWritePossible() throws IOException {
ServletOutputStream output = asyncContext.getResponse().getOutputStream();
do {
int toWrite = content.length - written;
if (toWrite == 0) {
asyncContext.complete();
return;
}
toWrite = Math.min(toWrite, bufferSize);
// trigger the condition where the bytes are aggregated.
if (writes == 1)
toWrite -= 16;
output.write(content, written, toWrite);
++writes;
written += toWrite;
} while (output.isReady());
}
@Override
public void onError(Throwable t) {
asyncContext.complete();
}
});
}
});
try (Socket client = newClient()) {
String request = "" + "GET " + contextPath + servletPath + " HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n";
OutputStream output = client.getOutputStream();
output.write(request.getBytes("UTF-8"));
output.flush();
InputStream inputStream = client.getInputStream();
HttpTester.Response response = HttpTester.parseResponse(inputStream);
Assert.assertEquals(200, response.getStatus());
Assert.assertArrayEquals(content, response.getContent().getBytes("UTF-8"));
}
}
Aggregations