Search in sources :

Example 1 with HttpByteRange

use of jetbrains.buildServer.web.util.HttpByteRange in project teamcity-rest by JetBrains.

the class FilesSubResource method getContentByStream.

public static Response.ResponseBuilder getContentByStream(@NotNull final Element element, @NotNull final HttpServletRequest request, @NotNull final StreamingOutputProvider streamingOutputProvider) {
    // TeamCity API: need to lock artifacts while reading???  e.g. see JavaDoc for jetbrains.buildServer.serverSide.artifacts.BuildArtifacts.iterateArtifacts()
    if (!element.isContentAvailable()) {
        throw new NotFoundException("Cannot provide content for '" + element.getFullName() + "' (not a file).");
    }
    final String rangeHeader = request.getHeader(HttpHeaders.RANGE);
    Long fullFileSize = null;
    try {
        final long size = element.getSize();
        if (size >= 0) {
            fullFileSize = size;
        }
    } catch (IllegalStateException e) {
    // just do not set size in the case
    }
    Response.ResponseBuilder builder;
    if (StringUtil.isEmpty(rangeHeader)) {
        builder = Response.ok().entity(streamingOutputProvider.getStreamingOutput(null, null));
        if (fullFileSize != null) {
            builder.header(HttpHeaders.CONTENT_LENGTH, fullFileSize);
        }
    } else {
        if (!streamingOutputProvider.isRangeSupported()) {
            throw new BadRequestException("Ranged requests are not supported for this entity");
        }
        try {
            HttpByteRange range = new HttpByteRange(rangeHeader, fullFileSize);
            // todo: support requests with "Range: bytes=XX-" header and unknown content-length via multipart/byteranges Content-Type including Content-Range fields for each part
            if (range.getRangesCount() > 1) {
                builder = Response.status(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE).entity("Multiple Range header ranges are not (yet) supported");
            } else {
                final HttpByteRange.SimpleRange firstRange = range.getSimpleRangesIterator().next();
                builder = Response.status(HttpServletResponse.SC_PARTIAL_CONTENT);
                final long rangeLength = firstRange.getLength();
                builder.entity(streamingOutputProvider.getStreamingOutput(firstRange.getBeginIndex(), rangeLength));
                builder.header("Content-Range", range.getContentRangeHeaderValue(firstRange));
                if (fullFileSize != null) {
                    builder.header(HttpHeaders.CONTENT_LENGTH, rangeLength);
                }
            }
        } catch (ParseException e) {
            builder = Response.status(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE).entity("Error parsing Range header: " + e.getMessage());
            if (fullFileSize != null) {
                builder.header("Content-Range", HttpByteRange.getContentRangeHeaderValueFor416Response(fullFileSize));
            }
        }
    }
    builder.header("Accept-Ranges", HttpByteRange.RANGE_UNIT_BYTES);
    if (TeamCityProperties.getBooleanOrTrue("rest.build.artifacts.setMimeType")) {
        builder = builder.type(WebUtil.getMimeType(request, element.getName()));
    } else {
        builder = builder.type(MediaType.APPLICATION_OCTET_STREAM_TYPE);
    }
    if (TeamCityProperties.getBooleanOrTrue("rest.build.artifacts.forceContentDisposition.Attachment")) {
        // make sure the file is not displayed in the browser (TW-27206)
        builder = builder.header("Content-Disposition", WebUtil.getContentDispositionValue(request, "attachment", element.getName()));
    } else {
        builder = builder.header("Content-Disposition", WebUtil.getContentDispositionValue(request, null, element.getName()));
    }
    if (element instanceof ArtifactTreeElement) {
        final Long lastModified = ((ArtifactTreeElement) element).getLastModified();
        if (lastModified != null) {
            builder.lastModified(new Date(lastModified));
        }
        final long size = element.getSize();
        // mark ETag as "weak"
        builder.header("ETag", "W/\"" + EncryptUtil.md5((size >= 0 ? String.valueOf(size) : "") + (lastModified != null ? lastModified : "")) + "\"");
    } else {
        final long size = element.getSize();
        if (size >= 0) {
            // mark ETag as "weak"
            builder.header("ETag", "W/\"" + EncryptUtil.md5(String.valueOf(size)) + "\"");
        }
    }
    return builder;
}
Also used : HttpByteRange(jetbrains.buildServer.web.util.HttpByteRange) NotFoundException(jetbrains.buildServer.server.rest.errors.NotFoundException) Date(java.util.Date) HttpServletResponse(javax.servlet.http.HttpServletResponse) BadRequestException(jetbrains.buildServer.server.rest.errors.BadRequestException) ParseException(java.text.ParseException) ArtifactTreeElement(jetbrains.buildServer.web.artifacts.browser.ArtifactTreeElement)

Aggregations

ParseException (java.text.ParseException)1 Date (java.util.Date)1 HttpServletResponse (javax.servlet.http.HttpServletResponse)1 BadRequestException (jetbrains.buildServer.server.rest.errors.BadRequestException)1 NotFoundException (jetbrains.buildServer.server.rest.errors.NotFoundException)1 ArtifactTreeElement (jetbrains.buildServer.web.artifacts.browser.ArtifactTreeElement)1 HttpByteRange (jetbrains.buildServer.web.util.HttpByteRange)1