List of usage examples for javax.servlet.http HttpServletResponse SC_NOT_MODIFIED
int SC_NOT_MODIFIED
To view the source code for javax.servlet.http HttpServletResponse SC_NOT_MODIFIED.
Click Source Link
From source file:inti.ws.spring.resource.ResourceController.java
protected void resource(String name, WebResource resource, HttpServletRequest request, HttpServletResponse response, ConfigParserSettings settings) throws Exception { String tmp;/*from w ww. ja v a 2s. c o m*/ resource.updateIfNeeded(); if ((tmp = request.getHeader(HttpHeaders.IF_MODIFIED_SINCE)) != null) { if (resource.getLastModified() <= dateFormatter.parseDate(tmp)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } } else if ((tmp = request.getHeader(HttpHeaders.IF_NONE_MATCH)) != null) { if (tmp.equals(resource.getMessageDigest())) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } } if (settings != null) { try { applyCachingHeader(response, resource, settings); } catch (Exception exception) { LOGGER.debug("", exception); } if (settings.getContentType() != null) { response.setHeader(HttpHeaders.CONTENT_TYPE, settings.getContentType()); } if (settings.getContentEncoding() != null) { response.setHeader(HttpHeaders.CONTENT_ENCODING, settings.getContentEncoding()); } try { resource.processResponse(request, response, settings); } catch (Exception exception) { LOGGER.debug("", exception); } byte[] data = resource.getByteContent(settings); if (data != null) { response.getOutputStream().write(data); response.getOutputStream().close(); } } }
From source file:org.openmrs.module.atomfeed.web.AtomFeedDownloadServletTest.java
/** * @see AtomFeedDownloadServlet#doHead(javax.servlet.http.HttpServletRequest, * javax.servlet.http.HttpServletResponse) * @verifies send not modified error if atom feed has not changed *//*from ww w.j a v a2s . c om*/ @Test public void doHead_shouldSendNotModifiedErrorIfAtomFeedHasNotChanged() throws Exception { // create servlet and corresponding request and response object to be sent AtomFeedDownloadServlet atomFeedDownloadServlet = new AtomFeedDownloadServlet(); MockHttpServletRequest request = new MockHttpServletRequest("HEAD", "/atomfeed"); request.setContextPath("/somecontextpath"); MockHttpServletResponse response = new MockHttpServletResponse(); // intentionally change atom feed in order to not depend from other tests AtomFeedUtil.objectCreated(new Encounter()); // read atom feed header specific information from the header file String headerFileContent = AtomFeedUtil.readFeedHeaderFile(); int contentLength = 0; String etagToken = ""; Date lastModified = null; if (StringUtils.isNotBlank(headerFileContent)) { contentLength = headerFileContent.length() + Integer .valueOf(StringUtils.substringBetween(headerFileContent, "<entriesSize>", "</entriesSize>")); etagToken = StringUtils.substringBetween(headerFileContent, "<versionId>", "</versionId>"); try { lastModified = new SimpleDateFormat(AtomFeedUtil.RFC_3339_DATE_FORMAT) .parse(StringUtils.substringBetween(headerFileContent, "<updated>", "</updated>")); } catch (ParseException e) { // ignore it here } } // set request headers request.addHeader("If-None-Match", '"' + etagToken + '"'); request.addHeader("If-Modified-Since", lastModified); atomFeedDownloadServlet.service(request, response); // check response headers Assert.assertEquals(contentLength, response.getContentLength()); Assert.assertEquals("application/atom+xml", response.getContentType()); Assert.assertEquals(HttpServletResponse.SC_NOT_MODIFIED, response.getStatus()); Assert.assertNotNull(response.getHeader("Last-Modified")); }
From source file:com.autentia.common.util.web.ClasspathServlet.java
/** * Serve the file from the classpath//from w w w . j ava 2 s . c om */ @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String path = request.getPathInfo(); /* if this servlet is not mapped to a path, use the request URI */ if (path == null) { path = request.getRequestURI().substring(request.getContextPath().length()); } if (!path.endsWith(PAGE_403)) { final String extension = path.substring(path.lastIndexOf('.')); if (!allowedExtensions.contains(extension)) { response.sendError(403, path + " denied"); return; } } final URL resource = Thread.currentThread().getContextClassLoader().getResource(path.substring(1)); if (resource == null) { response.sendError(404, path + " not found on classpath"); } else { /* check modification date */ final long ifModifiedSince = request.getDateHeader("If-Modified-Since"); final long lastModified = resource.openConnection().getLastModified(); if (ifModifiedSince != -1 && lastModified <= ifModifiedSince) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } if (log.isDebugEnabled()) { log.debug("Resolving URL " + path); } /* write to response */ response.setContentType(getServletContext().getMimeType(path)); final OutputStream out = new BufferedOutputStream(response.getOutputStream(), 512); final InputStream in = new BufferedInputStream(resource.openStream(), 512); final byte[] data = new byte[512]; int len; try { while ((len = in.read(data)) != -1) { out.write(data, 0, len); } } finally { in.close(); out.close(); } } }
From source file:org.b3log.solo.processor.FileUploadProcessor.java
@Override public void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { if (QN_ENABLED) { return;//ww w .ja v a 2s .co m } final String uri = req.getRequestURI(); String key = StringUtils.substringAfter(uri, "/upload/"); key = StringUtils.substringBeforeLast(key, "?"); // Erase Qiniu template key = StringUtils.substringBeforeLast(key, "?"); // Erase Qiniu template String path = UPLOAD_DIR + key; path = URLDecoder.decode(path, "UTF-8"); if (!FileUtil.isExistingFile(new File(path))) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } final byte[] data = IOUtils.toByteArray(new FileInputStream(path)); final String ifNoneMatch = req.getHeader("If-None-Match"); final String etag = "\"" + MD5.hash(new String(data)) + "\""; resp.addHeader("Cache-Control", "public, max-age=31536000"); resp.addHeader("ETag", etag); resp.setHeader("Server", "Latke Static Server (v" + SoloServletListener.VERSION + ")"); if (etag.equals(ifNoneMatch)) { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } final OutputStream output = resp.getOutputStream(); IOUtils.write(data, output); output.flush(); IOUtils.closeQuietly(output); }
From source file:com.harrywu.springweb.common.StreamingViewRenderer.java
@Override public void renderMergedOutputModel(Map<String, Object> objectMap, HttpServletRequest request, HttpServletResponse response) throws Exception { InputStream dataStream = (InputStream) objectMap.get(INPUT_STREAM); if (dataStream == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return;/*from w w w . ja va 2 s . co m*/ } long length = (Long) objectMap.get(CONTENT_LENGTH); String fileName = (String) objectMap.get(FILENAME); Date lastModifiedObj = (Date) objectMap.get(LAST_MODIFIED); if (StringUtils.isEmpty(fileName) || lastModifiedObj == null) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } long lastModified = lastModifiedObj.getTime(); String contentType = (String) objectMap.get(CONTENT_TYPE); // 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, fileName)) { response.setHeader("ETag", fileName); // Required in 304. response.sendError(HttpServletResponse.SC_NOT_MODIFIED); 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.setHeader("ETag", fileName); // Required in 304. response.sendError(HttpServletResponse.SC_NOT_MODIFIED); 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, fileName)) { 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; } 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 = 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 content disposition. 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"; } else if (!contentType.startsWith("image")) { // 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. 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", fileName); response.setDateHeader("Last-Modified", lastModified); response.setDateHeader("Expires", System.currentTimeMillis() + DEFAULT_EXPIRE_TIME); // Send requested file (part(s)) to client // ------------------------------------------------ // Prepare streams. InputStream input = null; OutputStream output = null; try { // Open streams. input = new BufferedInputStream(dataStream); 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); response.setHeader("Content-Length", String.valueOf(r.length)); copy(input, output, length, 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. // Copy single part range. copy(input, output, length, r.start, r.length); } else { // Return multiple parts of file. response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. // 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, length, r.start, r.length); } // End with multipart boundary. sos.println(); sos.println("--" + MULTIPART_BOUNDARY + "--"); } } finally { // Gently close streams. close(output); close(input); close(dataStream); } }
From source file:io.wcm.wcm.commons.caching.CacheHeaderTest.java
@Test public void testIsNotModified_WithIfModifiedSinceHeader_Publish() throws Exception { when(request.getAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME)).thenReturn(WCMMode.DISABLED); when(request.getHeader(HEADER_IF_MODIFIED_SINCE)).thenReturn(formatDate(SAMPLE_CALENDAR_2.getTime())); assertTrue(CacheHeader.isNotModified(resource, request, response)); verify(response).setStatus(HttpServletResponse.SC_NOT_MODIFIED); verifyNoMoreInteractions(response);/*ww w . ja va2 s.co m*/ }
From source file:com.haulmont.cuba.web.sys.CubaWebJarsHandler.java
@Override public boolean handleRequest(VaadinSession session, VaadinRequest request, VaadinResponse response) throws IOException { String path = request.getPathInfo(); if (StringUtils.isEmpty(path) || StringUtils.isNotEmpty(path) && !path.startsWith(VAADIN_WEBJARS_PREFIX)) { return false; }/*from ww w. ja va2 s.c om*/ log.trace("WebJar resource requested: {}", path.replace(VAADIN_WEBJARS_PREFIX, "")); String errorMessage = checkResourcePath(path); if (StringUtils.isNotEmpty(errorMessage)) { log.warn(errorMessage); response.sendError(HttpServletResponse.SC_FORBIDDEN, errorMessage); return false; } URL resourceUrl = getStaticResourceUrl(path); if (resourceUrl == null) { resourceUrl = getClassPathResourceUrl(path); } if (resourceUrl == null) { String msg = String.format("Requested WebJar resource is not found: %s", path); response.sendError(HttpServletResponse.SC_NOT_FOUND, msg); log.warn(msg); return false; } String resourceName = getResourceName(path); String mimeType = servletContext.getMimeType(resourceName); response.setContentType(mimeType != null ? mimeType : FileTypesHelper.DEFAULT_MIME_TYPE); String cacheControl = "public, max-age=0, must-revalidate"; int resourceCacheTime = getCacheTime(resourceName); if (resourceCacheTime > 0) { cacheControl = "max-age=" + String.valueOf(resourceCacheTime); } response.setHeader("Cache-Control", cacheControl); response.setDateHeader("Expires", System.currentTimeMillis() + (resourceCacheTime * 1000)); InputStream inputStream = null; try { URLConnection connection = resourceUrl.openConnection(); long lastModifiedTime = connection.getLastModified(); // Remove milliseconds to avoid comparison problems (milliseconds // are not returned by the browser in the "If-Modified-Since" // header). lastModifiedTime = lastModifiedTime - lastModifiedTime % 1000; response.setDateHeader("Last-Modified", lastModifiedTime); if (browserHasNewestVersion(request, lastModifiedTime)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return true; } inputStream = connection.getInputStream(); copy(inputStream, response.getOutputStream()); return true; } finally { if (inputStream != null) { inputStream.close(); } } }
From source file:ch.entwine.weblounge.test.util.TestSiteUtils.java
/** * Test for the correct response when modified since header is set. * /*from w ww .jav a 2 s . c o m*/ * @param request * the http request * @param date * the expected modification date * @param logger * used to log test output * @param params * the request parameters * @throws Exception * if processing the request fails */ public static void testModifiedHeader(HttpUriRequest request, Date modificationDate, Logger logger, String[][] params) throws Exception { DefaultHttpClient httpClient = new DefaultHttpClient(); Date before = new Date(modificationDate.getTime() - Times.MS_PER_DAY); Date after = new Date(modificationDate.getTime() + Times.MS_PER_DAY); SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); try { request.removeHeaders("If-None-Match"); request.setHeader("If-Modified-Since", format.format(after)); logger.info("Sending 'If-Modified-Since' request to {}", request.getURI()); HttpResponse response = TestUtils.request(httpClient, request, params); assertEquals(HttpServletResponse.SC_NOT_MODIFIED, response.getStatusLine().getStatusCode()); assertNull(response.getEntity()); } finally { httpClient.getConnectionManager().shutdown(); } httpClient = new DefaultHttpClient(); try { request.removeHeaders("If-None-Match"); request.setHeader("If-Modified-Since", format.format(before)); logger.info("Sending 'If-Modified-Since' request to {}", request.getURI()); HttpResponse response = TestUtils.request(httpClient, request, params); assertEquals(HttpServletResponse.SC_OK, response.getStatusLine().getStatusCode()); assertNotNull(response.getEntity()); response.getEntity().consumeContent(); } finally { httpClient.getConnectionManager().shutdown(); } }
From source file:org.tightblog.rendering.processors.MediaFileProcessor.java
@RequestMapping(method = { RequestMethod.GET, RequestMethod.HEAD }) void getMediaFile(HttpServletRequest request, HttpServletResponse response) throws IOException { WeblogRequest incomingRequest = WeblogRequest.create(request); Weblog weblog = weblogRepository.findByHandleAndVisibleTrue(incomingRequest.getWeblogHandle()); if (weblog == null) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return;// w ww. ja v a 2 s . c om } else { incomingRequest.setWeblog(weblog); } MediaFile mediaFile = null; // path info here is the resourceId String pathInfo = incomingRequest.getExtraPathInfo(); if (StringUtils.isNotBlank(pathInfo)) { mediaFile = mediaManager.getMediaFileWithContent(pathInfo); } if (mediaFile == null) { log.info("Could not obtain media file for resource path: ", request.getRequestURL()); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } weblogMediaCache.incrementIncomingRequests(); // DB stores last modified in millis, browser if-modified-since in seconds, so need to truncate millis from the former. long inDb = mediaFile.getLastUpdated().truncatedTo(ChronoUnit.SECONDS).toEpochMilli(); long inBrowser = getBrowserCacheExpireDate(request); if (inDb <= inBrowser) { weblogMediaCache.incrementRequestsHandledBy304(); response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } boolean useThumbnail = false; if (mediaFile.isImageFile() && "true".equals(request.getParameter("tn"))) { useThumbnail = true; } File desiredFile = useThumbnail ? mediaFile.getThumbnail() : mediaFile.getContent(); if (desiredFile == null) { log.info("Could not obtain {} file content for resource path: ", useThumbnail ? "thumbnail" : "", request.getRequestURL()); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } try (InputStream resourceStream = new FileInputStream(desiredFile); OutputStream out = response.getOutputStream()) { byte[] buf = new byte[Utilities.EIGHT_KB_IN_BYTES]; int length; while ((length = resourceStream.read(buf)) > 0) { out.write(buf, 0, length); } response.setContentType(useThumbnail ? MediaFile.THUMBNAIL_CONTENT_TYPE : mediaFile.getContentType()); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Last-Modified", mediaFile.getLastUpdated().toEpochMilli()); } catch (IOException ex) { log.error("Error obtaining media file {}", desiredFile.getAbsolutePath(), ex); if (!response.isCommitted()) { response.reset(); response.sendError(HttpServletResponse.SC_NOT_FOUND); } } }
From source file:com.sastix.cms.server.utils.MultipartFileSender.java
public void serveResource() throws Exception { if (response == null || request == null) { return;/*from www . ja v a2s .co m*/ } Long length = Files.size(filepath); String fileName = filepath.getFileName().toString(); FileTime lastModifiedObj = Files.getLastModifiedTime(filepath); if (StringUtils.isEmpty(fileName) || lastModifiedObj == null) { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } long lastModified = LocalDateTime .ofInstant(lastModifiedObj.toInstant(), ZoneId.of(ZoneOffset.systemDefault().getId())) .toEpochSecond(ZoneOffset.UTC); // 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 && HttpUtils.matches(ifNoneMatch, fileName)) { response.setHeader("ETag", fileName); // Required in 304. response.sendError(HttpServletResponse.SC_NOT_MODIFIED); 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.setHeader("ETag", fileName); // Required in 304. response.sendError(HttpServletResponse.SC_NOT_MODIFIED); 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 && !HttpUtils.matches(ifMatch, fileName)) { 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<>(); // 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; } 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", "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 content disposition. 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"; } else if (!contentType.startsWith("image")) { // 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. String accept = request.getHeader("Accept"); disposition = accept != null && HttpUtils.accepts(accept, contentType) ? "inline" : "attachment"; } LOG.debug("Content-Type : {}", contentType); // Initialize response. response.reset(); response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setHeader("Content-Type", contentType); response.setHeader("Content-Disposition", disposition + ";filename=\"" + fileName + "\""); LOG.debug("Content-Disposition : {}", disposition); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("ETag", fileName); response.setDateHeader("Last-Modified", lastModified); response.setDateHeader("Expires", System.currentTimeMillis() + DEFAULT_EXPIRE_TIME); // Send requested file (part(s)) to client ------------------------------------------------ // Prepare streams. try (InputStream input = new BufferedInputStream(Files.newInputStream(filepath)); OutputStream output = response.getOutputStream()) { if (ranges.isEmpty() || ranges.get(0) == full) { // Return full file. LOG.debug("Return full file"); response.setContentType(contentType); response.setHeader("Content-Range", "bytes " + full.start + "-" + full.end + "/" + full.total); response.setHeader("Content-Length", String.valueOf(full.length)); Range.copy(input, output, length, full.start, full.length); } else if (ranges.size() == 1) { // Return single part of file. Range r = ranges.get(0); LOG.debug("Return 1 part of file : from ({}) to ({})", r.start, r.end); 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. // Copy single part range. Range.copy(input, output, length, r.start, r.length); } else { // Return multiple parts of file. response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. // Cast back to ServletOutputStream to get the easy println methods. ServletOutputStream sos = (ServletOutputStream) output; // Copy multi part range. for (Range r : ranges) { LOG.debug("Return multi part of file : from ({}) to ({})", r.start, r.end); // 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. Range.copy(input, output, length, r.start, r.length); } // End with multipart boundary. sos.println(); sos.println("--" + MULTIPART_BOUNDARY + "--"); } } }