Example usage for org.springframework.http HttpHeaders RANGE

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

Introduction

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

Prototype

String RANGE

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

Click Source Link

Document

The HTTP Range header field name.

Usage

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

/**
 * Parse the range header./*  w  w  w  .  j av a  2 s. 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>/*from  w w w  .  j  a  v  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:org.springframework.web.servlet.resource.ResourceHttpRequestHandler.java

/**
 * Processes a resource request./*from ww  w  . java 2  s  .c o  m*/
 * <p>Checks for the existence of the requested resource in the configured list of locations.
 * If the resource does not exist, a {@code 404} response will be returned to the client.
 * If the resource exists, the request will be checked for the presence of the
 * {@code Last-Modified} header, and its value will be compared against the last-modified
 * timestamp of the given resource, returning a {@code 304} status code if the
 * {@code Last-Modified} value  is greater. If the resource is newer than the
 * {@code Last-Modified} value, or the header is not present, the content resource
 * of the resource will be written to the response with caching headers
 * set to expire one year in the future.
 */
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    // For very general mappings (e.g. "/") we need to check 404 first
    Resource resource = getResource(request);
    if (resource == null) {
        logger.trace("No matching resource found - returning 404");
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
    }

    if (HttpMethod.OPTIONS.matches(request.getMethod())) {
        response.setHeader("Allow", getAllowHeader());
        return;
    }

    // Supported methods and required session
    checkRequest(request);

    // Header phase
    if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
        logger.trace("Resource not modified - returning 304");
        return;
    }

    // Apply cache settings, if any
    prepareResponse(response);

    // Check the media type for the resource
    MediaType mediaType = getMediaType(request, resource);
    if (mediaType != null) {
        if (logger.isTraceEnabled()) {
            logger.trace("Determined media type '" + mediaType + "' for " + resource);
        }
    } else {
        if (logger.isTraceEnabled()) {
            logger.trace("No media type found for " + resource + " - not sending a content-type header");
        }
    }

    // Content phase
    if (METHOD_HEAD.equals(request.getMethod())) {
        setHeaders(response, resource, mediaType);
        logger.trace("HEAD request - skipping content");
        return;
    }

    ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
    if (request.getHeader(HttpHeaders.RANGE) == null) {
        Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
        setHeaders(response, resource, mediaType);
        this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
    } else {
        Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
        response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
        ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
        try {
            List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            this.resourceRegionHttpMessageConverter.write(HttpRange.toResourceRegions(httpRanges, resource),
                    mediaType, outputMessage);
        } catch (IllegalArgumentException ex) {
            response.setHeader("Content-Range", "bytes */" + resource.contentLength());
            response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
        }
    }
}