Search in sources :

Example 1 with WriterOutputStream

use of org.eclipse.jetty.io.WriterOutputStream in project bnd by bndtools.

the class ETaggingResourceHandler method handle.

public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    if (baseRequest.isHandled())
        return;
    boolean skipContentBody = false;
    if (!HttpMethods.GET.equals(request.getMethod())) {
        if (!HttpMethods.HEAD.equals(request.getMethod())) {
            // try another handler
            super.handle(target, baseRequest, request, response);
            return;
        }
        skipContentBody = true;
    }
    Resource resource = getResource(request);
    if (resource == null || !resource.exists()) {
        // no resource - try other handlers
        super.handle(target, baseRequest, request, response);
        return;
    }
    // We are going to serve something
    baseRequest.setHandled(true);
    if (resource.isDirectory()) {
        response.sendError(HttpStatus.FORBIDDEN_403);
    }
    // set some headers
    long last_modified = resource.lastModified();
    if (last_modified > 0) {
        long if_modified = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
        if (if_modified > 0 && last_modified / 1000 <= if_modified / 1000) {
            response.setStatus(HttpStatus.NOT_MODIFIED_304);
            return;
        }
    }
    String etag = calculateETag(resource);
    String incomingETag = request.getHeader(HttpHeaders.IF_NONE_MATCH);
    if (incomingETag != null) {
        if (incomingETag.equals(etag)) {
            response.setStatus(HttpStatus.NOT_MODIFIED_304);
            return;
        }
    }
    response.setHeader(HttpHeaders.ETAG, etag);
    Buffer mime = _mimeTypes.getMimeByExtension(resource.toString());
    if (mime == null)
        mime = _mimeTypes.getMimeByExtension(request.getPathInfo());
    // set the headers
    doResponseHeaders(response, resource, mime != null ? mime.toString() : null);
    response.setDateHeader(HttpHeaders.LAST_MODIFIED, last_modified);
    if (skipContentBody)
        return;
    // Send the content
    OutputStream out = null;
    try {
        out = response.getOutputStream();
    } catch (IllegalStateException e) {
        out = new WriterOutputStream(response.getWriter());
    }
    resource.writeTo(out, 0, resource.length());
}
Also used : Buffer(org.eclipse.jetty.io.Buffer) OutputStream(java.io.OutputStream) WriterOutputStream(org.eclipse.jetty.io.WriterOutputStream) Resource(org.eclipse.jetty.util.resource.Resource) WriterOutputStream(org.eclipse.jetty.io.WriterOutputStream)

Example 2 with WriterOutputStream

use of org.eclipse.jetty.io.WriterOutputStream 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

OutputStream (java.io.OutputStream)2 WriterOutputStream (org.eclipse.jetty.io.WriterOutputStream)2 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 ByteBuffer (java.nio.ByteBuffer)1 AsyncContext (javax.servlet.AsyncContext)1 Buffer (org.eclipse.jetty.io.Buffer)1 Callback (org.eclipse.jetty.util.Callback)1 MultiPartOutputStream (org.eclipse.jetty.util.MultiPartOutputStream)1 Resource (org.eclipse.jetty.util.resource.Resource)1