List of usage examples for javax.servlet.http HttpServletRequest getDateHeader
public long getDateHeader(String name);
long
value that represents a Date
object. From source file:org.alfresco.web.app.servlet.BaseDownloadContentServlet.java
/** * Processes the download request using the current context i.e. no authentication checks are made, it is presumed * they have already been done.// www. j a va 2 s . co m * * @param req * The HTTP request * @param res * The HTTP response * @param allowLogIn * Indicates whether guest users without access to the content should be redirected to the log in page. If * <code>false</code>, a status 403 forbidden page is displayed instead. */ protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res, boolean allowLogIn, boolean transmitContent) throws ServletException, IOException { Log logger = getLogger(); String uri = req.getRequestURI(); if (logger.isDebugEnabled()) { String queryString = req.getQueryString(); logger.debug("Processing URL: " + uri + ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : "")); } uri = uri.substring(req.getContextPath().length()); StringTokenizer t = new StringTokenizer(uri, "/"); int tokenCount = t.countTokens(); t.nextToken(); // skip servlet name // attachment mode (either 'attach' or 'direct') String attachToken = t.nextToken(); boolean attachment = URL_ATTACH.equals(attachToken) || URL_ATTACH_LONG.equals(attachToken); ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext()); // get or calculate the noderef and filename to download as NodeRef nodeRef; String filename; // do we have a path parameter instead of a NodeRef? String path = req.getParameter(ARG_PATH); if (path != null && path.length() != 0) { // process the name based path to resolve the NodeRef and the Filename element try { PathRefInfo pathInfo = resolveNamePath(getServletContext(), path); nodeRef = pathInfo.NodeRef; filename = pathInfo.Filename; } catch (IllegalArgumentException e) { Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, HttpServletResponse.SC_NOT_FOUND, logger); return; } } else { // a NodeRef must have been specified if no path has been found if (tokenCount < 6) { throw new IllegalArgumentException("Download URL did not contain all required args: " + uri); } // assume 'workspace' or other NodeRef based protocol for remaining URL elements StoreRef storeRef = new StoreRef(URLDecoder.decode(t.nextToken()), URLDecoder.decode(t.nextToken())); String id = URLDecoder.decode(t.nextToken()); // build noderef from the appropriate URL elements nodeRef = new NodeRef(storeRef, id); if (tokenCount > 6) { // found additional relative path elements i.e. noderefid/images/file.txt // this allows a url to reference siblings nodes via a cm:name based relative path // solves the issue with opening HTML content containing relative URLs in HREF or IMG tags etc. List<String> paths = new ArrayList<String>(tokenCount - 5); while (t.hasMoreTokens()) { paths.add(URLDecoder.decode(t.nextToken())); } filename = paths.get(paths.size() - 1); try { NodeRef parentRef = serviceRegistry.getNodeService().getPrimaryParent(nodeRef).getParentRef(); FileInfo fileInfo = serviceRegistry.getFileFolderService().resolveNamePath(parentRef, paths); nodeRef = fileInfo.getNodeRef(); } catch (FileNotFoundException e) { Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, HttpServletResponse.SC_NOT_FOUND, logger); return; } } else { // filename is last remaining token filename = t.nextToken(); } } // get qualified of the property to get content from - default to ContentModel.PROP_CONTENT QName propertyQName = ContentModel.PROP_CONTENT; String property = req.getParameter(ARG_PROPERTY); if (property != null && property.length() != 0) { propertyQName = QName.createQName(property); } if (logger.isDebugEnabled()) { logger.debug("Found NodeRef: " + nodeRef); logger.debug("Will use filename: " + filename); logger.debug("For property: " + propertyQName); logger.debug("With attachment mode: " + attachment); } // get the services we need to retrieve the content NodeService nodeService = serviceRegistry.getNodeService(); ContentService contentService = serviceRegistry.getContentService(); // Check that the node still exists if (!nodeService.exists(nodeRef)) { Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND, HttpServletResponse.SC_NOT_FOUND, logger); return; } try { // check that the user has at least READ_CONTENT access - else redirect to an error or login page if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn)) { return; } // check If-Modified-Since header and set Last-Modified header as appropriate Date modified = (Date) nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED); if (modified != null) { long modifiedSince = req.getDateHeader(HEADER_IF_MODIFIED_SINCE); if (modifiedSince > 0L) { // round the date to the ignore millisecond value which is not supplied by header long modDate = (modified.getTime() / 1000L) * 1000L; if (modDate <= modifiedSince) { if (logger.isDebugEnabled()) logger.debug("Returning 304 Not Modified."); res.setStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } } res.setDateHeader(HEADER_LAST_MODIFIED, modified.getTime()); res.setHeader(HEADER_CACHE_CONTROL, "must-revalidate, max-age=0"); res.setHeader(HEADER_ETAG, "\"" + Long.toString(modified.getTime()) + "\""); } if (attachment == true) { setHeaderContentDisposition(req, res, filename); } // get the content reader ContentReader reader = contentService.getReader(nodeRef, propertyQName); // ensure that it is safe to use reader = FileContentReader.getSafeContentReader(reader, Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING), nodeRef, reader); String mimetype = reader.getMimetype(); // fall back if unable to resolve mimetype property if (mimetype == null || mimetype.length() == 0) { MimetypeService mimetypeMap = serviceRegistry.getMimetypeService(); mimetype = MIMETYPE_OCTET_STREAM; int extIndex = filename.lastIndexOf('.'); if (extIndex != -1) { String ext = filename.substring(extIndex + 1); mimetype = mimetypeMap.getMimetype(ext); } } // explicitly set the content disposition header if the content is powerpoint if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) || mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE))) { setHeaderContentDisposition(req, res, filename); } // get the content and stream directly to the response output stream // assuming the repo is capable of streaming in chunks, this should allow large files // to be streamed directly to the browser response stream. res.setHeader(HEADER_ACCEPT_RANGES, "bytes"); // for a GET request, transmit the content else just the headers are sent if (transmitContent) { try { boolean processedRange = false; String range = req.getHeader(HEADER_CONTENT_RANGE); if (range == null) { range = req.getHeader(HEADER_RANGE); } if (range != null) { if (logger.isDebugEnabled()) logger.debug("Found content range header: " + range); // ensure the range header is starts with "bytes=" and process the range(s) if (range.length() > 6) { HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService); processedRange = rangeProcessor.processRange(res, reader, range.substring(6), nodeRef, propertyQName, mimetype, req.getHeader(HEADER_USER_AGENT)); } } if (processedRange == false) { if (logger.isDebugEnabled()) logger.debug("Sending complete file content..."); // set mimetype for the content and the character encoding for the stream res.setContentType(mimetype); res.setCharacterEncoding(reader.getEncoding()); // MNT-10642 Alfresco Explorer has javascript vulnerability opening HTML files if (req.getRequestURI().contains("/d/d/") && (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml") || mimetype.equals("text/xml"))) { String content = reader.getContentString(); if (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml")) { // process with HTML stripper content = StringUtils.stripUnsafeHTMLTags(content, false); } else if (mimetype.equals("text/xml") && mimetype.equals("text/x-component")) { // IE supports "behaviour" which means that css can load a .htc file that could // contain XSS code in the form of jscript, vbscript etc, to stop it form being // evaluated we set the contient type to text/plain res.setContentType("text/plain"); } String encoding = reader.getEncoding(); byte[] bytes = encoding != null ? content.getBytes(encoding) : content.getBytes(); res.setContentLength(bytes.length); res.getOutputStream().write(bytes); return; } // return the complete entity range long size = reader.getSize(); res.setHeader(HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size - 1L) + "/" + Long.toString(size)); res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size)); reader.getContent(res.getOutputStream()); } } catch (SocketException e1) { // the client cut the connection - our mission was accomplished apart from a little error message if (logger.isDebugEnabled()) logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader); } catch (ContentIOException e2) { if (logger.isInfoEnabled()) logger.info("Failed stream read:\n\tnode: " + nodeRef + " due to: " + e2.getMessage()); } catch (Throwable err) { if (err.getCause() instanceof SocketException) { // the client cut the connection - our mission was accomplished apart from a little error message if (logger.isDebugEnabled()) logger.debug( "Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader); } else throw err; } } else { if (logger.isDebugEnabled()) logger.debug("HEAD request processed - no content sent."); res.getOutputStream().close(); } } catch (Throwable err) { throw new AlfrescoRuntimeException( "Error during download content servlet processing: " + err.getMessage(), err); } }
From source file:hu.api.SivaPlayerVideoServlet.java
private void doAction(HttpServletRequest request, HttpServletResponse response, String requestType) throws ServletException, IOException { // Check if it's an AJAX request this.isAJAXRequest = (request.getParameter("ajax") != null && request.getParameter("ajax").equals("true")); // Allow Cross-Origin-Requests response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "1000"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); // URL pattern: /videoId // Get request parameter from URL and check if it has been set. // Show 400 if less or more parameters than allowed. String requestedVideo = request.getPathInfo(); if (requestedVideo == null || requestedVideo.split("/").length < 2 || requestedVideo.split("/")[1].equals("")) { this.sendError(response, HttpServletResponse.SC_BAD_REQUEST, "The video folder has to be specified for using this web service."); return;// ww w .jav a 2s .c o m } this.persistenceProvider = (IPersistenceProvider) getServletContext().getAttribute("PersistenceProvider"); this.mailService = (MailService) getServletContext().getAttribute("mailService"); this.brandingConfiguration = (BrandingConfiguration) getServletContext() .getAttribute("brandingConfiguration"); // Check if it's a watching request if (request.getPathInfo().endsWith("/watch.html")) { this.providePlayer(request, response); return; } // Check if it's a log request and perform logging if so if (request.getPathInfo().endsWith("/log") && requestType.equals("POST")) { this.doLogging(request, response); return; } // Check if it's a checkSession request and provide session status if so if (requestedVideo.endsWith("/getStats.js")) { this.getStats(request, response); return; } // Check if user requests user secret and perform login if (request.getPathInfo().endsWith("/getSecret.js") && requestType.equals("POST")) { this.provideUserSecret(request, response, requestType); return; } // Check if current session exists and if it is allowed to access this // video, stop further execution, if so. boolean result = handleAccess(request, response, requestType); if (!result) { return; } // Check if it's collaboration request and provide data if (request.getPathInfo().endsWith("/getCollaboration.js")) { this.provideCollaboration(request, response); return; } // Check if it's a thread creation request if (request.getPathInfo().endsWith("/createCollaborationThread.js")) { this.createCollaborationThread(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/createCollaborationPost.js")) { this.createCollaborationPost(request, response); return; } // Check if it's a post activation request if (request.getPathInfo().endsWith("/activateCollaborationPost.js")) { this.activateCollaborationPost(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/deleteCollaborationThread.js")) { this.deleteCollaborationThread(request, response); return; } // Check if it's a post creation request if (request.getPathInfo().endsWith("/deleteCollaborationPost.js")) { this.deleteCollaborationPost(request, response); return; } // Check if it's a checkSession request and provide session status if so if (requestedVideo.endsWith("/checkSession.js")) { this.provideSessionStatus(request, response); return; } // Decode the file name from the URL and check if file actually exists // in // file system, send 404 if not File file = new File(videoPath, URLDecoder.decode(requestedVideo, "UTF-8")); if (!file.exists()) { this.sendError(response, HttpServletResponse.SC_NOT_FOUND, "File not found"); return; } // Create log entry for file request this.logFileRequest(requestedVideo); // Check if configuration is requested and do needed preparing and // stop standard file preparation if (file.getName().equals("export.js")) { this.provideConfigFile(request, response, file); return; } // Prepare some variables. The ETag is an unique identifier of the file. String fileName = file.getName(); long length = file.length(); long lastModified = file.lastModified(); String eTag = fileName + "_" + length + "_" + lastModified; long expires = System.currentTimeMillis() + DEFAULT_EXPIRE_TIME; // Validate request headers for caching // --------------------------------------------------- // If-None-Match header should contain "*" or ETag. If so, then return // 304. String ifNoneMatch = request.getHeader("If-None-Match"); if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", eTag); // Required in 304. response.setDateHeader("Expires", expires); // Postpone cache with 1 // week. return; } // If-Modified-Since header should be greater than LastModified. If so, // then return 304. // This header is ignored if any If-None-Match header is specified. long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (ifNoneMatch == null && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModified) { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("ETag", eTag); // Required in 304. response.setDateHeader("Expires", expires); // Postpone cache with 1 // week. return; } // Validate request headers for resume // ---------------------------------------------------- // If-Match header should contain "*" or ETag. If not, then return 412. String ifMatch = request.getHeader("If-Match"); if (ifMatch != null && !matches(ifMatch, eTag)) { response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return; } // If-Unmodified-Since header should be greater than LastModified. If // not, then return 412. long ifUnmodifiedSince = request.getDateHeader("If-Unmodified-Since"); if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModified) { response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return; } // Validate and process range // ------------------------------------------------------------- // Prepare some variables. The full Range represents the complete file. Range full = new Range(0, length - 1, length); List<Range> ranges = new ArrayList<Range>(); // Validate and process Range and If-Range headers. String range = request.getHeader("Range"); if (range != null) { // Range header should match format "bytes=n-n,n-n,n-n...". If not, // then return 416. if (!range.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) { response.setHeader("Content-Range", "bytes */" + length); // Required // in // 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } // If-Range header should either match ETag or be greater then // LastModified. If not, // then return full file. String ifRange = request.getHeader("If-Range"); if (ifRange != null && !ifRange.equals(eTag)) { try { long ifRangeTime = request.getDateHeader("If-Range"); // Throws // IAE // if // invalid. if (ifRangeTime != -1 && ifRangeTime + 1000 < lastModified) { ranges.add(full); } } catch (IllegalArgumentException ignore) { ranges.add(full); } } // If any valid If-Range header, then process each part of byte // range. if (ranges.isEmpty()) { for (String part : range.substring(6).split(",")) { // Assuming a file with length of 100, the following // examples returns bytes at: // 50-80 (50 to 80), 40- (40 to length=100), -20 // (length-20=80 to length=100). long start = sublong(part, 0, part.indexOf("-")); long end = sublong(part, part.indexOf("-") + 1, part.length()); if (start == -1) { start = length - end; end = length - 1; } else if (end == -1 || end > length - 1) { end = length - 1; } // Check if Range is syntactically valid. If not, then // return 416. if (start > end) { response.setHeader("Content-Range", "bytes */" + length); // Required // in // 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return; } // Add range. ranges.add(new Range(start, end, length)); } } } // Prepare and initialize response // -------------------------------------------------------- // Get content type by file name and set default GZIP support and // content disposition. String contentType = getServletContext().getMimeType(fileName); boolean acceptsGzip = false; String disposition = "inline"; // If content type is unknown, then set the default value. // For all content types, see: // http://www.w3schools.com/media/media_mimeref.asp // To add new content types, add new mime-mapping entry in web.xml. if (contentType == null) { contentType = "application/octet-stream"; } // If content type is text, then determine whether GZIP content encoding // is supported by // the browser and expand content type with the one and right character // encoding. if (contentType.startsWith("text")) { String acceptEncoding = request.getHeader("Accept-Encoding"); acceptsGzip = acceptEncoding != null && accepts(acceptEncoding, "gzip"); contentType += ";charset=UTF-8"; } // Else, expect for images, determine content disposition. If content // type is supported by // the browser, then set to inline, else attachment which will pop a // 'save as' dialogue. else if (!contentType.startsWith("image")) { String accept = request.getHeader("Accept"); disposition = accept != null && accepts(accept, contentType) ? "inline" : "attachment"; } // Initialize response. response.reset(); response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setHeader("Content-Disposition", disposition + ";filename=\"" + fileName + "\""); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("ETag", eTag); response.setDateHeader("Last-Modified", lastModified); response.setDateHeader("Expires", expires); // Send requested file (part(s)) to client // ------------------------------------------------ // Prepare streams. RandomAccessFile input = null; OutputStream output = null; try { // Open streams. input = new RandomAccessFile(file, "r"); output = response.getOutputStream(); if (ranges.isEmpty() || ranges.get(0) == full) { // Return full file. Range r = full; response.setContentType(contentType); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total); if (requestType.equals("GET")) { if (acceptsGzip) { // The browser accepts GZIP, so GZIP the content. response.setHeader("Content-Encoding", "gzip"); output = new GZIPOutputStream(output, DEFAULT_BUFFER_SIZE); } else { // Content length is not directly predictable in case of // GZIP. // So only add it if there is no means of GZIP, else // browser will hang. response.setHeader("Content-Length", String.valueOf(r.length)); } // Copy full range. copy(input, output, r.start, r.length); } } else if (ranges.size() == 1) { // Return single part of file. Range r = ranges.get(0); response.setContentType(contentType); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total); response.setHeader("Content-Length", String.valueOf(r.length)); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. if (requestType.equals("GET")) { // Copy single part range. copy(input, output, r.start, r.length); } } else { // Return multiple parts of file. response.setContentType("multipart/byteranges; boundary=" + MULTIPART_BOUNDARY); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206. if (requestType.equals("GET")) { // Cast back to ServletOutputStream to get the easy println // methods. ServletOutputStream sos = (ServletOutputStream) output; // Copy multi part range. for (Range r : ranges) { // Add multipart boundary and header fields for every // range. sos.println(); sos.println("--" + MULTIPART_BOUNDARY); sos.println("Content-Type: " + contentType); sos.println("Content-Range: bytes " + r.start + "-" + r.end + "/" + r.total); // Copy single part range of multi part range. copy(input, output, r.start, r.length); } // End with multipart boundary. sos.println(); sos.println("--" + MULTIPART_BOUNDARY + "--"); } } } finally { // Gently close streams. close(output); close(input); } }
From source file:org.wyona.yanel.servlet.YanelServlet.java
/** * Get global data located below reserved prefix *///from w w w .j a va 2s.c o m private void getGlobalData(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Resource resource = getResource(request, response); String path = resource.getPath(); java.util.Map<String, String> properties = new HashMap<String, String>(); final String pathPrefix = "/" + reservedPrefix + "/"; final String ABOUT_PAGE_PATH = pathPrefix + "about.html"; // About Yanel final String ABOUT_REALM_PAGE_PATH = pathPrefix + "about-realm.html"; // About realm final String RESOURCE_TYPES_PATH_PREFIX = pathPrefix + "resource-types/"; //XXX REFACTORME: in the cases where we simply use a resource-type's view // we should implement org.wyona.yanel.core.api.ResourceTypeMatcherV1 ( cf. http://lists.wyona.org/pipermail/yanel-development/2009-June/003749.html ) Realm realm; Environment environment = getEnvironment(request, response); ResourceConfiguration rc; YanelGlobalResourceTypeMatcher RTmatcher = new YanelGlobalResourceTypeMatcher(pathPrefix, servletContextRealPath); try { realm = getRealm(request); rc = RTmatcher.getResourceConfiguration(environment, realm, path); } catch (Exception e) { throw new ServletException(e.getMessage(), e); } if (rc != null) { if (generateResponseFromRTview(request, response, -1, rc, path)) { return; } response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_FOUND); return; } else if (path.equals(ABOUT_PAGE_PATH)) { //XXX REFACTORME: we should define an "about" resource-type instead! response.setStatus(javax.servlet.http.HttpServletResponse.SC_OK); response.setHeader("Content-Type", "text/html"); PrintWriter w = response.getWriter(); w.print(About.toHTML(yanelInstance.getVersion(), yanelInstance.getRevision(), yanelInstance.getTargetEnvironment())); return; } else if (path.equals(ABOUT_REALM_PAGE_PATH)) { //XXX REFACTORME: we should define an "about-realm" resource-type instead! response.setStatus(javax.servlet.http.HttpServletResponse.SC_OK); response.setHeader("Content-Type", "text/html"); PrintWriter w = response.getWriter(); w.print(AboutRealm.toHTML(realm)); return; } else if (path.startsWith(RESOURCE_TYPES_PATH_PREFIX)) { final String[] namespaceURI_and_rest = path.substring(RESOURCE_TYPES_PATH_PREFIX.length()).split("::", 2); final String namespaceURI = namespaceURI_and_rest[0]; final String[] name_and_rest = namespaceURI_and_rest[1].split("/", 2); final String name = name_and_rest[0]; // INFO: Decode URL, e.g. /yanel/resource-types/^http:^2f^2fwww.wyona.org^2fyanel^2fresource^2f1.0::user-admin/dummy.css final String decoded_namespaceURI = HttpServletRequestHelper.decodeURIinURLpath('^', namespaceURI); log.debug("decoded_namespaceURI: " + decoded_namespaceURI); if (log.isDebugEnabled()) log.debug("decoded_namespaceURI: " + decoded_namespaceURI); // The request (see resource.getPath()) seems to replace 'http://' or 'http%3a%2f%2f' by 'http:/', so let's change this back final String namespace = !decoded_namespaceURI.equals(namespaceURI) ? decoded_namespaceURI : namespaceURI.replaceAll("http:/", "http://"); rc = new ResourceConfiguration(name, namespace, properties); try { Resource resourceOfPrefix = yanelInstance.getResourceManager().getResource(environment, realm, path, rc); String htdocsPath; if (name_and_rest[1].startsWith(reservedPrefix + "/")) { htdocsPath = "rtyanelhtdocs:" + name_and_rest[1].substring(reservedPrefix.length()).replace('/', File.separatorChar); } else { htdocsPath = "rthtdocs:" + File.separatorChar + name_and_rest[1].replace('/', File.separatorChar); } SourceResolver resolver = new SourceResolver(resourceOfPrefix); Source source = resolver.resolve(htdocsPath, null); long sourceLastModified = -1; // INFO: Compare If-Modified-Since with lastModified and return 304 without content resp. check on ETag if (source instanceof YanelStreamSource) { sourceLastModified = ((YanelStreamSource) source).getLastModified(); long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (log.isDebugEnabled()) log.debug("sourceLastModified <= ifModifiedSince: " + sourceLastModified + " <= " + ifModifiedSince); if (ifModifiedSince != -1) { if (sourceLastModified <= ifModifiedSince) { response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED); return; } } } InputStream htdocIn = ((StreamSource) source).getInputStream(); if (htdocIn != null) { log.debug("Resource-Type specific data: " + htdocsPath); // TODO: Set more HTTP headers (size, etc.) String mimeType = guessMimeType(FilenameUtils.getExtension(FilenameUtils.getName(htdocsPath))); if (sourceLastModified >= 0) response.setDateHeader("Last-Modified", sourceLastModified); response.setHeader("Content-Type", mimeType); // INFO: Tell the client for how long it should cache the data which will be sent by the response if (cacheExpires != 0) { setExpiresHeader(response, cacheExpires); } byte buffer[] = new byte[8192]; int bytesRead; OutputStream out = response.getOutputStream(); while ((bytesRead = htdocIn.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } htdocIn.close(); return; } else { log.error("No such file or directory: " + htdocsPath); response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_FOUND); return; } } catch (Exception e) { throw new ServletException(e.getMessage(), e); } } else { File globalFile = org.wyona.commons.io.FileUtil.file(servletContextRealPath, "htdocs" + File.separator + path.substring(pathPrefix.length())); if (globalFile.exists()) { //log.debug("Get global file: " + globalFile); // INFO: Compare If-Modified-Since with lastModified and return 304 without content resp. check on ETag long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (ifModifiedSince != -1) { //log.debug("Last modified '" + globalFile.lastModified() + "' versus If-Modified-Since '" + ifModifiedSince + "'."); if (globalFile.lastModified() <= ifModifiedSince) { response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED); return; } } // TODO: Set more HTTP headers (size, etc.) String mimeType = guessMimeType(FilenameUtils.getExtension(globalFile.getName())); response.setHeader("Content-Type", mimeType); response.setDateHeader("Last-Modified", globalFile.lastModified()); // INFO: Tell the client for how long it should cache the data which will be sent by the response if (cacheExpires != 0) { //log.debug("Client should consider the content of '" + globalFile + "' as stale in '" + cacheExpires + "' hours from now on ..."); setExpiresHeader(response, cacheExpires); } else { //log.debug("No cache expires set."); } byte buffer[] = new byte[8192]; int bytesRead; InputStream in = new java.io.FileInputStream(globalFile); OutputStream out = response.getOutputStream(); while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } in.close(); return; } else { log.error("No such file or directory: " + globalFile); response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_FOUND); return; } } }
From source file:info.magnolia.cms.filters.RangeSupportFilter.java
private HttpServletResponse wrapResponse(final HttpServletRequest request, final HttpServletResponse response) { return new HttpServletResponseWrapper(response) { /** default length is max. We hope that the underlying code will set proper content length as a header before we proceed serving some bytes. */ private int length = Integer.MAX_VALUE; private final Map<String, Object> headers = new HashMap<String, Object>(); private String eTag; private List<RangeInfo> ranges; private RangeInfo full; private ServletOutputStream stream; private PrintWriter writer; @Override//ww w .j a va2s .c om public void addDateHeader(String name, long date) { super.addDateHeader(name, date); this.headers.put(name, date); if ("Last-Modified".equalsIgnoreCase(name)) { lastModTime = date; } } @Override public void setDateHeader(String name, long date) { super.setDateHeader(name, date); this.headers.put(name, date); if ("Last-Modified".equalsIgnoreCase(name)) { lastModTime = date; } } @Override public void addHeader(String name, String value) { if ("Content-Disposition".equalsIgnoreCase(name) && log.isDebugEnabled()) { log.warn("content disposition enforced by underlying filter/servlet"); } super.addHeader(name, value); this.headers.put(name, value); } @Override public void setHeader(String name, String value) { if ("Content-Disposition".equalsIgnoreCase(name) && log.isDebugEnabled()) { log.warn("content disposition enforced by underlying filter/servlet"); } super.setHeader(name, value); this.headers.put(name, value); } @Override public void addIntHeader(String name, int value) { super.addIntHeader(name, value); this.headers.put(name, value); } @Override public void setIntHeader(String name, int value) { super.setIntHeader(name, value); this.headers.put(name, value); } @Override public void setContentLength(int len) { this.length = len; // do not propagate length up. We might not be able to change it once it is set. We will set it ourselves once we are ready to serve bytes. } @Override public ServletOutputStream getOutputStream() throws IOException { // make sure we set stream only once. Multiple calls to this method are allowed. if (this.stream == null) { ServletOutputStream stream = super.getOutputStream(); // wrap the response to filter out everything except desired range this.stream = addRangeSupportWrapper(request, response, stream); if (!isServeContent || this.stream == null) { // swallow output on head requests this.stream = new ServletOutputStream() { @Override public void write(int b) throws IOException { // do nothing, we do not write any output now } }; } } return stream; } private ServletOutputStream addRangeSupportWrapper(final HttpServletRequest request, final HttpServletResponse response, ServletOutputStream stream) throws IOException { if (!processContent(request, response)) { // we might have to return null stream instead as the previous method already called res.sendError(); return null; } if (headers.containsKey("Content-Range")) { // doesn't work for tomcat as it accesses underlying stream under our hands!!! log.debug("Range request was handled by underlying filter/servlet."); return stream; } if (ranges == null || ranges.isEmpty()) { // no op, serve all as usual log.debug("Didn't find any range to speak of. Serving all content as usual."); if (length != Integer.MAX_VALUE) { // set real length when we know it response.setContentLength(length); } } else if (ranges.size() == 1) { RangeInfo range = ranges.get(0); log.debug("Serving range [{}].", range); // setting 206 header is essential for some clients. The would abort if response is set to 200 response.setStatus(SC_PARTIAL_CONTENT); stream = new RangedOutputStream(stream, range); } else { log.error("Requested multiple ranges [{}].", ranges.size()); // TODO: add support for multiple ranges (sent as multipart request), for now just send error back response.setHeader("Content-Range", "bytes */" + length); response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); // again we might have to return null stream after calling sendError() as the original stream might no longer be valid } return stream; } @Override public PrintWriter getWriter() throws IOException { if (!wrapWriter) { return super.getWriter(); } if (this.writer == null) { this.writer = new PrintWriter(new OutputStreamWriter(getOutputStream())); } return writer; } private boolean processContent(HttpServletRequest request, HttpServletResponse response) throws IOException { log.debug("Serving binary on uri {} was last modified at {}", new Object[] { request.getRequestURI(), lastModTime }); if (!isRequestValid(request, response)) { log.debug("Skipping request {} since it doesn't require body", new Object[] { request.getRequestURI() }); return false; } if (!processRange(request)) { log.debug("Could not process range of request {}", new Object[] { request.getRequestURI() }); return false; } return true; } private boolean processRange(HttpServletRequest request) throws IOException { full = new RangeInfo(0, length - 1, length); ranges = new ArrayList<RangeInfo>(); String range = request.getHeader("Range"); // Valid range header format is "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); response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return false; } // If-Range header must 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"); if (ifRangeTime != -1 && ifRangeTime + 1000 < lastModTime) { ranges.add(full); } } catch (IllegalArgumentException ignore) { // happens when if-range contains something else then date ranges.add(full); } } // in case there were no invalid If-Range headers, then look at requested byte ranges. if (ranges.isEmpty()) { for (String part : range.substring(6).split(",")) { int start = intSubstring(StringUtils.substringBefore(part, "-")); int end = intSubstring(StringUtils.substringAfter(part, "-")); if (start == -1) { start = length - end; end = length - 1; } else if (end == -1 || end > length - 1) { end = length - 1; } // Is range valid? if (start > end) { response.setHeader("Content-Range", "bytes */" + length); // Required in 416. response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); return false; } // Add range. ranges.add(new RangeInfo(start, end, length)); } } response.setHeader("ETag", eTag); if (ranges.size() == 1) { RangeInfo r = ranges.get(0); response.setHeader("Accept-Ranges", "bytes"); response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.totalLengthOfServedBinary); length = r.lengthOfRange; } return true; } private int intSubstring(String value) { return value.length() > 0 ? Integer.parseInt(value) : -1; } @Override public void flushBuffer() throws IOException { if (writer != null) { writer.flush(); } if (stream != null) { stream.flush(); } super.flushBuffer(); } private boolean isRequestValid(HttpServletRequest request, HttpServletResponse response) throws IOException { String fileName = StringUtils.substringAfterLast(request.getRequestURI(), "/"); eTag = fileName + "_" + length + "_" + lastModTime; // If-None-Match header should contain "*" or ETag. String ifNoneMatch = request.getHeader("If-None-Match"); if (ifNoneMatch != null && matches(ifNoneMatch, eTag)) { response.setHeader("ETag", eTag); // Required in 304. log.debug("Returning {} on header If-None-Match", HttpServletResponse.SC_NOT_MODIFIED); response.sendError(HttpServletResponse.SC_NOT_MODIFIED); return false; } // If-Modified-Since header must be greater than LastModified. ignore if If-None-Match header exists long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (ifNoneMatch == null && ifModifiedSince != -1 && ifModifiedSince + 1000 > lastModTime) { response.setHeader("ETag", eTag); // Required in 304. // 304 response should contain Date header unless running on timeless server (see 304 response docu) response.addDateHeader("Date", lastModTime); log.debug("Returning {} on header If-Modified-Since", HttpServletResponse.SC_NOT_MODIFIED); response.sendError(HttpServletResponse.SC_NOT_MODIFIED); return false; } // If-Match header should contain "*" or ETag. String ifMatch = request.getHeader("If-Match"); if (ifMatch != null && !matches(ifMatch, eTag)) { log.debug("Returning {} on header If-Match", HttpServletResponse.SC_PRECONDITION_FAILED); response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return false; } // If-Unmodified-Since header must be greater than LastModified. long ifUnmodifiedSince = request.getDateHeader("If-Unmodified-Since"); if (ifUnmodifiedSince != -1 && ifUnmodifiedSince + 1000 <= lastModTime) { log.debug("Returning {} on header If-Unmodified-Since", HttpServletResponse.SC_PRECONDITION_FAILED); response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); return false; } log.debug("Passed all precondition checkes for request {}", request.getRequestURI()); return true; } }; }
From source file:org.jahia.bin.Render.java
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception { if (isDisabled()) { resp.sendError(HttpServletResponse.SC_NOT_FOUND); return null; }/*from w w w .j a va 2 s . c o m*/ String method = req.getMethod(); if (req.getParameter(METHOD_TO_CALL) != null) { method = req.getParameter(METHOD_TO_CALL).toUpperCase(); } if (!isMethodAllowed(method)) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); return null; } long startTime = System.currentTimeMillis(); String sessionId = null; try { final HttpSession session = req.getSession(); if (logger.isInfoEnabled()) { sessionId = session.getId(); } URLResolver urlResolver = urlResolverFactory.createURLResolver(req.getPathInfo(), req.getServerName(), workspace, req); req.setAttribute("urlResolver", urlResolver); session.setAttribute("workspace", urlResolver.getWorkspace()); if (sessionExpiryTime != null && session.getMaxInactiveInterval() != sessionExpiryTime * 60) { session.setMaxInactiveInterval(sessionExpiryTime * 60); } RenderContext renderContext = createRenderContext(req, resp, jcrSessionFactory.getCurrentUser()); renderContext.setWorkspace(urlResolver.getWorkspace()); urlResolver.setRenderContext(renderContext); req.getSession().setAttribute(Constants.SESSION_LOCALE, urlResolver.getLocale()); jcrSessionFactory.setCurrentLocale(urlResolver.getLocale()); if (renderContext.isPreviewMode() && req.getParameter(ALIAS_USER) != null && !JahiaUserManagerService.isGuest(jcrSessionFactory.getCurrentUser())) { JahiaUserManagerService userManagerService = ServicesRegistry.getInstance() .getJahiaUserManagerService(); JCRUserNode userNode = userManagerService.lookupUser(req.getParameter(ALIAS_USER), urlResolver.getSiteKey()); if (userNode != null) { jcrSessionFactory.setCurrentAliasedUser(userNode.getJahiaUser()); } } // check permission try { if (!hasAccess(urlResolver.getNode())) { if (JahiaUserManagerService.isGuest(jcrSessionFactory.getCurrentUser())) { throw new JahiaUnauthorizedException(); } else { throw new JahiaForbiddenAccessException(); } } } catch (PathNotFoundException e) { } renderContext.setSiteInfo(urlResolver.getSiteInfo()); if (renderContext.isPreviewMode() && req.getParameter(PREVIEW_DATE) != null && !JahiaUserManagerService.isGuest(jcrSessionFactory.getCurrentUser())) { Calendar previewDate = Calendar.getInstance(); previewDate.setTime(new Date(new Long(req.getParameter(PREVIEW_DATE)))); jcrSessionFactory.setCurrentPreviewDate(previewDate); } if (method.equals(METHOD_GET)) { Resource resource; resource = urlResolver.getResource(); if (!StringUtils.isEmpty(urlResolver.getRedirectUrl()) && (StringUtils.isEmpty(resource.getTemplate()) || StringUtils.equals(resource.getTemplate(), "default"))) { Map<String, List<String>> parameters = new HashMap<String, List<String>>(); parameters.put(NEW_NODE_OUTPUT_FORMAT, LIST_WITH_EMPTY_STRING); parameters.put(REDIRECT_HTTP_RESPONSE_CODE, REDIRECT_CODE_MOVED_PERMANENTLY); performRedirect(urlResolver.getRedirectUrl(), StringUtils.isEmpty(urlResolver.getVanityUrl()) ? "/" + urlResolver.getLocale().toString() + urlResolver.getPath() : urlResolver.getVanityUrl(), req, resp, parameters, false); } else { renderContext.setMainResource(resource); if (renderContext.getSite() == null) { // If Site has not been resolved by the servlet (so far only dashboard mode is doing that JCRSiteNode site = resource.getNode().getResolveSite(); if (!Url.isLocalhost(req.getServerName()) && !renderContext.isEditMode()) { JCRSessionWrapper session1 = resource.getNode().getSession(); if (urlResolver.getSiteKey() != null && (site == null || !site.getSiteKey().equals(urlResolver.getSiteKey()))) { site = (JCRSiteNode) session1.getNode("/sites/" + urlResolver.getSiteKey()); } else if (renderContext.isLiveMode() && urlResolver.getSiteKeyByServerName() != null && (site == null || !site.getSiteKey().equals(urlResolver.getSiteKeyByServerName()))) { site = (JCRSiteNode) session1 .getNode("/sites/" + urlResolver.getSiteKeyByServerName()); } } String jsite = null; HttpServletRequest request = renderContext.getRequest(); if (request != null) { jsite = request.getParameter("jsite"); } if (jsite == null && renderContext.getMainResource() != null) { jsite = (String) renderContext.getMainResource().getModuleParams().get("jsite"); } if (jsite != null) { try { site = (JCRSiteNode) resource.getNode().getSession().getNodeByIdentifier(jsite); } catch (ItemNotFoundException e) { if (JahiaUserManagerService.isGuest(jcrSessionFactory.getCurrentUser())) { throw new JahiaUnauthorizedException(); } else { throw new JahiaForbiddenAccessException(); } } } if (resource.getNode().getPath().startsWith("/sites/") && (site == null || (!site.getPath() .startsWith("/modules/") && !site.isAllowsUnlistedLanguages() && !(renderContext.isLiveMode() ? site.getActiveLiveLanguagesAsLocales().contains(urlResolver.getLocale()) : site.getLanguagesAsLocales().contains(urlResolver.getLocale()))))) { throw new PathNotFoundException("This language does not exist on this site"); } renderContext.setSite(site); } // resource.pushWrapper("wrapper.fullpage"); if (urlResolver.getPath().endsWith(".do")) { Action action = templateService.getActions().get(resource.getResolvedTemplate()); Map<String, List<String>> parameters = toParameterMapOfListOfString(req); if (action != null) { doAction(req, resp, urlResolver, renderContext, resource, action, parameters); } else { logger.error("Action {} does not exist", resource.getResolvedTemplate()); throw new PathNotFoundException("Action does not exist"); } } else { long lastModified = getLastModified(resource, renderContext); if (lastModified == -1) { // servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp, renderContext, resource, startTime); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < (lastModified / 1000 * 1000)) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp, renderContext, resource, startTime); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } } } else if (method.equals(METHOD_HEAD)) { doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp, renderContext, urlResolver); } else if (method.equals(METHOD_PUT)) { doPut(req, resp, renderContext, urlResolver); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp, renderContext, urlResolver); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req, resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req, resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } } catch (Exception e) { List<ErrorHandler> handlers = templateService.getErrorHandler(); for (ErrorHandler handler : handlers) { if (handler.handle(e, req, resp)) { return null; } } DefaultErrorHandler.getInstance().handle(e, req, resp); } finally { if (logger.isInfoEnabled()) { StringBuilder sb = new StringBuilder(100); sb.append("Rendered [").append(req.getRequestURI()); if (jcrSessionFactory.getCurrentUser() != null) { sb.append("] user=[").append(jcrSessionFactory.getCurrentUser().getUsername()); } sb.append("] ip=[").append(req.getRemoteAddr()).append("] sessionID=[").append(sessionId) .append("] in [").append(System.currentTimeMillis() - startTime).append("ms]"); logger.info(sb.toString()); } } return null; }
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.java2 s . c om */ 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.wyona.yanel.servlet.YanelServlet.java
/** * Generate response from a resource view, whereas it will be checked first if the resource already wrote the response (if so, then just return) * * @param view View of resource// ww w . ja v a2s.c o m * @param res Resource which handles the request in order to generate a response * @param request TODO * @param response TODO * @param statusCode HTTP response status code (because one is not able to get status code from response) * @param doc TODO * @param size TODO * @param lastModified TODO * @param trackInfo Tracking information bean which might be updated by resource if resource is implementing trackable * * @return response to the client / browser */ private HttpServletResponse generateResponse(View view, Resource res, HttpServletRequest request, HttpServletResponse response, int statusCode, Document doc, long size, long lastModified, TrackingInformationV1 trackInfo) throws ServletException, IOException { //log.debug("Generate response: " + res.getPath()); // TODO: It seems like no header fields are being set (e.g. Content-Length, ...). Please see below ... // INFO: Check if viewable resource has already created a response if (!view.isResponse()) { if (logAccessIsApplicable(view.getMimeType(), res)) { //log.debug("Mime type '" + view.getMimeType() + "' of request: " + request.getServletPath() + "?" + request.getQueryString()); doLogAccess(request, response, statusCode, res, trackInfo); } log.debug("It seems that resource '" + res.getPath() + "' has directly created the response."); try { if ("true".equals(res.getResourceConfigProperty("yanel:no-cache"))) { log.debug("Set no-cache headers..."); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1. response.setHeader("Pragma", "no-cache"); // HTTP 1.0. response.setDateHeader("Expires", 0); // Proxies. } } catch (Exception e) { log.error(e, e); } return response; } // INFO: Set mime type and encoding String mimeType = view.getMimeType(); if (view.getEncoding() != null) { mimeType = patchMimeType(mimeType, request); response.setContentType(mimeType + "; charset=" + view.getEncoding()); } else if (res.getConfiguration() != null && res.getConfiguration().getEncoding() != null) { mimeType = patchMimeType(mimeType, request); response.setContentType(mimeType + "; charset=" + res.getConfiguration().getEncoding()); } else { // try to guess if we have to set the default encoding if (mimeType != null && mimeType.startsWith("text") || mimeType.equals("application/xml") || mimeType.equals("application/xhtml+xml") || mimeType.equals("application/atom+xml") || mimeType.equals("application/x-javascript")) { mimeType = patchMimeType(mimeType, request); response.setContentType(mimeType + "; charset=" + DEFAULT_ENCODING); } else { // probably binary mime-type, don't set encoding mimeType = patchMimeType(mimeType, request); response.setContentType(mimeType); } } if (logAccessIsApplicable(mimeType, res)) { //log.debug("Mime type '" + mimeType + "' of request: " + request.getServletPath() + "?" + request.getQueryString()); doLogAccess(request, response, statusCode, res, trackInfo); } // INFO: Set HTTP headers HashMap<?, ?> headers = view.getHttpHeaders(); Iterator<?> iter = headers.keySet().iterator(); while (iter.hasNext()) { String name = (String) iter.next(); String value = (String) headers.get(name); if (log.isDebugEnabled()) { log.debug("set http header: " + name + ": " + value); } response.setHeader(name, value); } try { if ("true".equals(res.getResourceConfigProperty("yanel:no-cache"))) { log.debug("Set no-cache headers..."); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1. response.setHeader("Pragma", "no-cache"); // HTTP 1.0. response.setDateHeader("Expires", 0); // Proxies. } } catch (Exception e) { log.error(e, e); } // INFO: Confirm DNT (do not track) String dntValue = request.getHeader("DNT"); if (dntValue != null) { response.setHeader("DNT", dntValue); // INFO: See spec about response header at http://tools.ietf.org/html/draft-mayer-do-not-track-00 } else { //log.debug("No DNT (do not track) header set, hence do not echo."); } // Possibly embed toolbar: // TODO: Check if user is authorized to actually see toolbar (Current flaw: Enabled Toolbar, Login, Toolbar is enabled, Logout, Toolbar is still visible!) if (yanelUI.isToolbarEnabled(request)) { // TODO: Check whether resource configuration has toolbar configured as suppressed: if ("suppress".equals(res.getResConfiguration("yanel.toolbar"))) { if (mimeType != null && mimeType.indexOf("html") > 0) { // TODO: What about other query strings or frames or TinyMCE (e.g. link.htm)? if (request.getParameter(YANEL_RESOURCE_USECASE) == null) { // INFO: In the case of a yanel resource usecase do NOT add the toolbar if (toolbarMasterSwitch.equals("on")) { OutputStream os = response.getOutputStream(); try { Usecase usecase = new Usecase(TOOLBAR_USECASE); Realm realm = map.getRealm(request.getServletPath()); Identity identity = getIdentityFromRequest(request, realm); String path = map.getPath(realm, request.getServletPath()); // NOTE: This extra authorization check is necessary within a multi-realm environment, because after activating the toolbar with a query string, the toolbar flag attached to the session will be ignored by doAccessControl(). One could possibly do this check within doAccessControl(), but could be a peformance issue! Or as an alternative one could refactor the code, such that the toolbar session flag is realm aware. if (realm.getPolicyManager().authorize(path, identity, usecase)) { yanelUI.mergeToolbarWithContent(request, response, res, view); return response; } else { log.warn("Toolbar authorization denied (Realm: '" + realm.getName() + "', User: '" + identity.getUsername() + "', Path: '" + path + "')!"); } } catch (Exception e) { String message = "Error merging toolbar into content: " + e.getMessage(); //log.error(message, e); log.error(e, e); Element exceptionElement = (Element) doc.getDocumentElement() .appendChild(doc.createElementNS(NAMESPACE, EXCEPTION_TAG_NAME)); exceptionElement.appendChild(doc.createTextNode(message)); response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR); setYanelOutput(request, response, doc); return response; } } else { log.info("Toolbar has been disabled. Please check web.xml!"); } } else { log.warn("Yanel resource usecase is not null, but set to '" + request.getParameter(YANEL_RESOURCE_USECASE) + "' and hence Yanel toolbar is suppressed/omitted in order to avoid that users are leaving the usecase because they might click on some toolbar menu item."); } } else { log.info("No HTML related mime type: " + mimeType); } } else { log.debug("Toolbar is turned off."); } InputStream is = view.getInputStream(); if (is != null) { try { // Compare If-Modified-Since with lastModified and return 304 without content resp. check on ETag long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if (ifModifiedSince != -1) { //log.debug("Client set 'If-Modified-Since' ..."); if (res instanceof ModifiableV2) { long resourceLastMod = ((ModifiableV2) res).getLastModified(); //log.debug(resourceLastMod + " " + ifModifiedSince); if (resourceLastMod <= ifModifiedSince) { response.setStatus(javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED); return response; } } else { // TODO: Many resources do not implement ModifiableV2 and hence never return a lastModified and hence the browser will never ask for ifModifiedSince! //log.warn("Resource of path '" + res.getPath() + "' is not ModifiableV2 and hence cannot be cached!"); if (log.isDebugEnabled()) log.debug("Resource of path '" + res.getPath() + "' is not ModifiableV2 and hence cannot be cached!"); } } } catch (Exception e) { log.error(e.getMessage(), e); } if (lastModified >= 0) response.setDateHeader("Last-Modified", lastModified); if (size > 0) { if (log.isDebugEnabled()) log.debug("Size of " + request.getRequestURI() + ": " + size); response.setContentLength((int) size); } else { if (log.isDebugEnabled()) log.debug("No size for " + request.getRequestURI() + ": " + size); } try { // INFO: Check whether InputStream is empty and try to Write content into response byte buffer[] = new byte[8192]; int bytesRead; bytesRead = is.read(buffer); if (bytesRead != -1) { java.io.OutputStream os = response.getOutputStream(); os.write(buffer, 0, bytesRead); while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); } else { log.warn("Returned content size of request '" + request.getRequestURI() + "' is 0"); } } catch (Exception e) { log.error("Writing into response failed for request '" + request.getRequestURL() + "' (Client: " + getClientAddressOfUser(request) + ")"); // INFO: For example in the case of ClientAbortException log.error(e, e); throw new ServletException(e); } finally { //log.debug("Close InputStream in any case!"); is.close(); // INFO: Make sure to close InputStream, because otherwise we get bugged with open files } return response; } else { String message = "Returned InputStream of request '" + request.getRequestURI() + "' is null!"; Element exceptionElement = (Element) doc.getDocumentElement() .appendChild(doc.createElementNS(NAMESPACE, EXCEPTION_TAG_NAME)); exceptionElement.appendChild(doc.createTextNode(message)); response.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR); setYanelOutput(request, response, doc); is.close(); return response; } }
From source file:org.sakaiproject.content.impl.BaseContentService.java
/** * Process the access request for a resource. * /* w w w . j ava2 s. c om*/ * @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 = ""; }/*ww w. j av a2 s. co 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(); } } }; }