/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.web.portal.image;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.enonic.cms.framework.util.HttpServletUtil;
import com.enonic.cms.core.Attribute;
import com.enonic.cms.core.Path;
import com.enonic.cms.core.content.access.ContentAccessResolver;
import com.enonic.cms.core.image.ImageRequest;
import com.enonic.cms.core.image.ImageRequestParser;
import com.enonic.cms.core.image.ImageResponse;
import com.enonic.cms.core.portal.ReservedLocalPaths;
import com.enonic.cms.core.portal.ResourceNotFoundException;
import com.enonic.cms.core.portal.image.ImageProcessorException;
import com.enonic.cms.core.portal.image.ImageRequestAccessResolver;
import com.enonic.cms.core.portal.image.ImageService;
import com.enonic.cms.core.portal.livetrace.ImageRequestTrace;
import com.enonic.cms.core.portal.livetrace.ImageRequestTracer;
import com.enonic.cms.core.portal.livetrace.PortalRequestTrace;
import com.enonic.cms.core.portal.livetrace.PortalRequestTracer;
import com.enonic.cms.core.portal.rendering.tracing.RenderTrace;
import com.enonic.cms.core.security.user.UserEntity;
import com.enonic.cms.core.structure.SiteEntity;
import com.enonic.cms.core.structure.SitePath;
import com.enonic.cms.core.structure.SiteProperties;
import com.enonic.cms.core.structure.SitePropertyNames;
import com.enonic.cms.core.structure.menuitem.MenuItemEntity;
import com.enonic.cms.web.portal.PortalWebContext;
import com.enonic.cms.web.portal.handler.WebHandlerBase;
@Component
public final class ImageHandler
extends WebHandlerBase
{
private ImageService imageService;
private final ImageRequestParser requestParser = new ImageRequestParser();
@Override
protected boolean canHandle( final Path localPath )
{
return localPath.containsSubPath( "_image" );
}
@Override
protected void doHandle( final PortalWebContext context )
throws Exception
{
final HttpServletRequest request = context.getRequest();
final HttpServletResponse response = context.getResponse();
final SitePath sitePath = context.getSitePath();
final UserEntity loggedInUser;
final PortalRequestTrace portalRequestTrace =
PortalRequestTracer.startTracing( (String) request.getAttribute( Attribute.ORIGINAL_URL ), livePortalTraceService );
try
{
final ImageResponse imageResponse;
try
{
PortalRequestTracer.traceMode( portalRequestTrace, previewService );
PortalRequestTracer.traceHttpRequest( portalRequestTrace, request );
PortalRequestTracer.traceRequestedSitePath( portalRequestTrace, sitePath );
PortalRequestTracer.traceRequestedSite( portalRequestTrace, siteDao.findByKey( sitePath.getSiteKey() ) );
loggedInUser = resolveLoggedInUser( request, response, sitePath );
PortalRequestTracer.traceRequester( portalRequestTrace, loggedInUser );
final ImageRequestTrace imageRequestTrace = ImageRequestTracer.startTracing( livePortalTraceService );
try
{
verifyValidMenuItemInPath( sitePath );
final ImageRequest imageRequest = createImageRequest( request );
try
{
imageResponse = processImageRequest( imageRequest, sitePath, imageRequestTrace );
}
catch ( ImageProcessorException e )
{
response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage() );
return;
}
ImageRequestTracer.traceSize( imageRequestTrace, (long) imageResponse.getSize() );
}
finally
{
ImageRequestTracer.stopTracing( imageRequestTrace, livePortalTraceService );
}
}
finally
{
PortalRequestTracer.stopTracing( portalRequestTrace, livePortalTraceService );
}
serveResponse( response, sitePath, imageResponse );
}
catch ( Exception e )
{
throw new ImageRequestException( sitePath, request.getHeader( "referer" ), e );
}
}
private ImageResponse processImageRequest( final ImageRequest imageRequest, final SitePath sitePath,
final ImageRequestTrace imageRequestTrace )
throws ImageProcessorException
{
ImageRequestTracer.traceImageRequest( imageRequestTrace, imageRequest );
checkRequestAccess( imageRequest, sitePath );
final ImageResponse imageResponse = imageService.process( imageRequest );
if ( imageResponse.isImageNotFound() )
{
throw new ResourceNotFoundException( sitePath.getSiteKey(), sitePath.getLocalPath() );
}
return imageResponse;
}
private void serveResponse( final HttpServletResponse response, final SitePath sitePath, final ImageResponse imageResponse )
throws IOException
{
final boolean anonymousAccess = securityService.getLoggedInPortalUser().isAnonymous();
setHttpHeaders( response, sitePath, anonymousAccess );
response.setContentType( imageResponse.getMimeType() );
response.setContentLength( imageResponse.getSize() );
HttpServletUtil.setContentDisposition( response, false, imageResponse.getName() );
HttpServletUtil.copyNoCloseOut( imageResponse.getDataAsStream(), response.getOutputStream() );
}
private UserEntity resolveLoggedInUser( final HttpServletRequest request, final HttpServletResponse response, final SitePath sitePath )
{
UserEntity loggedInUser = securityService.getLoggedInPortalUserAsEntity();
final SiteProperties siteProperties = sitePropertiesService.getSiteProperties( sitePath.getSiteKey() );
if ( loggedInUser.isAnonymous() )
{
if ( siteProperties.getPropertyAsBoolean( SitePropertyNames.AUTOLOGIN_HTTP_REMOTE_USER_ENABLED ) )
{
loggedInUser = autoLoginService.autologinWithRemoteUser( request, siteDao.findByKey( sitePath.getSiteKey() ) );
}
}
if ( loggedInUser.isAnonymous() )
{
if ( siteProperties.getPropertyAsBoolean( SitePropertyNames.AUTOLOGIN_REMEMBER_ME_COOKIE_ENABLED ) )
{
loggedInUser = autoLoginService.autologinWithCookie( siteDao.findByKey( sitePath.getSiteKey() ), request, response );
}
}
return loggedInUser;
}
private ImageRequest createImageRequest( final HttpServletRequest request )
{
final HashMap<String, String> params = new HashMap<String, String>();
final Enumeration e = request.getParameterNames();
while ( e.hasMoreElements() )
{
final String key = (String) e.nextElement();
params.put( key, request.getParameter( key ) );
}
final boolean encodeParams = !RenderTrace.isExecutingInDebugMode();
final ImageRequest imageRequest = requestParser.parse( request.getPathInfo(), params, encodeParams );
imageRequest.setRequester( securityService.getLoggedInPortalUser() );
imageRequest.setRequestDateTime( new DateTime() );
return imageRequest;
}
private void verifyValidMenuItemInPath( final SitePath sitePath )
{
SiteEntity site = siteDao.findByKey( sitePath.getSiteKey() );
Path menuItemPath = getImageMenuItemPath( sitePath );
MenuItemEntity menuItem = site.resolveMenuItemByPath( menuItemPath );
if ( menuItem == null )
{
throw new ResourceNotFoundException( sitePath.getSiteKey(), sitePath.getLocalPath() );
}
}
private Path getImageMenuItemPath( final SitePath sitePath )
{
String pathAsString = sitePath.getLocalPath().toString();
if ( !pathAsString.contains( ReservedLocalPaths.PATH_IMAGE.toString() ) )
{
throw new ResourceNotFoundException( sitePath.getSiteKey(), sitePath.getLocalPath() );
}
int i = pathAsString.lastIndexOf( ReservedLocalPaths.PATH_IMAGE.toString() );
String menuItemPathAsString = pathAsString.substring( 0, i );
return new Path( menuItemPathAsString );
}
private void setHttpHeaders( final HttpServletResponse response, final SitePath sitePath, final boolean anonymousAccess )
{
final DateTime now = new DateTime();
HttpServletUtil.setDateHeader( response, now.toDate() );
final SiteProperties siteProperties = sitePropertiesService.getSiteProperties( sitePath.getSiteKey() );
final boolean cacheHeadersEnabled = siteProperties.getPropertyAsBoolean( SitePropertyNames.IMAGE_CACHE_HEADERS_ENABLED );
if ( cacheHeadersEnabled )
{
final boolean forceNoCache = siteProperties.getPropertyAsBoolean( SitePropertyNames.IMAGE_CACHE_HEADERS_FORCENOCACHE );
if ( forceNoCache )
{
HttpServletUtil.setCacheControlNoCache( response );
}
else
{
Integer siteCacheSettingsMaxAge = siteProperties.getPropertyAsInteger( SitePropertyNames.IMAGE_CACHE_HEADERS_MAXAGE );
enableHttpCacheHeaders( response, sitePath, now, siteCacheSettingsMaxAge, anonymousAccess );
}
}
}
private void checkRequestAccess( final ImageRequest imageRequest, final SitePath sitePath )
{
final UserEntity loggedInPortalUser = securityService.getLoggedInPortalUserAsEntity();
ImageRequestAccessResolver accessResolver = new ImageRequestAccessResolver( contentDao, new ContentAccessResolver( groupDao ) );
accessResolver.imageRequester( loggedInPortalUser );
accessResolver.requireMainVersion();
accessResolver.requireOnlineNow( timeService.getNowAsDateTime(), previewService );
final ImageRequestAccessResolver.Access access = accessResolver.isAccessible( imageRequest );
if ( access != ImageRequestAccessResolver.Access.OK )
{
throw new ResourceNotFoundException( sitePath.getSiteKey(), sitePath.getLocalPath() );
}
}
@Autowired
public void setImageService( final ImageService imageService )
{
this.imageService = imageService;
}
}