Example usage for org.springframework.http HttpHeaders CONTENT_RANGE

List of usage examples for org.springframework.http HttpHeaders CONTENT_RANGE

Introduction

In this page you can find the example usage for org.springframework.http HttpHeaders CONTENT_RANGE.

Prototype

String CONTENT_RANGE

To view the source code for org.springframework.http HttpHeaders CONTENT_RANGE.

Click Source Link

Document

The HTTP Content-Range header field name.

Usage

From source file:com.github.zhanhb.ckfinder.download.PathPartial.java

/**
 * Serve the specified resource, optionally including the data content.
 *
 * @param request The servlet request we are processing
 * @param response The servlet response we are creating
 * @param content Should the content be included?
 * @param path the resource to serve//w w w  .j  a  va2s. c  o  m
 *
 * @exception IOException if an input/output error occurs
 */
private void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content, Path path)
        throws IOException, ServletException {
    ActionContext context = new ActionContext().put(HttpServletRequest.class, request)
            .put(HttpServletResponse.class, response).put(ServletContext.class, request.getServletContext())
            .put(Path.class, path);
    if (path == null) {
        notFound.handle(context);
        return;
    }
    BasicFileAttributes attr;
    try {
        attr = Files.readAttributes(path, BasicFileAttributes.class);
    } catch (IOException ex) {
        notFound.handle(context);
        return;
    }
    context.put(BasicFileAttributes.class, attr);

    boolean isError = response.getStatus() >= HttpServletResponse.SC_BAD_REQUEST;
    // Check if the conditions specified in the optional If headers are
    // satisfied.
    // Checking If headers
    boolean included = (request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH) != null);
    String etag = this.eTag.getValue(context);
    if (!included && !isError && !checkIfHeaders(request, response, attr, etag)) {
        return;
    }
    // Find content type.
    String contentType = contentTypeResolver.getValue(context);
    // Get content length
    long contentLength = attr.size();
    // Special case for zero length files, which would cause a
    // (silent) ISE
    boolean serveContent = content && contentLength != 0;
    Range[] ranges = null;
    if (!isError) {
        if (useAcceptRanges) {
            // Accept ranges header
            response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
        }
        // Parse range specifier
        ranges = serveContent ? parseRange(request, response, attr, etag) : FULL;
        // ETag header
        response.setHeader(HttpHeaders.ETAG, etag);
        // Last-Modified header
        response.setDateHeader(HttpHeaders.LAST_MODIFIED, attr.lastModifiedTime().toMillis());
    }
    ServletOutputStream ostream = null;
    if (serveContent) {
        ostream = response.getOutputStream();
    }

    String disposition = contentDisposition.getValue(context);
    if (disposition != null) {
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, disposition);
    }

    // Check to see if a Filter, Valve of wrapper has written some content.
    // If it has, disable range requests and setting of a content length
    // since neither can be done reliably.
    if (isError || ranges == FULL) {
        // Set the appropriate output headers
        if (contentType != null) {
            log.debug("serveFile: contentType='{}'", contentType);
            response.setContentType(contentType);
        }
        if (contentLength >= 0) {
            setContentLengthLong(response, contentLength);
        }
        // Copy the input stream to our output stream (if requested)
        if (serveContent) {
            log.trace("Serving bytes");
            Files.copy(path, ostream);
        }
    } else if (ranges != null && ranges.length != 0) {
        // Partial content response.
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        if (ranges.length == 1) {
            Range range = ranges[0];
            response.addHeader(HttpHeaders.CONTENT_RANGE, range.toString());
            long length = range.end - range.start + 1;
            setContentLengthLong(response, length);
            if (contentType != null) {
                log.debug("serveFile: contentType='{}'", contentType);
                response.setContentType(contentType);
            }
            if (serveContent) {
                try (InputStream stream = Files.newInputStream(path)) {
                    copyRange(stream, ostream, range, new byte[Math.min((int) length, 8192)]);
                }
            }
        } else {
            response.setContentType("multipart/byteranges; boundary=" + MIME_SEPARATION);
            if (serveContent) {
                copy(path, ostream, ranges, contentType, new byte[Math.min((int) contentLength, 8192)]);
            }
        }
    }
}

From source file:com.github.zhanhb.ckfinder.download.PathPartial.java

/**
 * Parse the range header./*from   w w w  .  jav a 2s  .  c o  m*/
 *
 * @param request The servlet request we are processing
 * @param response The servlet response we are creating
 * @param attr File attributes
 * @param etag ETag of the entity
 * @return array of ranges
 */
@Nullable
@SuppressWarnings("ReturnOfCollectionOrArrayField")
private Range[] parseRange(HttpServletRequest request, HttpServletResponse response, BasicFileAttributes attr,
        String etag) throws IOException {
    // Checking If-Range
    String headerValue = request.getHeader(HttpHeaders.IF_RANGE);
    if (headerValue != null) {
        long headerValueTime = -1;
        try {
            headerValueTime = request.getDateHeader(HttpHeaders.IF_RANGE);
        } catch (IllegalArgumentException e) {
            // Ignore
        }
        // If the ETag the client gave does not match the entity
        // eTag, then the entire entity is returned.
        if (headerValueTime == -1 && !headerValue.trim().equals(etag)
                || attr.lastModifiedTime().toMillis() > headerValueTime + 1000) {
            // If the timestamp of the entity the client got is older than
            // the last modification date of the entity, the entire entity
            // is returned.
            return FULL;
        }
    }
    long fileLength = attr.size();
    if (fileLength == 0) {
        return FULL;
    }
    // Retrieving the range header (if any is specified
    String rangeHeader = request.getHeader(HttpHeaders.RANGE);
    if (rangeHeader == null) {
        return FULL;
    }
    // bytes is the only range unit supported (and I don't see the point
    // of adding new ones).
    if (!rangeHeader.startsWith("bytes=")) {
        return FULL;
    }
    // List which will contain all the ranges which are successfully
    // parsed.
    List<Range> result = new ArrayList<>(4);
    // Parsing the range list
    // "bytes=".length() = 6
    for (int index, last = 6;; last = index + 1) {
        index = rangeHeader.indexOf(',', last);
        boolean isLast = index == -1;
        final String rangeDefinition = (isLast ? rangeHeader.substring(last)
                : rangeHeader.substring(last, index)).trim();
        final int dashPos = rangeDefinition.indexOf('-');
        if (dashPos == -1) {
            break;
        }
        final Range currentRange = new Range(fileLength);
        try {
            if (dashPos == 0) {
                final long offset = Long.parseLong(rangeDefinition);
                if (offset == 0) { // -0, --0
                    break;
                }
                currentRange.start = Math.max(fileLength + offset, 0);
            } else {
                currentRange.start = Long.parseLong(rangeDefinition.substring(0, dashPos));
                if (dashPos < rangeDefinition.length() - 1) {
                    currentRange.end = Long
                            .parseLong(rangeDefinition.substring(dashPos + 1, rangeDefinition.length()));
                }
            }
        } catch (NumberFormatException e) {
            break;
        }
        if (!currentRange.validate()) {
            break;
        }
        result.add(currentRange);
        if (isLast) {
            int size = result.size();
            if (size == 0) {
                break;
            }
            return result.toArray(new Range[size]);
        }
    }
    response.addHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + fileLength);
    response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
    return null;
}

From source file:bjerne.gallery.controller.GalleryController.java

/**
 * Method used to return the binary of a gallery file (
 * {@link GalleryFile#getActualFile()} ). This method handles 304 redirects
 * (if file has not changed) and range headers if requested by browser. The
 * range parts is particularly important for videos. The correct response
 * status is set depending on the circumstances.
 * <p>// w w  w .j  av  a  2 s. c om
 * NOTE: the range logic should NOT be considered a complete implementation
 * - it's a bare minimum for making requests for byte ranges work.
 * 
 * @param request
 *            Request
 * @param galleryFile
 *            Gallery file
 * @return The binary of the gallery file, or a 304 redirect, or a part of
 *         the file.
 * @throws IOException
 *             If there is an issue accessing the binary file.
 */
private ResponseEntity<InputStreamResource> returnResource(WebRequest request, GalleryFile galleryFile)
        throws IOException {
    LOG.debug("Entering returnResource()");
    if (request.checkNotModified(galleryFile.getActualFile().lastModified())) {
        return null;
    }
    File file = galleryFile.getActualFile();
    String contentType = galleryFile.getContentType();
    String rangeHeader = request.getHeader(HttpHeaders.RANGE);
    long[] ranges = getRangesFromHeader(rangeHeader);
    long startPosition = ranges[0];
    long fileTotalSize = file.length();
    long endPosition = ranges[1] != 0 ? ranges[1] : fileTotalSize - 1;
    long contentLength = endPosition - startPosition + 1;
    LOG.debug("contentLength: {}, file length: {}", contentLength, fileTotalSize);

    LOG.debug("Returning resource {} as inputstream. Start position: {}", file.getCanonicalPath(),
            startPosition);
    InputStream boundedInputStream = new BoundedInputStream(new FileInputStream(file), endPosition + 1);

    InputStream is = new BufferedInputStream(boundedInputStream, 65536);
    InputStreamResource inputStreamResource = new InputStreamResource(is);
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentLength(contentLength);
    responseHeaders.setContentType(MediaType.valueOf(contentType));
    responseHeaders.add(HttpHeaders.ACCEPT_RANGES, "bytes");
    if (StringUtils.isNotBlank(rangeHeader)) {
        is.skip(startPosition);
        String contentRangeResponseHeader = "bytes " + startPosition + "-" + endPosition + "/" + fileTotalSize;
        responseHeaders.add(HttpHeaders.CONTENT_RANGE, contentRangeResponseHeader);
        LOG.debug("{} was not null but {}. Adding header {} to response: {}", HttpHeaders.RANGE, rangeHeader,
                HttpHeaders.CONTENT_RANGE, contentRangeResponseHeader);
    }
    HttpStatus status = (startPosition == 0 && contentLength == fileTotalSize) ? HttpStatus.OK
            : HttpStatus.PARTIAL_CONTENT;
    LOG.debug("Returning {}. Status: {}, content-type: {}, {}: {}, contentLength: {}", file, status,
            contentType, HttpHeaders.CONTENT_RANGE, responseHeaders.get(HttpHeaders.CONTENT_RANGE),
            contentLength);
    return new ResponseEntity<InputStreamResource>(inputStreamResource, responseHeaders, status);
}

From source file:com.github.zhanhb.ckfinder.download.PathPartial.java

/**
 * Copy the contents of the specified input stream to the specified output
 * stream, and ensure that both streams are closed before returning (even in
 * the face of an exception).// www . j  a va  2  s .  com
 *
 * @param path The cache entry for the source resource
 * @param ostream The output stream to write to
 * @param ranges Enumeration of the ranges the client wanted to retrieve
 * @param contentType Content type of the resource
 * @param buffer buffer to copy the resource
 * @exception IOException if an input/output error occurs
 */
private void copy(Path path, ServletOutputStream ostream, Range[] ranges, String contentType, byte[] buffer)
        throws IOException {
    IOException exception = null;
    for (Range currentRange : ranges) {
        try (InputStream stream = Files.newInputStream(path)) {
            // Writing MIME header.
            ostream.println();
            ostream.println("--" + MIME_SEPARATION);
            if (contentType != null) {
                ostream.println(HttpHeaders.CONTENT_TYPE + ": " + contentType);
            }
            ostream.println(HttpHeaders.CONTENT_RANGE + ": " + currentRange);
            ostream.println();
            // Printing content
            copyRange(stream, ostream, currentRange, buffer);
        } catch (IOException ex) {
            exception = ex;
        }
    }
    ostream.println();
    ostream.print("--" + MIME_SEPARATION + "--");
    if (exception != null) {
        throw exception;
    }
}