List of usage examples for javax.servlet.http HttpServletResponse setBufferSize
public void setBufferSize(int size);
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./* www . java2 s .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:org.gss_project.gss.server.rest.FilesHandler.java
/** * Serve the specified resource, optionally including the data content. *//from w w w.jav a 2s .c o m * @param req The servlet request we are processing * @param resp The servlet response we are creating * @param content Should the content be included? * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet-specified error occurs * @throws RpcException * @throws InsufficientPermissionsException * @throws ObjectNotFoundException */ @Override protected void serveResource(HttpServletRequest req, HttpServletResponse resp, boolean content) throws IOException, ServletException { boolean authDeferred = getAuthDeferred(req); String path = getInnerPath(req, PATH_FILES); if (path.equals("")) path = "/"; try { path = URLDecoder.decode(path, "UTF-8"); } catch (IllegalArgumentException e) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); return; } String progress = req.getParameter(PROGRESS_PARAMETER); if (logger.isDebugEnabled()) if (content) logger.debug("Serving resource '" + path + "' headers and data"); else logger.debug("Serving resource '" + path + "' headers only"); User user = getUser(req); User owner = getOwner(req); boolean exists = true; Object resource = null; FileHeader file = null; Folder folder = null; try { resource = getService().getResourceAtPath(owner.getId(), path, false); } catch (ObjectNotFoundException e) { exists = false; } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } if (!exists && authDeferred) { // We do not want to leak information if the request // was not authenticated. resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } if (resource instanceof Folder) folder = (Folder) resource; else file = (FileHeader) resource; // Note that file will be null, if (!exists). // Now it's time to perform the deferred authentication check. // Since regular signature checking was already performed, // we need to check the read-all flag or the signature-in-parameters. if (authDeferred) { if (file != null && !file.isReadForAll() && content) { // Check for GET with the signature in the request parameters. String auth = req.getParameter(AUTHORIZATION_PARAMETER); String dateParam = req.getParameter(DATE_PARAMETER); if (auth == null || dateParam == null) { // Check for a valid authentication cookie. if (req.getCookies() != null) { boolean found = false; for (Cookie cookie : req.getCookies()) if (Login.AUTH_COOKIE.equals(cookie.getName())) { String cookieauth = cookie.getValue(); int sepIndex = cookieauth.indexOf(Login.COOKIE_SEPARATOR); if (sepIndex == -1) { handleAuthFailure(req, resp); return; } String username = URLDecoder.decode(cookieauth.substring(0, sepIndex), "US-ASCII"); user = null; try { user = getService().findUser(username); } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } if (user == null) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } req.setAttribute(USER_ATTRIBUTE, user); String token = cookieauth.substring(sepIndex + 1); if (user.getAuthToken() == null) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } if (!Arrays.equals(user.getAuthToken(), Base64.decodeBase64(token))) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } found = true; break; } if (!found) { handleAuthFailure(req, resp); return; } } else { handleAuthFailure(req, resp); return; } } else { long timestamp; try { timestamp = DateUtil.parseDate(dateParam).getTime(); } catch (DateParseException e) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage()); return; } // Fetch the Authorization parameter and find the user specified in it. String[] authParts = auth.split(" "); if (authParts.length != 2) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } String username = authParts[0]; String signature = authParts[1]; user = null; try { user = getService().findUser(username); } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } if (user == null) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } req.setAttribute(USER_ATTRIBUTE, user); // Remove the servlet path from the request URI. String p = req.getRequestURI(); String servletPath = req.getContextPath() + req.getServletPath(); p = p.substring(servletPath.length()); // Validate the signature in the Authorization parameter. String data = req.getMethod() + dateParam + p; if (!isSignatureValid(signature, user, data)) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } } } else if (folder != null && folder.isReadForAll() || file != null && file.isReadForAll()) { //This case refers to a folder or file with public privileges //For a read-for-all folder request, pretend the owner is making it. user = owner; req.setAttribute(USER_ATTRIBUTE, user); } else if (folder != null && !folder.isReadForAll()) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } else { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } } // If the resource is not a collection, and the resource path // ends with "/" or "\", return NOT FOUND. if (folder == null) if (path.endsWith("/") || path.endsWith("\\")) { resp.sendError(HttpServletResponse.SC_NOT_FOUND, req.getRequestURI()); return; } // Workaround for IE's broken caching behavior. if (folder != null) resp.setHeader("Expires", "-1"); // A request for upload progress. if (progress != null && content) { serveProgress(req, resp, progress, user, file); return; } // Fetch the version to retrieve, if specified. String verStr = req.getParameter(VERSION_PARAM); int version = 0; FileBody oldBody = null; if (verStr != null && file != null) try { version = Integer.valueOf(verStr); } catch (NumberFormatException e) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, req.getRequestURI()); return; } if (version > 0) try { oldBody = getService().getFileVersion(user.getId(), file.getId(), version); } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } catch (ObjectNotFoundException e) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (InsufficientPermissionsException e) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } // Check if the conditions specified in the optional If headers are // satisfied. Doing this for folders would require recursive checking // for all of their children, which in turn would defy the purpose of // the optimization. if (folder == null) { // Checking If headers. if (!checkIfHeaders(req, resp, file, oldBody)) return; } else if (!checkIfModifiedSince(req, resp, folder)) return; // Find content type. String contentType = null; boolean isContentHtml = false; boolean expectJSON = false; if (file != null) { contentType = version > 0 ? oldBody.getMimeType() : file.getCurrentBody().getMimeType(); if (contentType == null) { contentType = context.getMimeType(file.getName()); file.getCurrentBody().setMimeType(contentType); } } else { // folder != null String accept = req.getHeader("Accept"); // The order in this conditional pessimizes the common API case, // but is important for backwards compatibility with existing // clients who send no accept header and expect a JSON response. if (accept != null && accept.contains("text/html")) { contentType = "text/html;charset=UTF-8"; isContentHtml = true; //this is the case when clients send the appropriate headers, the contentType is "text/html" //and expect a JSON response. The above check applies to FireGSS client expectJSON = !authDeferred ? true : false; } else if (authDeferred && req.getMethod().equals(METHOD_GET)) { contentType = "text/html;charset=UTF-8"; isContentHtml = true; expectJSON = false; } else { contentType = "application/json;charset=UTF-8"; expectJSON = true; } } ArrayList ranges = null; long contentLength = -1L; if (file != null) { // Parse range specifier. ranges = parseRange(req, resp, file, oldBody); // ETag header resp.setHeader("ETag", getETag(file, oldBody)); // Last-Modified header. String lastModified = oldBody == null ? getLastModifiedHttp(file.getAuditInfo()) : getLastModifiedHttp(oldBody.getAuditInfo()); resp.setHeader("Last-Modified", lastModified); // X-GSS-Metadata header. try { resp.setHeader("X-GSS-Metadata", renderJson(user, file, oldBody)); } catch (InsufficientPermissionsException e) { resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } // Get content length. contentLength = version > 0 ? oldBody.getFileSize() : file.getCurrentBody().getFileSize(); // Special case for zero length files, which would cause a // (silent) ISE when setting the output buffer size. if (contentLength == 0L) content = false; } else // Set the folder X-GSS-Metadata header. try { resp.setHeader("X-GSS-Metadata", renderJsonMetadata(user, folder)); } catch (InsufficientPermissionsException e) { resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } ServletOutputStream ostream = null; PrintWriter writer = null; if (content) try { ostream = resp.getOutputStream(); } catch (IllegalStateException e) { // If it fails, we try to get a Writer instead if we're // trying to serve a text file if (contentType == null || contentType.startsWith("text") || contentType.endsWith("xml")) writer = resp.getWriter(); else throw e; } if (folder != null || (ranges == null || ranges.isEmpty()) && req.getHeader("Range") == null || ranges == FULL) { // Set the appropriate output headers if (contentType != null) { if (logger.isDebugEnabled()) logger.debug("contentType='" + contentType + "'"); resp.setContentType(contentType); } if (file != null && contentLength >= 0) { if (logger.isDebugEnabled()) logger.debug("contentLength=" + contentLength); if (contentLength < Integer.MAX_VALUE) resp.setContentLength((int) contentLength); else // Set the content-length as String to be able to use a long resp.setHeader("content-length", "" + contentLength); } InputStream renderResult = null; String relativePath = getRelativePath(req); String contextPath = req.getContextPath(); String servletPath = req.getServletPath(); String contextServletPath = contextPath + servletPath; if (folder != null && content) // Serve the directory browser for a public folder if (isContentHtml && !expectJSON) { try { folder = getService().expandFolder(folder); } catch (ObjectNotFoundException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } catch (RpcException e) { //We send 500 instead of 404 because this folder has been loaded before in this method and it is //impossible to not be found now resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, path); return; } renderResult = renderHtml(contextServletPath, relativePath, folder, user); } // Serve the directory for an ordinary folder or for fireGSS client else try { renderResult = renderJson(user, folder); } catch (InsufficientPermissionsException e) { resp.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } // Copy the input stream to our output stream (if requested) if (content) { try { resp.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } try { if (file != null) if (needsContentDisposition(req)) resp.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + getDispositionFilename(file)); else resp.setHeader("Content-Disposition", "inline; filename*=UTF-8''" + getDispositionFilename(file)); if (ostream != null) copy(file, renderResult, ostream, req, oldBody); else copy(file, renderResult, writer, req, oldBody); if (file != null) updateAccounting(owner, new Date(), contentLength); } catch (ObjectNotFoundException e) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (InsufficientPermissionsException e) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } } else { if (ranges == null || ranges.isEmpty()) return; // Partial content response. resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (ranges.size() == 1) { Range range = (Range) ranges.get(0); resp.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length); long length = range.end - range.start + 1; if (length < Integer.MAX_VALUE) resp.setContentLength((int) length); else // Set the content-length as String to be able to use a long resp.setHeader("content-length", "" + length); if (contentType != null) { if (logger.isDebugEnabled()) logger.debug("contentType='" + contentType + "'"); resp.setContentType(contentType); } if (content) { try { resp.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } try { if (ostream != null) copy(file, ostream, range, req, oldBody); else copy(file, writer, range, req, oldBody); updateAccounting(owner, new Date(), contentLength); } catch (ObjectNotFoundException e) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (InsufficientPermissionsException e) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } } else { resp.setContentType("multipart/byteranges; boundary=" + mimeSeparation); if (content) { try { resp.setBufferSize(output); } catch (IllegalStateException e) { // Silent catch } try { if (ostream != null) copy(file, ostream, ranges.iterator(), contentType, req, oldBody); else copy(file, writer, ranges.iterator(), contentType, req, oldBody); updateAccounting(owner, new Date(), contentLength); } catch (ObjectNotFoundException e) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } catch (InsufficientPermissionsException e) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return; } catch (RpcException e) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } } } }
From source file:org.sakaiproject.content.impl.BaseContentService.java
/** * Process the access request for a resource. * /* w w w.j a v a 2 s. co m*/ * @param req * @param req * @param res * @param ref * @param copyrightAcceptedRefs * @throws PermissionException * @throws IdUnusedException * @throws ServerOverloadException * @throws CopyrightException */ protected void handleAccessResource(HttpServletRequest req, HttpServletResponse res, Reference ref, Collection<String> copyrightAcceptedRefs) throws EntityPermissionException, EntityNotDefinedException, EntityAccessOverloadException, EntityCopyrightException { // we only access resources, not collections if (ref.getId().endsWith(Entity.SEPARATOR)) throw new EntityNotDefinedException(ref.getReference()); // need read permission if (!allowGetResource(ref.getId())) throw new EntityPermissionException(sessionManager.getCurrentSessionUserId(), AUTH_RESOURCE_READ, ref.getReference()); ContentResource resource = null; try { resource = getResource(ref.getId()); } catch (IdUnusedException e) { throw new EntityNotDefinedException(e.getId()); } catch (PermissionException e) { throw new EntityPermissionException(e.getUser(), e.getLock(), e.getResource()); } catch (TypeException e) { throw new EntityNotDefinedException(ref.getReference()); } // if this entity requires a copyright agreement, and has not yet been set, get one if (((BaseResourceEdit) resource).requiresCopyrightAgreement() && !copyrightAcceptedRefs.contains(resource.getReference())) { throw new EntityCopyrightException(ref.getReference()); } // Wrap up the resource if we need to. resource = m_contentFilterService.wrap(resource); // Set some headers to tell browsers to revalidate and check for updated files res.addHeader("Cache-Control", "must-revalidate, private"); res.addHeader("Expires", "-1"); try { long len = resource.getContentLength(); String contentType = resource.getContentType(); ResourceProperties rp = resource.getProperties(); long lastModTime = 0; try { Time modTime = rp.getTimeProperty(ResourceProperties.PROP_MODIFIED_DATE); lastModTime = modTime.getTime(); } catch (Exception e1) { M_log.info("Could not retrieve modified time for: " + resource.getId()); } // KNL-1316 tell the browser when our file was last modified for caching reasons if (lastModTime > 0) { SimpleDateFormat rfc1123Date = new SimpleDateFormat(RFC1123_DATE, LOCALE_US); rfc1123Date.setTimeZone(TimeZone.getTimeZone("GMT")); res.addHeader("Last-Modified", rfc1123Date.format(lastModTime)); } // for url content type, encode a redirect to the body URL if (contentType.equalsIgnoreCase(ResourceProperties.TYPE_URL)) { if (len < MAX_URL_LENGTH) { byte[] content = resource.getContent(); if ((content == null) || (content.length == 0)) { throw new IdUnusedException(ref.getReference()); } // An invalid URI format will get caught by the outermost catch block URI uri = new URI(new String(content, "UTF-8")); eventTrackingService.post( eventTrackingService.newEvent(EVENT_RESOURCE_READ, resource.getReference(null), false)); //SAK-23587 process any macros present in this URL String decodedUrl = URLDecoder.decode(uri.toString(), "UTF-8"); decodedUrl = expandMacros(decodedUrl); res.sendRedirect(decodedUrl); } else { // we have a text/url mime type, but the body is too long to issue as a redirect throw new EntityNotDefinedException(ref.getReference()); } } else { // use the last part, the file name part of the id, for the download file name String fileName = Validator.getFileName(ref.getId()); String disposition = null; if (Validator.letBrowserInline(contentType)) { // if this is an html file we have more checks String lcct = contentType.toLowerCase(); if ((lcct.startsWith("text/") || lcct.startsWith("image/") || lcct.contains("html") || lcct.contains("script")) && m_serverConfigurationService.getBoolean(SECURE_INLINE_HTML, true)) { // increased checks to handle more mime-types - https://jira.sakaiproject.org/browse/KNL-749 boolean fileInline = false; boolean folderInline = false; try { fileInline = rp.getBooleanProperty(ResourceProperties.PROP_ALLOW_INLINE); } catch (EntityPropertyNotDefinedException e) { // we expect this so nothing to do! } if (!fileInline) try { folderInline = resource.getContainingCollection().getProperties() .getBooleanProperty(ResourceProperties.PROP_ALLOW_INLINE); } catch (EntityPropertyNotDefinedException e) { // we expect this so nothing to do! } if (fileInline || folderInline) { disposition = Web.buildContentDisposition(fileName, false); } } else { disposition = Web.buildContentDisposition(fileName, false); } } // drop through to attachment if (disposition == null) { disposition = Web.buildContentDisposition(fileName, true); } // NOTE: Only set the encoding on the content we have to. // Files uploaded by the user may have been created with different encodings, such as ISO-8859-1; // rather than (sometimes wrongly) saying its UTF-8, let the browser auto-detect the encoding. // If the content was created through the WYSIWYG editor, the encoding does need to be set (UTF-8). String encoding = resource.getProperties().getProperty(ResourceProperties.PROP_CONTENT_ENCODING); if (encoding != null && encoding.length() > 0) { contentType = contentType + "; charset=" + encoding; } // KNL-1316 let's see if the user already has a cached copy. Code copied and modified from Tomcat DefaultServlet.java long headerValue = req.getDateHeader("If-Modified-Since"); if (headerValue != -1 && (lastModTime < headerValue + 1000)) { // The entity has not been modified since the date specified by the client. This is not an error case. res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } ArrayList<Range> ranges = parseRange(req, res, len); res.addHeader("Accept-Ranges", "bytes"); if (req.getHeader("Range") == null || (ranges == null) || (ranges.isEmpty())) { // stream the content using a small buffer to keep memory managed InputStream content = null; OutputStream out = null; try { content = resource.streamContent(); if (content == null) { throw new IdUnusedException(ref.getReference()); } res.setContentType(contentType); res.addHeader("Content-Disposition", disposition); // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4187336 if (len <= Integer.MAX_VALUE) { res.setContentLength((int) len); } else { res.addHeader("Content-Length", Long.toString(len)); } // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRange(content, out, 0, len - 1); } catch (ServerOverloadException e) { throw e; } catch (Exception ignore) { } finally { // be a good little program and close the stream - freeing up valuable system resources if (content != null) { content.close(); } if (out != null) { try { out.close(); } catch (Exception ignore) { } } } // Track event - only for full reads eventTrackingService.post( eventTrackingService.newEvent(EVENT_RESOURCE_READ, resource.getReference(null), false)); } else { // Output partial content. Adapted from Apache Tomcat 5.5.27 DefaultServlet.java res.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (ranges.size() == 1) { // Single response Range range = (Range) ranges.get(0); res.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length); long length = range.end - range.start + 1; if (length < Integer.MAX_VALUE) { res.setContentLength((int) length); } else { // Set the content-length as String to be able to use a long res.setHeader("content-length", "" + length); } res.addHeader("Content-Disposition", disposition); if (contentType != null) { res.setContentType(contentType); } // stream the content using a small buffer to keep memory managed InputStream content = null; OutputStream out = null; try { content = resource.streamContent(); if (content == null) { throw new IdUnusedException(ref.getReference()); } // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRange(content, out, range.start, range.end); } catch (ServerOverloadException e) { throw e; } catch (SocketException e) { //a socket exception usualy means the client aborted the connection or similar if (M_log.isDebugEnabled()) { M_log.debug("SocketExcetion", e); } } catch (Exception ignore) { } finally { // be a good little program and close the stream - freeing up valuable system resources if (content != null) { content.close(); } if (out != null) { try { out.close(); } catch (IOException ignore) { // ignore } } } } else { // Multipart response res.setContentType("multipart/byteranges; boundary=" + MIME_SEPARATOR); // stream the content using a small buffer to keep memory managed OutputStream out = null; try { // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRanges(resource, out, ranges.iterator(), contentType); } catch (SocketException e) { //a socket exception usualy means the client aborted the connection or similar if (M_log.isDebugEnabled()) { M_log.debug("SocketExcetion", e); } } catch (Exception ignore) { M_log.error("Swallowing exception", ignore); } finally { // be a good little program and close the stream - freeing up valuable system resources if (out != null) { try { out.close(); } catch (IOException ignore) { // ignore } } } } // output multiple ranges } // output partial content } // output resource } catch (Exception t) { throw new EntityNotDefinedException(ref.getReference(), t); } }
From source file:org.sakaiproject.lessonbuildertool.service.LessonBuilderAccessService.java
public HttpAccess getHttpAccess() { return new HttpAccess() { public void handleAccess(HttpServletRequest req, HttpServletResponse res, Reference ref, Collection copyrightAcceptedRefs) throws EntityPermissionException, EntityNotDefinedException, EntityAccessOverloadException, EntityCopyrightException { // preauthorized by encrypted key boolean isAuth = false; // if the id is null, the request was for just ".../content" String refId = ref.getId(); if (refId == null) { refId = ""; }/*from w ww . j av a 2s. c o m*/ if (!refId.startsWith("/item")) { throw new EntityNotDefinedException(ref.getReference()); } String itemString = refId.substring("/item/".length()); // string is of form /item/NNN/url. get the number int i = itemString.indexOf("/"); if (i < 0) { throw new EntityNotDefinedException(ref.getReference()); } // get session. The problem here is that some multimedia tools don't reliably // pass JSESSIONID String sessionParam = req.getParameter("lb.session"); if (sessionParam != null) { try { Cipher sessionCipher = Cipher.getInstance("Blowfish"); sessionCipher.init(Cipher.DECRYPT_MODE, sessionKey); byte[] sessionBytes = DatatypeConverter.parseHexBinary(sessionParam); sessionBytes = sessionCipher.doFinal(sessionBytes); String sessionString = new String(sessionBytes); int j = sessionString.indexOf(":"); String sessionId = sessionString.substring(0, j); String url = sessionString.substring(j + 1); UsageSession s = UsageSessionService.getSession(sessionId); if (s == null || s.isClosed() || url == null || !url.equals(refId)) { throw new EntityPermissionException(sessionManager.getCurrentSessionUserId(), ContentHostingService.AUTH_RESOURCE_READ, ref.getReference()); } else { isAuth = true; } } catch (Exception e) { System.out.println("unable to decode lb.session " + e); } } // basically there are two checks to be done: is the item accessible in Lessons, // and is the underlying resource accessible in Sakai. // This code really does check both. Sort of. // 1) it checks accessibility to the containing page by seeing if it has been visited. // This is stricter than necessary, but there's no obvious reason to let people use this // who aren't following an actual URL we gave them. // 2) it checks group access as part of the normal resource permission check. Sakai // should sync the two. We actually don't check it for items in student home directories, // as far as I can tell // 3) it checks availability (prerequisites) by calling the code from SimplePageBean // We could rewrite this with the new LessonsAccess methods, but since we have to do // resource permission checking also, and there's some duplication, it doesn't seem worth // rewriting this code. What I've done is review it to make sure it does the same thing. String id = itemString.substring(i); itemString = itemString.substring(0, i); boolean pushedAdvisor = false; try { securityService.pushAdvisor(allowReadAdvisor); pushedAdvisor = true; Long itemId = 0L; try { itemId = (Long) Long.parseLong(itemString); } catch (Exception e) { throw new EntityNotDefinedException(ref.getReference()); } // say we've read this if (itemId != 0L) track(itemId.longValue(), sessionManager.getCurrentSessionUserId()); // code here is also in simplePageBean.isItemVisible. change it there // too if you change this logic SimplePageItem item = simplePageToolDao.findItem(itemId.longValue()); SimplePage currentPage = simplePageToolDao.getPage(item.getPageId()); String owner = currentPage.getOwner(); // if student content String group = currentPage.getGroup(); // if student content if (group != null) group = "/site/" + currentPage.getSiteId() + "/group/" + group; String currentSiteId = currentPage.getSiteId(); // first let's make sure the user is allowed to access // the containing page if (!isAuth && !canReadPage(currentSiteId)) { throw new EntityPermissionException(sessionManager.getCurrentSessionUserId(), ContentHostingService.AUTH_RESOURCE_READ, ref.getReference()); } // If the resource is the actual one in the item, or // it is in the containing folder, then do lesson builder checking. // otherwise do normal resource checking if (!isAuth) { boolean useLb = false; // I've seen sakai id's with //, not sure why. they work but will mess up the comparison String itemResource = item.getSakaiId().replace("//", "/"); // only use lb security if the user has visited the page // this handles the various page release issues, although // it's not quite as flexible as the real code. But I don't // see any reason to help the user follow URLs that they can't // legitimately have seen. if (simplePageToolDao.isPageVisited(item.getPageId(), sessionManager.getCurrentSessionUserId(), owner)) { if (id.equals(itemResource)) useLb = true; else { // not exact, but see if it's in the containing folder int endFolder = itemResource.lastIndexOf("/"); if (endFolder > 0) { String folder = itemResource.substring(0, endFolder + 1); if (id.startsWith(folder)) useLb = true; } } } if (useLb) { // key into access cache String accessKey = itemString + ":" + sessionManager.getCurrentSessionUserId(); // special access if we have a student site and item is in worksite of one of the students // Normally we require that the person doing the access be able to see the file, but in // that specific case we allow the access. Note that in order to get a sakaiid pointing // into the user's space, the person editing the page must have been able to read the file. // this allows a user in your group to share any of your resources that he can see. String usersite = null; if (owner != null && group != null && id.startsWith("/user/")) { String username = id.substring(6); int slash = username.indexOf("/"); if (slash > 0) usersite = username.substring(0, slash); // normally it is /user/EID, so convert to userid try { usersite = UserDirectoryService.getUserId(usersite); } catch (Exception e) { } ; String itemcreator = item.getAttribute("addedby"); // suppose a member of the group adds a resource from another member of // the group. (This will only work if they have read access to it.) // We don't want to gimick access in that case. I think if you // add your own item, you've given consent. But not if someone else does. // itemcreator == null is for items added before this patch. I'm going to // continue to allow access for them, to avoid breaking existing content. if (usersite != null && itemcreator != null && !usersite.equals(itemcreator)) usersite = null; } // code here is also in simplePageBean.isItemVisible. change it there // too if you change this logic // for a student page, if it's in one of the groups' worksites, allow it // The assumption is that only one of those people can put content in the // page, and then only if the can see it. if (owner != null && usersite != null && authzGroupService.getUserRole(usersite, group) != null) { // OK } else if (owner != null && group == null && id.startsWith("/user/" + owner)) { // OK } else { // do normal checking for other content if (pushedAdvisor) { securityService.popAdvisor(); pushedAdvisor = false; } // our version of allowget does not check hidden but does everything else // if it's a student page, however use the normal check so students can't // use this to bypass release control if (owner == null && !allowGetResource(id, currentSiteId) || owner != null && !contentHostingService.allowGetResource(id)) { throw new EntityPermissionException(sessionManager.getCurrentSessionUserId(), ContentHostingService.AUTH_RESOURCE_READ, ref.getReference()); } securityService.pushAdvisor(allowReadAdvisor); pushedAdvisor = true; } // now enforce LB access restrictions if any if (item != null && item.isPrerequisite() && !"true".equals((String) accessCache.get(accessKey))) { // computing requirements is so messy that it's worth // instantiating // a SimplePageBean to do it. Otherwise we have to duplicate // lots of // code that changes. And we want it to be a transient bean // because there are // caches that we aren't trying to manage in the long term // but don't do this unless the item needs checking if (!canSeeAll(currentPage.getSiteId())) { SimplePageBean simplePageBean = new SimplePageBean(); simplePageBean.setMessageLocator(messageLocator); simplePageBean.setToolManager(toolManager); simplePageBean.setSecurityService(securityService); simplePageBean.setSessionManager(sessionManager); simplePageBean.setSiteService(siteService); simplePageBean.setContentHostingService(contentHostingService); simplePageBean.setSimplePageToolDao(simplePageToolDao); simplePageBean.setForumEntity(forumEntity); simplePageBean.setQuizEntity(quizEntity); simplePageBean.setAssignmentEntity(assignmentEntity); simplePageBean.setBltiEntity(bltiEntity); simplePageBean.setGradebookIfc(gradebookIfc); simplePageBean.setMemoryService(memoryService); simplePageBean.setCurrentSiteId(currentPage.getSiteId()); simplePageBean.setCurrentPage(currentPage); simplePageBean.setCurrentPageId(currentPage.getPageId()); simplePageBean.init(); if (!simplePageBean.isItemAvailable(item, item.getPageId())) { throw new EntityPermissionException(null, null, null); } } accessCache.put(accessKey, "true"); } } else { // normal security. no reason to use advisor if (pushedAdvisor) securityService.popAdvisor(); pushedAdvisor = false; // not uselb -- their allowget, not ours. theirs checks hidden if (!contentHostingService.allowGetResource(id)) { throw new EntityPermissionException(sessionManager.getCurrentSessionUserId(), ContentHostingService.AUTH_RESOURCE_READ, ref.getReference()); } } } // access checks are OK, get the thing // first see if it's not in resources, i.e. // if it doesn't start with /access/content it's something odd. redirect to it. // probably resources access control won't apply to it String url = contentHostingService.getUrl(id); // https://heidelberg.rutgers.edu/access/citation/content/group/24da8519-08c2-4c8c-baeb-8abdfd6c69d7/New%20Citation%20List int n = url.indexOf("//"); if (n > 0) { n = url.indexOf("/", n + 2); if (n > 0) { String path = url.substring(n); if (!path.startsWith("/access/content")) { res.sendRedirect(url); return; } } } ContentResource resource = null; try { resource = contentHostingService.getResource(id); } catch (IdUnusedException e) { throw new EntityNotDefinedException(e.getId()); } catch (PermissionException e) { throw new EntityPermissionException(e.getUser(), e.getLock(), e.getResource()); } catch (TypeException e) { throw new EntityNotDefinedException(id); } // we only do copyright on resources. I.e. not on inline things,which are MULTIMEDIA if (item.getType() == SimplePageItem.RESOURCE && needsCopyright(resource)) { throw new EntityCopyrightException(resource.getReference()); } try { // Wrap it in any filtering needed. resource = contentFilterService.wrap(resource); // following cast is redundant is current kernels, but is needed for Sakai 2.6.1 long len = (long) resource.getContentLength(); String contentType = resource.getContentType(); // for url resource type, encode a redirect to the body URL // in 2.10 have to check resourcetype, but in previous releasese // it doesn't get copied in site copy, so check content type. 10 doesn't set the contenttype to url // so we have to check both to work in all versions if (contentType.equalsIgnoreCase(ResourceProperties.TYPE_URL) || "org.sakaiproject.content.types.urlResource" .equalsIgnoreCase(resource.getResourceType())) { if (len < MAX_URL_LENGTH) { byte[] content = resource.getContent(); if ((content == null) || (content.length == 0)) { throw new IdUnusedException(ref.getReference()); } // An invalid URI format will get caught by the // outermost catch block URI uri = new URI(new String(content, "UTF-8")); eventTrackingService.post( eventTrackingService.newEvent(ContentHostingService.EVENT_RESOURCE_READ, resource.getReference(null), false)); res.sendRedirect(uri.toASCIIString()); } else { // we have a text/url mime type, but the body is too // long to issue as a redirect throw new EntityNotDefinedException(ref.getReference()); } } else { // use the last part, the file name part of the id, for // the download file name String fileName = Web.encodeFileName(req, Validator.getFileName(ref.getId())); String disposition = null; boolean inline = false; if (Validator.letBrowserInline(contentType)) { // type can be inline, but if HTML we have more checks to do if (inlineHtml || (!"text/html".equalsIgnoreCase(contentType) && !"application/xhtml+xml".equals(contentType))) // easy cases: not HTML or HTML always OK inline = true; else { // HTML and html is not allowed globally. code copied from BaseContentServices ResourceProperties rp = resource.getProperties(); boolean fileInline = false; boolean folderInline = false; try { fileInline = rp.getBooleanProperty(ResourceProperties.PROP_ALLOW_INLINE); } catch (EntityPropertyNotDefinedException e) { // we expect this so nothing to do! } if (!fileInline) try { folderInline = resource.getContainingCollection().getProperties() .getBooleanProperty(ResourceProperties.PROP_ALLOW_INLINE); } catch (EntityPropertyNotDefinedException e) { // we expect this so nothing to do! } if (fileInline || folderInline) { inline = true; } } } if (inline) { disposition = "inline; filename=\"" + fileName + "\""; } else { disposition = "attachment; filename=\"" + fileName + "\""; } // NOTE: Only set the encoding on the content we have // to. // Files uploaded by the user may have been created with // different encodings, such as ISO-8859-1; // rather than (sometimes wrongly) saying its UTF-8, let // the browser auto-detect the encoding. // If the content was created through the WYSIWYG // editor, the encoding does need to be set (UTF-8). String encoding = resource.getProperties() .getProperty(ResourceProperties.PROP_CONTENT_ENCODING); if (encoding != null && encoding.length() > 0) { contentType = contentType + "; charset=" + encoding; } // from contenthosting res.addHeader("Cache-Control", "must-revalidate, private"); res.addHeader("Expires", "-1"); ResourceProperties rp = resource.getProperties(); long lastModTime = 0; try { Time modTime = rp.getTimeProperty(ResourceProperties.PROP_MODIFIED_DATE); lastModTime = modTime.getTime(); } catch (Exception e1) { M_log.info("Could not retrieve modified time for: " + resource.getId()); } // KNL-1316 tell the browser when our file was last modified for caching reasons if (lastModTime > 0) { SimpleDateFormat rfc1123Date = new SimpleDateFormat(RFC1123_DATE, LOCALE_US); rfc1123Date.setTimeZone(TimeZone.getTimeZone("GMT")); res.addHeader("Last-Modified", rfc1123Date.format(lastModTime)); } // KNL-1316 let's see if the user already has a cached copy. Code copied and modified from Tomcat DefaultServlet.java long headerValue = req.getDateHeader("If-Modified-Since"); if (headerValue != -1 && (lastModTime < headerValue + 1000)) { // The entity has not been modified since the date specified by the client. This is not an error case. res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } ArrayList<Range> ranges = parseRange(req, res, len); if (req.getHeader("Range") == null || (ranges == null) || (ranges.isEmpty())) { // stream the content using a small buffer to keep memory managed InputStream content = null; OutputStream out = null; try { content = resource.streamContent(); if (content == null) { throw new IdUnusedException(ref.getReference()); } res.setContentType(contentType); res.addHeader("Content-Disposition", disposition); res.addHeader("Accept-Ranges", "bytes"); // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4187336 if (len <= Integer.MAX_VALUE) { res.setContentLength((int) len); } else { res.addHeader("Content-Length", Long.toString(len)); } // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRange(content, out, 0, len - 1); } catch (ServerOverloadException e) { throw e; } catch (Exception ignore) { } finally { // be a good little program and close the stream - freeing up valuable system resources if (content != null) { content.close(); } if (out != null) { try { out.close(); } catch (Exception ignore) { } } } // Track event - only for full reads eventTrackingService.post( eventTrackingService.newEvent(ContentHostingService.EVENT_RESOURCE_READ, resource.getReference(null), false)); } else { // Output partial content. Adapted from Apache Tomcat 5.5.27 DefaultServlet.java res.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (ranges.size() == 1) { // Single response Range range = (Range) ranges.get(0); res.addHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.length); long length = range.end - range.start + 1; if (length < Integer.MAX_VALUE) { res.setContentLength((int) length); } else { // Set the content-length as String to be able to use a long res.setHeader("content-length", "" + length); } res.addHeader("Content-Disposition", disposition); if (contentType != null) { res.setContentType(contentType); } // stream the content using a small buffer to keep memory managed InputStream content = null; OutputStream out = null; try { content = resource.streamContent(); if (content == null) { throw new IdUnusedException(ref.getReference()); } // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRange(content, out, range.start, range.end); } catch (ServerOverloadException e) { throw e; } catch (SocketException e) { //a socket exception usualy means the client aborted the connection or similar if (M_log.isDebugEnabled()) { M_log.debug("SocketExcetion", e); } } catch (Exception ignore) { } finally { // be a good little program and close the stream - freeing up valuable system resources IOUtils.closeQuietly(content); IOUtils.closeQuietly(out); } } else { // Multipart response res.setContentType("multipart/byteranges; boundary=" + MIME_SEPARATOR); // stream the content using a small buffer to keep memory managed OutputStream out = null; try { // set the buffer of the response to match what we are reading from the request if (len < STREAM_BUFFER_SIZE) { res.setBufferSize((int) len); } else { res.setBufferSize(STREAM_BUFFER_SIZE); } out = res.getOutputStream(); copyRanges(resource, out, ranges.iterator(), contentType); } catch (SocketException e) { //a socket exception usualy means the client aborted the connection or similar if (M_log.isDebugEnabled()) { M_log.debug("SocketExcetion", e); } } catch (Exception ignore) { M_log.error("Swallowing exception", ignore); } finally { // be a good little program and close the stream - freeing up valuable system resources IOUtils.closeQuietly(out); } } // output multiple ranges } // output partial content } } catch (Exception t) { throw new EntityNotDefinedException(ref.getReference()); // following won't work in 2.7.1 // throw new EntityNotDefinedException(ref.getReference(), t); } // not sure why we're trapping exceptions and calling them not defined, but // a few types are needed by the caller } catch (EntityCopyrightException ce) { // copyright exception needs to go as is, to give copyright alert throw ce; } catch (EntityPermissionException pe) { // also want permission exceptions; it will generate a login page throw pe; } catch (Exception ex) { throw new EntityNotDefinedException(ref.getReference()); } finally { if (pushedAdvisor) securityService.popAdvisor(); } } }; }