You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ah...@apache.org on 2013/01/10 23:47:20 UTC
[11/25] removed componentlocator and inject
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/f40e7b75/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java
----------------------------------------------------------------------
diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java b/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java
index ee4cec6..89ccf59 100644
--- a/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java
+++ b/awsapi/src/com/cloud/bridge/service/controller/s3/S3ObjectAction.java
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.UUID;
import javax.activation.DataHandler;
+import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
@@ -46,11 +47,9 @@ import com.amazon.s3.GetObjectAccessControlPolicyResponse;
import com.cloud.bridge.io.MTOMAwareResultStreamWriter;
import com.cloud.bridge.model.SAcl;
import com.cloud.bridge.model.SAclVO;
-import com.cloud.bridge.model.SBucket;
import com.cloud.bridge.model.SBucketVO;
import com.cloud.bridge.persist.dao.MultipartLoadDao;
import com.cloud.bridge.persist.dao.SBucketDao;
-import com.cloud.bridge.persist.dao.SBucketDaoImpl;
import com.cloud.bridge.service.S3Constants;
import com.cloud.bridge.service.S3RestServlet;
import com.cloud.bridge.service.UserContext;
@@ -68,1200 +67,1198 @@ import com.cloud.bridge.service.core.s3.S3GetObjectResponse;
import com.cloud.bridge.service.core.s3.S3Grant;
import com.cloud.bridge.service.core.s3.S3MetaDataEntry;
import com.cloud.bridge.service.core.s3.S3MultipartPart;
+import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions;
import com.cloud.bridge.service.core.s3.S3PolicyContext;
import com.cloud.bridge.service.core.s3.S3PutObjectInlineRequest;
import com.cloud.bridge.service.core.s3.S3PutObjectInlineResponse;
-import com.cloud.bridge.service.core.s3.S3PutObjectRequest;
import com.cloud.bridge.service.core.s3.S3Response;
-import com.cloud.bridge.service.core.s3.S3SetBucketAccessControlPolicyRequest;
import com.cloud.bridge.service.core.s3.S3SetObjectAccessControlPolicyRequest;
-import com.cloud.bridge.service.core.s3.S3PolicyAction.PolicyActions;
import com.cloud.bridge.service.exception.PermissionDeniedException;
import com.cloud.bridge.util.Converter;
import com.cloud.bridge.util.DateHelper;
import com.cloud.bridge.util.HeaderParam;
-import com.cloud.bridge.util.ServletRequestDataSource;
import com.cloud.bridge.util.OrderedPair;
-import com.cloud.utils.component.ComponentLocator;
+import com.cloud.bridge.util.ServletRequestDataSource;
public class S3ObjectAction implements ServletAction {
protected final static Logger logger = Logger.getLogger(S3ObjectAction.class);
- protected final SBucketDao bucketDao = ComponentLocator.inject(SBucketDaoImpl.class);
+ @Inject SBucketDao bucketDao;
private DocumentBuilderFactory dbf = null;
-
- public S3ObjectAction() {
- dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware( true );
-
- }
-
- public void execute(HttpServletRequest request, HttpServletResponse response)
- throws IOException, XMLStreamException
- {
- String method = request.getMethod();
- String queryString = request.getQueryString();
- String copy = null;
-
- response.addHeader( "x-amz-request-id", UUID.randomUUID().toString());
-
- if ( method.equalsIgnoreCase( "GET" ))
- {
- if ( queryString != null && queryString.length() > 0 )
- {
- if (queryString.contains("acl")) executeGetObjectAcl(request, response);
- else if (queryString.contains("uploadId")) executeListUploadParts(request, response);
- else executeGetObject(request, response);
- }
- else executeGetObject(request, response);
- }
- else if (method.equalsIgnoreCase( "PUT" ))
- {
- if ( queryString != null && queryString.length() > 0 )
- {
- if (queryString.contains("acl")) executePutObjectAcl(request, response);
- else if (queryString.contains("partNumber")) executeUploadPart(request, response);
- else executePutObject(request, response);
- }
- else if ( null != (copy = request.getHeader( "x-amz-copy-source" )))
- {
- executeCopyObject(request, response, copy.trim());
- }
- else executePutObject(request, response);
- }
- else if (method.equalsIgnoreCase( "DELETE" ))
- {
- if ( queryString != null && queryString.length() > 0 )
- {
- if (queryString.contains("uploadId")) executeAbortMultipartUpload(request, response);
- else executeDeleteObject(request, response);
- }
- else executeDeleteObject(request, response);
- }
- else if (method.equalsIgnoreCase( "HEAD" ))
- {
- executeHeadObject(request, response);
- }
- else if (method.equalsIgnoreCase( "POST" ))
- {
- if ( queryString != null && queryString.length() > 0 )
- {
- if (queryString.contains("uploads")) executeInitiateMultipartUpload(request, response);
- else if (queryString.contains("uploadId")) executeCompleteMultipartUpload(request, response);
- }
- else if ( request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY) !=null )
- executePlainPostObject (request, response);
- // TODO - Having implemented the request, now provide an informative HTML page response
- else
- executePostObject(request, response);
- }
- else throw new IllegalArgumentException( "Unsupported method in REST request");
- }
-
-
- private void executeCopyObject(HttpServletRequest request, HttpServletResponse response, String copy)
- throws IOException, XMLStreamException
- {
+
+ public S3ObjectAction() {
+ dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware( true );
+
+ }
+
+ @Override
+ public void execute(HttpServletRequest request, HttpServletResponse response)
+ throws IOException, XMLStreamException
+ {
+ String method = request.getMethod();
+ String queryString = request.getQueryString();
+ String copy = null;
+
+ response.addHeader( "x-amz-request-id", UUID.randomUUID().toString());
+
+ if ( method.equalsIgnoreCase( "GET" ))
+ {
+ if ( queryString != null && queryString.length() > 0 )
+ {
+ if (queryString.contains("acl")) executeGetObjectAcl(request, response);
+ else if (queryString.contains("uploadId")) executeListUploadParts(request, response);
+ else executeGetObject(request, response);
+ }
+ else executeGetObject(request, response);
+ }
+ else if (method.equalsIgnoreCase( "PUT" ))
+ {
+ if ( queryString != null && queryString.length() > 0 )
+ {
+ if (queryString.contains("acl")) executePutObjectAcl(request, response);
+ else if (queryString.contains("partNumber")) executeUploadPart(request, response);
+ else executePutObject(request, response);
+ }
+ else if ( null != (copy = request.getHeader( "x-amz-copy-source" )))
+ {
+ executeCopyObject(request, response, copy.trim());
+ }
+ else executePutObject(request, response);
+ }
+ else if (method.equalsIgnoreCase( "DELETE" ))
+ {
+ if ( queryString != null && queryString.length() > 0 )
+ {
+ if (queryString.contains("uploadId")) executeAbortMultipartUpload(request, response);
+ else executeDeleteObject(request, response);
+ }
+ else executeDeleteObject(request, response);
+ }
+ else if (method.equalsIgnoreCase( "HEAD" ))
+ {
+ executeHeadObject(request, response);
+ }
+ else if (method.equalsIgnoreCase( "POST" ))
+ {
+ if ( queryString != null && queryString.length() > 0 )
+ {
+ if (queryString.contains("uploads")) executeInitiateMultipartUpload(request, response);
+ else if (queryString.contains("uploadId")) executeCompleteMultipartUpload(request, response);
+ }
+ else if ( request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY) !=null )
+ executePlainPostObject (request, response);
+ // TODO - Having implemented the request, now provide an informative HTML page response
+ else
+ executePostObject(request, response);
+ }
+ else throw new IllegalArgumentException( "Unsupported method in REST request");
+ }
+
+
+ private void executeCopyObject(HttpServletRequest request, HttpServletResponse response, String copy)
+ throws IOException, XMLStreamException
+ {
S3CopyObjectRequest engineRequest = new S3CopyObjectRequest();
String versionId = null;
-
- String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- String sourceBucketName = null;
- String sourceKey = null;
-
- // [A] Parse the x-amz-copy-source header into usable pieces
- // Check to find a ?versionId= value if any
- int index = copy.indexOf( '?' );
- if (-1 != index)
- {
- versionId = copy.substring( index+1 );
- if (versionId.startsWith( "versionId=" )) engineRequest.setVersion( versionId.substring( 10 ));
- copy = copy.substring( 0, index );
- }
-
- // The value of copy should look like: "bucket-name/object-name"
- index = copy.indexOf( '/' );
-
- // In case it looks like "/bucket-name/object-name" discard a leading '/' if it exists
- if ( 0 == index )
- {
- copy = copy.substring(1);
- index = copy.indexOf( '/' );
- }
-
- if ( -1 == index )
- throw new IllegalArgumentException( "Invalid x-amz-copy-source header value [" + copy + "]" );
-
- sourceBucketName = copy.substring( 0, index );
- sourceKey = copy.substring( index+1 );
-
-
- // [B] Set the object used in the SOAP request so it can do the bulk of the work for us
+
+ String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ String sourceBucketName = null;
+ String sourceKey = null;
+
+ // [A] Parse the x-amz-copy-source header into usable pieces
+ // Check to find a ?versionId= value if any
+ int index = copy.indexOf( '?' );
+ if (-1 != index)
+ {
+ versionId = copy.substring( index+1 );
+ if (versionId.startsWith( "versionId=" )) engineRequest.setVersion( versionId.substring( 10 ));
+ copy = copy.substring( 0, index );
+ }
+
+ // The value of copy should look like: "bucket-name/object-name"
+ index = copy.indexOf( '/' );
+
+ // In case it looks like "/bucket-name/object-name" discard a leading '/' if it exists
+ if ( 0 == index )
+ {
+ copy = copy.substring(1);
+ index = copy.indexOf( '/' );
+ }
+
+ if ( -1 == index )
+ throw new IllegalArgumentException( "Invalid x-amz-copy-source header value [" + copy + "]" );
+
+ sourceBucketName = copy.substring( 0, index );
+ sourceKey = copy.substring( index+1 );
+
+
+ // [B] Set the object used in the SOAP request so it can do the bulk of the work for us
engineRequest.setSourceBucketName( sourceBucketName );
engineRequest.setSourceKey( sourceKey );
engineRequest.setDestinationBucketName( bucketName );
engineRequest.setDestinationKey( key );
-
+
engineRequest.setDataDirective( request.getHeader( "x-amz-metadata-directive" ));
- engineRequest.setMetaEntries( extractMetaData( request ));
- engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
- engineRequest.setConditions( conditionalRequest( request, true ));
-
-
- // [C] Do the actual work and return the result
- S3CopyObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
-
+ engineRequest.setMetaEntries( extractMetaData( request ));
+ engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
+ engineRequest.setConditions( conditionalRequest( request, true ));
+
+
+ // [C] Do the actual work and return the result
+ S3CopyObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
+
versionId = engineResponse.getCopyVersion();
if (null != versionId) response.addHeader( "x-amz-copy-source-version-id", versionId );
versionId = engineResponse.getPutVersion();
if (null != versionId) response.addHeader( "x-amz-version-id", versionId );
-
- // To allow the copy object result to be serialized via Axiom classes
- CopyObjectResponse allBuckets = S3SerializableServiceImplementation.toCopyObjectResponse( engineResponse );
-
- OutputStream outputStream = response.getOutputStream();
- response.setStatus(200);
- response.setContentType("application/xml");
- // The content-type literally should be "application/xml; charset=UTF-8"
- // but any compliant JVM supplies utf-8 by default;
-
- MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("CopyObjectResult", outputStream );
- resultWriter.startWrite();
- resultWriter.writeout(allBuckets);
- resultWriter.stopWrite();
-
- }
-
- private void executeGetObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException, XMLStreamException
- {
- String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
-
- S3GetObjectAccessControlPolicyRequest engineRequest = new S3GetObjectAccessControlPolicyRequest();
- engineRequest.setBucketName( bucketName );
- engineRequest.setKey( key );
-
- // -> is this a request for a specific version of the object? look for "versionId=" in the query string
- String queryString = request.getQueryString();
- if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
-
- S3AccessControlPolicy engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
- int resultCode = engineResponse.getResultCode();
- if (200 != resultCode) {
- response.setStatus( resultCode );
- return;
- }
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
-
-
- // To allow the get object acl policy result to be serialized via Axiom classes
- GetObjectAccessControlPolicyResponse onePolicy = S3SerializableServiceImplementation.toGetObjectAccessControlPolicyResponse( engineResponse );
-
- OutputStream outputStream = response.getOutputStream();
- response.setStatus(200);
- response.setContentType("application/xml");
- // The content-type literally should be "application/xml; charset=UTF-8"
- // but any compliant JVM supplies utf-8 by default;
-
- MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("GetObjectAccessControlPolicyResult", outputStream );
- resultWriter.startWrite();
- resultWriter.writeout(onePolicy);
- resultWriter.stopWrite();
- }
-
- private void executePutObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- // [A] Determine that there is an applicable bucket which might have an ACL set
-
- String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
-
- SBucketVO bucket = bucketDao.getByName( bucketName );
- String owner = null;
+
+ // To allow the copy object result to be serialized via Axiom classes
+ CopyObjectResponse allBuckets = S3SerializableServiceImplementation.toCopyObjectResponse( engineResponse );
+
+ OutputStream outputStream = response.getOutputStream();
+ response.setStatus(200);
+ response.setContentType("application/xml");
+ // The content-type literally should be "application/xml; charset=UTF-8"
+ // but any compliant JVM supplies utf-8 by default;
+
+ MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("CopyObjectResult", outputStream );
+ resultWriter.startWrite();
+ resultWriter.writeout(allBuckets);
+ resultWriter.stopWrite();
+
+ }
+
+ private void executeGetObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException, XMLStreamException
+ {
+ String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+
+ S3GetObjectAccessControlPolicyRequest engineRequest = new S3GetObjectAccessControlPolicyRequest();
+ engineRequest.setBucketName( bucketName );
+ engineRequest.setKey( key );
+
+ // -> is this a request for a specific version of the object? look for "versionId=" in the query string
+ String queryString = request.getQueryString();
+ if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
+
+ S3AccessControlPolicy engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
+ int resultCode = engineResponse.getResultCode();
+ if (200 != resultCode) {
+ response.setStatus( resultCode );
+ return;
+ }
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+
+
+ // To allow the get object acl policy result to be serialized via Axiom classes
+ GetObjectAccessControlPolicyResponse onePolicy = S3SerializableServiceImplementation.toGetObjectAccessControlPolicyResponse( engineResponse );
+
+ OutputStream outputStream = response.getOutputStream();
+ response.setStatus(200);
+ response.setContentType("application/xml");
+ // The content-type literally should be "application/xml; charset=UTF-8"
+ // but any compliant JVM supplies utf-8 by default;
+
+ MTOMAwareResultStreamWriter resultWriter = new MTOMAwareResultStreamWriter ("GetObjectAccessControlPolicyResult", outputStream );
+ resultWriter.startWrite();
+ resultWriter.writeout(onePolicy);
+ resultWriter.stopWrite();
+ }
+
+ private void executePutObjectAcl(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ // [A] Determine that there is an applicable bucket which might have an ACL set
+
+ String bucketName = (String)request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String)request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+
+ SBucketVO bucket = bucketDao.getByName( bucketName );
+ String owner = null;
if ( null != bucket )
- owner = bucket.getOwnerCanonicalId();
+ owner = bucket.getOwnerCanonicalId();
if (null == owner)
- {
- logger.error( "ACL update failed since " + bucketName + " does not exist" );
- throw new IOException("ACL update failed");
- }
+ {
+ logger.error( "ACL update failed since " + bucketName + " does not exist" );
+ throw new IOException("ACL update failed");
+ }
if (null == key)
- {
- logger.error( "ACL update failed since " + bucketName + " does not contain the expected key" );
- throw new IOException("ACL update failed");
- }
-
- // [B] Obtain the grant request which applies to the acl request string. This latter is supplied as the value of the x-amz-acl header.
-
- S3SetObjectAccessControlPolicyRequest engineRequest = new S3SetObjectAccessControlPolicyRequest();
- S3Grant grantRequest = new S3Grant();
- S3AccessControlList aclRequest = new S3AccessControlList();
-
- String aclRequestString = request.getHeader("x-amz-acl");
- OrderedPair <Integer,Integer> accessControlsForObjectOwner = SAclVO.getCannedAccessControls(aclRequestString,"SObject");
- grantRequest.setPermission(accessControlsForObjectOwner.getFirst());
- grantRequest.setGrantee(accessControlsForObjectOwner.getSecond());
- grantRequest.setCanonicalUserID(owner);
- aclRequest.addGrant(grantRequest);
- engineRequest.setAcl(aclRequest);
- engineRequest.setBucketName(bucketName);
- engineRequest.setKey(key);
-
-
- // [C] Allow an S3Engine to handle the S3SetObjectAccessControlPolicyRequest
- S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
- response.setStatus( engineResponse.getResultCode());
-
- }
-
- private void executeGetObject(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
-
-
- S3GetObjectRequest engineRequest = new S3GetObjectRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setInlineData(true);
- engineRequest.setReturnData(true);
- //engineRequest.setReturnMetadata(true);
- engineRequest = setRequestByteRange( request, engineRequest );
-
- // -> is this a request for a specific version of the object? look for "versionId=" in the query string
- String queryString = request.getQueryString();
- if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
-
- S3GetObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
- response.setStatus( engineResponse.getResultCode());
-
- if (engineResponse.getResultCode() >=400 ) {
- return;
- }
- String deleteMarker = engineResponse.getDeleteMarker();
- if ( null != deleteMarker ) {
- response.addHeader( "x-amz-delete-marker", "true" );
- response.addHeader( "x-amz-version-id", deleteMarker );
- }
- else {
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
- // -> was the get conditional?
- if (!conditionPassed( request, response, engineResponse.getLastModified().getTime(), engineResponse.getETag()))
- return;
-
-
- // -> is there data to return
- // -> from the Amazon REST documentation it appears that Meta data is only returned as part of a HEAD request
- //returnMetaData( engineResponse, response );
-
- DataHandler dataHandler = engineResponse.getData();
- if (dataHandler != null) {
- response.addHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- response.addHeader("Last-Modified", DateHelper.getDateDisplayString(
- DateHelper.GMT_TIMEZONE, engineResponse.getLastModified().getTime(), "E, d MMM yyyy HH:mm:ss z"));
-
- response.setContentLength((int)engineResponse.getContentLength());
- S3RestServlet.writeResponse(response, dataHandler.getInputStream());
- }
- }
-
- private void executePutObject(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- String continueHeader = request.getHeader( "Expect" );
- if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
- S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
- }
-
- long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
-
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setContentLength(contentLength);
- engineRequest.setMetaEntries( extractMetaData( request ));
- engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
-
- DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
- engineRequest.setData(dataHandler);
-
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
- response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
- /**
- * Once versioining is turned on then to delete an object requires specifying a version
- * parameter. A deletion marker is set once versioning is turned on in a bucket.
- */
- private void executeDeleteObject(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
-
- S3DeleteObjectRequest engineRequest = new S3DeleteObjectRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
-
- // -> is this a request for a specific version of the object? look for "versionId=" in the query string
- String queryString = request.getQueryString();
- if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
-
- S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
-
- response.setStatus( engineResponse.getResultCode());
- String version = engineRequest.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
- /*
- * The purpose of a plain POST operation is to add an object to a specified bucket using HTML forms.
- * The capability is for developer and tester convenience providing a simple browser-based upload
- * feature as an alternative to using PUTs.
- * In the case of PUTs the upload information is passed through HTTP headers. However in the case of a
- * POST this information must be supplied as form fields. Many of these are mandatory or otherwise
- * the POST request will be rejected.
- * The requester using the HTML page must submit valid credentials sufficient for checking that
- * the bucket to which the object is to be added has WRITE permission for that user. The AWS access
- * key field on the form is taken to be synonymous with the user canonical ID for this purpose.
- */
- private void executePlainPostObject(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- String continueHeader = request.getHeader( "Expect" );
- if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
- S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
- }
-
- long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
-
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- String accessKey = (String) request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY);
- String signature = (String) request.getAttribute(S3Constants.PLAIN_POST_SIGNATURE);
- S3Grant grant = new S3Grant();
- grant.setCanonicalUserID(accessKey);
- grant.setGrantee(SAcl.GRANTEE_USER);
- grant.setPermission(SAcl.PERMISSION_FULL);
- S3AccessControlList acl = new S3AccessControlList();
- acl.addGrant(grant);
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setAcl(acl);
- engineRequest.setContentLength(contentLength);
- engineRequest.setMetaEntries( extractMetaData( request ));
- engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
-
- DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
- engineRequest.setData(dataHandler);
-
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
- response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
-
- private void executeHeadObject(HttpServletRequest request, HttpServletResponse response) throws IOException
- {
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
-
- S3GetObjectRequest engineRequest = new S3GetObjectRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setInlineData(true); // -> need to set so we get ETag etc returned
- engineRequest.setReturnData(true);
- engineRequest.setReturnMetadata(true);
- engineRequest = setRequestByteRange( request, engineRequest );
-
- // -> is this a request for a specific version of the object? look for "versionId=" in the query string
- String queryString = request.getQueryString();
- if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
-
- S3GetObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
- response.setStatus( engineResponse.getResultCode());
-
- //bucket lookup for non-existance key
-
- if ( engineResponse.getResultCode() == 404 )
- return;
-
- String deleteMarker = engineResponse.getDeleteMarker();
- if ( null != deleteMarker ) {
- response.addHeader( "x-amz-delete-marker", "true" );
- response.addHeader( "x-amz-version-id", deleteMarker );
- }
- else {
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
- // -> was the head request conditional?
- if (!conditionPassed( request, response, engineResponse.getLastModified().getTime(), engineResponse.getETag()))
- return;
-
-
- // -> for a head request we return everything except the data
- returnMetaData( engineResponse, response );
-
- DataHandler dataHandler = engineResponse.getData();
- if (dataHandler != null) {
- response.addHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- response.addHeader("Last-Modified", DateHelper.getDateDisplayString(
- DateHelper.GMT_TIMEZONE, engineResponse.getLastModified().getTime(), "E, d MMM yyyy HH:mm:ss z"));
-
- response.setContentLength((int)engineResponse.getContentLength());
- }
- }
-
- // There is a problem with POST since the 'Signature' and 'AccessKey' parameters are not
- // determined until we hit this function (i.e., they are encoded in the body of the message
- // they are not HTTP request headers). All the values we used to get in the request headers
- // are not encoded in the request body.
+ {
+ logger.error( "ACL update failed since " + bucketName + " does not contain the expected key" );
+ throw new IOException("ACL update failed");
+ }
+
+ // [B] Obtain the grant request which applies to the acl request string. This latter is supplied as the value of the x-amz-acl header.
+
+ S3SetObjectAccessControlPolicyRequest engineRequest = new S3SetObjectAccessControlPolicyRequest();
+ S3Grant grantRequest = new S3Grant();
+ S3AccessControlList aclRequest = new S3AccessControlList();
+
+ String aclRequestString = request.getHeader("x-amz-acl");
+ OrderedPair <Integer,Integer> accessControlsForObjectOwner = SAclVO.getCannedAccessControls(aclRequestString,"SObject");
+ grantRequest.setPermission(accessControlsForObjectOwner.getFirst());
+ grantRequest.setGrantee(accessControlsForObjectOwner.getSecond());
+ grantRequest.setCanonicalUserID(owner);
+ aclRequest.addGrant(grantRequest);
+ engineRequest.setAcl(aclRequest);
+ engineRequest.setBucketName(bucketName);
+ engineRequest.setKey(key);
+
+
+ // [C] Allow an S3Engine to handle the S3SetObjectAccessControlPolicyRequest
+ S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
+ response.setStatus( engineResponse.getResultCode());
+
+ }
+
+ private void executeGetObject(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+
+
+ S3GetObjectRequest engineRequest = new S3GetObjectRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setInlineData(true);
+ engineRequest.setReturnData(true);
+ //engineRequest.setReturnMetadata(true);
+ engineRequest = setRequestByteRange( request, engineRequest );
+
+ // -> is this a request for a specific version of the object? look for "versionId=" in the query string
+ String queryString = request.getQueryString();
+ if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
+
+ S3GetObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
+ response.setStatus( engineResponse.getResultCode());
+
+ if (engineResponse.getResultCode() >=400 ) {
+ return;
+ }
+ String deleteMarker = engineResponse.getDeleteMarker();
+ if ( null != deleteMarker ) {
+ response.addHeader( "x-amz-delete-marker", "true" );
+ response.addHeader( "x-amz-version-id", deleteMarker );
+ }
+ else {
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+ // -> was the get conditional?
+ if (!conditionPassed( request, response, engineResponse.getLastModified().getTime(), engineResponse.getETag()))
+ return;
+
+
+ // -> is there data to return
+ // -> from the Amazon REST documentation it appears that Meta data is only returned as part of a HEAD request
+ //returnMetaData( engineResponse, response );
+
+ DataHandler dataHandler = engineResponse.getData();
+ if (dataHandler != null) {
+ response.addHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ response.addHeader("Last-Modified", DateHelper.getDateDisplayString(
+ DateHelper.GMT_TIMEZONE, engineResponse.getLastModified().getTime(), "E, d MMM yyyy HH:mm:ss z"));
+
+ response.setContentLength((int)engineResponse.getContentLength());
+ S3RestServlet.writeResponse(response, dataHandler.getInputStream());
+ }
+ }
+
+ private void executePutObject(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String continueHeader = request.getHeader( "Expect" );
+ if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
+ S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
+ }
+
+ long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
+
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setContentLength(contentLength);
+ engineRequest.setMetaEntries( extractMetaData( request ));
+ engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
+
+ DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
+ engineRequest.setData(dataHandler);
+
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
+ response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+ /**
+ * Once versioining is turned on then to delete an object requires specifying a version
+ * parameter. A deletion marker is set once versioning is turned on in a bucket.
+ */
+ private void executeDeleteObject(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+
+ S3DeleteObjectRequest engineRequest = new S3DeleteObjectRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+
+ // -> is this a request for a specific version of the object? look for "versionId=" in the query string
+ String queryString = request.getQueryString();
+ if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
+
+ S3Response engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
+
+ response.setStatus( engineResponse.getResultCode());
+ String version = engineRequest.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+ /*
+ * The purpose of a plain POST operation is to add an object to a specified bucket using HTML forms.
+ * The capability is for developer and tester convenience providing a simple browser-based upload
+ * feature as an alternative to using PUTs.
+ * In the case of PUTs the upload information is passed through HTTP headers. However in the case of a
+ * POST this information must be supplied as form fields. Many of these are mandatory or otherwise
+ * the POST request will be rejected.
+ * The requester using the HTML page must submit valid credentials sufficient for checking that
+ * the bucket to which the object is to be added has WRITE permission for that user. The AWS access
+ * key field on the form is taken to be synonymous with the user canonical ID for this purpose.
+ */
+ private void executePlainPostObject(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String continueHeader = request.getHeader( "Expect" );
+ if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
+ S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
+ }
+
+ long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
+
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ String accessKey = (String) request.getAttribute(S3Constants.PLAIN_POST_ACCESS_KEY);
+ String signature = (String) request.getAttribute(S3Constants.PLAIN_POST_SIGNATURE);
+ S3Grant grant = new S3Grant();
+ grant.setCanonicalUserID(accessKey);
+ grant.setGrantee(SAcl.GRANTEE_USER);
+ grant.setPermission(SAcl.PERMISSION_FULL);
+ S3AccessControlList acl = new S3AccessControlList();
+ acl.addGrant(grant);
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setAcl(acl);
+ engineRequest.setContentLength(contentLength);
+ engineRequest.setMetaEntries( extractMetaData( request ));
+ engineRequest.setCannedAccess( request.getHeader( "x-amz-acl" ));
+
+ DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
+ engineRequest.setData(dataHandler);
+
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest(engineRequest);
+ response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+
+ private void executeHeadObject(HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+
+ S3GetObjectRequest engineRequest = new S3GetObjectRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setInlineData(true); // -> need to set so we get ETag etc returned
+ engineRequest.setReturnData(true);
+ engineRequest.setReturnMetadata(true);
+ engineRequest = setRequestByteRange( request, engineRequest );
+
+ // -> is this a request for a specific version of the object? look for "versionId=" in the query string
+ String queryString = request.getQueryString();
+ if (null != queryString) engineRequest.setVersion( returnParameter( queryString, "versionId=" ));
+
+ S3GetObjectResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
+ response.setStatus( engineResponse.getResultCode());
+
+ //bucket lookup for non-existance key
+
+ if ( engineResponse.getResultCode() == 404 )
+ return;
+
+ String deleteMarker = engineResponse.getDeleteMarker();
+ if ( null != deleteMarker ) {
+ response.addHeader( "x-amz-delete-marker", "true" );
+ response.addHeader( "x-amz-version-id", deleteMarker );
+ }
+ else {
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+ // -> was the head request conditional?
+ if (!conditionPassed( request, response, engineResponse.getLastModified().getTime(), engineResponse.getETag()))
+ return;
+
+
+ // -> for a head request we return everything except the data
+ returnMetaData( engineResponse, response );
+
+ DataHandler dataHandler = engineResponse.getData();
+ if (dataHandler != null) {
+ response.addHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ response.addHeader("Last-Modified", DateHelper.getDateDisplayString(
+ DateHelper.GMT_TIMEZONE, engineResponse.getLastModified().getTime(), "E, d MMM yyyy HH:mm:ss z"));
+
+ response.setContentLength((int)engineResponse.getContentLength());
+ }
+ }
+
+ // There is a problem with POST since the 'Signature' and 'AccessKey' parameters are not
+ // determined until we hit this function (i.e., they are encoded in the body of the message
+ // they are not HTTP request headers). All the values we used to get in the request headers
+ // are not encoded in the request body.
+ //
+ // add ETag header computed as Base64 MD5 whenever object is uploaded or updated
//
- // add ETag header computed as Base64 MD5 whenever object is uploaded or updated
- //
- private void executePostObject( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String contentType = request.getHeader( "Content-Type" );
- int boundaryIndex = contentType.indexOf( "boundary=" );
- String boundary = "--" + (contentType.substring( boundaryIndex + 9 ));
- String lastBoundary = boundary + "--";
-
- InputStreamReader isr = new InputStreamReader( request.getInputStream());
- BufferedReader br = new BufferedReader( isr );
-
- StringBuffer temp = new StringBuffer();
- String oneLine = null;
- String name = null;
- String value = null;
- String metaName = null; // -> after stripped off the x-amz-meta-
- boolean isMetaTag = false;
- int countMeta = 0;
- int state = 0;
-
- // [A] First parse all the parts out of the POST request and message body
- // -> bucket name is still encoded in a Host header
- S3AuthParams params = new S3AuthParams();
- List<S3MetaDataEntry> metaSet = new ArrayList<S3MetaDataEntry>();
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName( bucket );
-
- // -> the last body part contains the content that is used to write the S3 object, all
- // other body parts are header values
- while( null != (oneLine = br.readLine()))
- {
- if ( oneLine.startsWith( lastBoundary ))
- {
- // -> this is the data of the object to put
- if (0 < temp.length())
- {
- value = temp.toString();
- temp.setLength( 0 );
-
- engineRequest.setContentLength( value.length());
- engineRequest.setDataAsString( value );
- }
- break;
- }
- else if ( oneLine.startsWith( boundary ))
- {
- // -> this is the header data
- if (0 < temp.length())
- {
- value = temp.toString().trim();
- temp.setLength( 0 );
- //System.out.println( "param: " + name + " = " + value );
-
- if (name.equalsIgnoreCase( "key" )) {
- engineRequest.setKey( value );
- }
- else if (name.equalsIgnoreCase( "x-amz-acl" )) {
- engineRequest.setCannedAccess( value );
- }
- else if (isMetaTag) {
- S3MetaDataEntry oneMeta = new S3MetaDataEntry();
- oneMeta.setName( metaName );
- oneMeta.setValue( value );
- metaSet.add( oneMeta );
- countMeta++;
- metaName = null;
- }
-
- // -> build up the headers so we can do authentication on this POST
- HeaderParam oneHeader = new HeaderParam();
- oneHeader.setName( name );
- oneHeader.setValue( value );
- params.addHeader( oneHeader );
- }
- state = 1;
- }
- else if (1 == state && 0 == oneLine.length())
- {
- // -> data of a body part starts here
- state = 2;
- }
- else if (1 == state)
- {
- // -> the name of the 'name-value' pair is encoded in the Content-Disposition header
- if (oneLine.startsWith( "Content-Disposition: form-data;"))
- {
- isMetaTag = false;
- int nameOffset = oneLine.indexOf( "name=" );
- if (-1 != nameOffset)
- {
- name = oneLine.substring( nameOffset+5 );
- if (name.startsWith( "\"" )) name = name.substring( 1 );
- if (name.endsWith( "\"" )) name = name.substring( 0, name.length()-1 );
- name = name.trim();
-
- if (name.startsWith( "x-amz-meta-" )) {
- metaName = name.substring( 11 );
- isMetaTag = true;
- }
- }
- }
- }
- else if (2 == state)
- {
- // -> the body parts data may take up multiple lines
- //System.out.println( oneLine.length() + " body data: " + oneLine );
- temp.append( oneLine );
- }
+ private void executePostObject( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String contentType = request.getHeader( "Content-Type" );
+ int boundaryIndex = contentType.indexOf( "boundary=" );
+ String boundary = "--" + (contentType.substring( boundaryIndex + 9 ));
+ String lastBoundary = boundary + "--";
+
+ InputStreamReader isr = new InputStreamReader( request.getInputStream());
+ BufferedReader br = new BufferedReader( isr );
+
+ StringBuffer temp = new StringBuffer();
+ String oneLine = null;
+ String name = null;
+ String value = null;
+ String metaName = null; // -> after stripped off the x-amz-meta-
+ boolean isMetaTag = false;
+ int countMeta = 0;
+ int state = 0;
+
+ // [A] First parse all the parts out of the POST request and message body
+ // -> bucket name is still encoded in a Host header
+ S3AuthParams params = new S3AuthParams();
+ List<S3MetaDataEntry> metaSet = new ArrayList<S3MetaDataEntry>();
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName( bucket );
+
+ // -> the last body part contains the content that is used to write the S3 object, all
+ // other body parts are header values
+ while( null != (oneLine = br.readLine()))
+ {
+ if ( oneLine.startsWith( lastBoundary ))
+ {
+ // -> this is the data of the object to put
+ if (0 < temp.length())
+ {
+ value = temp.toString();
+ temp.setLength( 0 );
+
+ engineRequest.setContentLength( value.length());
+ engineRequest.setDataAsString( value );
+ }
+ break;
+ }
+ else if ( oneLine.startsWith( boundary ))
+ {
+ // -> this is the header data
+ if (0 < temp.length())
+ {
+ value = temp.toString().trim();
+ temp.setLength( 0 );
+ //System.out.println( "param: " + name + " = " + value );
+
+ if (name.equalsIgnoreCase( "key" )) {
+ engineRequest.setKey( value );
+ }
+ else if (name.equalsIgnoreCase( "x-amz-acl" )) {
+ engineRequest.setCannedAccess( value );
+ }
+ else if (isMetaTag) {
+ S3MetaDataEntry oneMeta = new S3MetaDataEntry();
+ oneMeta.setName( metaName );
+ oneMeta.setValue( value );
+ metaSet.add( oneMeta );
+ countMeta++;
+ metaName = null;
+ }
+
+ // -> build up the headers so we can do authentication on this POST
+ HeaderParam oneHeader = new HeaderParam();
+ oneHeader.setName( name );
+ oneHeader.setValue( value );
+ params.addHeader( oneHeader );
+ }
+ state = 1;
+ }
+ else if (1 == state && 0 == oneLine.length())
+ {
+ // -> data of a body part starts here
+ state = 2;
+ }
+ else if (1 == state)
+ {
+ // -> the name of the 'name-value' pair is encoded in the Content-Disposition header
+ if (oneLine.startsWith( "Content-Disposition: form-data;"))
+ {
+ isMetaTag = false;
+ int nameOffset = oneLine.indexOf( "name=" );
+ if (-1 != nameOffset)
+ {
+ name = oneLine.substring( nameOffset+5 );
+ if (name.startsWith( "\"" )) name = name.substring( 1 );
+ if (name.endsWith( "\"" )) name = name.substring( 0, name.length()-1 );
+ name = name.trim();
+
+ if (name.startsWith( "x-amz-meta-" )) {
+ metaName = name.substring( 11 );
+ isMetaTag = true;
+ }
+ }
+ }
+ }
+ else if (2 == state)
+ {
+ // -> the body parts data may take up multiple lines
+ //System.out.println( oneLine.length() + " body data: " + oneLine );
+ temp.append( oneLine );
+ }
// else System.out.println( oneLine.length() + " preamble: " + oneLine );
- }
-
-
- // [B] Authenticate the POST request after we have all the headers
- try {
- S3RestServlet.authenticateRequest( request, params );
- }
- catch( Exception e ) {
- throw new IOException( e.toString());
- }
-
- // [C] Perform the request
+ }
+
+
+ // [B] Authenticate the POST request after we have all the headers
+ try {
+ S3RestServlet.authenticateRequest( request, params );
+ }
+ catch( Exception e ) {
+ throw new IOException( e.toString());
+ }
+
+ // [C] Perform the request
if (0 < countMeta) engineRequest.setMetaEntries( metaSet.toArray(new S3MetaDataEntry[0]));
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
- response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- String version = engineResponse.getVersion();
- if (null != version) response.addHeader( "x-amz-version-id", version );
- }
-
- /**
- * Save all the information about the multipart upload request in the database so once it is finished
- * (in the future) we can create the real S3 object.
- *
- * @throws IOException
- */
- private void executeInitiateMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().handleRequest( engineRequest );
+ response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ String version = engineResponse.getVersion();
+ if (null != version) response.addHeader( "x-amz-version-id", version );
+ }
+
+ /**
+ * Save all the information about the multipart upload request in the database so once it is finished
+ * (in the future) we can create the real S3 object.
+ *
+ * @throws IOException
+ */
+ private void executeInitiateMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
{
- // This request is via a POST which typically has its auth parameters inside the message
- try {
- S3RestServlet.authenticateRequest( request, S3RestServlet.extractRequestHeaders( request ));
- }
- catch( Exception e ) {
- throw new IOException( e.toString());
- }
-
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- String cannedAccess = request.getHeader( "x-amz-acl" );
- S3MetaDataEntry[] meta = extractMetaData( request );
-
+ // This request is via a POST which typically has its auth parameters inside the message
+ try {
+ S3RestServlet.authenticateRequest( request, S3RestServlet.extractRequestHeaders( request ));
+ }
+ catch( Exception e ) {
+ throw new IOException( e.toString());
+ }
+
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ String cannedAccess = request.getHeader( "x-amz-acl" );
+ S3MetaDataEntry[] meta = extractMetaData( request );
+
// -> the S3 engine has easy access to all the privileged checking code
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setCannedAccess( cannedAccess );
- engineRequest.setMetaEntries( meta );
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().initiateMultipartUpload( engineRequest );
- int result = engineResponse.getResultCode();
- response.setStatus( result );
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setCannedAccess( cannedAccess );
+ engineRequest.setMetaEntries( meta );
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().initiateMultipartUpload( engineRequest );
+ int result = engineResponse.getResultCode();
+ response.setStatus( result );
if (200 != result) return;
-
+
// -> there is no SOAP version of this function
- StringBuffer xml = new StringBuffer();
+ StringBuffer xml = new StringBuffer();
xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
xml.append( "<InitiateMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
xml.append( "<Key>" ).append( key ).append( "</Key>" );
xml.append( "<UploadId>" ).append( engineResponse.getUploadId()).append( "</UploadId>" );
xml.append( "</InitiateMultipartUploadResult>" );
-
- response.setContentType("text/xml; charset=UTF-8");
- S3RestServlet.endResponse(response, xml.toString());
- }
-
- private void executeUploadPart( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
- String continueHeader = request.getHeader( "Expect" );
- if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
- S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
- }
-
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- int partNumber = -1;
- int uploadId = -1;
-
- long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
-
- String temp = request.getParameter("uploadId");
- if (null != temp) uploadId = Integer.parseInt( temp );
-
- temp = request.getParameter("partNumber");
- if (null != temp) partNumber = Integer.parseInt( temp );
- if (partNumber < 1 || partNumber > 10000) {
- logger.error("uploadPart invalid part number " + partNumber );
- response.setStatus(416);
+
+ response.setContentType("text/xml; charset=UTF-8");
+ S3RestServlet.endResponse(response, xml.toString());
+ }
+
+ private void executeUploadPart( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ String continueHeader = request.getHeader( "Expect" );
+ if (continueHeader != null && continueHeader.equalsIgnoreCase("100-continue")) {
+ S3RestServlet.writeResponse(response, "HTTP/1.1 100 Continue\r\n");
+ }
+
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ int partNumber = -1;
+ int uploadId = -1;
+
+ long contentLength = Converter.toLong(request.getHeader("Content-Length"), 0);
+
+ String temp = request.getParameter("uploadId");
+ if (null != temp) uploadId = Integer.parseInt( temp );
+
+ temp = request.getParameter("partNumber");
+ if (null != temp) partNumber = Integer.parseInt( temp );
+ if (partNumber < 1 || partNumber > 10000) {
+ logger.error("uploadPart invalid part number " + partNumber );
+ response.setStatus(416);
return;
- }
-
- // -> verification
- try {
- MultipartLoadDao uploadDao = new MultipartLoadDao();
- if (null == uploadDao.multipartExits( uploadId )) {
- response.setStatus(404);
- return;
- }
-
- // -> another requirement is that only the upload initiator can upload parts
- String initiator = uploadDao.getInitiator( uploadId );
- if (null == initiator || !initiator.equals( UserContext.current().getAccessKey())) {
- response.setStatus(403);
- return;
- }
- }
- catch( Exception e ) {
- logger.error("executeUploadPart failed due to " + e.getMessage(), e);
- response.setStatus(500);
- return;
- }
-
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setContentLength(contentLength);
- DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
- engineRequest.setData(dataHandler);
-
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().saveUploadPart( engineRequest, uploadId, partNumber );
- if (null != engineResponse.getETag()) response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
- response.setStatus(engineResponse.getResultCode());
- }
-
- /**
- * This function is required to both parsing XML on the request and return XML as part of its result.
- *
- * @param request
- * @param response
- * @throws IOException
- */
- private void executeCompleteMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
- // [A] This request is via a POST which typically has its auth parameters inside the message
- try {
- S3RestServlet.authenticateRequest( request, S3RestServlet.extractRequestHeaders( request ));
- }
- catch( Exception e ) {
- throw new IOException( e.toString());
- }
-
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- S3MultipartPart[] parts = null;
- S3MetaDataEntry[] meta = null;
- String cannedAccess = null;
- int uploadId = -1;
-
+ }
+
+ // -> verification
+ try {
+ MultipartLoadDao uploadDao = new MultipartLoadDao();
+ if (null == uploadDao.multipartExits( uploadId )) {
+ response.setStatus(404);
+ return;
+ }
+
+ // -> another requirement is that only the upload initiator can upload parts
+ String initiator = uploadDao.getInitiator( uploadId );
+ if (null == initiator || !initiator.equals( UserContext.current().getAccessKey())) {
+ response.setStatus(403);
+ return;
+ }
+ }
+ catch( Exception e ) {
+ logger.error("executeUploadPart failed due to " + e.getMessage(), e);
+ response.setStatus(500);
+ return;
+ }
+
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setContentLength(contentLength);
+ DataHandler dataHandler = new DataHandler(new ServletRequestDataSource(request));
+ engineRequest.setData(dataHandler);
+
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().saveUploadPart( engineRequest, uploadId, partNumber );
+ if (null != engineResponse.getETag()) response.setHeader("ETag", "\"" + engineResponse.getETag() + "\"");
+ response.setStatus(engineResponse.getResultCode());
+ }
+
+ /**
+ * This function is required to both parsing XML on the request and return XML as part of its result.
+ *
+ * @param request
+ * @param response
+ * @throws IOException
+ */
+ private void executeCompleteMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ // [A] This request is via a POST which typically has its auth parameters inside the message
+ try {
+ S3RestServlet.authenticateRequest( request, S3RestServlet.extractRequestHeaders( request ));
+ }
+ catch( Exception e ) {
+ throw new IOException( e.toString());
+ }
+
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ S3MultipartPart[] parts = null;
+ S3MetaDataEntry[] meta = null;
+ String cannedAccess = null;
+ int uploadId = -1;
+
// AWS S3 specifies that the keep alive connection is by sending whitespace characters until done
- // Therefore the XML version prolog is prepended to the stream in advance
+ // Therefore the XML version prolog is prepended to the stream in advance
OutputStream outputStream = response.getOutputStream();
outputStream.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>".getBytes());
- String temp = request.getParameter("uploadId");
- if (null != temp) uploadId = Integer.parseInt( temp );
-
-
- // [B] Look up all the uploaded body parts and related info
- try {
- MultipartLoadDao uploadDao = new MultipartLoadDao();
- if (null == uploadDao.multipartExits( uploadId )) {
- response.setStatus(404);
- returnErrorXML( 404, "NotFound", outputStream );
- return;
- }
-
- // -> another requirement is that only the upload initiator can upload parts
- String initiator = uploadDao.getInitiator( uploadId );
- if (null == initiator || !initiator.equals( UserContext.current().getAccessKey())) {
- response.setStatus(403);
- returnErrorXML( 403, "Forbidden", outputStream );
- return;
- }
-
- parts = uploadDao.getParts( uploadId, 10000, 0 );
- meta = uploadDao.getMeta( uploadId );
- cannedAccess = uploadDao.getCannedAccess( uploadId );
- }
- catch( Exception e ) {
- logger.error("executeCompleteMultipartUpload failed due to " + e.getMessage(), e);
- response.setStatus(500);
- returnErrorXML( 500, "InternalError", outputStream );
- return;
- }
-
-
- // [C] Parse the given XML body part and perform error checking
- OrderedPair<Integer,String> match = verifyParts( request.getInputStream(), parts );
- if (200 != match.getFirst().intValue()) {
- response.setStatus(match.getFirst().intValue());
- returnErrorXML( match.getFirst().intValue(), match.getSecond(), outputStream );
- return;
- }
-
-
- // [D] Ask the engine to create a newly re-constituted object
- S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
- engineRequest.setBucketName(bucket);
- engineRequest.setKey(key);
- engineRequest.setMetaEntries(meta);
- engineRequest.setCannedAccess(cannedAccess);
-
- S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().concatentateMultipartUploads( response, engineRequest, parts, outputStream );
- int result = engineResponse.getResultCode();
- // -> free all multipart state since we now have one concatentated object
- if (200 == result) ServiceProvider.getInstance().getS3Engine().freeUploadParts( bucket, uploadId, false );
-
- // If all successful then clean up all left over parts
- // Notice that "<?xml version=\"1.0\" encoding=\"utf-8\"?>" has already been written into the servlet output stream at the beginning of section [A]
- if ( 200 == result )
- {
- StringBuffer xml = new StringBuffer();
- xml.append( "<CompleteMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
- xml.append( "<Location>" ).append( "http://" + bucket + ".s3.amazonaws.com/" + key ).append( "</Location>" );
- xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
- xml.append( "<Key>" ).append( key ).append( "</Key>" );
- xml.append( "<ETag>\"" ).append( engineResponse.getETag()).append( "\"</ETag>" );
- xml.append( "</CompleteMultipartUploadResult>" );
- String xmlString = xml.toString().replaceAll("^\\s+", ""); // Remove leading whitespace characters
- outputStream.write( xmlString.getBytes());
- outputStream.close();
- }
- else returnErrorXML( result, null, outputStream );
- }
-
- private void executeAbortMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
- String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- int uploadId = -1;
-
- String temp = request.getParameter("uploadId");
- if (null != temp) uploadId = Integer.parseInt( temp );
-
- int result = ServiceProvider.getInstance().getS3Engine().freeUploadParts( bucket, uploadId, true );
+ String temp = request.getParameter("uploadId");
+ if (null != temp) uploadId = Integer.parseInt( temp );
+
+
+ // [B] Look up all the uploaded body parts and related info
+ try {
+ MultipartLoadDao uploadDao = new MultipartLoadDao();
+ if (null == uploadDao.multipartExits( uploadId )) {
+ response.setStatus(404);
+ returnErrorXML( 404, "NotFound", outputStream );
+ return;
+ }
+
+ // -> another requirement is that only the upload initiator can upload parts
+ String initiator = uploadDao.getInitiator( uploadId );
+ if (null == initiator || !initiator.equals( UserContext.current().getAccessKey())) {
+ response.setStatus(403);
+ returnErrorXML( 403, "Forbidden", outputStream );
+ return;
+ }
+
+ parts = uploadDao.getParts( uploadId, 10000, 0 );
+ meta = uploadDao.getMeta( uploadId );
+ cannedAccess = uploadDao.getCannedAccess( uploadId );
+ }
+ catch( Exception e ) {
+ logger.error("executeCompleteMultipartUpload failed due to " + e.getMessage(), e);
+ response.setStatus(500);
+ returnErrorXML( 500, "InternalError", outputStream );
+ return;
+ }
+
+
+ // [C] Parse the given XML body part and perform error checking
+ OrderedPair<Integer,String> match = verifyParts( request.getInputStream(), parts );
+ if (200 != match.getFirst().intValue()) {
+ response.setStatus(match.getFirst().intValue());
+ returnErrorXML( match.getFirst().intValue(), match.getSecond(), outputStream );
+ return;
+ }
+
+
+ // [D] Ask the engine to create a newly re-constituted object
+ S3PutObjectInlineRequest engineRequest = new S3PutObjectInlineRequest();
+ engineRequest.setBucketName(bucket);
+ engineRequest.setKey(key);
+ engineRequest.setMetaEntries(meta);
+ engineRequest.setCannedAccess(cannedAccess);
+
+ S3PutObjectInlineResponse engineResponse = ServiceProvider.getInstance().getS3Engine().concatentateMultipartUploads( response, engineRequest, parts, outputStream );
+ int result = engineResponse.getResultCode();
+ // -> free all multipart state since we now have one concatentated object
+ if (200 == result) ServiceProvider.getInstance().getS3Engine().freeUploadParts( bucket, uploadId, false );
+
+ // If all successful then clean up all left over parts
+ // Notice that "<?xml version=\"1.0\" encoding=\"utf-8\"?>" has already been written into the servlet output stream at the beginning of section [A]
+ if ( 200 == result )
+ {
+ StringBuffer xml = new StringBuffer();
+ xml.append( "<CompleteMultipartUploadResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
+ xml.append( "<Location>" ).append( "http://" + bucket + ".s3.amazonaws.com/" + key ).append( "</Location>" );
+ xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
+ xml.append( "<Key>" ).append( key ).append( "</Key>" );
+ xml.append( "<ETag>\"" ).append( engineResponse.getETag()).append( "\"</ETag>" );
+ xml.append( "</CompleteMultipartUploadResult>" );
+ String xmlString = xml.toString().replaceAll("^\\s+", ""); // Remove leading whitespace characters
+ outputStream.write( xmlString.getBytes());
+ outputStream.close();
+ }
+ else returnErrorXML( result, null, outputStream );
+ }
+
+ private void executeAbortMultipartUpload( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ String bucket = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ int uploadId = -1;
+
+ String temp = request.getParameter("uploadId");
+ if (null != temp) uploadId = Integer.parseInt( temp );
+
+ int result = ServiceProvider.getInstance().getS3Engine().freeUploadParts( bucket, uploadId, true );
response.setStatus( result );
- }
-
- private void executeListUploadParts( HttpServletRequest request, HttpServletResponse response ) throws IOException
- {
- String bucketName = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
- String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
- String owner = null;
- String initiator = null;
- S3MultipartPart[] parts = null;
- int remaining = 0;
- int uploadId = -1;
- int maxParts = 1000;
- int partMarker = 0;
- int nextMarker = 0;
-
- String temp = request.getParameter("uploadId");
- if (null != temp) uploadId = Integer.parseInt( temp );
-
- temp = request.getParameter("max-parts");
- if (null != temp) {
- maxParts = Integer.parseInt( temp );
- if (maxParts > 1000 || maxParts < 0) maxParts = 1000;
- }
-
- temp = request.getParameter("part-number-marker");
- if (null != temp) partMarker = Integer.parseInt( temp );
-
-
- // -> does the bucket exist, we may need it to verify access permissions
- SBucketVO bucket = bucketDao.getByName(bucketName);
- if (bucket == null) {
- logger.error( "listUploadParts failed since " + bucketName + " does not exist" );
- response.setStatus(404);
- return;
- }
-
- try {
- MultipartLoadDao uploadDao = new MultipartLoadDao();
- OrderedPair<String,String> exists = uploadDao.multipartExits( uploadId );
- if (null == exists) {
- response.setStatus(404);
- return;
- }
- owner = exists.getFirst();
-
- // -> the multipart initiator or bucket owner can do this action
- initiator = uploadDao.getInitiator( uploadId );
- if (null == initiator || !initiator.equals( UserContext.current().getAccessKey()))
- {
- try {
- // -> write permission on a bucket allows a PutObject / DeleteObject action on any object in the bucket
- S3PolicyContext context = new S3PolicyContext( PolicyActions.ListMultipartUploadParts, bucketName );
- context.setKeyName( exists.getSecond());
- S3Engine.verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_WRITE );
- }
- catch (PermissionDeniedException e) {
- response.setStatus(403);
- return;
- }
- }
-
- parts = uploadDao.getParts( uploadId, maxParts, partMarker );
- remaining = uploadDao.numParts( uploadId, partMarker+maxParts );
- }
- catch( Exception e ) {
- logger.error("List Uploads failed due to " + e.getMessage(), e);
- response.setStatus(500);
- }
-
-
- StringBuffer xml = new StringBuffer();
- xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
- xml.append( "<ListPartsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
- xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
- xml.append( "<Key>" ).append( key ).append( "</Key>" );
- xml.append( "<UploadId>" ).append( uploadId ).append( "</UploadId>" );
-
- // -> currently we just have the access key and have no notion of a display name
- xml.append( "<Initiator>" );
- xml.append( "<ID>" ).append( initiator ).append( "</ID>" );
- xml.append( "<DisplayName></DisplayName>" );
- xml.append( "</Initiator>" );
- xml.append( "<Owner>" );
- xml.append( "<ID>" ).append( owner ).append( "</ID>" );
- xml.append( "<DisplayName></DisplayName>" );
- xml.append( "</Owner>" );
-
- StringBuffer partsList = new StringBuffer();
- for( int i=0; i < parts.length; i++ )
- {
- S3MultipartPart onePart = parts[i];
- if (null == onePart) break;
-
- nextMarker = onePart.getPartNumber();
- partsList.append( "<Part>" );
- partsList.append( "<PartNumber>" ).append( nextMarker ).append( "</PartNumber>" );
- partsList.append( "<LastModified>" ).append( DatatypeConverter.printDateTime( onePart.getLastModified())).append( "</LastModified>" );
- partsList.append( "<ETag>\"" ).append( onePart.getETag()).append( "\"</ETag>" );
- partsList.append( "<Size>" ).append( onePart.getSize()).append( "</Size>" );
- partsList.append( "</Part>" );
- }
-
- xml.append( "<StorageClass>STANDARD</StorageClass>" );
- xml.append( "<PartNumberMarker>" ).append( partMarker ).append( "</PartNumberMarker>" );
- xml.append( "<NextPartNumberMarker>" ).append( nextMarker ).append( "</NextPartNumberMarker>" );
- xml.append( "<MaxParts>" ).append( maxParts ).append( "</MaxParts>" );
- xml.append( "<IsTruncated>" ).append((0 < remaining ? "true" : "false" )).append( "</IsTruncated>" );
-
- xml.append( partsList.toString());
- xml.append( "</ListPartsResult>" );
-
- response.setStatus(200);
- response.setContentType("text/xml; charset=UTF-8");
- S3RestServlet.endResponse(response, xml.toString());
- }
-
- /**
- * Support the "Range: bytes=0-399" header with just one byte range.
- * @param request
- * @param engineRequest
- * @return
- */
- private S3GetObjectRequest setRequestByteRange( HttpServletRequest request, S3GetObjectRequest engineRequest )
- {
- String temp = request.getHeader( "Range" );
- if (null == temp) return engineRequest;
-
- int offset = temp.indexOf( "=" );
- if (-1 != offset)
- {
- String range = temp.substring( offset+1 );
-
- String[] parts = range.split( "-" );
- if (2 >= parts.length) {
- // -> the end byte is inclusive
- engineRequest.setByteRangeStart( Long.parseLong(parts[0]));
- engineRequest.setByteRangeEnd( Long.parseLong(parts[1])+1);
- }
- }
- return engineRequest;
- }
-
- private S3ConditionalHeaders conditionalRequest( HttpServletRequest request, boolean isCopy )
- {
- S3ConditionalHeaders headers = new S3ConditionalHeaders();
-
- if (isCopy) {
- headers.setModifiedSince( request.getHeader( "x-amz-copy-source-if-modified-since" ));
- headers.setUnModifiedSince( request.getHeader( "x-amz-copy-source-if-unmodified-since" ));
- headers.setMatch( request.getHeader( "x-amz-copy-source-if-match" ));
- headers.setNoneMatch( request.getHeader( "x-amz-copy-source-if-none-match" ));
- }
- else {
- headers.setModifiedSince( request.getHeader( "If-Modified-Since" ));
- headers.setUnModifiedSince( request.getHeader( "If-Unmodified-Since" ));
- headers.setMatch( request.getHeader( "If-Match" ));
- headers.setNoneMatch( request.getHeader( "If-None-Match" ));
- }
+ }
+
+ private void executeListUploadParts( HttpServletRequest request, HttpServletResponse response ) throws IOException
+ {
+ String bucketName = (String) request.getAttribute(S3Constants.BUCKET_ATTR_KEY);
+ String key = (String) request.getAttribute(S3Constants.OBJECT_ATTR_KEY);
+ String owner = null;
+ String initiator = null;
+ S3MultipartPart[] parts = null;
+ int remaining = 0;
+ int uploadId = -1;
+ int maxParts = 1000;
+ int partMarker = 0;
+ int nextMarker = 0;
+
+ String temp = request.getParameter("uploadId");
+ if (null != temp) uploadId = Integer.parseInt( temp );
+
+ temp = request.getParameter("max-parts");
+ if (null != temp) {
+ maxParts = Integer.parseInt( temp );
+ if (maxParts > 1000 || maxParts < 0) maxParts = 1000;
+ }
+
+ temp = request.getParameter("part-number-marker");
+ if (null != temp) partMarker = Integer.parseInt( temp );
+
+
+ // -> does the bucket exist, we may need it to verify access permissions
+ SBucketVO bucket = bucketDao.getByName(bucketName);
+ if (bucket == null) {
+ logger.error( "listUploadParts failed since " + bucketName + " does not exist" );
+ response.setStatus(404);
+ return;
+ }
+
+ try {
+ MultipartLoadDao uploadDao = new MultipartLoadDao();
+ OrderedPair<String,String> exists = uploadDao.multipartExits( uploadId );
+ if (null == exists) {
+ response.setStatus(404);
+ return;
+ }
+ owner = exists.getFirst();
+
+ // -> the multipart initiator or bucket owner can do this action
+ initiator = uploadDao.getInitiator( uploadId );
+ if (null == initiator || !initiator.equals( UserContext.current().getAccessKey()))
+ {
+ try {
+ // -> write permission on a bucket allows a PutObject / DeleteObject action on any object in the bucket
+ S3PolicyContext context = new S3PolicyContext( PolicyActions.ListMultipartUploadParts, bucketName );
+ context.setKeyName( exists.getSecond());
+ S3Engine.verifyAccess( context, "SBucket", bucket.getId(), SAcl.PERMISSION_WRITE );
+ }
+ catch (PermissionDeniedException e) {
+ response.setStatus(403);
+ return;
+ }
+ }
+
+ parts = uploadDao.getParts( uploadId, maxParts, partMarker );
+ remaining = uploadDao.numParts( uploadId, partMarker+maxParts );
+ }
+ catch( Exception e ) {
+ logger.error("List Uploads failed due to " + e.getMessage(), e);
+ response.setStatus(500);
+ }
+
+
+ StringBuffer xml = new StringBuffer();
+ xml.append( "<?xml version=\"1.0\" encoding=\"utf-8\"?>" );
+ xml.append( "<ListPartsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" );
+ xml.append( "<Bucket>" ).append( bucket ).append( "</Bucket>" );
+ xml.append( "<Key>" ).append( key ).append( "</Key>" );
+ xml.append( "<UploadId>" ).append( uploadId ).append( "</UploadId>" );
+
+ // -> currently we just have the access key and have no notion of a display name
+ xml.append( "<Initiator>" );
+ xml.append( "<ID>" ).append( initiator ).append( "</ID>" );
+ xml.append( "<DisplayName></DisplayName>" );
+ xml.append( "</Initiator>" );
+ xml.append( "<Owner>" );
+ xml.append( "<ID>" ).append( owner ).append( "</ID>" );
+ xml.append( "<DisplayName></DisplayName>" );
+ xml.append( "</Owner>" );
+
+ StringBuffer partsList = new StringBuffer();
+ for( int i=0; i < parts.length; i++ )
+ {
+ S3MultipartPart onePart = parts[i];
+ if (null == onePart) break;
+
+ nextMarker = onePart.getPartNumber();
+ partsList.append( "<Part>" );
+ partsList.append( "<PartNumber>" ).append( nextMarker ).append( "</PartNumber>" );
+ partsList.append( "<LastModified>" ).append( DatatypeConverter.printDateTime( onePart.getLastModified())).append( "</LastModified>" );
+ partsList.append( "<ETag>\"" ).append( onePart.getETag()).append( "\"</ETag>" );
+ partsList.append( "<Size>" ).append( onePart.getSize()).append( "</Size>" );
+ partsList.append( "</Part>" );
+ }
+
+ xml.append( "<StorageClass>STANDARD</StorageClass>" );
+ xml.append( "<PartNumberMarker>" ).append( partMarker ).append( "</PartNumberMarker>" );
+ xml.append( "<NextPartNumberMarker>" ).append( nextMarker ).append( "</NextPartNumberMarker>" );
+ xml.append( "<MaxParts>" ).append( maxParts ).append( "</MaxParts>" );
+ xml.append( "<IsTruncated>" ).append((0 < remaining ? "true" : "false" )).append( "</IsTruncated>" );
+
+ xml.append( partsList.toString());
+ xml.append( "</ListPartsResult>" );
+
+ response.setStatus(200);
+ response.setContentType("text/xml; charset=UTF-8");
+ S3RestServlet.endResponse(response, xml.toString());
+ }
+
+ /**
+ * Support the "Range: bytes=0-399" header with just one byte range.
+ * @param request
+ * @param engineRequest
+ * @return
+ */
+ private S3GetObjectRequest setRequestByteRange( HttpServletRequest request, S3GetObjectRequest engineRequest )
+ {
+ String temp = request.getHeader( "Range" );
+ if (null == temp) return engineRequest;
+
+ int offset = temp.indexOf( "=" );
+ if (-1 != offset)
+ {
+ String range = temp.substring( offset+1 );
+
+ String[] parts = range.split( "-" );
+ if (2 >= parts.length) {
+ // -> the end byte is inclusive
+ engineRequest.setByteRangeStart( Long.parseLong(parts[0]));
+ engineRequest.setByteRangeEnd( Long.parseLong(parts[1])+1);
+ }
+ }
+ return engineRequest;
+ }
+
+ private S3ConditionalHeaders conditionalRequest( HttpServletRequest request, boolean isCopy )
+ {
+ S3ConditionalHeaders headers = new S3ConditionalHeaders();
+
+ if (isCopy) {
+ headers.setModifiedSince( request.getHeader( "x-amz-copy-source-if-modified-since" ));
+ headers.setUnModifiedSince( request.getHeader( "x-amz-copy-source-if-unmodified-since" ));
+ headers.setMatch( request.getHeader( "x-amz-copy-source-if-match" ));
+ headers.setNoneMatch( request.getHeader( "x-amz-copy-source-if-none-match" ));
+ }
+ else {
+ headers.setModifiedSince( request.getHeader( "If-Modified-Since" ));
+ headers.setUnModifiedSince( request.getHeader( "If-Unmodified-Since" ));
+ headers.setMatch( request.getHeader( "If-Match" ));
+ headers.setNoneMatch( request.getHeader( "If-None-Match" ));
+ }
return headers;
- }
-
- private boolean conditionPassed( HttpServletRequest request, HttpServletResponse response, Date lastModified, String ETag )
- {
- S3ConditionalHeaders ifCond = conditionalRequest( request, false );
-
- if (0 > ifCond.ifModifiedSince( lastModified )) {
- response.setStatus( 304 );
- return false;
- }
- if (0 > ifCond.ifUnmodifiedSince( lastModified )) {
- response.setStatus( 412 );
- return false;
- }
- if (0 > ifCond.ifMatchEtag( ETag )) {
- response.setStatus( 412 );
- return false;
- }
- if (0 > ifCond.ifNoneMatchEtag( ETag )) {
- response.setStatus( 412 );
- return false;
- }
- return true;
- }
-
- /**
- * Return the saved object's meta data back to the client as HTTP "x-amz-meta-" headers.
- * This function is constructing an HTTP header and these headers have a defined syntax
- * as defined in rfc2616. Any characters that could cause an invalid HTTP header will
- * prevent that meta data from being returned via the REST call (as is defined in the Amazon
- * spec). These characters can be defined if using the SOAP API as well as the REST API.
- *
- * @param engineResponse
- * @param response
- */
- private void returnMetaData( S3GetObjectResponse engineResponse, HttpServletResponse response )
- {
- boolean ignoreMeta = false;
- int ignoredCount = 0;
-
- S3MetaDataEntry[] metaSet = engineResponse.getMetaEntries();
- for( int i=0; null != metaSet && i < metaSet.length; i++ )
- {
- String name = metaSet[i].getName();
- String value = metaSet[i].getValue();
- byte[] nameBytes = name.getBytes();
- ignoreMeta = false;
-
- // -> cannot have control characters (octets 0 - 31) and DEL (127), in an HTTP header
- for( int j=0; j < name.length(); j++ ) {
- if ((0 <= nameBytes[j] && 31 >= nameBytes[j]) || 127 == nameBytes[j]) {
- ignoreMeta = true;
- break;
- }
- }
-
- // ->
<TRUNCATED>