/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.server.service.admin.mvc.controller; import java.io.File; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; import org.springframework.web.util.UrlPathHelper; import com.enonic.cms.framework.blob.BlobRecord; import com.enonic.cms.framework.util.HttpServletRangeUtil; import com.enonic.cms.framework.util.HttpServletUtil; import com.enonic.cms.core.Path; import com.enonic.cms.core.PathAndParams; import com.enonic.cms.core.RequestParameters; import com.enonic.cms.core.content.ContentEntity; import com.enonic.cms.core.content.ContentKey; import com.enonic.cms.core.content.ContentVersionEntity; import com.enonic.cms.core.content.ContentVersionKey; import com.enonic.cms.core.content.access.ContentAccessResolver; import com.enonic.cms.core.content.binary.AttachmentNotFoundException; import com.enonic.cms.core.content.binary.AttachmentRequest; import com.enonic.cms.core.content.binary.AttachmentRequestResolver; import com.enonic.cms.core.content.binary.BinaryDataEntity; import com.enonic.cms.core.content.binary.BinaryDataKey; import com.enonic.cms.core.content.binary.ContentBinaryDataEntity; import com.enonic.cms.core.content.binary.InvalidBinaryPathException; import com.enonic.cms.core.security.SecurityService; import com.enonic.cms.core.security.user.UserEntity; import com.enonic.cms.store.dao.BinaryDataDao; import com.enonic.cms.store.dao.ContentDao; import com.enonic.cms.store.dao.GroupDao; @Controller("adminAttachmentController") public class AttachmentController extends AbstractController implements InitializingBean { private static final Logger LOG = LoggerFactory.getLogger( AttachmentController.class ); private BinaryDataDao binaryDataDao; private ContentDao contentDao; private GroupDao groupDao; private SecurityService securityService; private AttachmentRequestResolver attachmentRequestResolver; private UrlPathHelper urlEncodingUrlPathHelper; public void afterPropertiesSet() throws Exception { this.urlEncodingUrlPathHelper = new UrlPathHelper(); this.urlEncodingUrlPathHelper.setUrlDecode( true ); attachmentRequestResolver = new AttachmentRequestResolver() { @Override protected BinaryDataKey getBinaryData( ContentEntity content, String label ) { BinaryDataEntity binaryData; if ( label == null ) { binaryData = content.getMainVersion().getOneAndOnlyBinaryData(); } else { binaryData = content.getMainVersion().getBinaryData( label ); } if ( "source".equals( label ) && binaryData == null ) { binaryData = content.getMainVersion().getOneAndOnlyBinaryData(); } if ( binaryData != null ) { return new BinaryDataKey( binaryData.getKey() ); } return null; } @Override protected ContentEntity getContent( ContentKey contentKey ) { return contentDao.findByKey( contentKey ); } }; } public final ModelAndView handleRequestInternal( HttpServletRequest request, HttpServletResponse response ) throws Exception { final UserEntity loggedInUser = securityService.getLoggedInAdminConsoleUserAsEntity(); try { final PathAndParams pathAndParams = resolvePathAndParams( request ); final AttachmentRequest attachmentRequest = attachmentRequestResolver.resolveBinaryDataKey( pathAndParams ); final ContentEntity content = resolveContent( attachmentRequest, pathAndParams ); checkContentAccess( loggedInUser, content, pathAndParams ); final ContentVersionEntity contentVersion = resolveContentVersion( content, request, pathAndParams ); final ContentBinaryDataEntity contentBinaryData = resolveContentBinaryData( contentVersion, attachmentRequest, pathAndParams ); final BinaryDataEntity binaryData = contentBinaryData.getBinaryData(); boolean download = "true".equals( request.getParameter( "download" ) ); download = download || "true".equals( request.getParameter( "_download" ) ); final BlobRecord blob = binaryDataDao.getBlob( binaryData.getBinaryDataKey() ); if ( blob == null ) { throw AttachmentNotFoundException.notFound( binaryData.getBinaryDataKey() ); } putBinaryOnResponse( download, request, response, binaryData, blob ); return null; } catch ( InvalidBinaryPathException e ) { LOG.warn( e.getMessage() ); response.sendError( HttpServletResponse.SC_NOT_FOUND ); } catch ( AttachmentNotFoundException e ) { LOG.warn( e.getMessage() ); response.sendError( HttpServletResponse.SC_NOT_FOUND ); } return null; } private PathAndParams resolvePathAndParams( HttpServletRequest request ) { @SuppressWarnings({"unchecked"}) Map<String, String[]> parameterMap = request.getParameterMap(); RequestParameters requestParameters = new RequestParameters( parameterMap ); String pathAsString = urlEncodingUrlPathHelper.getRequestUri( request ); Path path = new Path( pathAsString ); return new PathAndParams( path, requestParameters ); } private void putBinaryOnResponse( boolean download, final HttpServletRequest request, HttpServletResponse response, BinaryDataEntity binaryData, BlobRecord blob ) throws IOException { final File file = blob.getAsFile(); final String mimeType = HttpServletUtil.resolveMimeType( getServletContext(), binaryData.getName() ); if ( file != null ) { HttpServletRangeUtil.processRequest( request, response, binaryData.getName(), mimeType, file, download ); } else { HttpServletUtil.setContentDisposition( response, download, binaryData.getName() ); response.setContentType( mimeType ); response.setContentLength( (int) blob.getLength() ); HttpServletUtil.copyNoCloseOut( blob.getStream(), response.getOutputStream() ); } } private ContentEntity resolveContent( AttachmentRequest attachmentRequest, PathAndParams pathAndParams ) { final ContentEntity content = contentDao.findByKey( attachmentRequest.getContentKey() ); if ( content == null || content.isDeleted() ) { throw AttachmentNotFoundException.notFound( pathAndParams.getPath().toString() ); } return content; } private ContentVersionEntity resolveContentVersion( ContentEntity content, HttpServletRequest request, PathAndParams pathAndParams ) { String versionParam = request.getParameter( "_version" ); if ( StringUtils.isNotBlank( versionParam ) ) { ContentVersionEntity contentVersion = content.getVersion( new ContentVersionKey( versionParam ) ); if ( contentVersion == null ) { throw AttachmentNotFoundException.notFound( pathAndParams.getPath().toString() ); } return contentVersion; } return content.getMainVersion(); } private ContentBinaryDataEntity resolveContentBinaryData( ContentVersionEntity contentVersion, AttachmentRequest attachmentRequest, PathAndParams pathAndParams ) { final ContentBinaryDataEntity contentBinaryData = contentVersion.getContentBinaryData( attachmentRequest.getBinaryDataKey() ); if ( contentBinaryData == null ) { throw AttachmentNotFoundException.notFound( pathAndParams.getPath().toString() ); } return contentBinaryData; } private void checkContentAccess( UserEntity loggedInUser, ContentEntity content, PathAndParams pathAndParams ) { if ( !new ContentAccessResolver( groupDao ).hasReadContentAccess( loggedInUser, content ) ) { throw AttachmentNotFoundException.notFound( pathAndParams.getPath().toString() ); } } @Autowired public void setBinaryDataDao( BinaryDataDao binaryDataDao ) { this.binaryDataDao = binaryDataDao; } @Autowired public void setContentDao( ContentDao dao ) { contentDao = dao; } @Autowired public void setSecurityService( SecurityService value ) { this.securityService = value; } @Autowired public void setGroupDao( GroupDao groupDao ) { this.groupDao = groupDao; } }