Example usage for javax.servlet.http HttpServletRequest getDateHeader

List of usage examples for javax.servlet.http HttpServletRequest getDateHeader

Introduction

In this page you can find the example usage for javax.servlet.http HttpServletRequest getDateHeader.

Prototype

public long getDateHeader(String name);

Source Link

Document

Returns the value of the specified request header as a long value that represents a Date object.

Usage

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();
            }
        }
    };
}