Search in sources :

Example 81 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class AsyncIOServletTest method testWriteListenerFromOtherThread.

@Test
public void testWriteListenerFromOtherThread() throws Exception {
    start(new HttpServlet() {

        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            AsyncContext asyncContext = request.startAsync();
            asyncContext.setTimeout(0);
            request.getInputStream().setReadListener(new Listener(asyncContext));
        }
    });
    int cores = 4;
    int iterations = 10;
    CountDownLatch latch = new CountDownLatch(cores * iterations);
    Deque<Throwable> failures = new LinkedBlockingDeque<>();
    for (int i = 0; i < cores; ++i) {
        client.getExecutor().execute(() -> {
            for (int j = 0; j < iterations; ++j) {
                try {
                    ContentResponse response = client.newRequest(newURI()).method(HttpMethod.POST).path(servletPath).content(new InputStreamContentProvider(new ByteArrayInputStream(new byte[16 * 1024]) {

                        @Override
                        public int read(byte[] b, int off, int len) {
                            sleep(5);
                            return super.read(b, off, Math.min(len, 4242));
                        }
                    })).send();
                    Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
                    latch.countDown();
                } catch (Throwable x) {
                    failures.offer(x);
                }
            }
        });
    }
    Assert.assertTrue(latch.await(30, TimeUnit.SECONDS));
    Assert.assertTrue(failures.isEmpty());
}
Also used : BufferingResponseListener(org.eclipse.jetty.client.util.BufferingResponseListener) WriteListener(javax.servlet.WriteListener) ReadListener(javax.servlet.ReadListener) LinkedBlockingDeque(java.util.concurrent.LinkedBlockingDeque) ContentResponse(org.eclipse.jetty.client.api.ContentResponse) HttpServlet(javax.servlet.http.HttpServlet) HttpServletResponse(javax.servlet.http.HttpServletResponse) AsyncContext(javax.servlet.AsyncContext) UncheckedIOException(java.io.UncheckedIOException) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) InputStreamContentProvider(org.eclipse.jetty.client.util.InputStreamContentProvider) CountDownLatch(java.util.concurrent.CountDownLatch) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) ByteArrayInputStream(java.io.ByteArrayInputStream) Test(org.junit.Test)

Example 82 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class HttpClientStreamTest method testInputStreamResponseListenerBufferedRead.

@Test
public void testInputStreamResponseListenerBufferedRead() throws Exception {
    AtomicReference<AsyncContext> asyncContextRef = new AtomicReference<>();
    CountDownLatch latch = new CountDownLatch(1);
    start(new AbstractHandler() {

        @Override
        public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            baseRequest.setHandled(true);
            asyncContextRef.set(request.startAsync());
            latch.countDown();
        }
    });
    InputStreamResponseListener listener = new InputStreamResponseListener();
    client.newRequest("localhost", connector.getLocalPort()).scheme(getScheme()).timeout(5, TimeUnit.SECONDS).send(listener);
    Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
    AsyncContext asyncContext = asyncContextRef.get();
    Assert.assertNotNull(asyncContext);
    Random random = new Random();
    byte[] chunk = new byte[64];
    random.nextBytes(chunk);
    ServletOutputStream output = asyncContext.getResponse().getOutputStream();
    output.write(chunk);
    output.flush();
    // Use a buffer larger than the data
    // written to test that the read returns.
    byte[] buffer = new byte[2 * chunk.length];
    InputStream stream = listener.getInputStream();
    int totalRead = 0;
    while (totalRead < chunk.length) {
        int read = stream.read(buffer);
        Assert.assertTrue(read > 0);
        totalRead += read;
    }
    asyncContext.complete();
    Response response = listener.get(5, TimeUnit.SECONDS);
    Assert.assertEquals(200, response.getStatus());
}
Also used : Request(org.eclipse.jetty.server.Request) InputStreamResponseListener(org.eclipse.jetty.client.util.InputStreamResponseListener) ServletOutputStream(javax.servlet.ServletOutputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) HttpServletResponse(javax.servlet.http.HttpServletResponse) AtomicReference(java.util.concurrent.atomic.AtomicReference) AsyncContext(javax.servlet.AsyncContext) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) AbstractHandler(org.eclipse.jetty.server.handler.AbstractHandler) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) ContentResponse(org.eclipse.jetty.client.api.ContentResponse) Response(org.eclipse.jetty.client.api.Response) HttpServletResponse(javax.servlet.http.HttpServletResponse) Random(java.util.Random) Test(org.junit.Test)

Example 83 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class HttpClientStreamTest method testInputStreamResponseListenerClosedBeforeContent.

@Test(expected = AsynchronousCloseException.class)
public void testInputStreamResponseListenerClosedBeforeContent() throws Exception {
    AtomicReference<AsyncContext> contextRef = new AtomicReference<>();
    start(new AbstractHandler() {

        @Override
        public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
            baseRequest.setHandled(true);
            contextRef.set(request.startAsync());
            response.flushBuffer();
        }
    });
    CountDownLatch latch = new CountDownLatch(1);
    InputStreamResponseListener listener = new InputStreamResponseListener() {

        @Override
        public void onContent(Response response, ByteBuffer content, Callback callback) {
            super.onContent(response, content, new Callback() {

                @Override
                public void failed(Throwable x) {
                    latch.countDown();
                    callback.failed(x);
                }
            });
        }
    };
    client.newRequest("localhost", connector.getLocalPort()).scheme(getScheme()).send(listener);
    Response response = listener.get(5, TimeUnit.SECONDS);
    Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
    InputStream input = listener.getInputStream();
    input.close();
    AsyncContext asyncContext = contextRef.get();
    asyncContext.getResponse().getOutputStream().write(new byte[1024]);
    asyncContext.complete();
    Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
    // Throws
    input.read();
}
Also used : InputStreamResponseListener(org.eclipse.jetty.client.util.InputStreamResponseListener) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) Request(org.eclipse.jetty.server.Request) HttpServletRequest(javax.servlet.http.HttpServletRequest) HttpServletResponse(javax.servlet.http.HttpServletResponse) AtomicReference(java.util.concurrent.atomic.AtomicReference) AsyncContext(javax.servlet.AsyncContext) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBuffer(java.nio.ByteBuffer) AbstractHandler(org.eclipse.jetty.server.handler.AbstractHandler) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) ContentResponse(org.eclipse.jetty.client.api.ContentResponse) Response(org.eclipse.jetty.client.api.Response) HttpServletResponse(javax.servlet.http.HttpServletResponse) Callback(org.eclipse.jetty.util.Callback) Test(org.junit.Test)

Example 84 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class AsyncIOServletTest method testIsReadyAtEOF.

@Test
public void testIsReadyAtEOF() throws Exception {
    String text = "TEST\n";
    byte[] data = text.getBytes(StandardCharsets.UTF_8);
    start(new HttpServlet() {

        @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            assertScope();
            response.flushBuffer();
            AsyncContext async = request.startAsync();
            ServletInputStream input = request.getInputStream();
            ServletOutputStream output = response.getOutputStream();
            input.setReadListener(new ReadListener() {

                transient int _i = 0;

                transient boolean _minusOne = false;

                transient boolean _finished = false;

                @Override
                public void onDataAvailable() throws IOException {
                    assertScope();
                    while (input.isReady() && !input.isFinished()) {
                        int b = input.read();
                        if (b == -1)
                            _minusOne = true;
                        else if (data[_i++] != b)
                            throw new IllegalStateException();
                    }
                    if (input.isFinished())
                        _finished = true;
                }

                @Override
                public void onAllDataRead() throws IOException {
                    assertScope();
                    output.write(String.format("i=%d eof=%b finished=%b", _i, _minusOne, _finished).getBytes(StandardCharsets.UTF_8));
                    async.complete();
                }

                @Override
                public void onError(Throwable t) {
                    assertScope();
                    t.printStackTrace();
                    async.complete();
                }
            });
        }
    });
    ContentResponse response = client.newRequest(newURI()).method(HttpMethod.POST).path(servletPath).header(HttpHeader.CONNECTION, "close").content(new StringContentProvider(text)).timeout(5, TimeUnit.SECONDS).send();
    String responseContent = response.getContentAsString();
    assertThat(responseContent, containsString("i=" + data.length + " eof=true finished=true"));
}
Also used : ServletOutputStream(javax.servlet.ServletOutputStream) ContentResponse(org.eclipse.jetty.client.api.ContentResponse) StringContentProvider(org.eclipse.jetty.client.util.StringContentProvider) HttpServlet(javax.servlet.http.HttpServlet) HttpServletResponse(javax.servlet.http.HttpServletResponse) AsyncContext(javax.servlet.AsyncContext) Matchers.containsString(org.hamcrest.Matchers.containsString) UncheckedIOException(java.io.UncheckedIOException) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) ReadListener(javax.servlet.ReadListener) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) ServletInputStream(javax.servlet.ServletInputStream) Test(org.junit.Test)

Example 85 with AsyncContext

use of javax.servlet.AsyncContext in project jetty.project by eclipse.

the class ResourceService method sendData.

/* ------------------------------------------------------------ */
protected boolean sendData(HttpServletRequest request, HttpServletResponse response, boolean include, final HttpContent content, Enumeration<String> reqRanges) throws IOException {
    final long content_length = content.getContentLengthValue();
    // Get the output stream (or writer)
    OutputStream out = null;
    boolean written;
    try {
        out = response.getOutputStream();
        // has something already written to the response?
        written = out instanceof HttpOutput ? ((HttpOutput) out).isWritten() : true;
    } catch (IllegalStateException e) {
        out = new WriterOutputStream(response.getWriter());
        // there may be data in writer buffer, so assume written
        written = true;
    }
    if (LOG.isDebugEnabled())
        LOG.debug(String.format("sendData content=%s out=%s async=%b", content, out, request.isAsyncSupported()));
    if (reqRanges == null || !reqRanges.hasMoreElements() || content_length < 0) {
        //  if there were no ranges, send entire entity
        if (include) {
            // write without headers
            content.getResource().writeTo(out, 0, content_length);
        } else // else if we can't do a bypass write because of wrapping
        if (written || !(out instanceof HttpOutput)) {
            // write normally
            putHeaders(response, content, written ? -1 : 0);
            ByteBuffer buffer = content.getIndirectBuffer();
            if (buffer != null)
                BufferUtil.writeTo(buffer, out);
            else
                content.getResource().writeTo(out, 0, content_length);
        } else // else do a bypass write
        {
            // write the headers
            putHeaders(response, content, 0);
            // write the content asynchronously if supported
            if (request.isAsyncSupported() && content.getContentLengthValue() > response.getBufferSize()) {
                final AsyncContext context = request.startAsync();
                context.setTimeout(0);
                ((HttpOutput) out).sendContent(content, new Callback() {

                    @Override
                    public void succeeded() {
                        context.complete();
                        content.release();
                    }

                    @Override
                    public void failed(Throwable x) {
                        if (x instanceof IOException)
                            LOG.debug(x);
                        else
                            LOG.warn(x);
                        context.complete();
                        content.release();
                    }

                    @Override
                    public String toString() {
                        return String.format("ResourceService@%x$CB", ResourceService.this.hashCode());
                    }
                });
                return false;
            }
            // otherwise write content blocking
            ((HttpOutput) out).sendContent(content);
        }
    } else {
        // Parse the satisfiable ranges
        List<InclusiveByteRange> ranges = InclusiveByteRange.satisfiableRanges(reqRanges, content_length);
        //  if there are no satisfiable ranges, send 416 response
        if (ranges == null || ranges.size() == 0) {
            putHeaders(response, content, 0);
            response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
            response.setHeader(HttpHeader.CONTENT_RANGE.asString(), InclusiveByteRange.to416HeaderRangeString(content_length));
            content.getResource().writeTo(out, 0, content_length);
            return true;
        }
        //  since were here now), send that range with a 216 response
        if (ranges.size() == 1) {
            InclusiveByteRange singleSatisfiableRange = ranges.get(0);
            long singleLength = singleSatisfiableRange.getSize(content_length);
            putHeaders(response, content, singleLength);
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            if (!response.containsHeader(HttpHeader.DATE.asString()))
                response.addDateHeader(HttpHeader.DATE.asString(), System.currentTimeMillis());
            response.setHeader(HttpHeader.CONTENT_RANGE.asString(), singleSatisfiableRange.toHeaderRangeString(content_length));
            content.getResource().writeTo(out, singleSatisfiableRange.getFirst(content_length), singleLength);
            return true;
        }
        //  multiple non-overlapping valid ranges cause a multipart
        //  216 response which does not require an overall
        //  content-length header
        //
        putHeaders(response, content, -1);
        String mimetype = (content == null ? null : content.getContentTypeValue());
        if (mimetype == null)
            LOG.warn("Unknown mimetype for " + request.getRequestURI());
        MultiPartOutputStream multi = new MultiPartOutputStream(out);
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        if (!response.containsHeader(HttpHeader.DATE.asString()))
            response.addDateHeader(HttpHeader.DATE.asString(), System.currentTimeMillis());
        // If the request has a "Request-Range" header then we need to
        // send an old style multipart/x-byteranges Content-Type. This
        // keeps Netscape and acrobat happy. This is what Apache does.
        String ctp;
        if (request.getHeader(HttpHeader.REQUEST_RANGE.asString()) != null)
            ctp = "multipart/x-byteranges; boundary=";
        else
            ctp = "multipart/byteranges; boundary=";
        response.setContentType(ctp + multi.getBoundary());
        InputStream in = content.getResource().getInputStream();
        long pos = 0;
        // calculate the content-length
        int length = 0;
        String[] header = new String[ranges.size()];
        for (int i = 0; i < ranges.size(); i++) {
            InclusiveByteRange ibr = ranges.get(i);
            header[i] = ibr.toHeaderRangeString(content_length);
            length += ((i > 0) ? 2 : 0) + 2 + multi.getBoundary().length() + 2 + (mimetype == null ? 0 : HttpHeader.CONTENT_TYPE.asString().length() + 2 + mimetype.length()) + 2 + HttpHeader.CONTENT_RANGE.asString().length() + 2 + header[i].length() + 2 + 2 + (ibr.getLast(content_length) - ibr.getFirst(content_length)) + 1;
        }
        length += 2 + 2 + multi.getBoundary().length() + 2 + 2;
        response.setContentLength(length);
        for (int i = 0; i < ranges.size(); i++) {
            InclusiveByteRange ibr = ranges.get(i);
            multi.startPart(mimetype, new String[] { HttpHeader.CONTENT_RANGE + ": " + header[i] });
            long start = ibr.getFirst(content_length);
            long size = ibr.getSize(content_length);
            if (in != null) {
                // Handle non cached resource
                if (start < pos) {
                    in.close();
                    in = content.getResource().getInputStream();
                    pos = 0;
                }
                if (pos < start) {
                    in.skip(start - pos);
                    pos = start;
                }
                IO.copy(in, multi, size);
                pos += size;
            } else
                // Handle cached resource
                content.getResource().writeTo(multi, start, size);
        }
        if (in != null)
            in.close();
        multi.close();
    }
    return true;
}
Also used : InputStream(java.io.InputStream) OutputStream(java.io.OutputStream) MultiPartOutputStream(org.eclipse.jetty.util.MultiPartOutputStream) WriterOutputStream(org.eclipse.jetty.io.WriterOutputStream) AsyncContext(javax.servlet.AsyncContext) IOException(java.io.IOException) WriterOutputStream(org.eclipse.jetty.io.WriterOutputStream) ByteBuffer(java.nio.ByteBuffer) MultiPartOutputStream(org.eclipse.jetty.util.MultiPartOutputStream) Callback(org.eclipse.jetty.util.Callback)

Aggregations

AsyncContext (javax.servlet.AsyncContext)120 IOException (java.io.IOException)61 HttpServletRequest (javax.servlet.http.HttpServletRequest)53 ServletException (javax.servlet.ServletException)52 HttpServletResponse (javax.servlet.http.HttpServletResponse)50 Test (org.junit.Test)43 CountDownLatch (java.util.concurrent.CountDownLatch)33 HttpServlet (javax.servlet.http.HttpServlet)32 InterruptedIOException (java.io.InterruptedIOException)24 ServletOutputStream (javax.servlet.ServletOutputStream)20 ReadListener (javax.servlet.ReadListener)19 ServletInputStream (javax.servlet.ServletInputStream)19 AsyncEvent (javax.servlet.AsyncEvent)18 ContentResponse (org.eclipse.jetty.client.api.ContentResponse)18 AsyncListener (javax.servlet.AsyncListener)15 UncheckedIOException (java.io.UncheckedIOException)14 DeferredContentProvider (org.eclipse.jetty.client.util.DeferredContentProvider)14 Request (org.eclipse.jetty.server.Request)13 Matchers.containsString (org.hamcrest.Matchers.containsString)13 WriteListener (javax.servlet.WriteListener)11