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.orderofthebee.addons.support.tools.share.AbstractLogFileWebScript.java
protected boolean processSingleRange(final WebScriptResponse res, final File file, final String range, final String mimetype) throws IOException { // return the specific set of bytes as requested in the content-range header /*/* www.j a v a2 s .c om*/ * Examples of byte-content-range-spec values, assuming that the entity contains total of 1234 bytes: * The first 500 bytes: * bytes 0-499/1234 * The second 500 bytes: * bytes 500-999/1234 * All except for the first 500 bytes: * bytes 500-1233/1234 */ /* * 'Range' header example: * bytes=10485760-20971519 */ boolean processedRange = false; Range r = null; try { r = Range.constructRange(range, mimetype, file.length()); } catch (final IllegalArgumentException err) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Failed to parse range header - returning 416 status code: " + err.getMessage()); } res.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); res.setHeader(HEADER_CONTENT_RANGE, "\"*\""); res.getOutputStream().close(); return true; } // set Partial Content status and range headers final String contentRange = "bytes " + Long.toString(r.start) + "-" + Long.toString(r.end) + "/" + Long.toString(file.length()); res.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); res.setContentType(mimetype); res.setHeader(HEADER_CONTENT_RANGE, contentRange); res.setHeader(HEADER_CONTENT_LENGTH, Long.toString((r.end - r.start) + 1L)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Processing: Content-Range: " + contentRange); } InputStream is = null; try { // output the binary data for the range OutputStream os = null; os = res.getOutputStream(); is = new FileInputStream(file); this.streamRangeBytes(r, is, os, 0L); os.close(); processedRange = true; } catch (final IOException err) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Unable to process single range due to IO Exception: " + err.getMessage()); } throw err; } finally { if (is != null) { is.close(); } } return processedRange; }
From source file:com.liferay.lms.servlet.SCORMFileServerServlet.java
/** * Procesa los metodos HTTP GET y POST.<br> * Busca en la ruta que se le ha pedido el comienzo del directorio * "contenidos" y sirve el fichero./*from w ww. j a v a 2s . c o m*/ */ protected void processRequest(HttpServletRequest request, HttpServletResponse response, boolean content) throws ServletException, java.io.IOException { String mime_type; String charset; String patharchivo; String uri; try { User user = PortalUtil.getUser(request); if (user == null) { String userId = null; String companyId = null; Cookie[] cookies = ((HttpServletRequest) request).getCookies(); if (Validator.isNotNull(cookies)) { for (Cookie c : cookies) { if ("COMPANY_ID".equals(c.getName())) { companyId = c.getValue(); } else if ("ID".equals(c.getName())) { userId = hexStringToStringByAscii(c.getValue()); } } } if (userId != null && companyId != null) { try { Company company = CompanyLocalServiceUtil.getCompany(Long.parseLong(companyId)); Key key = company.getKeyObj(); String userIdPlain = Encryptor.decrypt(key, userId); user = UserLocalServiceUtil.getUser(Long.valueOf(userIdPlain)); // Now you can set the liferayUser into a thread local // for later use or // something like that. } catch (Exception pException) { throw new RuntimeException(pException); } } } String rutaDatos = SCORMContentLocalServiceUtil.getBaseDir(); // Se comprueba que el usuario tiene permisos para acceder. // Damos acceso a todo el mundo al directorio "personalizacion", // para permitir mostrar a todos la pantalla de identificacion. uri = URLDecoder.decode(request.getRequestURI(), "UTF-8"); uri = uri.substring(uri.indexOf("scorm/") + "scorm/".length()); patharchivo = rutaDatos + "/" + uri; String[] params = uri.split("/"); long groupId = GetterUtil.getLong(params[1]); String uuid = params[2]; SCORMContent scormContent = SCORMContentLocalServiceUtil.getSCORMContentByUuidAndGroupId(uuid, groupId); boolean allowed = false; if (user == null) { user = UserLocalServiceUtil.getDefaultUser(PortalUtil.getDefaultCompanyId()); } PermissionChecker pc = PermissionCheckerFactoryUtil.create(user); allowed = pc.hasPermission(groupId, SCORMContent.class.getName(), scormContent.getScormId(), ActionKeys.VIEW); if (!allowed) { AssetEntry scormAsset = AssetEntryLocalServiceUtil.getEntry(SCORMContent.class.getName(), scormContent.getPrimaryKey()); long scormAssetId = scormAsset.getEntryId(); int typeId = new Long((new SCORMLearningActivityType()).getTypeId()).intValue(); long[] groupIds = user.getGroupIds(); for (long gId : groupIds) { List<LearningActivity> acts = LearningActivityLocalServiceUtil .getLearningActivitiesOfGroupAndType(gId, typeId); for (LearningActivity act : acts) { String entryId = LearningActivityLocalServiceUtil.getExtraContentValue(act.getActId(), "assetEntry"); if (Validator.isNotNull(entryId) && Long.valueOf(entryId) == scormAssetId) { allowed = pc.hasPermission(gId, LearningActivity.class.getName(), act.getActId(), ActionKeys.VIEW); if (allowed) { break; } } } if (allowed) { break; } } } if (allowed) { File archivo = new File(patharchivo); // Si el archivo existe y no es un directorio se sirve. Si no, // no se hace nada. if (archivo.exists() && archivo.isFile()) { // El content type siempre antes del printwriter mime_type = MimeTypesUtil.getContentType(archivo); charset = ""; if (archivo.getName().toLowerCase().endsWith(".html") || archivo.getName().toLowerCase().endsWith(".htm")) { mime_type = "text/html"; if (isISO(FileUtils.readFileToString(archivo))) { charset = "ISO-8859-1"; } } if (archivo.getName().toLowerCase().endsWith(".swf")) { mime_type = "application/x-shockwave-flash"; } if (archivo.getName().toLowerCase().endsWith(".mp4")) { mime_type = "video/mp4"; } if (archivo.getName().toLowerCase().endsWith(".flv")) { mime_type = "video/x-flv"; } response.setContentType(mime_type); if (Validator.isNotNull(charset)) { response.setCharacterEncoding(charset); } response.addHeader("Content-Type", mime_type + (Validator.isNotNull(charset) ? "; " + charset : "")); /*if (archivo.getName().toLowerCase().endsWith(".swf") || archivo.getName().toLowerCase().endsWith(".flv")) { response.addHeader("Content-Length", String.valueOf(archivo.length())); } */ if (archivo.getName().toLowerCase().endsWith("imsmanifest.xml")) { FileInputStream fis = new FileInputStream(patharchivo); String sco = ParamUtil.get(request, "scoshow", ""); Document manifest = SAXReaderUtil.read(fis); if (sco.length() > 0) { Element organizatEl = manifest.getRootElement().element("organizations") .element("organization"); Element selectedItem = selectItem(organizatEl, sco); if (selectedItem != null) { selectedItem.detach(); java.util.List<Element> items = organizatEl.elements("item"); for (Element item : items) { organizatEl.remove(item); } organizatEl.add(selectedItem); } } //clean unused resources. Element resources = manifest.getRootElement().element("resources"); java.util.List<Element> theResources = resources.elements("resource"); Element organizatEl = manifest.getRootElement().element("organizations") .element("organization"); java.util.List<String> identifiers = getIdentifierRefs(organizatEl); for (Element resource : theResources) { String identifier = resource.attributeValue("identifier"); if (!identifiers.contains(identifier)) { resources.remove(resource); } } response.getWriter().print(manifest.asXML()); fis.close(); return; } if (mime_type.startsWith("text") || mime_type.endsWith("javascript") || mime_type.equals("application/xml")) { java.io.OutputStream out = response.getOutputStream(); FileInputStream fis = new FileInputStream(patharchivo); byte[] buffer = new byte[512]; int i = 0; while (fis.available() > 0) { i = fis.read(buffer); if (i == 512) out.write(buffer); else out.write(buffer, 0, i); } fis.close(); out.flush(); out.close(); return; } //If not manifest String fileName = archivo.getName(); long length = archivo.length(); long lastModified = archivo.lastModified(); String eTag = fileName + "_" + length + "_" + lastModified; long expires = System.currentTimeMillis() + DEFAULT_EXPIRE_TIME; 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; } 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; } // 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)); } } } boolean acceptsGzip = false; String disposition = "inline"; if (mime_type.startsWith("text")) { //String acceptEncoding = request.getHeader("Accept-Encoding"); // acceptsGzip = acceptEncoding != null && accepts(acceptEncoding, "gzip"); // mime_type += ";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 (!mime_type.startsWith("image")) { String accept = request.getHeader("Accept"); disposition = accept != null && accepts(accept, mime_type) ? "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(archivo, "r"); output = response.getOutputStream(); if (ranges.isEmpty() || ranges.get(0) == full) { // Return full file. Range r = full; response.setContentType(mime_type); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total); if (content) { // 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(mime_type); 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 (content) { // 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 (content) { // 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: " + mime_type); 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); } } else { //java.io.OutputStream out = response.getOutputStream(); response.sendError(404); //out.write(uri.getBytes()); } } else { response.sendError(401); } } catch (Exception e) { System.out.println("Error en el processRequest() de ServidorArchivos: " + e.getMessage()); } }
From source file:edu.chalmers.dat076.moviefinder.controller.FileController.java
/** * Process the actual request.//from ww w . j ava 2 s . c o m * * @param request The request to be processed. * @param response The response to be created. * @param content Whether the request body should be written (GET) or not * (HEAD). * @throws IOException If something fails at I/O level. */ private void processRequest(HttpServletRequest request, HttpServletResponse response, boolean content, String path, String defaultContentType) throws IOException { // Validate the requested file ------------------------------------------------------------ // URL-decode the file name (might contain spaces and on) and prepare file object. File file = new File(path); // Check if file actually exists in filesystem. if (!file.exists()) { // Do your thing if the file appears to be non-existing. // Throw an exception, or send 404, or show default/warning page, or just ignore it. response.sendError(HttpServletResponse.SC_NOT_FOUND); 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() + FileControllerUtils.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 && FileControllerUtils.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 && !FileControllerUtils.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<>(); // 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 = FileControllerUtils.sublong(part, 0, part.indexOf("-")); long end = FileControllerUtils.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 = request.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 = defaultContentType; //} // 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 && FileControllerUtils.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 && FileControllerUtils.accepts(accept, contentType) ? "inline" : "attachment"; } // Initialize response. response.reset(); response.setBufferSize(FileControllerUtils.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 (content) { if (acceptsGzip) { // The browser accepts GZIP, so GZIP the content. response.setHeader("Content-Encoding", "gzip"); output = new GZIPOutputStream(output, FileControllerUtils.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. FileControllerUtils.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 (content) { // Copy single part range. FileControllerUtils.copy(input, output, r.start, r.length); } } else { // Return multiple parts of file. response.setContentType("multipart/byteranges; boundary=" + FileControllerUtils.MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. if (content) { // 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("--" + FileControllerUtils.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. FileControllerUtils.copy(input, output, r.start, r.length); } // End with multipart boundary. sos.println(); sos.println("--" + FileControllerUtils.MULTIPART_BOUNDARY + "--"); } } } finally { // Gently close streams. FileControllerUtils.close(output); FileControllerUtils.close(input); } }
From source file:org.springframework.web.servlet.resource.ResourceHttpRequestHandler.java
/** * Processes a resource request./*w w w . j a va 2s .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); } } }
From source file:de.digitalcollections.streaming.euphoria.controller.StreamingController.java
/** * Create response for the request.//from www. j a v a 2 s. com * * @param id The id of requested content. * @param extension The (target) file extension/format of requested content. * @param request The request to be responded to. * @param response The response to the request. * @param head "true" if response body should be written (GET) or "false" if not (HEAD). * @throws IOException If something fails at I/O level. */ private void respond(String id, String extension, HttpServletRequest request, HttpServletResponse response, boolean head) throws IOException { logRequestHeaders(request); response.reset(); // try to get access to resource Resource resource; try { resource = getResource(id, extension); } catch (ResourceIOException ex) { LOGGER.warn("*** Response {}: Error referencing streaming resource with id {} and extension {}", HttpServletResponse.SC_NOT_FOUND, id, extension); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // get resource metadata ResourceInfo resourceInfo = new ResourceInfo(id, resource); if (resourceInfo.length <= 0) { LOGGER.warn("*** Response {}: Error streaming resource with id {} and extension {}: not found/no size", HttpServletResponse.SC_NOT_FOUND, id, extension); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if (preconditionFailed(request, resourceInfo)) { LOGGER.warn( "*** Response {}: Precondition If-Match/If-Unmodified-Since failed for resource with id {} and extension {}.", HttpServletResponse.SC_PRECONDITION_FAILED, id, extension); response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return; } setCacheHeaders(response, resourceInfo); if (notModified(request, resourceInfo)) { LOGGER.debug("*** Response {}: 'Not modified'-response for resource with id {} and extension {}.", HttpServletResponse.SC_NOT_MODIFIED, id, extension); response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } List<Range> ranges = getRanges(request, resourceInfo); if (ranges == null) { response.setHeader("Content-Range", "bytes */" + resourceInfo.length); LOGGER.warn("Response {}: Header Range for resource with id {} and extension {} not satisfiable", HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE, id, extension); response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } if (!ranges.isEmpty()) { response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); } else { ranges.add(new Range(0, resourceInfo.length - 1)); // Full content. } String contentType = setContentHeaders(request, response, resourceInfo, ranges); boolean acceptsGzip = false; // 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"; } if (head) { return; } writeContent(response, resource, resourceInfo, ranges, contentType, acceptsGzip); LOGGER.debug("*** RESPONSE FINISHED ***"); }
From source file:org.orderofthebee.addons.support.tools.share.ContentStreamer.java
protected boolean processSingleRange(final Response res, final File file, final String range, final String mimetype) throws IOException { // return the specific set of bytes as requested in the content-range header /*/*from w w w .ja v a2 s .c o m*/ * Examples of byte-content-range-spec values, assuming that the entity contains total of 1234 bytes: * The first 500 bytes: * bytes 0-499/1234 * The second 500 bytes: * bytes 500-999/1234 * All except for the first 500 bytes: * bytes 500-1233/1234 */ /* * 'Range' header example: * bytes=10485760-20971519 */ boolean processedRange = false; Range r = null; try { r = Range.constructRange(range, mimetype, file.length()); } catch (final IllegalArgumentException err) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Failed to parse range header - returning 416 status code: " + err.getMessage()); } res.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); res.setHeader(HEADER_CONTENT_RANGE, "\"*\""); res.getOutputStream().close(); return true; } // set Partial Content status and range headers final String contentRange = "bytes " + Long.toString(r.start) + "-" + Long.toString(r.end) + "/" + Long.toString(file.length()); res.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); res.setContentType(mimetype); res.setHeader(HEADER_CONTENT_RANGE, contentRange); res.setHeader(HEADER_CONTENT_LENGTH, Long.toString((r.end - r.start) + 1L)); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Processing: Content-Range: " + contentRange); } InputStream is = null; try { // output the binary data for the range OutputStream os = null; os = res.getOutputStream(); is = new FileInputStream(file); this.streamRangeBytes(r, is, os, 0L); os.close(); processedRange = true; } catch (final IOException err) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Unable to process single range due to IO Exception: " + err.getMessage()); } throw err; } finally { if (is != null) { is.close(); } } return processedRange; }
From source file:com.xpn.xwiki.web.DownloadActionTest.java
@Test public void testOutsideRange() throws XWikiException, IOException { // This test expects a 416 response final Date d = new Date(); createAttachment(d, DEFAULT_FILE_NAME); setRequestExpectations(DEFAULT_URI, null, null, "bytes=129-145", -1l); getMockery().checking(new Expectations() { {//from w w w .j a va2 s. com one(DownloadActionTest.this.response) .setStatus(with(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE)); } }); Assert.assertNull(this.action.render(getContext())); }
From source file:net.yacy.http.servlets.YaCyDefaultServlet.java
/** * send static content/*from w w w .j a va 2 s . c o m*/ * * @param request * @param response * @param include is a include file (send without changing/adding headers) * @param resource the static content * @param reqRanges * @throws IOException */ protected void sendData(HttpServletRequest request, HttpServletResponse response, boolean include, Resource resource, Enumeration<String> reqRanges) throws IOException { final long content_length = resource.length(); // Get the output stream (or writer) OutputStream out; try { out = response.getOutputStream(); } catch (IllegalStateException e) { out = new WriterOutputStream(response.getWriter()); } // remove the last-modified field since caching otherwise does not work /* https://www.ietf.org/rfc/rfc2616.txt "if the response does have a Last-Modified time, the heuristic expiration value SHOULD be no more than some fraction of the interval since that time. A typical setting of this fraction might be 10%." */ if (response.containsHeader(HeaderFramework.LAST_MODIFIED)) { response.getHeaders(HeaderFramework.LAST_MODIFIED).clear(); // if this field is present, the reload-time is a 10% fraction of ttl and other caching headers do not work } // cache-control: allow shared caching (i.e. proxies) and set expires age for cache response.setHeader(HeaderFramework.CACHE_CONTROL, "public, max-age=" + Integer.toString(600)); // seconds; ten minutes if (reqRanges == null || !reqRanges.hasMoreElements() || content_length < 0) { // if there were no ranges, send entire entity if (include) { resource.writeTo(out, 0, content_length); } else { writeHeaders(response, resource, content_length); resource.writeTo(out, 0, content_length); } } else { // Parse the satisfiable ranges List<?> ranges = InclusiveByteRange.satisfiableRanges(reqRanges, content_length); // if there are no satisfiable ranges, send 416 response if (ranges == null || ranges.isEmpty()) { writeHeaders(response, resource, content_length); response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); response.setHeader(HttpHeader.CONTENT_RANGE.asString(), InclusiveByteRange.to416HeaderRangeString(content_length)); resource.writeTo(out, 0, content_length); out.close(); return; } // if there is only a single valid range (must be satisfiable // since were here now), send that range with a 216 response if (ranges.size() == 1) { InclusiveByteRange singleSatisfiableRange = (InclusiveByteRange) ranges.get(0); long singleLength = singleSatisfiableRange.getSize(content_length); writeHeaders(response, resource, singleLength); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); response.setHeader(HttpHeader.CONTENT_RANGE.asString(), singleSatisfiableRange.toHeaderRangeString(content_length)); resource.writeTo(out, singleSatisfiableRange.getFirst(content_length), singleLength); out.close(); return; } // multiple non-overlapping valid ranges cause a multipart // 216 response which does not require an overall // content-length header // writeHeaders(response, resource, -1); String mimetype = response.getContentType(); if (mimetype == null) { ConcurrentLog.warn("FILEHANDLER", "YaCyDefaultServlet: Unknown mimetype for " + request.getRequestURI()); } MultiPartOutputStream multi = new MultiPartOutputStream(out); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // If the request has a "Request-Range" header then we need to // send an old style multipart/x-byteranges Content-Type. This // keeps Netscape and acrobat happy. This is what Apache does. String ctp; if (request.getHeader(HttpHeader.REQUEST_RANGE.asString()) != null) { ctp = "multipart/x-byteranges; boundary="; } else { ctp = "multipart/byteranges; boundary="; } response.setContentType(ctp + multi.getBoundary()); InputStream in = resource.getInputStream(); long pos = 0; // calculate the content-length int length = 0; String[] header = new String[ranges.size()]; for (int i = 0; i < ranges.size(); i++) { InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i); header[i] = ibr.toHeaderRangeString(content_length); length += ((i > 0) ? 2 : 0) + 2 + multi.getBoundary().length() + 2 + (mimetype == null ? 0 : HeaderFramework.CONTENT_TYPE.length() + 2 + mimetype.length()) + 2 + HeaderFramework.CONTENT_RANGE.length() + 2 + header[i].length() + 2 + 2 + (ibr.getLast(content_length) - ibr.getFirst(content_length)) + 1; } length += 2 + 2 + multi.getBoundary().length() + 2 + 2; response.setContentLength(length); for (int i = 0; i < ranges.size(); i++) { InclusiveByteRange ibr = (InclusiveByteRange) ranges.get(i); multi.startPart(mimetype, new String[] { HeaderFramework.CONTENT_RANGE + ": " + header[i] }); long start = ibr.getFirst(content_length); long size = ibr.getSize(content_length); if (in != null) { // Handle non cached resource if (start < pos) { in.close(); in = resource.getInputStream(); pos = 0; } if (pos < start) { in.skip(start - pos); pos = start; } FileUtils.copy(in, multi, size); pos += size; } else // Handle cached resource { (resource).writeTo(multi, start, size); } } if (in != null) in.close(); multi.close(); } }
From source file:com.xpn.xwiki.web.DownloadActionTest.java
@Test public void testOutsideRestRange() throws XWikiException, IOException { // This test expects a 416 response final Date d = new Date(); createAttachment(d, DEFAULT_FILE_NAME); setRequestExpectations(DEFAULT_URI, null, null, "bytes=129-", -1L); getMockery().checking(new Expectations() { {/*from ww w .j a v a2s . c o m*/ one(DownloadActionTest.this.response) .setStatus(with(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE)); } }); Assert.assertNull(this.action.render(getContext())); }
From source file:org.openhab.ui.cometvisu.servlet.CometVisuServlet.java
/** * Process the actual request./*from w w w .j a va 2s . c o m*/ * * @param request * The request to be processed. * @param response * The response to be created. * @param content * Whether the request body should be written (GET) or not * (HEAD). * @throws IOException * If something fails at I/O level. * * @author BalusC * @link * http://balusc.blogspot.com/2009/02/fileservlet-supporting-resume-and * .html */ private void processStaticRequest(File file, HttpServletRequest request, HttpServletResponse response, boolean content) throws IOException { // Validate the requested file // ------------------------------------------------------------ if (file == null) { // Get requested file by path info. String requestedFile = request.getPathInfo(); // Check if file is actually supplied to the request URL. if (requestedFile == null) { // Do your thing if the file is not supplied to the request URL. // Throw an exception, or send 404, or show default/warning // page, or // just ignore it. response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // URL-decode the file name (might contain spaces and on) and // prepare // file object. file = new File(rootFolder, URLDecoder.decode(requestedFile, "UTF-8")); } // Check if file actually exists in filesystem. if (!file.exists()) { // Do your thing if the file appears to be non-existing. // Throw an exception, or send 404, or show default/warning page, or // just ignore it. response.sendError(HttpServletResponse.SC_NOT_FOUND); 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 (content) { 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 (content) { // 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 (content) { // 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); } }