Package com.dotmarketing.servlets

Source Code of com.dotmarketing.servlets.SpeedyAssetServlet

package com.dotmarketing.servlets;

import static com.dotmarketing.business.PermissionAPI.PERMISSION_READ;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.dotmarketing.beans.Identifier;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.business.web.WebAPILocator;
import com.dotmarketing.cache.LiveCache;
import com.dotmarketing.cache.WorkingCache;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.fileassets.business.IFileAsset;
import com.dotmarketing.util.Config;
import com.dotmarketing.util.Constants;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotcms.repackage.com.google.common.io.Files;
import com.dotcms.util.DownloadUtil;
import com.dotcms.util.DownloadUtil.ThreadLocalHTTPDate;
import com.liferay.portal.PortalException;
import com.liferay.portal.SystemException;
import com.liferay.portal.model.User;
import com.liferay.util.FileUtil;

public class SpeedyAssetServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;
  private static String realPath = null;
  private static String assetPath = "/assets";
 
  private static PermissionAPI permissionAPI = APILocator.getPermissionAPI();

    public void init(ServletConfig config) throws ServletException {
        // Set the asset paths
        try {
            realPath = Config.getStringProperty("ASSET_REAL_PATH");
        } catch (Exception e) { }
        try {
            assetPath = Config.getStringProperty("ASSET_PATH");
        } catch (Exception e) { }
    }




    protected void service(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

    if (Config.CONTEXT == null) {
      Config.CONTEXT = this.getServletContext();
      Logger.error(this, "Config.CONTEXT is null. RESETTING  Cannot Serve Files without this!!!!!!");
    }



    File f;
    boolean PREVIEW_MODE = false;
    boolean EDIT_MODE = false;
    HttpSession session = request.getSession(false);
    boolean serveWorkingVersion = false;
    boolean isLoggedToBackend = false;

    if(session != null) {
      PREVIEW_MODE = ((session.getAttribute(com.dotmarketing.util.WebKeys.PREVIEW_MODE_SESSION) != null));
      try {
        EDIT_MODE = (((session.getAttribute(com.dotmarketing.util.WebKeys.EDIT_MODE_SESSION) != null)));
        isLoggedToBackend = WebAPILocator.getUserWebAPI().isLoggedToBackend(request);
      } catch (DotRuntimeException e) {
        Logger.error(this, "Error: Unable to determine if there's a logged user.", e);
      } catch (PortalException e) {
        Logger.error(this, "Error: Unable to determine if there's a logged user.", e);
      } catch (SystemException e) {
        Logger.error(this, "Error: Unable to determine if there's a logged user.", e);
      }

    }
    //GIT-4506
    if(isLoggedToBackend){
      if(!EDIT_MODE && !PREVIEW_MODE)// LIVE_MODE
        serveWorkingVersion = false;
      else
        serveWorkingVersion = true;
    }else{
      serveWorkingVersion = false;//Frontend
    }

        User user = null;
        try {
            if (session != null)
                user = (com.liferay.portal.model.User) session.getAttribute(com.dotmarketing.util.WebKeys.CMS_USER);
          if(user==null){
        user = WebAPILocator.getUserWebAPI().getLoggedInUser(request);
      }
        } catch (Exception nsue) {
            Logger.warn(this, "Exception trying to getUser: " + nsue.getMessage(), nsue);
        }

    String uri = "";
    try {

      String relativePath = null;
      if(request.getParameter("path") == null) {

        // Getting the identifier from the path like /dotAsset/{identifier}.{ext} E.G. /dotAsset/1234.js
        StringTokenizer _st = new StringTokenizer(request.getRequestURI(), "/");

        Logger.debug(this, "Requesting by url: " + request.getRequestURI());

        String _fileName = null;
        while(_st.hasMoreElements()){
          _fileName = _st.nextToken();
        }

        Logger.debug(this, "Parsed filename: " + _fileName);

        String identifier = UtilMethods.getFileName(_fileName);
        Identifier ident = null;
        Logger.debug(SpeedyAssetServlet.class, "Loading identifier: " + identifier);
        try{
          ident = APILocator.getIdentifierAPI().find(identifier);
        }catch(Exception ex){
          Logger.debug(SpeedyAssetServlet.class, "Identifier not found going to try as a File Asset", ex);
        }
        if(ident != null && ident.getURI() != null && !ident.getURI().equals("")){

          if(serveWorkingVersion){
            uri = WorkingCache.getPathFromCache(ident.getURI(), ident.getHostId());
            if(!UtilMethods.isSet(realPath)){
              f = new File(FileUtil.getRealPath(assetPath + uri));
            }else{
              f = new File(realPath + uri);
            }
            if(uri == null || !f.exists() || !f.canRead()) {
              if(uri == null){
                Logger.warn(SpeedyAssetServlet.class, "URI is null");
              }
              if( !f.exists()){
                Logger.warn(SpeedyAssetServlet.class, "f does not exist : Config.CONTEXT=" +Config.CONTEXT);
                Logger.warn(SpeedyAssetServlet.class, "f does not exist : " + f.getAbsolutePath());
              }
              if( !f.canRead()){
                Logger.warn(SpeedyAssetServlet.class, "f cannot be read : Config.CONTEXT=" +Config.CONTEXT);
                Logger.warn(SpeedyAssetServlet.class, "f cannot be read : " + f.getAbsolutePath());
              }
              response.sendError(404);
              return;
            }

          }else {
            try{
              uri = LiveCache.getPathFromCache(ident.getURI(), ident.getHostId());
            }catch (Exception e) {
              if(isLoggedToBackend){
                response.setHeader( "Pragma", "no-cache" );
                response.setHeader( "Cache-Control", "no-cache" );
                response.setDateHeader( "Expires", 0 );
                response.sendError(404);
                return;
              }
            }
            if(!UtilMethods.isSet(realPath)){
              f = new File(FileUtil.getRealPath(assetPath + uri));
            }else{
              f = new File(realPath + uri);
            }
            if(uri == null || !f.exists() || !f.canRead()) {
              if(uri == null){
                Logger.warn(SpeedyAssetServlet.class, "URI is null");
              }
              if( !f.exists()){
                Logger.warn(SpeedyAssetServlet.class, "f does not exist : Config.CONTEXT=" +Config.CONTEXT);
                Logger.warn(SpeedyAssetServlet.class, "f does not exist : " + f.getAbsolutePath());
              }
              if( !f.canRead()){
                Logger.warn(SpeedyAssetServlet.class, "f cannot be read  : Config.CONTEXT=" +Config.CONTEXT);
                Logger.warn(SpeedyAssetServlet.class, "f cannot be read : " + f.getAbsolutePath());
              }



              response.sendError(404);
              return;
            }
          }
        } else {
          Logger.warn(this, "Invalid identifier passed: url = " + request.getRequestURI());
          //Invalid identifier number passed
          response.sendError(404);
          return;
        }

      } else{
        relativePath = request.getParameter("path");
        f = new File(APILocator.getFileAPI().getRealAssetsRootPath() + relativePath);
        if(!f.exists() || !f.canRead()) {
          Logger.warn(this, "Invalid path passed: path = " + relativePath + ", file doesn't exists.");
          //Invalid path given
          response.sendError(404);
          return;
        }
      }

      if(f.getPath().endsWith(".groovy") || f.getPath().endsWith(".php") || f.getPath().endsWith(".rb"
          || f.getPath().endsWith(".vtl")|| f.getPath().endsWith(".vm")){
        Logger.warn(this, "SpeedyAsset servlet should not serve this types: .groovy, .php, .rb, .vtl and .vm  ");
        return;
       
      }

      String inode = null;

      IFileAsset file = null;
      Identifier identifier = null;
      boolean canRead = false;
      if(UtilMethods.isSet(relativePath) && relativePath.contains("fileAsset")){
        String[] splits = relativePath.split(Pattern.quote(File.separator));
        if(splits.length>0){
          inode = splits[3];
          Contentlet cont =  null;
          try{
            cont = APILocator.getContentletAPI().find(inode, user, true);
            file = APILocator.getFileAssetAPI().fromContentlet(cont);
            identifier = APILocator.getIdentifierAPI().find(cont);
            canRead = true;
          }catch(Exception e){ 
            Logger.warn(this, "Unable to find file asset contentlet with inode " + inode, e);
          }
        }
      }else if(UtilMethods.isSet(uri) && uri.contains("fileAsset")){
        String[] splits = uri.split(Pattern.quote(File.separator));
        if(splits.length>0){
          inode = splits[3];
          Contentlet cont =  null;
          try{
            cont = APILocator.getContentletAPI().find(inode, user, true);
            file = APILocator.getFileAssetAPI().fromContentlet(cont);
            identifier = APILocator.getIdentifierAPI().find(cont);
            canRead = true;
          }catch(Exception e){ 
            Logger.warn(this, "Unable to find file asset contentlet with inode " + inode, e);
          }
        }
      }else{
     
        inode = UtilMethods.getFileName(f.getName());
        file = APILocator.getFileAPI().find(inode, user, true);
        identifier = APILocator.getIdentifierAPI().find((com.dotmarketing.portlets.files.model.File)file);
        com.dotmarketing.portlets.files.model.File fProxy = new com.dotmarketing.portlets.files.model.File();
              fProxy.setIdentifier(identifier.getInode());
              canRead = permissionAPI.doesUserHavePermission(fProxy, PERMISSION_READ, user, true);
      }
//      Identifier identifier = APILocator.getIdentifierAPI().findFromInode(Long.parseLong(inode));
     

      String mimeType = APILocator.getFileAPI().getMimeType(f.getName());
      if (mimeType == null)
        mimeType = "application/octet-stream";

      response.setContentType(mimeType);

      //Checking permissions
          /**
           * Build a fake proxy file object so we
           * can get inheritable permissions on it
           * without having to hit cache or db
           */
           

            if (!canRead) {
              if(user == null){
                request.getSession(true).setAttribute(com.dotmarketing.util.WebKeys.REDIRECT_AFTER_LOGIN, request.getRequestURI());//DOTCMS-5682
                //Sending user to unauthorized the might send him to login
                response.sendError(401, "The requested file is unauthorized");
              }else{
                //sending the user to forbidden
                response.sendError(403, "The requested file is forbidden");
              }
               return;
            }
           
            response.setHeader("Content-Disposition","filename=\"" + file.getFileName() + "\"");

      /*
       * Setting the proper content headers
       */
      if(request.getParameter("dotcms_force_download") != null || request.getParameter("force_download") != null) {
        String url = request.getRequestURL().toString();
        String filename = url.substring(url.lastIndexOf("/") + 1, url.length());
        filename = file.getFileName();
        response.setHeader("Content-Type", "application/force-download");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
      } else {
        boolean _adminMode = false;
        try {
            _adminMode = (session!=null && session.getAttribute(com.dotmarketing.util.WebKeys.ADMIN_MODE_SESSION) != null);
        }catch(Exception e){

        }

          // Set the expiration time
        if (!_adminMode) {

            if(!DownloadUtil.isModifiedEtag(request, response, inode, f.lastModified(), f.length())) {
                return;
            }

                /* if we are in ADMIN MODE, don't cache */
        }else{
            GregorianCalendar expiration = new GregorianCalendar();
          expiration.add(java.util.Calendar.MONTH, -1);
          response.setHeader("Expires", DownloadUtil.httpDate.get().format(expiration.getTime()));
          response.setHeader("Cache-Control", "max-age=-1");
        }

      }


      ServletOutputStream out = null;
      FileChannel from = null;
      WritableByteChannel to = null;
      RandomAccessFile input = null;
      try {
        out = response.getOutputStream();
        from = new FileInputStream(f).getChannel();
        to = Channels.newChannel(out);
        //DOTCMS-5716
        //32 MB at a time 
        int maxTransferSize = (32 * 1024 * 1024) ;
        long size = from.size();
        long position = 0;
       
        boolean responseSent = false;
        byte[] data = Files.toByteArray(f);
              //ServletOutputStream sos = response.getOutputStream();
        //extract range header
        String rangeHeader = request.getHeader("range");
        if(UtilMethods.isSet(rangeHeader)){
           response.setHeader("Accept-Ranges", "bytes");
          // Range header should match format "bytes=n-n,n-n,n-n...". If not, then return 416.
          if (!rangeHeader.matches("^bytes=\\d*-\\d*(,\\d*-\\d*)*$")) {
            response.setHeader("Content-Range", "bytes */" + data.length); // Required in 416.
            response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
            return;
          }
          //parse multiple range bytes
          ArrayList<SpeedyAssetServletUtil.ByteRange> ranges = SpeedyAssetServletUtil.parseRange(rangeHeader, data.length);
          if (ranges != null){
            SpeedyAssetServletUtil.ByteRange full = new SpeedyAssetServletUtil.ByteRange(0, f.length() - 1, f.length());
            if (ranges.isEmpty() || ranges.get(0).equals(full)) {
              // Return full file.
              input = new RandomAccessFile(f, "r");
              SpeedyAssetServletUtil.ByteRange r = full;
              response.setContentType(file.getMimeType());
              response.setHeader("Content-Range", "bytes " + r.start + "-" + r.end + "/" + r.total);
              response.setHeader("Content-Length", String.valueOf(r.length));
              // Copy full range.
              SpeedyAssetServletUtil.copy(input, out, r.start, r.length);
            } else if (ranges.size() == 1){
              SpeedyAssetServletUtil.ByteRange range = ranges.get(0);
              input = new RandomAccessFile(f, "r");
              // Check if Range is syntactically valid. If not, then return 416.
              if (range.start > range.end) {
                response.setHeader("Content-Range", "bytes */" + data.length); // Required in 416.
                response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                return;
              }
              response.setContentType(file.getMimeType());
              response.setHeader("Content-Range", "bytes " + range.start + "-" + range.end + "/" + range.total);
              response.setHeader("Content-Length", String.valueOf(range.length));
                    response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 206.
              SpeedyAssetServletUtil.copy(input, out, range.start, range.length);
            }else{
              response.setContentType("multipart/byteranges; boundary=" + SpeedyAssetServletUtil.MULTIPART_BOUNDARY);
              response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                input = new RandomAccessFile(f, "r");
              for (SpeedyAssetServletUtil.ByteRange r : ranges) {
                if (r.start > r.end) {
                  response.setHeader("Content-Range", "bytes */" + data.length); // Required in 416.
                  response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                  return;
                }
                // Add multipart boundary and header fields for every range.
                out.println();
                out.println("--" + SpeedyAssetServletUtil.MULTIPART_BOUNDARY);
                out.println("Content-Type: " + file.getMimeType());
                out.println("Content-Range: bytes " + r.start + "-" + r.end + "/" + r.total);
                out.println();

                // Copy single part range of multi part range.
                SpeedyAssetServletUtil.copy(input, out, r.start, r.length);
              }
              // End with multipart boundary.
              out.println();
              out.println("--" + SpeedyAssetServletUtil.MULTIPART_BOUNDARY + "--");
            }
            responseSent = true;
         
        }
        if(!responseSent){
          response.setContentLength(data.length);
          response.setHeader("Content-Length", String.valueOf(f.length()));
          while (position < size) {
            position +=  from.transferTo(position, maxTransferSize, to);
          }
        }
      } catch (Exception e) {
        Logger.warn(this, e + " Error for = " + request.getRequestURI() + (request.getQueryString() != null?"?"+request.getQueryString():"") );
        Logger.debug(this, "Error serving asset = " + request.getRequestURI() + (request.getQueryString() != null?"?"+request.getQueryString():""), e);

      } finally {
        if(to != null)
          to.close();
        if(from != null)
          from.close();
        if(out != null)
          out.close();
        if(input !=null)
          input.close();
      }

    } catch (Exception e) {
      Logger.debug(this, "General Error occurred serving asset = " + request.getRequestURI() + (request.getQueryString() != null?"?"+request.getQueryString():""), e);
      //DOTCMS-1981
      //response.sendError(404, "Asset not Found");
    }
  }
}
TOP

Related Classes of com.dotmarketing.servlets.SpeedyAssetServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.