// // ======================================================================== // 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.server; import java.io.EOFException; import java.io.IOException; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeoutException; import javax.servlet.ReadListener; import org.eclipse.jetty.util.BufferUtil; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class HttpInputTest { private final Queue<String> _history = new LinkedBlockingQueue<>(); private final Queue<String> _fillAndParseSimulate = new LinkedBlockingQueue<>(); private final ReadListener _listener = new ReadListener() { @Override public void onError(Throwable t) { _history.add("l.onError:" + t); } @Override public void onDataAvailable() throws IOException { _history.add("l.onDataAvailable"); } @Override public void onAllDataRead() throws IOException { _history.add("l.onAllDataRead"); } }; private HttpInput _in; public class TContent extends HttpInput.Content { private final String _content; public TContent(String content) { super(BufferUtil.toBuffer(content)); _content = content; } @Override public void succeeded() { _history.add("Content succeeded " + _content); super.succeeded(); } @Override public void failed(Throwable x) { _history.add("Content failed " + _content); super.failed(x); } } @Before public void before() { _in = new HttpInput(new HttpChannelState(new HttpChannel(null, new HttpConfiguration(), null, null) { @Override public void asyncReadFillInterested() { _history.add("asyncReadFillInterested"); } }) { @Override public void onReadUnready() { _history.add("s.onReadUnready"); super.onReadUnready(); } @Override public boolean onReadPossible() { _history.add("s.onReadPossible"); return super.onReadPossible(); } @Override public boolean onContentAdded() { _history.add("s.onDataAvailable"); return super.onContentAdded(); } @Override public boolean onReadReady() { _history.add("s.onReadReady"); return super.onReadReady(); } }) { @Override protected void produceContent() throws IOException { _history.add("produceContent " + _fillAndParseSimulate.size()); for (String s = _fillAndParseSimulate.poll(); s != null; s = _fillAndParseSimulate.poll()) { if ("_EOF_".equals(s)) _in.eof(); else _in.addContent(new TContent(s)); } } @Override protected void blockForContent() throws IOException { _history.add("blockForContent"); super.blockForContent(); } }; } @After public void after() { Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testEmpty() throws Exception { Assert.assertThat(_in.available(), Matchers.equalTo(0)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testRead() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); Assert.assertThat(_in.available(), Matchers.equalTo(2)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'E')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'F')); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'G')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'H')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testReRead() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); Assert.assertThat(_in.available(), Matchers.equalTo(2)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'E')); _in.prependContent(new HttpInput.Content(BufferUtil.toBuffer("abcde"))); Assert.assertThat(_in.available(), Matchers.equalTo(5)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(0L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'a')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(1L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'b')); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(2L)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'c')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'d')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'e')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'F')); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'G')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'H')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testBlockingRead() throws Exception { new Thread() { public void run() { try { Thread.sleep(500); _in.addContent(new TContent("AB")); } catch (Throwable th) { th.printStackTrace(); } } }.start(); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("blockForContent")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testReadEOF() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _in.eof(); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.available(), Matchers.equalTo(2)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo(-1)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testReadEarlyEOF() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _in.earlyEOF(); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.available(), Matchers.equalTo(2)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); try { _in.read(); Assert.fail(); } catch (EOFException eof) { Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); } Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testBlockingEOF() throws Exception { new Thread() { public void run() { try { Thread.sleep(500); _in.eof(); } catch (Throwable th) { th.printStackTrace(); } } }.start(); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo(-1)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("blockForContent")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testAsyncEmpty() throws Exception { _in.setReadListener(_listener); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testAsyncRead() throws Exception { _in.setReadListener(_listener); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.addContent(new TContent("AB")); _fillAndParseSimulate.add("CD"); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); Assert.assertThat(_history.poll(), Matchers.equalTo("l.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 1")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo((int)'C')); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'D')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testAsyncEOF() throws Exception { _in.setReadListener(_listener); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.eof(); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.read(), Matchers.equalTo(-1)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testAsyncReadEOF() throws Exception { _in.setReadListener(_listener); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.addContent(new TContent("AB")); _fillAndParseSimulate.add("_EOF_"); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); Assert.assertThat(_history.poll(), Matchers.equalTo("l.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_in.read(), Matchers.equalTo((int)'B')); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 1")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isFinished(), Matchers.equalTo(false)); Assert.assertThat(_in.read(), Matchers.equalTo(-1)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testAsyncError() throws Exception { _in.setReadListener(_listener); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(false)); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onReadUnready")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.failed(new TimeoutException()); Assert.assertThat(_history.poll(), Matchers.equalTo("s.onDataAvailable")); Assert.assertThat(_history.poll(), Matchers.nullValue()); _in.run(); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); Assert.assertThat(_history.poll(), Matchers.equalTo("l.onError:java.util.concurrent.TimeoutException")); Assert.assertThat(_history.poll(), Matchers.nullValue()); Assert.assertThat(_in.isReady(), Matchers.equalTo(true)); try { _in.read(); Assert.fail(); } catch (IOException e) { Assert.assertThat(e.getCause(), Matchers.instanceOf(TimeoutException.class)); Assert.assertThat(_in.isFinished(), Matchers.equalTo(true)); } Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testRecycle() throws Exception { testAsyncRead(); _in.recycle(); testAsyncRead(); _in.recycle(); testReadEOF(); } @Test public void testConsumeAll() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertFalse(_in.consumeAll()); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 2")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 0")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } @Test public void testConsumeAllEOF() throws Exception { _in.addContent(new TContent("AB")); _in.addContent(new TContent("CD")); _fillAndParseSimulate.offer("EF"); _fillAndParseSimulate.offer("GH"); _fillAndParseSimulate.offer("_EOF_"); Assert.assertThat(_in.read(), Matchers.equalTo((int)'A')); Assert.assertTrue(_in.consumeAll()); Assert.assertThat(_in.getContentConsumed(), Matchers.equalTo(8L)); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded AB")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded CD")); Assert.assertThat(_history.poll(), Matchers.equalTo("produceContent 3")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded EF")); Assert.assertThat(_history.poll(), Matchers.equalTo("Content succeeded GH")); Assert.assertThat(_history.poll(), Matchers.nullValue()); } }