ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/test/org/apache/coyote/http2/TestAsyncTimeout.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/test/org/apache/coyote/http2/TestAsyncTimeout.java
Status
scanned
Type
file
Name
TestAsyncTimeout.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
8827 (8.6 KB)
MD5
d72fc4beb053670abb474c0b7deac904
SHA1
edc51a48a00bb4734f96d38b6a12e0ee43da7843
SHA256
0afbf7de3dba8891f3df4753d92348b5f98213a1462894b47eedb7820ff88f1a
SHA512

      
    
SHA1_git
454ad32183cf6fa28bc7246c87664a89ca9b5f70
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
TestAsyncTimeout.java | 8.6 KB |

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.coyote.http2; import java.io.IOException; import java.io.PrintWriter; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import jakarta.servlet.AsyncContext; import jakarta.servlet.AsyncEvent; import jakarta.servlet.AsyncListener; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; import org.apache.catalina.Wrapper; import org.apache.catalina.startup.Tomcat; public class TestAsyncTimeout extends Http2TestBase { @Test public void testTimeout() throws Exception { enableHttp2(); Tomcat tomcat = getTomcatInstance(); Context ctxt = getProgrammaticRootContext(); // This is the target of the HTTP/2 upgrade request Tomcat.addServlet(ctxt, "simple", new SimpleServlet()); ctxt.addServletMappingDecoded("/simple", "simple"); // This is the servlet that does that actual test // This latch is used to signal that that async thread used by the test // has ended. It isn't essential to the test but it allows the test to // complete without Tomcat logging an error about a still running thread. CountDownLatch latch = new CountDownLatch(1); Wrapper w = Tomcat.addServlet(ctxt, "async", new AsyncTimeoutServlet(latch)); w.setAsyncSupported(true); ctxt.addServletMappingDecoded("/async", "async"); tomcat.start(); openClientConnection(); doHttpUpgrade(); sendClientPreface(); validateHttp2InitialResponse(); // Reset connection window size after initial response sendWindowUpdate(0, SimpleServlet.CONTENT_LENGTH); // Include the response body in the trace so we can check for the PASS / // FAIL text. output.setTraceBody(true); // Send request byte[] frameHeader = new byte[9]; ByteBuffer headersPayload = ByteBuffer.allocate(128); buildGetRequest(frameHeader, headersPayload, null, 3, "/async"); writeFrame(frameHeader, headersPayload); // Headers parser.readFrame(); // Body parser.readFrame(); // Check that the expected text was received String trace = output.getTrace(); Assert.assertTrue(trace, trace.contains("PASS")); latch.await(10, TimeUnit.SECONDS); } public static class AsyncTimeoutServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final transient CountDownLatch latch; public AsyncTimeoutServlet(CountDownLatch latch) { this.latch = latch; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // The idea of this test is that the timeout kicks in after 2 // seconds and stops the async thread early rather than letting it // complete the full 5 seconds of processing. final AsyncContext asyncContext = request.startAsync(); response.setStatus(HttpServletResponse.SC_OK); response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); // Only want to call complete() once (else we get stack traces in // the logs so use this to track when complete() is called). AtomicBoolean completeCalled = new AtomicBoolean(false); Ticker ticker = new Ticker(asyncContext, completeCalled); TimeoutListener listener = new TimeoutListener(latch, ticker, completeCalled); asyncContext.addListener(listener); asyncContext.setTimeout(2000); ticker.start(); } } private static class Ticker extends Thread { private final AsyncContext asyncContext; private final AtomicBoolean completeCalled; private volatile boolean running = true; Ticker(AsyncContext asyncContext, AtomicBoolean completeCalled) { this.asyncContext = asyncContext; this.completeCalled = completeCalled; } public void end() { running = false; } @Override public void run() { try { PrintWriter pw = asyncContext.getResponse().getWriter(); int counter = 0; // If the test works running will be set to false before // counter reaches 50. while (running && counter < 50) { sleep(100); counter++; pw.print("Tick " + counter); } // Need to call complete() here if the test fails but complete() // should have been called by the listener. Use the flag to make // sure we only call complete once. if (completeCalled.compareAndSet(false, true)) { asyncContext.complete(); } } catch (IOException | InterruptedException e) { // Ignore } } } private static class TimeoutListener implements AsyncListener { private final AtomicBoolean ended = new AtomicBoolean(false); private final CountDownLatch latch; private final Ticker ticker; private final AtomicBoolean completeCalled; TimeoutListener(CountDownLatch latch, Ticker ticker, AtomicBoolean completeCalled) { this.latch = latch; this.ticker = ticker; this.completeCalled = completeCalled; } @Override public void onTimeout(AsyncEvent event) throws IOException { ticker.end(); // Wait for the ticker to exit to avoid concurrent access to the // response and associated writer. // Excessively long timeout just in case things so wrong so test // does not lock up. try { ticker.join(10 * 1000); } catch (InterruptedException e) { throw new IOException(e); } if (ended.compareAndSet(false, true)) { PrintWriter pw = event.getAsyncContext().getResponse().getWriter(); pw.write("PASS"); pw.flush(); // If the timeout fires we should always need to call complete() // here but use the flag to be safe. if (completeCalled.compareAndSet(false, true)) { event.getAsyncContext().complete(); } } } @Override public void onStartAsync(AsyncEvent event) throws IOException { // NO-OP } @Override public void onError(AsyncEvent event) throws IOException { // NO-OP } @Override public void onComplete(AsyncEvent event) throws IOException { if (ended.compareAndSet(false, true)) { PrintWriter pw = event.getAsyncContext().getResponse().getWriter(); pw.write("FAIL"); pw.flush(); } try { // Wait for the async thread to end before we signal that the // test is complete. This avoids logging an exception about a // still running thread when the unit test shuts down. ticker.join(); latch.countDown(); } catch (InterruptedException e) { // Ignore } } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
13.9
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9