http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f40e7b75/awsapi/src/com/cloud/bridge/service/S3RestServlet.java ---------------------------------------------------------------------- diff --git a/awsapi/src/com/cloud/bridge/service/S3RestServlet.java b/awsapi/src/com/cloud/bridge/service/S3RestServlet.java index c1458a7..c824fca 100644 --- a/awsapi/src/com/cloud/bridge/service/S3RestServlet.java +++ b/awsapi/src/com/cloud/bridge/service/S3RestServlet.java @@ -18,21 +18,22 @@ package com.cloud.bridge.service; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.OutputStream; import java.io.InputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.SignatureException; import java.sql.SQLException; import java.util.Enumeration; +import javax.inject.Inject; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.DatatypeConverter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.bind.*; import org.apache.axis2.AxisFault; import org.apache.log4j.Logger; @@ -45,10 +46,7 @@ import com.cloud.bridge.io.MultiPartDimeInputStream; import com.cloud.bridge.model.SAcl; import com.cloud.bridge.model.UserCredentialsVO; import com.cloud.bridge.persist.dao.CloudStackConfigurationDao; -import com.cloud.bridge.persist.dao.CloudStackConfigurationDaoImpl; import com.cloud.bridge.persist.dao.UserCredentialsDao; - -import com.cloud.bridge.persist.dao.UserCredentialsDaoImpl; import com.cloud.bridge.service.controller.s3.S3BucketAction; import com.cloud.bridge.service.controller.s3.S3ObjectAction; import com.cloud.bridge.service.controller.s3.ServiceProvider; @@ -66,151 +64,155 @@ import com.cloud.bridge.util.ConfigurationHelper; import com.cloud.bridge.util.HeaderParam; import com.cloud.bridge.util.RestAuth; import com.cloud.bridge.util.S3SoapAuth; -import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; - -import net.sf.ehcache.Cache; public class S3RestServlet extends HttpServlet { - private static final long serialVersionUID = -6168996266762804877L; - public static final String ENABLE_S3_API="enable.s3.api"; - private static boolean isS3APIEnabled = false; - - public static final Logger logger = Logger.getLogger(S3RestServlet.class); - protected final CloudStackConfigurationDao csDao = ComponentLocator.inject(CloudStackConfigurationDaoImpl.class); - protected final UserCredentialsDao ucDao = ComponentLocator.inject(UserCredentialsDaoImpl.class); - - protected void doGet(HttpServletRequest req, HttpServletResponse resp) { - processRequest( req, resp, "GET" ); - } - + private static final long serialVersionUID = -6168996266762804877L; + public static final String ENABLE_S3_API="enable.s3.api"; + private static boolean isS3APIEnabled = false; + + public static final Logger logger = Logger.getLogger(S3RestServlet.class); + @Inject CloudStackConfigurationDao csDao; + @Inject UserCredentialsDao ucDao; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) { + processRequest( req, resp, "GET" ); + } + + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) { - // -> DIME requests are authenticated via the SOAP auth mechanism - String type = req.getHeader( "Content-Type" ); - if ( null != type && type.equalsIgnoreCase( "application/dime" )) - processDimeRequest(req, resp); - else processRequest( req, resp, "POST" ); + // -> DIME requests are authenticated via the SOAP auth mechanism + String type = req.getHeader( "Content-Type" ); + if ( null != type && type.equalsIgnoreCase( "application/dime" )) + processDimeRequest(req, resp); + else processRequest( req, resp, "POST" ); } - + + @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) { processRequest( req, resp, "PUT" ); } - + + @Override protected void doHead(HttpServletRequest req, HttpServletResponse resp) { processRequest( req, resp, "HEAD" ); } - + + @Override protected void doOptions(HttpServletRequest req, HttpServletResponse resp) { processRequest( req, resp, "OPTIONS" ); } - + + @Override protected void doDelete( HttpServletRequest req, HttpServletResponse resp ) { processRequest( req, resp, "DELETE" ); } - + + @Override public void init( ServletConfig config ) throws ServletException { - try{ - ConfigurationHelper.preConfigureConfigPathFromServletContext(config.getServletContext()); - // check if API is enabled - String value = csDao.getConfigValue(ENABLE_S3_API); - if(value != null) { - isS3APIEnabled = Boolean.valueOf(value); - } - logger.info("S3Engine :: Configuration value is : " + value); - - }catch(Exception e){ - throw new ServletException("Error initializing awsapi: " + e.getMessage()); + try{ + ConfigurationHelper.preConfigureConfigPathFromServletContext(config.getServletContext()); + // check if API is enabled + String value = csDao.getConfigValue(ENABLE_S3_API); + if(value != null) { + isS3APIEnabled = Boolean.valueOf(value); + } + logger.info("S3Engine :: Configuration value is : " + value); + + }catch(Exception e){ + throw new ServletException("Error initializing awsapi: " + e.getMessage()); } - - } - - - - /** - * POST requests do not get authenticated on entry. The associated - * access key and signature headers are embedded in the message not encoded - * as HTTP headers. - */ + + } + + + + /** + * POST requests do not get authenticated on entry. The associated + * access key and signature headers are embedded in the message not encoded + * as HTTP headers. + */ private void processRequest( HttpServletRequest request, HttpServletResponse response, String method ) { Transaction txn = Transaction.open("cloudbridge", Transaction.AWSAPI_DB, true); try { - logRequest(request); - - // Our extensions to the S3 REST API for simple management actions - // are conveyed with Request parameter "Action". - // The present extensions are either to set up the user credentials - // (see the cloud-bridge-register script for more detail) or - // to report our version of this capability. - // -> unauthenticated calls, should still be done over HTTPS - String cloudAction = request.getParameter( "Action" ); - - if(!isS3APIEnabled){ - throw new RuntimeException("Amazon S3 API is disabled."); - } - - + logRequest(request); + + // Our extensions to the S3 REST API for simple management actions + // are conveyed with Request parameter "Action". + // The present extensions are either to set up the user credentials + // (see the cloud-bridge-register script for more detail) or + // to report our version of this capability. + // -> unauthenticated calls, should still be done over HTTPS + String cloudAction = request.getParameter( "Action" ); + + if(!isS3APIEnabled){ + throw new RuntimeException("Amazon S3 API is disabled."); + } + + if (null != cloudAction) { - if (cloudAction.equalsIgnoreCase( "SetUserKeys" )) { - setUserKeys(request, response); - return; - } - - if (cloudAction.equalsIgnoreCase( "SetCertificate" )) - // At present a noop - return; - - if (cloudAction.equalsIgnoreCase( "CloudS3Version" )) { - cloudS3Version(request, response); - return; - } - } - - + if (cloudAction.equalsIgnoreCase( "SetUserKeys" )) { + setUserKeys(request, response); + return; + } + + if (cloudAction.equalsIgnoreCase( "SetCertificate" )) + // At present a noop + return; + + if (cloudAction.equalsIgnoreCase( "CloudS3Version" )) { + cloudS3Version(request, response); + return; + } + } + + txn.start(); - // -> authenticated calls - if ( !((method.equalsIgnoreCase( "POST" ) && !(request.getQueryString().equalsIgnoreCase("delete"))) ) ){ - S3AuthParams params = extractRequestHeaders( request ); - authenticateRequest( request, params ); - } - - ServletAction action = routeRequest(request); - if ( action != null ) { - action.execute(request, response); - } - else { - response.setStatus(404); - endResponse(response, "File not found"); - } - txn.close(); + // -> authenticated calls + if ( !((method.equalsIgnoreCase( "POST" ) && !(request.getQueryString().equalsIgnoreCase("delete"))) ) ){ + S3AuthParams params = extractRequestHeaders( request ); + authenticateRequest( request, params ); + } + + ServletAction action = routeRequest(request); + if ( action != null ) { + action.execute(request, response); + } + else { + response.setStatus(404); + endResponse(response, "File not found"); + } + txn.close(); } catch( InvalidBucketName e) { - logger.error("Unexpected exception " + e.getMessage(), e); - response.setStatus(400); - endResponse(response, "Invalid Bucket Name - " + e.toString()); + logger.error("Unexpected exception " + e.getMessage(), e); + response.setStatus(400); + endResponse(response, "Invalid Bucket Name - " + e.toString()); } catch(PermissionDeniedException e) { - logger.error("Unexpected exception " + e.getMessage(), e); - response.setStatus(403); - endResponse(response, "Access denied - " + e.toString()); + logger.error("Unexpected exception " + e.getMessage(), e); + response.setStatus(403); + endResponse(response, "Access denied - " + e.toString()); } catch(Throwable e) { - logger.error("Unexpected exception " + e.getMessage(), e); - response.setStatus(404); - endResponse(response, "Bad request"); - + logger.error("Unexpected exception " + e.getMessage(), e); + response.setStatus(404); + endResponse(response, "Bad request"); + } finally { - - try { - response.flushBuffer(); - } catch (IOException e) { - logger.error("Unexpected exception " + e.getMessage(), e); - } + + try { + response.flushBuffer(); + } catch (IOException e) { + logger.error("Unexpected exception " + e.getMessage(), e); + } } } - + /** * Provide an easy way to determine the version of the implementation running. * @@ -218,7 +220,7 @@ public class S3RestServlet extends HttpServlet { */ private void cloudS3Version( HttpServletRequest request, HttpServletResponse response ) { String version = new String( "<?xml version=\"1.0\" encoding=\"utf-8\"?><CloudS3Version>1.04</CloudS3Version>" ); - response.setStatus(200); + response.setStatus(200); endResponse(response, version); } @@ -242,236 +244,236 @@ public class S3RestServlet extends HttpServlet { */ @DB private void setUserKeys( HttpServletRequest request, HttpServletResponse response ) { - String[] accessKey = null; - String[] secretKey = null; - - try { - // -> both these parameters are required + String[] accessKey = null; + String[] secretKey = null; + + try { + // -> both these parameters are required accessKey = request.getParameterValues( "accesskey" ); - if ( null == accessKey || 0 == accessKey.length ) { - response.sendError(530, "Missing accesskey parameter" ); - return; - } + if ( null == accessKey || 0 == accessKey.length ) { + response.sendError(530, "Missing accesskey parameter" ); + return; + } secretKey = request.getParameterValues( "secretkey" ); if ( null == secretKey || 0 == secretKey.length ) { - response.sendError(530, "Missing secretkey parameter" ); - return; + response.sendError(530, "Missing secretkey parameter" ); + return; } } catch( Exception e ) { - logger.error("SetUserKeys exception " + e.getMessage(), e); - response.setStatus(500); - endResponse(response, "SetUserKeys exception " + e.getMessage()); - return; + logger.error("SetUserKeys exception " + e.getMessage(), e); + response.setStatus(500); + endResponse(response, "SetUserKeys exception " + e.getMessage()); + return; } try { // -> use the keys to see if the account actually exists - //ServiceProvider.getInstance().getEC2Engine().validateAccount( accessKey[0], secretKey[0] ); - //UserCredentialsDaoImpl credentialDao = new UserCredentialsDao(); + //ServiceProvider.getInstance().getEC2Engine().validateAccount( accessKey[0], secretKey[0] ); + //UserCredentialsDaoImpl credentialDao = new UserCredentialsDao(); Transaction txn = Transaction.open(Transaction.AWSAPI_DB); txn.start(); - UserCredentialsVO user = new UserCredentialsVO(accessKey[0], secretKey[0]); - user = ucDao.persist(user); - txn.commit(); - txn.close(); - //credentialDao.setUserKeys( accessKey[0], secretKey[0] ); - + UserCredentialsVO user = new UserCredentialsVO(accessKey[0], secretKey[0]); + user = ucDao.persist(user); + txn.commit(); + txn.close(); + //credentialDao.setUserKeys( accessKey[0], secretKey[0] ); + } catch( Exception e ) { - logger.error("SetUserKeys " + e.getMessage(), e); - response.setStatus(401); - endResponse(response, e.toString()); - return; + logger.error("SetUserKeys " + e.getMessage(), e); + response.setStatus(401); + endResponse(response, e.toString()); + return; } - response.setStatus(200); + response.setStatus(200); endResponse(response, "User keys set successfully"); } - + /** * We are using the S3AuthParams class to hide where the header values are coming * from so that the authenticateRequest call can be made from several places. */ public static S3AuthParams extractRequestHeaders( HttpServletRequest request ) { - S3AuthParams params = new S3AuthParams(); - - Enumeration headers = request.getHeaderNames(); - if (null != headers) - { - while( headers.hasMoreElements()) - { - HeaderParam oneHeader = new HeaderParam(); - String headerName = (String)headers.nextElement(); - oneHeader.setName( headerName ); - oneHeader.setValue( request.getHeader( headerName )); - params.addHeader( oneHeader ); - } - } - return params; + S3AuthParams params = new S3AuthParams(); + + Enumeration headers = request.getHeaderNames(); + if (null != headers) + { + while( headers.hasMoreElements()) + { + HeaderParam oneHeader = new HeaderParam(); + String headerName = (String)headers.nextElement(); + oneHeader.setName( headerName ); + oneHeader.setValue( request.getHeader( headerName )); + params.addHeader( oneHeader ); + } + } + return params; } - + public static void authenticateRequest( HttpServletRequest request, S3AuthParams params ) - throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException - { - RestAuth auth = new RestAuth(ServiceProvider.getInstance().getUseSubDomain()); - String AWSAccessKey = null; - String signature = null; - String authorization = null; - - // [A] Is it an annonymous request? - if (null == (authorization = params.getHeader( "Authorization" ))) { + throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException + { + RestAuth auth = new RestAuth(ServiceProvider.getInstance().getUseSubDomain()); + String AWSAccessKey = null; + String signature = null; + String authorization = null; + + // [A] Is it an annonymous request? + if (null == (authorization = params.getHeader( "Authorization" ))) { UserContext.current().initContext(); return; - } - - // [B] Is it an authenticated request? - int offset = authorization.indexOf( "AWS" ); - if (-1 != offset) { - String temp = authorization.substring( offset+3 ).trim(); - offset = temp.indexOf( ":" ); - AWSAccessKey = temp.substring( 0, offset ); - signature = temp.substring( offset+1 ); - } - - // [C] Calculate the signature from the request's headers - auth.setDateHeader( request.getHeader( "Date" )); - auth.setContentTypeHeader( request.getHeader( "Content-Type" )); - auth.setContentMD5Header( request.getHeader( "Content-MD5" )); - auth.setHostHeader( request.getHeader( "Host" )); - auth.setQueryString( request.getQueryString()); - auth.addUriPath( request.getRequestURI()); - - // -> are their any Amazon specific (i.e. 'x-amz-' ) headers? - HeaderParam[] headers = params.getHeaders(); - for( int i=0; null != headers && i < headers.length; i++ ) - { - String headerName = headers[i].getName(); - String ignoreCase = headerName.toLowerCase(); - if (ignoreCase.startsWith( "x-amz-" )) - auth.addAmazonHeader( headerName + ":" + headers[i].getValue()); - } - - UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); - if (info == null) throw new PermissionDeniedException("Unable to authenticate access key: " + AWSAccessKey); - - try { - if (auth.verifySignature( request.getMethod(), info.getSecretKey(), signature )) { - UserContext.current().initContext(AWSAccessKey, info.getSecretKey(), AWSAccessKey, info.getDescription(), request); - return; - } - - - } catch (SignatureException e) { - throw new PermissionDeniedException(e); - - } catch (UnsupportedEncodingException e) { - throw new PermissionDeniedException(e); - } - throw new PermissionDeniedException("Invalid signature"); - } - - - + } + + // [B] Is it an authenticated request? + int offset = authorization.indexOf( "AWS" ); + if (-1 != offset) { + String temp = authorization.substring( offset+3 ).trim(); + offset = temp.indexOf( ":" ); + AWSAccessKey = temp.substring( 0, offset ); + signature = temp.substring( offset+1 ); + } + + // [C] Calculate the signature from the request's headers + auth.setDateHeader( request.getHeader( "Date" )); + auth.setContentTypeHeader( request.getHeader( "Content-Type" )); + auth.setContentMD5Header( request.getHeader( "Content-MD5" )); + auth.setHostHeader( request.getHeader( "Host" )); + auth.setQueryString( request.getQueryString()); + auth.addUriPath( request.getRequestURI()); + + // -> are their any Amazon specific (i.e. 'x-amz-' ) headers? + HeaderParam[] headers = params.getHeaders(); + for( int i=0; null != headers && i < headers.length; i++ ) + { + String headerName = headers[i].getName(); + String ignoreCase = headerName.toLowerCase(); + if (ignoreCase.startsWith( "x-amz-" )) + auth.addAmazonHeader( headerName + ":" + headers[i].getValue()); + } + + UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); + if (info == null) throw new PermissionDeniedException("Unable to authenticate access key: " + AWSAccessKey); + + try { + if (auth.verifySignature( request.getMethod(), info.getSecretKey(), signature )) { + UserContext.current().initContext(AWSAccessKey, info.getSecretKey(), AWSAccessKey, info.getDescription(), request); + return; + } + + + } catch (SignatureException e) { + throw new PermissionDeniedException(e); + + } catch (UnsupportedEncodingException e) { + throw new PermissionDeniedException(e); + } + throw new PermissionDeniedException("Invalid signature"); + } + + + private ServletAction routeRequest(HttpServletRequest request) { - // URL routing for S3 REST calls. - String pathInfo = request.getPathInfo(); - String bucketName = null; - String key = null; - - String serviceEndpoint = ServiceProvider.getInstance().getServiceEndpoint(); - String host = request.getHeader("Host"); - - // Check for unrecognized forms of URI information in request - - if ( ( pathInfo == null ) || ( pathInfo.indexOf('/') != 0 ) ) - if ( "POST".equalsIgnoreCase(request.getMethod()) ) - // Case where request is POST operation with no pathinfo - // This is the POST alternative to PUT described at s3.amazonaws.com API doc page 141 - { - return routePlainPostRequest (request); - } - - - // Irrespective of whether the requester is using subdomain or full host naming of path expressions - // to buckets, wherever the request is made up of a service endpoint followed by a /, in AWS S3 this always - // conveys a ListAllMyBuckets command - - if ( (serviceEndpoint.equalsIgnoreCase( host )) && (pathInfo.equalsIgnoreCase("/")) ) { - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "/"); - return new S3BucketAction(); // for ListAllMyBuckets - } - - // Because there is a leading / at position 0 of pathInfo, now subtract this to process the remainder - pathInfo = pathInfo.substring(1); - - if (ServiceProvider.getInstance().getUseSubDomain()) - - { - // -> verify the format of the bucket name - int endPos = host.indexOf( ServiceProvider.getInstance().getMasterDomain()); - if ( endPos > 0 ) - { - bucketName = host.substring(0, endPos); - S3Engine.verifyBucketName( bucketName, false ); - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); - } - else request.setAttribute(S3Constants.BUCKET_ATTR_KEY, ""); - - if (pathInfo == null || pathInfo.equalsIgnoreCase("/")) - { - return new S3BucketAction(); - } - else { - String objectKey = pathInfo.substring(1); - request.setAttribute(S3Constants.OBJECT_ATTR_KEY, objectKey); - return new S3ObjectAction(); - } - } - - else - - { - - int endPos = pathInfo.indexOf('/'); // Subsequent / character? - - if (endPos < 1) - { - bucketName = pathInfo; - S3Engine.verifyBucketName( bucketName, false ); - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); - return new S3BucketAction(); - } - else - { - bucketName = pathInfo.substring(0, endPos); - key = pathInfo.substring(endPos + 1); - S3Engine.verifyBucketName( bucketName, false ); - - if (!key.isEmpty()) - { - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); - request.setAttribute(S3Constants.OBJECT_ATTR_KEY, pathInfo.substring(endPos + 1)); - return new S3ObjectAction(); - } - else { - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); - return new S3BucketAction(); - } - } - } + // URL routing for S3 REST calls. + String pathInfo = request.getPathInfo(); + String bucketName = null; + String key = null; + + String serviceEndpoint = ServiceProvider.getInstance().getServiceEndpoint(); + String host = request.getHeader("Host"); + + // Check for unrecognized forms of URI information in request + + if ( ( pathInfo == null ) || ( pathInfo.indexOf('/') != 0 ) ) + if ( "POST".equalsIgnoreCase(request.getMethod()) ) + // Case where request is POST operation with no pathinfo + // This is the POST alternative to PUT described at s3.amazonaws.com API doc page 141 + { + return routePlainPostRequest (request); + } + + + // Irrespective of whether the requester is using subdomain or full host naming of path expressions + // to buckets, wherever the request is made up of a service endpoint followed by a /, in AWS S3 this always + // conveys a ListAllMyBuckets command + + if ( (serviceEndpoint.equalsIgnoreCase( host )) && (pathInfo.equalsIgnoreCase("/")) ) { + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, "/"); + return new S3BucketAction(); // for ListAllMyBuckets + } + + // Because there is a leading / at position 0 of pathInfo, now subtract this to process the remainder + pathInfo = pathInfo.substring(1); + + if (ServiceProvider.getInstance().getUseSubDomain()) + + { + // -> verify the format of the bucket name + int endPos = host.indexOf( ServiceProvider.getInstance().getMasterDomain()); + if ( endPos > 0 ) + { + bucketName = host.substring(0, endPos); + S3Engine.verifyBucketName( bucketName, false ); + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); + } + else request.setAttribute(S3Constants.BUCKET_ATTR_KEY, ""); + + if (pathInfo == null || pathInfo.equalsIgnoreCase("/")) + { + return new S3BucketAction(); + } + else { + String objectKey = pathInfo.substring(1); + request.setAttribute(S3Constants.OBJECT_ATTR_KEY, objectKey); + return new S3ObjectAction(); + } + } + + else + + { + + int endPos = pathInfo.indexOf('/'); // Subsequent / character? + + if (endPos < 1) + { + bucketName = pathInfo; + S3Engine.verifyBucketName( bucketName, false ); + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); + return new S3BucketAction(); + } + else + { + bucketName = pathInfo.substring(0, endPos); + key = pathInfo.substring(endPos + 1); + S3Engine.verifyBucketName( bucketName, false ); + + if (!key.isEmpty()) + { + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); + request.setAttribute(S3Constants.OBJECT_ATTR_KEY, pathInfo.substring(endPos + 1)); + return new S3ObjectAction(); + } + else { + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketName); + return new S3BucketAction(); + } + } + } } - - + + public static void endResponse(HttpServletResponse response, String content) { - try { + try { byte[] data = content.getBytes(); response.setContentLength(data.length); OutputStream os = response.getOutputStream(); os.write(data); os.close(); - } catch(Throwable e) { - logger.error("Unexpected exception " + e.getMessage(), e); - } + } catch(Throwable e) { + logger.error("Unexpected exception " + e.getMessage(), e); + } } public static void writeResponse(HttpServletResponse response, String content) throws IOException { @@ -479,61 +481,61 @@ public class S3RestServlet extends HttpServlet { OutputStream os = response.getOutputStream(); os.write(data); } - + public static void writeResponse(HttpServletResponse response, InputStream is) throws IOException { - byte[] data = new byte[4096]; - int length = 0; - while((length = is.read(data)) > 0) { - response.getOutputStream().write(data, 0, length); - } + byte[] data = new byte[4096]; + int length = 0; + while((length = is.read(data)) > 0) { + response.getOutputStream().write(data, 0, length); + } } // Route for the case where request is POST operation with no pathinfo // This is the POST alternative to PUT described at s3.amazonaws.com API doc, Amazon Simple // Storage Service API Reference API Version 2006-03-01 page 141. // The purpose of the plain POST operation is to add an object to a specified bucket using HTML forms. - -private S3ObjectAction routePlainPostRequest (HttpServletRequest request) + + private S3ObjectAction routePlainPostRequest (HttpServletRequest request) { - // TODO - Remove the unnecessary fields below - // Obtain the mandatory fields from the HTML form or otherwise fail with a logger message - String keyString = request.getParameter("key"); - String metatagString = request.getParameter("x-amz-meta-tag"); - String bucketString = request.getParameter("Bucket"); - String aclString = request.getParameter("acl"); - String fileString = request.getParameter("file"); - - String accessKeyString = request.getParameter("AWSAccessKeyId"); - String signatureString = request.getParameter("Signature"); - - // Obtain the discretionary fields from the HTML form - String policyKeyString = request.getParameter("Policy"); - String metauuidString = request.getParameter("x-amz-meta-uuid"); - String redirectString = request.getParameter("redirect"); - - // if none of the above are null then ... - request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketString); - request.setAttribute(S3Constants.OBJECT_ATTR_KEY, keyString); - request.setAttribute(S3Constants.PLAIN_POST_ACCESS_KEY, accessKeyString); - request.setAttribute(S3Constants.PLAIN_POST_SIGNATURE, signatureString); - - // -> authenticated calls - try { - // S3AuthParams params = extractRequestHeaders( request ); - S3AuthParams params = new S3AuthParams(); - HeaderParam headerParam1 = new HeaderParam("accessKey", accessKeyString); - params.addHeader(headerParam1); - HeaderParam headerParam2 = new HeaderParam("secretKey", signatureString); - params.addHeader(headerParam2); - authenticateRequest( request, params ); - } - catch (Exception e) - { logger.warn("Authentication details insufficient"); } - - return new S3ObjectAction(); - - } - + // TODO - Remove the unnecessary fields below + // Obtain the mandatory fields from the HTML form or otherwise fail with a logger message + String keyString = request.getParameter("key"); + String metatagString = request.getParameter("x-amz-meta-tag"); + String bucketString = request.getParameter("Bucket"); + String aclString = request.getParameter("acl"); + String fileString = request.getParameter("file"); + + String accessKeyString = request.getParameter("AWSAccessKeyId"); + String signatureString = request.getParameter("Signature"); + + // Obtain the discretionary fields from the HTML form + String policyKeyString = request.getParameter("Policy"); + String metauuidString = request.getParameter("x-amz-meta-uuid"); + String redirectString = request.getParameter("redirect"); + + // if none of the above are null then ... + request.setAttribute(S3Constants.BUCKET_ATTR_KEY, bucketString); + request.setAttribute(S3Constants.OBJECT_ATTR_KEY, keyString); + request.setAttribute(S3Constants.PLAIN_POST_ACCESS_KEY, accessKeyString); + request.setAttribute(S3Constants.PLAIN_POST_SIGNATURE, signatureString); + + // -> authenticated calls + try { + // S3AuthParams params = extractRequestHeaders( request ); + S3AuthParams params = new S3AuthParams(); + HeaderParam headerParam1 = new HeaderParam("accessKey", accessKeyString); + params.addHeader(headerParam1); + HeaderParam headerParam2 = new HeaderParam("secretKey", signatureString); + params.addHeader(headerParam2); + authenticateRequest( request, params ); + } + catch (Exception e) + { logger.warn("Authentication details insufficient"); } + + return new S3ObjectAction(); + + } + /** * A DIME request is really a SOAP request that we are dealing with, and so its * authentication is the SOAP authentication approach. Since Axis2 does not handle @@ -543,17 +545,17 @@ private S3ObjectAction routePlainPostRequest (HttpServletRequest request) * @param response */ private void processDimeRequest(HttpServletRequest request, HttpServletResponse response) { - S3PutObjectRequest putRequest = null; - S3PutObjectResponse putResponse = null; - int bytesRead = 0; - + S3PutObjectRequest putRequest = null; + S3PutObjectResponse putResponse = null; + int bytesRead = 0; + S3Engine engine = new S3Engine(); - + try { - logRequest(request); - + logRequest(request); + MultiPartDimeInputStream ds = new MultiPartDimeInputStream( request.getInputStream()); - + // -> the first stream MUST be the SOAP party if (ds.nextInputStream()) { @@ -564,26 +566,26 @@ private S3ObjectAction routePlainPostRequest (HttpServletRequest request) ByteArrayInputStream bis = new ByteArrayInputStream( buffer, 0, bytesRead ); putRequest = toEnginePutObjectRequest( bis ); } - + // -> we only need to support a DIME message with two bodyparts if (null != putRequest && ds.nextInputStream()) { - InputStream is = ds.getInputStream(); - putRequest.setData( is ); + InputStream is = ds.getInputStream(); + putRequest.setData( is ); } // -> need to do SOAP level auth here, on failure return the SOAP fault StringBuffer xml = new StringBuffer(); String AWSAccessKey = putRequest.getAccessKey(); - UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); - try - { S3SoapAuth.verifySignature( putRequest.getSignature(), "PutObject", putRequest.getRawTimestamp(), AWSAccessKey, info.getSecretKey()); - - } catch( AxisFault e ) { - String reason = e.toString(); - int start = reason.indexOf( ".AxisFault:" ); - if (-1 != start) reason = reason.substring( start+11 ); - + UserInfo info = ServiceProvider.getInstance().getUserInfo(AWSAccessKey); + try + { S3SoapAuth.verifySignature( putRequest.getSignature(), "PutObject", putRequest.getRawTimestamp(), AWSAccessKey, info.getSecretKey()); + + } catch( AxisFault e ) { + String reason = e.toString(); + int start = reason.indexOf( ".AxisFault:" ); + if (-1 != start) reason = reason.substring( start+11 ); + xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" ); xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n" ); xml.append( "<soap:Body>\n" ); @@ -592,15 +594,15 @@ private S3ObjectAction routePlainPostRequest (HttpServletRequest request) xml.append( "<faultstring>" ).append( reason ).append( "</faultstring>\n" ); xml.append( "</soap:Fault>\n" ); xml.append( "</soap:Body></soap:Envelope>" ); - - endResponse(response, xml.toString()); - return; - } - - // -> PutObject S3 Bucket Policy would be done in the engine.handleRequest() call - UserContext.current().initContext( AWSAccessKey, info.getSecretKey(), AWSAccessKey, "S3 DIME request", request ); + + endResponse(response, xml.toString()); + return; + } + + // -> PutObject S3 Bucket Policy would be done in the engine.handleRequest() call + UserContext.current().initContext( AWSAccessKey, info.getSecretKey(), AWSAccessKey, "S3 DIME request", request ); putResponse = engine.handleRequest( putRequest ); - + xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" ); xml.append( "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:tns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" ); xml.append( "<soap:Body>" ); @@ -610,24 +612,24 @@ private S3ObjectAction routePlainPostRequest (HttpServletRequest request) xml.append( "<tns:LastModified>").append( DatatypeConverter.printDateTime(putResponse.getLastModified())).append( "</tns:LastModified>" ); xml.append( "</tns:PutObjectResponse></tns:PutObjectResponse>" ); xml.append( "</soap:Body></soap:Envelope>" ); - - endResponse(response, xml.toString()); + + endResponse(response, xml.toString()); } catch(PermissionDeniedException e) { - logger.error("Unexpected exception " + e.getMessage(), e); - response.setStatus(403); - endResponse(response, "Access denied"); + logger.error("Unexpected exception " + e.getMessage(), e); + response.setStatus(403); + endResponse(response, "Access denied"); } catch(Throwable e) { - logger.error("Unexpected exception " + e.getMessage(), e); + logger.error("Unexpected exception " + e.getMessage(), e); } finally { } } - + /** * Convert the SOAP XML we extract from the DIME message into our local object. * Here Axis2 is not parsing the SOAP for us. I tried to use the Amazon PutObject @@ -637,240 +639,240 @@ private S3ObjectAction routePlainPostRequest (HttpServletRequest request) * @return * @throws Exception */ - public static S3PutObjectRequest toEnginePutObjectRequest( InputStream is ) throws Exception - { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware( true ); - - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse( is ); - Node parent = null; - Node contents = null; - NodeList children = null; - String temp = null; - String element = null; - int count = 0; - - S3PutObjectRequest request = new S3PutObjectRequest(); - - // [A] Pull out the simple nodes first - NodeList part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Bucket" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setBucketName( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Key" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setKey( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "ContentLength" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - { - String length = contents.getFirstChild().getNodeValue(); - if (null != length) request.setContentLength( Long.decode( length )); - } - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "AWSAccessKeyId" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setAccessKey( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Signature" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setSignature( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Timestamp" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setRawTimestamp( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "StorageClass" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setStorageClass( contents.getFirstChild().getNodeValue()); - } - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Credential" ); - if (null != part) - { - if (null != (contents = part.item( 0 ))) - request.setCredential( contents.getFirstChild().getNodeValue()); - } - - - // [B] Get a list of all 'Metadata' elements - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Metadata" ); - if (null != part) - { - count = part.getLength(); - S3MetaDataEntry[] metaEntry = new S3MetaDataEntry[ count ]; - - for( int i=0; i < count; i++ ) - { - parent = part.item(i); - metaEntry[i] = new S3MetaDataEntry(); - - // -> get a list of all the children elements of the 'Metadata' parent element - if (null != (children = parent.getChildNodes())) - { - int numChildren = children.getLength(); - for( int j=0; j < numChildren; j++ ) - { - contents = children.item( j ); - element = contents.getNodeName().trim(); - if ( element.endsWith( "Name" )) - { - temp = contents.getFirstChild().getNodeValue(); - if (null != temp) metaEntry[i].setName( temp ); - } - else if (element.endsWith( "Value" )) - { - temp = contents.getFirstChild().getNodeValue(); - if (null != temp) metaEntry[i].setValue( temp ); - } - } - } - } - request.setMetaEntries( metaEntry ); - } - - // [C] Get a list of all Grant elements in an AccessControlList - part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Grant" ); - if (null != part) - { - S3AccessControlList engineAcl = new S3AccessControlList(); - - count = part.getLength(); + public static S3PutObjectRequest toEnginePutObjectRequest( InputStream is ) throws Exception + { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware( true ); + + DocumentBuilder db = dbf.newDocumentBuilder(); + Document doc = db.parse( is ); + Node parent = null; + Node contents = null; + NodeList children = null; + String temp = null; + String element = null; + int count = 0; + + S3PutObjectRequest request = new S3PutObjectRequest(); + + // [A] Pull out the simple nodes first + NodeList part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Bucket" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setBucketName( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Key" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setKey( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "ContentLength" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + { + String length = contents.getFirstChild().getNodeValue(); + if (null != length) request.setContentLength( Long.decode( length )); + } + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "AWSAccessKeyId" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setAccessKey( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Signature" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setSignature( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Timestamp" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setRawTimestamp( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "StorageClass" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setStorageClass( contents.getFirstChild().getNodeValue()); + } + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Credential" ); + if (null != part) + { + if (null != (contents = part.item( 0 ))) + request.setCredential( contents.getFirstChild().getNodeValue()); + } + + + // [B] Get a list of all 'Metadata' elements + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Metadata" ); + if (null != part) + { + count = part.getLength(); + S3MetaDataEntry[] metaEntry = new S3MetaDataEntry[ count ]; + for( int i=0; i < count; i++ ) { - parent = part.item(i); - S3Grant engineGrant = new S3Grant(); - - // -> get a list of all the children elements of the 'Grant' parent element - if (null != (children = parent.getChildNodes())) - { - int numChildren = children.getLength(); - for( int j=0; j < numChildren; j++ ) - { - contents = children.item( j ); - element = contents.getNodeName().trim(); - if ( element.endsWith( "Grantee" )) - { - NamedNodeMap attbs = contents.getAttributes(); - if (null != attbs) - { - Node type = attbs.getNamedItemNS( "http://www.w3.org/2001/XMLSchema-instance", "type" ); - if ( null != type ) - temp = type.getFirstChild().getNodeValue().trim(); - else temp = null; - - if ( null != temp && temp.equalsIgnoreCase( "CanonicalUser" )) - { - engineGrant.setGrantee(SAcl.GRANTEE_USER); - engineGrant.setCanonicalUserID( getChildNodeValue( contents, "ID" )); - } - else throw new UnsupportedOperationException( "Missing http://www.w3.org/2001/XMLSchema-instance:type value" ); - } - } - else if (element.endsWith( "Permission" )) - { - temp = contents.getFirstChild().getNodeValue().trim(); - if (temp.equalsIgnoreCase("READ" )) engineGrant.setPermission(SAcl.PERMISSION_READ); - else if (temp.equalsIgnoreCase("WRITE" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE); - else if (temp.equalsIgnoreCase("READ_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_READ_ACL); - else if (temp.equalsIgnoreCase("WRITE_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE_ACL); - else if (temp.equalsIgnoreCase("FULL_CONTROL")) engineGrant.setPermission(SAcl.PERMISSION_FULL); - else throw new UnsupportedOperationException( "Unsupported permission: " + temp ); - } - } - engineAcl.addGrant( engineGrant ); - } + parent = part.item(i); + metaEntry[i] = new S3MetaDataEntry(); + + // -> get a list of all the children elements of the 'Metadata' parent element + if (null != (children = parent.getChildNodes())) + { + int numChildren = children.getLength(); + for( int j=0; j < numChildren; j++ ) + { + contents = children.item( j ); + element = contents.getNodeName().trim(); + if ( element.endsWith( "Name" )) + { + temp = contents.getFirstChild().getNodeValue(); + if (null != temp) metaEntry[i].setName( temp ); + } + else if (element.endsWith( "Value" )) + { + temp = contents.getFirstChild().getNodeValue(); + if (null != temp) metaEntry[i].setValue( temp ); + } + } + } + } + request.setMetaEntries( metaEntry ); + } + + // [C] Get a list of all Grant elements in an AccessControlList + part = getElement( doc, "http://s3.amazonaws.com/doc/2006-03-01/", "Grant" ); + if (null != part) + { + S3AccessControlList engineAcl = new S3AccessControlList(); + + count = part.getLength(); + for( int i=0; i < count; i++ ) + { + parent = part.item(i); + S3Grant engineGrant = new S3Grant(); + + // -> get a list of all the children elements of the 'Grant' parent element + if (null != (children = parent.getChildNodes())) + { + int numChildren = children.getLength(); + for( int j=0; j < numChildren; j++ ) + { + contents = children.item( j ); + element = contents.getNodeName().trim(); + if ( element.endsWith( "Grantee" )) + { + NamedNodeMap attbs = contents.getAttributes(); + if (null != attbs) + { + Node type = attbs.getNamedItemNS( "http://www.w3.org/2001/XMLSchema-instance", "type" ); + if ( null != type ) + temp = type.getFirstChild().getNodeValue().trim(); + else temp = null; + + if ( null != temp && temp.equalsIgnoreCase( "CanonicalUser" )) + { + engineGrant.setGrantee(SAcl.GRANTEE_USER); + engineGrant.setCanonicalUserID( getChildNodeValue( contents, "ID" )); + } + else throw new UnsupportedOperationException( "Missing http://www.w3.org/2001/XMLSchema-instance:type value" ); + } + } + else if (element.endsWith( "Permission" )) + { + temp = contents.getFirstChild().getNodeValue().trim(); + if (temp.equalsIgnoreCase("READ" )) engineGrant.setPermission(SAcl.PERMISSION_READ); + else if (temp.equalsIgnoreCase("WRITE" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE); + else if (temp.equalsIgnoreCase("READ_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_READ_ACL); + else if (temp.equalsIgnoreCase("WRITE_ACP" )) engineGrant.setPermission(SAcl.PERMISSION_WRITE_ACL); + else if (temp.equalsIgnoreCase("FULL_CONTROL")) engineGrant.setPermission(SAcl.PERMISSION_FULL); + else throw new UnsupportedOperationException( "Unsupported permission: " + temp ); + } + } + engineAcl.addGrant( engineGrant ); + } + } + request.setAcl( engineAcl ); + } + return request; + } + + /** + * Have to deal with XML with and without namespaces. + */ + public static NodeList getElement( Document doc, String namespace, String tagName ) + { + NodeList part = doc.getElementsByTagNameNS( namespace, tagName ); + if (null == part || 0 == part.getLength()) part = doc.getElementsByTagName( tagName ); + + return part; + } + + /** + * Looking for the value of a specific child of the given parent node. + * + * @param parent + * @param childName + * @return + */ + private static String getChildNodeValue( Node parent, String childName ) + { + NodeList children = null; + Node element = null; + + if (null != (children = parent.getChildNodes())) + { + int numChildren = children.getLength(); + for( int i=0; i < numChildren; i++ ) + { + if (null != (element = children.item( i ))) + { + // -> name may have a namespace on it + String name = element.getNodeName().trim(); + if ( name.endsWith( childName )) + { + String value = element.getFirstChild().getNodeValue(); + if (null != value) value = value.trim(); + return value; + } + } } - request.setAcl( engineAcl ); - } - return request; - } - - /** - * Have to deal with XML with and without namespaces. - */ - public static NodeList getElement( Document doc, String namespace, String tagName ) - { - NodeList part = doc.getElementsByTagNameNS( namespace, tagName ); - if (null == part || 0 == part.getLength()) part = doc.getElementsByTagName( tagName ); - - return part; - } - - /** - * Looking for the value of a specific child of the given parent node. - * - * @param parent - * @param childName - * @return - */ - private static String getChildNodeValue( Node parent, String childName ) - { - NodeList children = null; - Node element = null; - - if (null != (children = parent.getChildNodes())) - { - int numChildren = children.getLength(); - for( int i=0; i < numChildren; i++ ) - { - if (null != (element = children.item( i ))) - { - // -> name may have a namespace on it - String name = element.getNodeName().trim(); - if ( name.endsWith( childName )) - { - String value = element.getFirstChild().getNodeValue(); - if (null != value) value = value.trim(); - return value; - } - } - } - } - return null; - } - + } + return null; + } + private void logRequest(HttpServletRequest request) { - if(logger.isInfoEnabled()) { - logger.info("Request method: " + request.getMethod()); - logger.info("Request contextPath: " + request.getContextPath()); - logger.info("Request pathInfo: " + request.getPathInfo()); - logger.info("Request pathTranslated: " + request.getPathTranslated()); - logger.info("Request queryString: " + request.getQueryString()); - logger.info("Request requestURI: " + request.getRequestURI()); - logger.info("Request requestURL: " + request.getRequestURL()); - logger.info("Request servletPath: " + request.getServletPath()); - Enumeration headers = request.getHeaderNames(); - if(headers != null) { - while(headers.hasMoreElements()) { - Object headerName = headers.nextElement(); - logger.info("Request header " + headerName + ":" + request.getHeader((String)headerName)); - } - } - - Enumeration params = request.getParameterNames(); - if(params != null) { - while(params.hasMoreElements()) { - Object paramName = params.nextElement(); - logger.info("Request parameter " + paramName + ":" + - request.getParameter((String)paramName)); - } - } - logger.info( "- End of request -" ); - } + if(logger.isInfoEnabled()) { + logger.info("Request method: " + request.getMethod()); + logger.info("Request contextPath: " + request.getContextPath()); + logger.info("Request pathInfo: " + request.getPathInfo()); + logger.info("Request pathTranslated: " + request.getPathTranslated()); + logger.info("Request queryString: " + request.getQueryString()); + logger.info("Request requestURI: " + request.getRequestURI()); + logger.info("Request requestURL: " + request.getRequestURL()); + logger.info("Request servletPath: " + request.getServletPath()); + Enumeration headers = request.getHeaderNames(); + if(headers != null) { + while(headers.hasMoreElements()) { + Object headerName = headers.nextElement(); + logger.info("Request header " + headerName + ":" + request.getHeader((String)headerName)); + } + } + + Enumeration params = request.getParameterNames(); + if(params != null) { + while(params.hasMoreElements()) { + Object paramName = params.nextElement(); + logger.info("Request parameter " + paramName + ":" + + request.getParameter((String)paramName)); + } + } + logger.info( "- End of request -" ); + } } }
