diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index a6593f8c734e..cd9eb701de25 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -406,8 +406,6 @@ public Action handling() */ protected Action unhandle() { - boolean readInterested = false; - synchronized (this) { if (LOG.isDebugEnabled()) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index 08622f5a3b2d..e5390e0b2bad 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -300,9 +300,6 @@ private void channelWrite(ByteBuffer content, boolean last, Callback callback) void onWriteComplete(boolean last, Throwable failure) { - if (LOG.isDebugEnabled()) - LOG.debug("onWriteComplete", failure); - boolean wake = false; Callback closedCallback = null; boolean release = false; @@ -361,6 +358,10 @@ void onWriteComplete(boolean last, Throwable failure) } } + if (LOG.isDebugEnabled()) + LOG.debug("onWriteComplete({},{}) {} c={} cb={} r={} w={}", + last, failure, stateString(), BufferUtil.toDetailString(closeContent), closedCallback, release, wake); + if (failure != null) _channel.abort(failure); @@ -572,7 +573,7 @@ public void close() throws IOException } if (LOG.isDebugEnabled()) - LOG.debug("close({}) {} e={}, c={}", blocker, stateString(), BufferUtil.toDetailString(content)); + LOG.debug("close() {} c={} b={}", stateString(), BufferUtil.toDetailString(content), blocker); if (content == null) { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java index 1932837f8ffd..ac41987849fd 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/AsyncCompletionTest.java @@ -178,7 +178,14 @@ public static Stream tests() tests.add(new Object[]{new AsyncWriteCompleteHandler(false, true), false, 200, __data}); tests.add(new Object[]{new AsyncWriteCompleteHandler(true, false), false, 200, __data}); tests.add(new Object[]{new AsyncWriteCompleteHandler(true, true), false, 200, __data}); - tests.add(new Object[]{new BlockingWriteCompleteHandler(), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(false, false, false), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(false, false, true), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(false, true, false), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(false, true, true), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(true, false, false), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(true, false, true), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(true, true, false), true, 200, __data}); + tests.add(new Object[]{new BlockingWriteCompleteHandler(true, true, true), true, 200, __data}); return tests.stream().map(Arguments::of); } @@ -237,7 +244,12 @@ public void testAsyncCompletion(Handler handler, boolean blocked, int status, St { if (System.nanoTime() > end) throw new TimeoutException(); - Thread.sleep(10); + try + { + X.exchange(null, 10, TimeUnit.MILLISECONDS).proceed(); + } + catch (TimeoutException e) + {} } } } @@ -251,6 +263,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques // register WriteListener // if ready write bytes // if ready complete + baseRequest.setHandled(true); AsyncContext context = request.startAsync(); ServletOutputStream out = response.getOutputStream(); out.setWriteListener(new WriteListener() @@ -309,7 +322,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques // if _unReady check that isReady() returns false and return // if _close then call close without checking isReady() // context.complete() without checking is ready - + baseRequest.setHandled(true); AsyncContext context = request.startAsync(); ServletOutputStream out = response.getOutputStream(); out.setWriteListener(new WriteListener() { @@ -357,11 +370,15 @@ public String toString() private static class BlockingWriteCompleteHandler extends AbstractHandler { - final CountDownLatch _unReadySeen = new CountDownLatch(1); - boolean _written; + final boolean _contentLength; + final boolean _close; + final boolean _dispatchComplete; - BlockingWriteCompleteHandler() + BlockingWriteCompleteHandler(boolean contentLength, boolean close, boolean dispatchComplete) { + _contentLength = contentLength; + _close = close; + _dispatchComplete = dispatchComplete; } @Override @@ -370,41 +387,62 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques // Start async // Do a blocking write in another thread // call complete while the write is still blocking + baseRequest.setHandled(true); AsyncContext context = request.startAsync(); ServletOutputStream out = response.getOutputStream(); CountDownLatch writing = new CountDownLatch(1); - context.start(() -> + + Runnable write = () -> { try { byte[] bytes = __data.getBytes(StandardCharsets.ISO_8859_1); response.setContentType("text/plain"); - response.setContentLength(bytes.length); + if (_contentLength) + response.setContentLength(bytes.length); writing.countDown(); + out.write(bytes); + + if (_close) + out.close(); } catch(Exception e) { e.printStackTrace(); } - }); + }; - try + Runnable complete = () -> + { + try + { + writing.await(5, TimeUnit.SECONDS); + Thread.sleep(200); + context.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + }; + + if (_dispatchComplete) { - writing.await(5, TimeUnit.SECONDS); - Thread.sleep(200); - context.complete(); + context.start(complete); + write.run(); } - catch(Exception e) + else { - throw new ServletException(e); + context.start(write); + complete.run(); } } @Override public String toString() { - return String.format("%s@%x{}", this.getClass().getSimpleName(), hashCode()); + return String.format("BWCH@%x{cl=%b,c=%b,dc=%b}", hashCode(), _contentLength, _close, _dispatchComplete); } } }