List of usage examples for javax.servlet.http HttpServletResponse SC_REQUESTED_RANGE_NOT_SATISFIABLE
int SC_REQUESTED_RANGE_NOT_SATISFIABLE
To view the source code for javax.servlet.http HttpServletResponse SC_REQUESTED_RANGE_NOT_SATISFIABLE.
Click Source Link
From source file:org.sakaiproject.nakamura.proxy.ICalProxyPostProcessor.java
/** * Parse the response as an iCalendar feed, throwing an IOException if the response * is too long.//from ww w . ja va 2 s.c o m * @throws ResponseFailedException * */ private Calendar loadCalendar(ProxyResponse response) throws IOException, ParserException, ResponseFailedException { // We won't bother checking the Content-Length header directly as it may not be // present, we'll just count the number of bytes read from the input stream. LengthLimitingInputStream input = new LengthLimitingInputStream(response.getResponseBodyAsInputStream(), this.maxResponseLength); try { return new CalendarBuilder().build(input); } // The LengthLimitingInputStream throws a StreamLengthException when a read() pushes // the number of read bytes over the limit catch (StreamLengthException e) { throw new ResponseFailedException(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, "The remote server's response was too long: " + e.getMessage()); } }
From source file:com.epam.catgenome.controller.util.MultipartFileSender.java
private List<Range> processRange(Long length, String fileName, Range full) throws IOException { // Prepare some variables. The full Range represents the complete file. List<Range> ranges = new ArrayList<>(); // Validate and process Range and If-Range headers. String range = request.getHeader("Range"); if (range != null) { // Range header should match format "bytes=n-n,n-n,n-n...". If not, then return 416. if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { response.setHeader(CONTENT_RANGE_HEADER, "bytes */" + length); // Required in 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; }//from w w w . ja v a2 s.c o m String ifRange = request.getHeader("If-Range"); if (ifRange != null && !ifRange.equals(fileName)) { try { long ifRangeTime = request.getDateHeader("If-Range"); // Throws IAE if invalid. if (ifRangeTime != -1) { ranges.add(full); } } catch (IllegalArgumentException ignore) { ranges.add(full); } } // If any valid If-Range header, then process each part of byte range. if (ranges.isEmpty()) { for (String part : range.substring(6).split(",")) { // Assuming a file with length of 100, the following examples returns bytes at: // 50-80 (50 to 80), 40- (40 to length=100), -20 (length-20=80 to length=100). long start = Range.sublong(part, 0, part.indexOf('-')); long end = Range.sublong(part, part.indexOf('-') + 1, part.length()); if (start == -1) { start = length - end; end = length - 1; } else if (end == -1 || end > length - 1) { end = length - 1; } // Check if Range is syntactically valid. If not, then return 416. if (start > end) { response.setHeader(CONTENT_RANGE_HEADER, "bytes */" + length); // Required in 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } // Add range. ranges.add(new Range(start, end, length)); } } } return ranges; }
From source file:org.alfresco.repo.web.util.HttpRangeProcessor.java
/** * Process multiple ranges.//from w w w. j av a 2s.com * * @param res HttpServletResponse * @param range Range header value * @param ref NodeRef to the content for streaming * @param property Content Property for the content * @param mimetype Mimetype of the content * @param userAgent User Agent of the caller * * @return true if processed range, false otherwise */ private boolean processMultiRange(Object res, String range, NodeRef ref, QName property, String mimetype, String userAgent) throws IOException { final Log logger = getLogger(); // Handle either HttpServletResponse or WebScriptResponse HttpServletResponse httpServletResponse = null; WebScriptResponse webScriptResponse = null; if (res instanceof HttpServletResponse) { httpServletResponse = (HttpServletResponse) res; } else if (res instanceof WebScriptResponse) { webScriptResponse = (WebScriptResponse) res; } if (httpServletResponse == null && webScriptResponse == null) { // Unknown response object type return false; } // return the sets of bytes as requested in the content-range header // the response will be formatted as multipart/byteranges media type message /* Examples of byte-ranges-specifier values (assuming an entity-body of length 10000): - The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-499 - The second 500 bytes (byte offsets 500-999, inclusive): bytes=500-999 - The final 500 bytes (byte offsets 9500-9999, inclusive): bytes=-500 - Or bytes=9500- - The first and last bytes only (bytes 0 and 9999): bytes=0-0,-1 - Several legal but not canonical specifications of byte offsets 500-999, inclusive: bytes=500-600,601-999 bytes=500-700,601-999 */ boolean processedRange = false; // get the content reader ContentReader reader = contentService.getReader(ref, property); final List<Range> ranges = new ArrayList<Range>(8); long entityLength = reader.getSize(); for (StringTokenizer t = new StringTokenizer(range, ", "); t.hasMoreTokens(); /**/) { try { ranges.add(Range.constructRange(t.nextToken(), mimetype, entityLength)); } catch (IllegalArgumentException err) { if (getLogger().isDebugEnabled()) getLogger() .debug("Failed to parse range header - returning 416 status code: " + err.getMessage()); if (httpServletResponse != null) { httpServletResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); httpServletResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\""); httpServletResponse.getOutputStream().close(); } else if (webScriptResponse != null) { webScriptResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); webScriptResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\""); webScriptResponse.getOutputStream().close(); } return true; } } if (ranges.size() != 0) { // merge byte ranges if possible - IE handles this well, FireFox not so much if (userAgent == null || userAgent.indexOf("MSIE ") != -1) { Collections.sort(ranges); for (int i = 0; i < ranges.size() - 1; i++) { Range first = ranges.get(i); Range second = ranges.get(i + 1); if (first.end + 1 >= second.start) { if (logger.isDebugEnabled()) logger.debug("Merging byte range: " + first + " with " + second); if (first.end < second.end) { // merge second range into first first.end = second.end; } // else we simply discard the second range - it is contained within the first // delete second range ranges.remove(i + 1); // reset loop index i--; } } } // calculate response content length long length = MULTIPART_BYTERANGES_BOUNDRY_END.length() + 2; for (Range r : ranges) { length += r.getLength(); } // output headers as we have at least one range to process OutputStream os = null; if (httpServletResponse != null) { httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); httpServletResponse.setHeader(HEADER_CONTENT_TYPE, MULTIPART_BYTERANGES_HEADER); httpServletResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString(length)); os = httpServletResponse.getOutputStream(); } else if (webScriptResponse != null) { webScriptResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); webScriptResponse.setHeader(HEADER_CONTENT_TYPE, MULTIPART_BYTERANGES_HEADER); webScriptResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString(length)); os = webScriptResponse.getOutputStream(); } InputStream is = null; try { for (Range r : ranges) { if (logger.isDebugEnabled()) logger.debug("Processing: " + r.getContentRange()); try { // output the header bytes for the range if (os instanceof ServletOutputStream) r.outputHeader((ServletOutputStream) os); // output the binary data for the range // need a new reader for each new InputStream is = contentService.getReader(ref, property).getContentInputStream(); streamRangeBytes(r, is, os, 0L); is.close(); is = null; // section marker and flush stream if (os instanceof ServletOutputStream) ((ServletOutputStream) os).println(); os.flush(); } catch (IOException err) { if (getLogger().isDebugEnabled()) getLogger().debug( "Unable to process multiple range due to IO Exception: " + err.getMessage()); throw err; } } } finally { if (is != null) { is.close(); } } // end marker if (os instanceof ServletOutputStream) ((ServletOutputStream) os).println(MULTIPART_BYTERANGES_BOUNDRY_END); os.close(); processedRange = true; } return processedRange; }
From source file:org.dspace.app.rest.utils.MultipartFileSenderTest.java
/** * If the If-Match doesn't match the ETAG then return 416 Status code * * @throws Exception//ww w. ja va2s .c o m */ @Test public void testIfMatchNoMatch() throws Exception { Long time = new Date().getTime(); MultipartFileSender multipartFileSender = MultipartFileSender.fromInputStream(is).with(requestWrapper) .withFileName(fileName).with(responseWrapper).withChecksum(checksum).withMimetype(mimeType) .withLength(length).withLastModified(time); when(request.getDateHeader(eq("If-Modified-Since"))).thenReturn(-1L); when(request.getDateHeader(eq("If-Unmodified-Since"))).thenReturn(-1L); when(request.getHeader(eq("If-Match"))).thenReturn("None-Matching-ETAG"); multipartFileSender.isValid(); assertEquals(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, responseWrapper.getStatusCode()); }
From source file:org.dspace.app.rest.utils.MultipartFileSender.java
private List<Range> getRanges(final Range fullRange) throws IOException { List<Range> ranges = new ArrayList<>(); // Validate and process Range and If-Range headers. String range = request.getHeader(RANGE); if (nonNull(range)) { // Range header should match format "bytes=n-n,n-n,n-n...". If not, then return 416. if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { log.error("Range header should match format \"bytes=n-n,n-n,n-n...\". If not, then return 416."); response.setHeader(CONTENT_RANGE, String.format(BYTES_DINVALID_BYTE_RANGE_FORMAT, length)); // Required in 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; }//w w w . j a v a2 s. com String ifRange = request.getHeader(IF_RANGE); if (nonNull(ifRange) && !ifRange.equals(fileName)) { try { //Assume that the If-Range contains a date long ifRangeTime = request.getDateHeader(IF_RANGE); // Throws IAE if invalid. if (ifRangeTime == -1 || ifRangeTime + 1000 <= lastModified) { //Our file has been updated, send the full range ranges.add(fullRange); } } catch (IllegalArgumentException ignore) { //Assume that the If-Range contains an ETag if (!matches(ifRange, checksum)) { //Our file has been updated, send the full range ranges.add(fullRange); } } } // If any valid If-Range header, then process each part of byte range. if (ranges.isEmpty()) { log.debug("If any valid If-Range header, then process each part of byte range."); for (String part : range.substring(6).split(",")) { // Assuming a file with length of 100, the following examples returns bytes at: // 50-80 (50 to 80), 40- (40 to length=100), -20 (length-20=80 to length=100). long start = Range.sublong(part, 0, part.indexOf("-")); long end = Range.sublong(part, part.indexOf("-") + 1, part.length()); if (start == -1) { start = length - end; end = length - 1; } else if (end == -1 || end > length - 1) { end = length - 1; } // Check if Range is syntactically valid. If not, then return 416. if (start > end) { log.warn("Check if Range is syntactically valid. If not, then return 416."); response.setHeader(CONTENT_RANGE, String.format(BYTES_DINVALID_BYTE_RANGE_FORMAT, length)); // Required in 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return null; } // Add range. ranges.add(new Range(start, end, length)); } } } return ranges; }
From source file:ch.entwine.weblounge.common.impl.request.Http11ProtocolHandler.java
/** * Method generateResponse.// w ww .jav a 2 s . c o m * * @param resp * @param type * @param is * @return boolean * @throws IOException * if generating the response fails */ public static boolean generateResponse(HttpServletResponse resp, Http11ResponseType type, InputStream is) throws IOException { /* first generate the response headers */ generateHeaders(resp, type); /* adjust the statistics */ ++stats[STATS_BODY_GENERATED]; incResponseStats(type.type, bodyStats); /* generate the response body */ try { if (resp.isCommitted()) log.warn("Response is already committed!"); switch (type.type) { case RESPONSE_OK: if (!type.isHeaderOnly() && is != null) { resp.setBufferSize(BUFFER_SIZE); OutputStream os = null; try { os = resp.getOutputStream(); IOUtils.copy(is, os); } catch (IOException e) { if (RequestUtils.isCausedByClient(e)) return true; } finally { IOUtils.closeQuietly(os); } } break; case RESPONSE_PARTIAL_CONTENT: if (type.from < 0 || type.to < 0 || type.from > type.to || type.to > type.size) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Invalid partial content parameters"); log.warn("Invalid partial content parameters"); } else if (!type.isHeaderOnly() && is != null) { resp.setBufferSize(BUFFER_SIZE); OutputStream os = resp.getOutputStream(); if (is.skip(type.from) != type.from) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Premature end of input stream"); log.warn("Premature end of input stream"); break; } try { /* get the temporary buffer for this thread */ byte[] tmp = buffer.get(); if (tmp == null) { tmp = new byte[BUFFER_SIZE]; buffer.set(tmp); } int read = type.to - type.from; int copy = read; int write = 0; read = is.read(tmp); while (copy > 0 && read >= 0) { copy -= read; write = copy > 0 ? read : read + copy; os.write(tmp, 0, write); stats[STATS_BYTES_WRITTEN] += write; read = is.read(tmp); } if (copy > 0) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Premature end of input stream"); log.warn("Premature end of input stream"); break; } os.flush(); os.close(); } catch (SocketException e) { log.debug("Request cancelled by client"); } } break; case RESPONSE_NOT_MODIFIED: /* NOTE: we MUST NOT return any content (RFC 2616)!!! */ break; case RESPONSE_PRECONDITION_FAILED: if (type.err == null) resp.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); else resp.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, type.err); break; case RESPONSE_REQUESTED_RANGE_NOT_SATISFIABLE: if (type.err == null) resp.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); else resp.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, type.err); break; case RESPONSE_METHOD_NOT_ALLOWED: if (type.err == null) resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); else resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, type.err); break; case RESPONSE_INTERNAL_SERVER_ERROR: default: if (type.err == null) resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); else resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, type.err); } } catch (IOException e) { if (e instanceof EOFException) { log.debug("Request canceled by client"); return true; } ++stats[STATS_ERRORS]; String message = e.getCause() != null ? e.getCause().getMessage() : e.getMessage(); Throwable cause = e.getCause() != null ? e.getCause() : e; log.warn("I/O exception while sending response: {}", message, cause); throw e; } return true; }
From source file:com.github.zhanhb.ckfinder.download.PathPartial.java
/** * Parse the range header./*from w w w.j a v a2s . 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:hu.api.SivaPlayerVideoServlet.java
private void doAction(HttpServletRequest request, HttpServletResponse response, String requestType) throws ServletException, IOException { // Check if it's an AJAX request this.isAJAXRequest = (request.getParameter("ajax") != null && request.getParameter("ajax").equals("true")); // Allow Cross-Origin-Requests response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "1000"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); // URL pattern: /videoId // Get request parameter from URL and check if it has been set. // Show 400 if less or more parameters than allowed. String requestedVideo = request.getPathInfo(); if (requestedVideo == null || requestedVideo.split("/").length < 2 || requestedVideo.split("/")[1].equals("")) { this.sendError(response, HttpServletResponse.SC_BAD_REQUEST, "The video folder has to be specified for using this web service."); return;//from w ww . java2 s . c o m } this.persistenceProvider = (IPersistenceProvider) getServletContext().getAttribute("PersistenceProvider"); this.mailService = (MailService) getServletContext().getAttribute("mailService"); this.brandingConfiguration = (BrandingConfiguration) getServletContext() .getAttribute("brandingConfiguration"); // Check if it's a watching request if (request.getPathInfo().endsWith("/watch.html")) { this.providePlayer(request, response); return; } // Check if it's a log request and perform logging if so if (request.getPathInfo().endsWith("/log") && requestType.equals("POST")) { this.doLogging(request, response); return; } // Check if it's a checkSession request and provide session status if so if (requestedVideo.endsWith("/getStats.js")) { this.getStats(request, response); return; } // Check if user requests user secret and perform login if (request.getPathInfo().endsWith("/getSecret.js") && requestType.equals("POST")) { this.provideUserSecret(request, response, requestType); return; } // Check if current session exists and if it is allowed to access this // video, stop further execution, if so. boolean result = handleAccess(request, response, requestType); if (!result) { return; } // Check if it's collaboration request and provide data if (request.getPathInfo().endsWith("/getCollaboration.js")) { this.provideCollaboration(request, response); return; } // Check if it's a thread creation request if (request.getPathInfo().endsWith("/createCollaborationThread.js")) { this.createCollaborationThread(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/createCollaborationPost.js")) { this.createCollaborationPost(request, response); return; } // Check if it's a post activation request if (request.getPathInfo().endsWith("/activateCollaborationPost.js")) { this.activateCollaborationPost(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/deleteCollaborationThread.js")) { this.deleteCollaborationThread(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/deleteCollaborationPost.js")) { this.deleteCollaborationPost(request, response); return; } // Check if it's a checkSession request and provide session status if so if (requestedVideo.endsWith("/checkSession.js")) { this.provideSessionStatus(request, response); return; } // Decode the file name from the URL and check if file actually exists // in // file system, send 404 if not File file = new File(videoPath, URLDecoder.decode(requestedVideo, "UTF-8")); if (!file.exists()) { this.sendError(response, HttpServletResponse.SC_NOT_FOUND, "File not found"); return; } // Create log entry for file request this.logFileRequest(requestedVideo); // Check if configuration is requested and do needed preparing and // stop standard file preparation if (file.getName().equals("export.js")) { this.provideConfigFile(request, response, file); return; } // Prepare some variables. The ETag is an unique identifier of the file. String fileName = file.getName(); long length = file.length(); long lastModified = file.lastModified(); String eTag = fileName + "_" + length + "_" + lastModified; long expires = System.currentTimeMillis() + DEFAULT_EXPIRE_TIME; // Validate request headers for caching // --------------------------------------------------- // If-None-Match header should contain "*" or ETag. If so, then return // 304. String ifNoneMatch = request.getHeader("If-None-Match"); if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", eTag); // Required in 304. response.setDateHeader("Expires", expires); // Postpone cache with 1 // week. return; } // If-Modified-Since header should be greater than LastModified. If so, // then return 304. // This header is ignored if any If-None-Match header is specified. long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (ifNoneMatch == null && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModified) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", eTag); // Required in 304. response.setDateHeader("Expires", expires); // Postpone cache with 1 // week. return; } // Validate request headers for resume // ---------------------------------------------------- // If-Match header should contain "*" or ETag. If not, then return 412. String ifMatch = request.getHeader("If-Match"); if (ifMatch != null && !matches(ifMatch, eTag)) { response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return; } // If-Unmodified-Since header should be greater than LastModified. If // not, then return 412. long ifUnmodifiedSince = request.getDateHeader("If-Unmodified-Since"); if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModified) { response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return; } // Validate and process range // ------------------------------------------------------------- // Prepare some variables. The full Range represents the complete file. Range full = new Range(0, length - 1, length); List<Range> ranges = new ArrayList<Range>(); // Validate and process Range and If-Range headers. String range = request.getHeader("Range"); if (range != null) { // Range header should match format "bytes=n-n,n-n,n-n...". If not, // then return 416. if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { response.setHeader("Content-Range", "bytes */" + length); // Required // in // 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } // If-Range header should either match ETag or be greater then // LastModified. If not, // then return full file. String ifRange = request.getHeader("If-Range"); if (ifRange != null && !ifRange.equals(eTag)) { try { long ifRangeTime = request.getDateHeader("If-Range"); // Throws // IAE // if // invalid. if (ifRangeTime != -1 && ifRangeTime + 1000 < lastModified) { ranges.add(full); } } catch (IllegalArgumentException ignore) { ranges.add(full); } } // If any valid If-Range header, then process each part of byte // range. if (ranges.isEmpty()) { for (String part : range.substring(6).split(",")) { // Assuming a file with length of 100, the following // examples returns bytes at: // 50-80 (50 to 80), 40- (40 to length=100), -20 // (length-20=80 to length=100). long start = sublong(part, 0, part.indexOf("-")); long end = sublong(part, part.indexOf("-") + 1, part.length()); if (start == -1) { start = length - end; end = length - 1; } else if (end == -1 || end > length - 1) { end = length - 1; } // Check if Range is syntactically valid. If not, then // return 416. if (start > end) { response.setHeader("Content-Range", "bytes */" + length); // Required // in // 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } // Add range. ranges.add(new Range(start, end, length)); } } } // Prepare and initialize response // -------------------------------------------------------- // Get content type by file name and set default GZIP support and // content disposition. String contentType = getServletContext().getMimeType(fileName); boolean acceptsGzip = false; String disposition = "inline"; // If content type is unknown, then set the default value. // For all content types, see: // http://www.w3schools.com/media/media_mimeref.asp // To add new content types, add new mime-mapping entry in web.xml. if (contentType == null) { contentType = "application/octet-stream"; } // If content type is text, then determine whether GZIP content encoding // is supported by // the browser and expand content type with the one and right character // encoding. if (contentType.startsWith("text")) { String acceptEncoding = request.getHeader("Accept-Encoding"); acceptsGzip = acceptEncoding != null && accepts(acceptEncoding, "gzip"); contentType += ";charset=UTF-8"; } // Else, expect for images, determine content disposition. If content // type is supported by // the browser, then set to inline, else attachment which will pop a // 'save as' dialogue. else if (!contentType.startsWith("image")) { String accept = request.getHeader("Accept"); disposition = accept != null && accepts(accept, contentType) ? "inline" : "attachment"; } // Initialize response. response.reset(); response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setHeader("Content-Disposition", disposition + ";filename=\"" + fileName + "\""); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("ETag", eTag); response.setDateHeader("Last-Modified", lastModified); response.setDateHeader("Expires", expires); // Send requested file (part(s)) to client // ------------------------------------------------ // Prepare streams. RandomAccessFile input = null; OutputStream output = null; try { // Open streams. input = new RandomAccessFile(file, "r"); output = response.getOutputStream(); if (ranges.isEmpty() || ranges.get(0) == full) { // Return full file. Range r = full; response.setContentType(contentType); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total); if (requestType.equals("GET")) { if (acceptsGzip) { // The browser accepts GZIP, so GZIP the content. response.setHeader("Content-Encoding", "gzip"); output = new GZIPOutputStream(output, DEFAULT_BUFFER_SIZE); } else { // Content length is not directly predictable in case of // GZIP. // So only add it if there is no means of GZIP, else // browser will hang. response.setHeader("Content-Length", String.valueOf(r.length)); } // Copy full range. copy(input, output, r.start, r.length); } } else if (ranges.size() == 1) { // Return single part of file. Range r = ranges.get(0); response.setContentType(contentType); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total); response.setHeader("Content-Length", String.valueOf(r.length)); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. if (requestType.equals("GET")) { // Copy single part range. copy(input, output, r.start, r.length); } } else { // Return multiple parts of file. response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. if (requestType.equals("GET")) { // Cast back to ServletOutputStream to get the easy println // methods. ServletOutputStream sos = (ServletOutputStream) output; // Copy multi part range. for (Range r : ranges) { // Add multipart boundary and header fields for every // range. sos.println(); sos.println("--" + MULTIPART_BOUNDARY); sos.println("Content-Type: " + contentType); sos.println("Content-Range: bytes " + r.start + "-" + r.end + "/" + r.total); // Copy single part range of multi part range. copy(input, output, r.start, r.length); } // End with multipart boundary. sos.println(); sos.println("--" + MULTIPART_BOUNDARY + "--"); } } } finally { // Gently close streams. close(output); close(input); } }
From source file:com.liferay.sync.servlet.DownloadServlet.java
protected void sendFileWithRangeHeader(HttpServletRequest request, HttpServletResponse response, String fileName, InputStream inputStream, long contentLength, String contentType) throws IOException { if (_log.isDebugEnabled()) { _log.debug("Accepting ranges for the file " + fileName); }// w w w. j a v a 2 s . c o m response.setHeader(HttpHeaders.ACCEPT_RANGES, HttpHeaders.ACCEPT_RANGES_BYTES_VALUE); List<Range> ranges = null; try { ranges = ServletResponseUtil.getRanges(request, response, contentLength); } catch (IOException ioe) { if (_log.isErrorEnabled()) { _log.error(ioe); } response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + contentLength); response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } if ((ranges == null) || ranges.isEmpty()) { ServletResponseUtil.sendFile(request, response, fileName, inputStream, contentLength, contentType); } else { if (_log.isDebugEnabled()) { _log.debug("Request has range header " + request.getHeader(HttpHeaders.RANGE)); } ServletResponseUtil.write(request, response, fileName, ranges, inputStream, contentLength, contentType); } }
From source file:com.meltmedia.cadmium.servlets.BasicFileServlet.java
/** * Sets the appropriate response headers and error status for bad ranges * /* www. j a v a2s . c o m*/ * @param context * @throws IOException */ public static void invalidRanges(FileRequestContext context) throws IOException { context.response.setHeader(CONTENT_RANGE_HEADER, "*/" + context.file.length()); context.response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); }