Java tutorial
/* * Author: Sunil Soman sunils@cs.ucsb.edu */ package edu.ucsb.eucalyptus.transport.query; import edu.ucsb.eucalyptus.cloud.EucalyptusCloudException; import edu.ucsb.eucalyptus.keys.Hashes; import edu.ucsb.eucalyptus.msgs.*; import edu.ucsb.eucalyptus.util.*; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.HandlerDescription; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUpload; import org.apache.http.protocol.HTTP; import org.apache.log4j.Logger; import org.apache.tools.ant.util.DateUtils; import org.apache.xml.dtm.ref.DTMNodeList; import org.bouncycastle.util.encoders.Base64; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONObject; import java.io.BufferedInputStream; import java.io.InputStream; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; import java.util.zip.GZIPInputStream; /******************************************************************************* * Copyright (c) 2009 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, only version 3 of the License. * * * This file is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. * * Please contact Eucalyptus Systems, Inc., 130 Castilian * Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/> * if you need additional information or have any questions. * * This file may incorporate work covered under the following copyright and * permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, with * or without modification, are permitted provided that the following * conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF * THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE * LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS * SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA * BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN * THE REGENTS DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT * OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR * WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH * ANY SUCH LICENSES OR RIGHTS. ******************************************************************************/ public class WalrusQueryDispatcher extends GenericHttpDispatcher implements RESTfulDispatcher { public static final String NAME = "WalrusQueryDispatcher"; public static final String IS_QUERY_REQUEST = NAME + "_IS_QUERY_REQUEST"; public static final String BINDING_NAMESPACE = NAME + "_BINDING_NAMESPACE"; private static Logger LOG = Logger.getLogger(WalrusQueryDispatcher.class); private static String HTTP_PARAM_SEPARATOR = "&"; private static String HTTP_ASSIGNMENT_OPERATOR = "="; private static String S3_NAMESPACE = "http://s3.amazonaws.com/doc/2006-03-01/"; private static String walrusBaseAddress = "/services/Walrus/"; private static String SERVICE = "service"; private static String BUCKET = "bucket"; private static String OBJECT = "object"; private Map<String, String> operationMap = populateOperationMap(); // Use getWriteMessenger and getReadMessenger to access these private static WalrusDataMessenger putMessenger; private static WalrusDataMessenger getMessenger; public static final int DATA_MESSAGE_SIZE = 102400; private Map<String, String> populateOperationMap() { Map<String, String> newMap = new HashMap<String, String>(); //Service operations newMap.put(SERVICE + HTTPVerb.GET.toString(), "ListAllMyBuckets"); //Bucket operations newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.acl.toString(), "GetBucketAccessControlPolicy"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.PUT.toString() + OperationParameter.acl.toString(), "SetBucketAccessControlPolicy"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString(), "ListBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.prefix.toString(), "ListBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.maxkeys.toString(), "ListBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.marker.toString(), "ListBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.delimiter.toString(), "ListBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.PUT.toString(), "CreateBucket"); newMap.put(BUCKET + HTTPVerb.DELETE.toString(), "DeleteBucket"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.location.toString(), "GetBucketLocation"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.logging.toString(), "GetBucketLoggingStatus"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.PUT.toString() + OperationParameter.logging.toString(), "SetBucketLoggingStatus"); //Object operations newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.GET.toString() + OperationParameter.acl.toString(), "GetObjectAccessControlPolicy"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.PUT.toString() + OperationParameter.acl.toString(), "SetObjectAccessControlPolicy"); newMap.put(BUCKET + WalrusQueryDispatcher.HTTPVerb.POST.toString(), "PostObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.PUT.toString(), "PutObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.PUT.toString() + WalrusProperties.COPY_SOURCE.toString(), "CopyObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.GET.toString(), "GetObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.DELETE.toString(), "DeleteObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.HEAD.toString(), "GetObject"); newMap.put(OBJECT + WalrusQueryDispatcher.HTTPVerb.GET.toString() + "extended", "GetObjectExtended"); return newMap; } public enum HTTPVerb { GET, PUT, DELETE, POST, HEAD; } public enum OperationParameter { acl, location, prefix, maxkeys, delimiter, marker, logging; private static String pattern = buildPattern(); private static String buildPattern() { StringBuilder s = new StringBuilder(); for (OperationParameter op : OperationParameter.values()) s.append("(").append(op.name()).append(")|"); s.deleteCharAt(s.length() - 1); return s.toString(); } public static String toPattern() { return pattern; } public static String getParameter(Map<String, String> map) { for (OperationParameter op : OperationParameter.values()) if (map.containsKey(op.toString())) return map.get(op.toString()); return null; } } private static String[] getTarget(String operationPath) { operationPath = operationPath.replaceAll("/{2,}", "/"); if (operationPath.startsWith("/")) operationPath = operationPath.substring(1); return operationPath.split("/"); } public enum RequiredQueryParams { Date } public boolean accepts(final HttpRequest httpRequest, final MessageContext messageContext) { //:: decide about whether or not to accept the request for processing ::// if (httpRequest.getService().equals(WalrusProperties.SERVICE_NAME)) return true; return false; } public String getOperation(HttpRequest httpRequest, MessageContext messageContext) throws EucalyptusCloudException { //Figure out if it is an operation on the service, a bucket or an object Map operationParams = new HashMap(); String[] target = null; String path = httpRequest.getOperationPath(); boolean walrusInternalOperation = false; if (path.length() > 0) { target = getTarget(path); } String verb = httpRequest.getHttpMethod(); Map<String, String> headers = httpRequest.getHeaders(); CaseInsensitiveMap caseInsensitiveHeaders = new CaseInsensitiveMap(headers); String operationKey = ""; Map<String, String> params = httpRequest.getParameters(); String operationName = null; long contentLength = 0; String contentLengthString = (String) messageContext.getProperty(HTTP.CONTENT_LEN); if (contentLengthString != null) { contentLength = Long.parseLong(contentLengthString); } if (caseInsensitiveHeaders.containsKey(StorageProperties.EUCALYPTUS_OPERATION)) { String value = caseInsensitiveHeaders.get(StorageProperties.EUCALYPTUS_OPERATION); for (WalrusProperties.WalrusInternalOperations operation : WalrusProperties.WalrusInternalOperations .values()) { if (value.toLowerCase().equals(operation.toString().toLowerCase())) { operationName = operation.toString(); walrusInternalOperation = true; break; } } if (!walrusInternalOperation) { for (WalrusProperties.StorageOperations operation : WalrusProperties.StorageOperations.values()) { if (value.toLowerCase().equals(operation.toString().toLowerCase())) { operationName = operation.toString(); walrusInternalOperation = true; break; } } } } if (target == null) { //target = service operationKey = SERVICE + verb; } else if (target.length < 2) { //target = bucket if (!target[0].equals("")) { operationKey = BUCKET + verb; operationParams.put("Bucket", target[0]); if (verb.equals(HTTPVerb.POST.toString())) { InputStream in = (InputStream) messageContext.getProperty("TRANSPORT_IN"); messageContext.setProperty(WalrusProperties.STREAMING_HTTP_PUT, Boolean.TRUE); String contentType = caseInsensitiveHeaders.get(HTTP.CONTENT_TYPE); int postContentLength = Integer.parseInt(caseInsensitiveHeaders.get(HTTP.CONTENT_LEN)); POSTRequestContext postRequestContext = new POSTRequestContext(in, contentType, postContentLength); FileUpload fileUpload = new FileUpload(new WalrusFileItemFactory()); InputStream formDataIn = null; String objectKey = null; String file = ""; String key; Map<String, String> formFields = new HashMap<String, String>(); try { List<FileItem> parts = fileUpload.parseRequest(postRequestContext); for (FileItem part : parts) { if (part.isFormField()) { String fieldName = part.getFieldName().toString().toLowerCase(); InputStream formFieldIn = part.getInputStream(); int bytesRead; String fieldValue = ""; byte[] bytes = new byte[512]; while ((bytesRead = formFieldIn.read(bytes)) > 0) { fieldValue += new String(bytes, 0, bytesRead); } formFields.put(fieldName, fieldValue); } else { formDataIn = part.getInputStream(); if (part.getName() != null) file = part.getName(); } } } catch (Exception ex) { LOG.warn(ex, ex); throw new EucalyptusCloudException("could not process form request"); } String authenticationHeader = ""; formFields.put(WalrusProperties.FormField.bucket.toString(), target[0]); if (formFields.containsKey(WalrusProperties.FormField.key.toString())) { objectKey = formFields.get(WalrusProperties.FormField.key.toString()); objectKey = objectKey.replaceAll("\\$\\{filename\\}", file); } if (formFields.containsKey(WalrusProperties.FormField.acl.toString())) { String acl = formFields.get(WalrusProperties.FormField.acl.toString()); headers.put(WalrusProperties.AMZ_ACL, acl); } if (formFields.containsKey(WalrusProperties.FormField.success_action_redirect.toString())) { String successActionRedirect = formFields .get(WalrusProperties.FormField.success_action_redirect.toString()); operationParams.put("SuccessActionRedirect", successActionRedirect); } if (formFields.containsKey(WalrusProperties.FormField.success_action_status.toString())) { Integer successActionStatus = Integer.parseInt( formFields.get(WalrusProperties.FormField.success_action_status.toString())); if (successActionStatus == 200 || successActionStatus == 201) operationParams.put("SuccessActionStatus", successActionStatus); else operationParams.put("SuccessActionStatus", 204); } else { operationParams.put("SuccessActionStatus", 204); } if (formFields.containsKey(WalrusProperties.FormField.policy.toString())) { String policy = new String( Base64.decode(formFields.remove(WalrusProperties.FormField.policy.toString()))); String policyData; try { policyData = new String(Base64.encode(policy.getBytes())); } catch (Exception ex) { LOG.warn(ex, ex); throw new EucalyptusCloudException("error reading policy data."); } //parse policy try { JSONObject policyObject = new JSONObject(policy); String expiration = (String) policyObject .get(WalrusProperties.PolicyHeaders.expiration.toString()); if (expiration != null) { Date expirationDate = DateUtils.parseIso8601DateTimeOrDate(expiration); if ((new Date()).getTime() > expirationDate.getTime()) { LOG.warn("Policy has expired."); //TODO: currently this will be reported as an invalid operation //Fix this to report a security exception throw new EucalyptusCloudException("Policy has expired."); } } List<String> policyItemNames = new ArrayList<String>(); JSONArray conditions = (JSONArray) policyObject .get(WalrusProperties.PolicyHeaders.conditions.toString()); for (int i = 0; i < conditions.length(); ++i) { Object policyItem = conditions.get(i); if (policyItem instanceof JSONObject) { JSONObject jsonObject = (JSONObject) policyItem; if (!exactMatch(jsonObject, formFields, policyItemNames)) { LOG.warn("Policy verification failed. "); throw new EucalyptusCloudException("Policy verification failed."); } } else if (policyItem instanceof JSONArray) { JSONArray jsonArray = (JSONArray) policyItem; if (!partialMatch(jsonArray, formFields, policyItemNames)) { LOG.warn("Policy verification failed. "); throw new EucalyptusCloudException("Policy verification failed."); } } } Set<String> formFieldsKeys = formFields.keySet(); for (String formKey : formFieldsKeys) { if (formKey.startsWith(WalrusProperties.IGNORE_PREFIX)) continue; boolean fieldOkay = false; for (WalrusProperties.IgnoredFields field : WalrusProperties.IgnoredFields .values()) { if (formKey.equals(field.toString().toLowerCase())) { fieldOkay = true; break; } } if (fieldOkay) continue; if (policyItemNames.contains(formKey)) continue; LOG.warn("All fields except those marked with x-ignore- should be in policy."); throw new EucalyptusCloudException( "All fields except those marked with x-ignore- should be in policy."); } } catch (Exception ex) { //rethrow if (ex instanceof EucalyptusCloudException) throw (EucalyptusCloudException) ex; LOG.warn(ex); } //all form uploads without a policy are anonymous if (formFields .containsKey(WalrusProperties.FormField.AWSAccessKeyId.toString().toLowerCase())) { String accessKeyId = formFields .remove(WalrusProperties.FormField.AWSAccessKeyId.toString().toLowerCase()); authenticationHeader += "AWS" + " " + accessKeyId + ":"; } if (formFields.containsKey(WalrusProperties.FormField.signature.toString())) { String signature = formFields.remove(WalrusProperties.FormField.signature.toString()); authenticationHeader += signature; headers.put(HMACQuerySecurityHandler.SecurityParameter.Authorization.toString(), authenticationHeader); } headers.put(WalrusProperties.FormField.FormUploadPolicyData.toString(), policyData); } operationParams.put("Key", objectKey); key = target[0] + "." + objectKey; String randomKey = key + "." + Hashes.getRandom(10); LinkedBlockingQueue<WalrusDataMessage> putQueue = getWriteMessenger() .interruptAllAndGetQueue(key, randomKey); Writer writer = new Writer(formDataIn, postContentLength, putQueue); writer.start(); operationParams.put("ContentLength", (new Long(postContentLength).toString())); operationParams.put(WalrusProperties.Headers.RandomKey.toString(), randomKey); } } else { operationKey = SERVICE + verb; } } else { //target = object operationKey = OBJECT + verb; String objectKey = ""; String splitOn = ""; for (int i = 1; i < target.length; ++i) { objectKey += splitOn + target[i]; splitOn = "/"; } operationParams.put("Bucket", target[0]); operationParams.put("Key", objectKey); if (!params.containsKey(OperationParameter.acl.toString())) { if (verb.equals(HTTPVerb.PUT.toString())) { if (caseInsensitiveHeaders.containsKey(WalrusProperties.COPY_SOURCE.toString())) { String copySource = caseInsensitiveHeaders.get(WalrusProperties.COPY_SOURCE.toString()); String[] sourceTarget = getTarget(copySource); String sourceObjectKey = ""; String sourceSplitOn = ""; if (sourceTarget.length > 1) { for (int i = 1; i < sourceTarget.length; ++i) { sourceObjectKey += sourceSplitOn + sourceTarget[i]; sourceSplitOn = "/"; } operationParams.put("SourceBucket", sourceTarget[0]); operationParams.put("SourceObject", sourceObjectKey); operationParams.put("DestinationBucket", operationParams.remove("Bucket")); operationParams.put("DestinationObject", operationParams.remove("Key")); String metaDataDirective = caseInsensitiveHeaders .get(WalrusProperties.METADATA_DIRECTIVE.toString()); if (metaDataDirective != null) { operationParams.put("MetadataDirective", metaDataDirective); } AccessControlListType accessControlList; if (contentLength > 0) { InputStream in = (InputStream) messageContext.getProperty("TRANSPORT_IN"); accessControlList = getAccessControlList(in); } else { accessControlList = new AccessControlListType(); } operationParams.put("AccessControlList", accessControlList); operationKey += WalrusProperties.COPY_SOURCE.toString(); Iterator<String> iterator = caseInsensitiveHeaders.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); for (WalrusProperties.CopyHeaders header : WalrusProperties.CopyHeaders.values()) { if (key.replaceAll("-", "").equals(header.toString().toLowerCase())) { String value = caseInsensitiveHeaders.get(key); parseExtendedHeaders(operationParams, header.toString(), value); } } } } else { throw new EucalyptusCloudException("Malformed COPY request"); } } else { messageContext.setProperty(WalrusProperties.STREAMING_HTTP_PUT, Boolean.TRUE); InputStream in = (InputStream) messageContext.getProperty("TRANSPORT_IN"); InputStream inStream = in; if ((!walrusInternalOperation) || (!WalrusProperties.StorageOperations.StoreSnapshot .toString().equals(operationName))) { inStream = new BufferedInputStream(in); } else { try { inStream = new GZIPInputStream(in); } catch (Exception ex) { LOG.warn(ex, ex); throw new EucalyptusCloudException("cannot process input"); } } String key = target[0] + "." + objectKey; String randomKey = key + "." + Hashes.getRandom(10); LinkedBlockingQueue<WalrusDataMessage> putQueue = getWriteMessenger() .interruptAllAndGetQueue(key, randomKey); Writer writer = new Writer(inStream, contentLength, putQueue); writer.start(); operationParams.put("ContentLength", (new Long(contentLength).toString())); operationParams.put(WalrusProperties.Headers.RandomKey.toString(), randomKey); } } else if (verb.equals(HTTPVerb.GET.toString())) { messageContext.setProperty(WalrusProperties.STREAMING_HTTP_GET, Boolean.TRUE); if (!walrusInternalOperation) { operationParams.put("GetData", Boolean.TRUE); operationParams.put("InlineData", Boolean.FALSE); operationParams.put("GetMetaData", Boolean.TRUE); Iterator<String> iterator = caseInsensitiveHeaders.keySet().iterator(); boolean isExtendedGet = false; while (iterator.hasNext()) { String key = iterator.next(); for (WalrusProperties.ExtendedGetHeaders header : WalrusProperties.ExtendedGetHeaders .values()) { if (key.replaceAll("-", "").equals(header.toString().toLowerCase())) { String value = caseInsensitiveHeaders.get(key); isExtendedGet = true; parseExtendedHeaders(operationParams, header.toString(), value); } } } if (isExtendedGet) { operationKey += "extended"; //only supported through SOAP operationParams.put("ReturnCompleteObjectOnConditionFailure", Boolean.FALSE); } } else { for (WalrusProperties.InfoOperations operation : WalrusProperties.InfoOperations.values()) { if (operation.toString().equals(operationName)) { messageContext.removeProperty(WalrusProperties.STREAMING_HTTP_GET); break; } } } if (params.containsKey(WalrusProperties.GetOptionalParameters.IsCompressed.toString())) { Boolean isCompressed = Boolean.parseBoolean( params.remove(WalrusProperties.GetOptionalParameters.IsCompressed.toString())); operationParams.put("IsCompressed", isCompressed); } } else if (verb.equals(HTTPVerb.HEAD.toString())) { messageContext.setProperty(WalrusProperties.STREAMING_HTTP_GET, Boolean.FALSE); if (!walrusInternalOperation) { operationParams.put("GetData", Boolean.FALSE); operationParams.put("InlineData", Boolean.FALSE); operationParams.put("GetMetaData", Boolean.TRUE); } } } } if (verb.equals(HTTPVerb.PUT.toString()) && params.containsKey(OperationParameter.acl.toString())) { //read ACL InputStream in = (InputStream) messageContext.getProperty("TRANSPORT_IN"); operationParams.put("AccessControlPolicy", getAccessControlPolicy(in)); } ArrayList paramsToRemove = new ArrayList(); boolean addMore = true; Iterator iterator = params.keySet().iterator(); while (iterator.hasNext()) { Object key = iterator.next(); String keyString = key.toString().toLowerCase(); boolean dontIncludeParam = false; for (HMACQuerySecurityHandler.SecurityParameter securityParam : HMACQuerySecurityHandler.SecurityParameter .values()) { if (keyString.equals(securityParam.toString().toLowerCase())) { dontIncludeParam = true; break; } } if (dontIncludeParam) continue; String value = params.get(key); if (value != null) { String[] keyStringParts = keyString.split("-"); if (keyStringParts.length > 1) { keyString = ""; for (int i = 0; i < keyStringParts.length; ++i) { keyString += toUpperFirst(keyStringParts[i]); } } else { keyString = toUpperFirst(keyString); } operationParams.put(keyString, value); } if (addMore) { //just add the first one to the key operationKey += keyString.toLowerCase(); addMore = false; } paramsToRemove.add(key); } for (Object key : paramsToRemove) { params.remove(key); } if (!walrusInternalOperation) { operationName = operationMap.get(operationKey); } httpRequest.setBindingArguments(operationParams); messageContext.setProperty(WalrusProperties.WALRUS_OPERATION, operationName); return operationName; } private boolean exactMatch(JSONObject jsonObject, Map formFields, List<String> policyItemNames) { Iterator<String> iterator = jsonObject.keys(); boolean returnValue = false; while (iterator.hasNext()) { String key = iterator.next(); key = key.replaceAll("\\$", ""); policyItemNames.add(key.toLowerCase()); try { if (jsonObject.get(key).equals(formFields.get(key))) returnValue = true; else returnValue = false; } catch (Exception ex) { ex.printStackTrace(); return false; } } return returnValue; } private boolean partialMatch(JSONArray jsonArray, Map<String, String> formFields, List<String> policyItemNames) { boolean returnValue = false; if (jsonArray.length() != 3) return false; try { String condition = (String) jsonArray.get(0); String key = (String) jsonArray.get(1); key = key.replaceAll("\\$", ""); policyItemNames.add(key.toLowerCase()); String value = (String) jsonArray.get(2); if (condition.contains("eq")) { if (value.equals(formFields.get(key))) returnValue = true; } else if (condition.contains("starts-with")) { if (!formFields.containsKey(key.toLowerCase())) return false; if (formFields.get(key.toLowerCase()).startsWith(value)) returnValue = true; } } catch (Exception ex) { ex.printStackTrace(); return false; } return returnValue; } private void parseExtendedHeaders(Map operationParams, String headerString, String value) { if (headerString.equals(WalrusProperties.ExtendedGetHeaders.Range.toString())) { String prefix = "bytes="; assert (value.startsWith(prefix)); value = value.substring(prefix.length()); String[] values = value.split("-"); assert (values.length == 2); if (values[0].equals("")) { operationParams.put(WalrusProperties.ExtendedHeaderRangeTypes.ByteRangeStart.toString(), new Long(0)); } else { operationParams.put(WalrusProperties.ExtendedHeaderRangeTypes.ByteRangeStart.toString(), Long.parseLong(values[0])); } assert (!values[1].equals("")); operationParams.put(WalrusProperties.ExtendedHeaderRangeTypes.ByteRangeEnd.toString(), Long.parseLong(values[1])); } else if (WalrusProperties.ExtendedHeaderDateTypes.contains(headerString)) { try { operationParams.put(headerString, DateUtils.parseIso8601DateTimeOrDate(value)); } catch (Exception ex) { ex.printStackTrace(); } } else { operationParams.put(headerString, value); } } private AccessControlPolicyType getAccessControlPolicy(InputStream in) throws EucalyptusCloudException { AccessControlPolicyType accessControlPolicy = new AccessControlPolicyType(); try { BufferedInputStream bufferedIn = new BufferedInputStream(in); byte[] bytes = new byte[DATA_MESSAGE_SIZE]; int bytesRead; String aclString = ""; while ((bytesRead = bufferedIn.read(bytes)) > 0) { aclString += new String(bytes, 0, bytesRead); } if (aclString.length() > 0) { XMLParser xmlParser = new XMLParser(aclString); String ownerId = xmlParser.getValue("//Owner/ID"); String displayName = xmlParser.getValue("//Owner/DisplayName"); CanonicalUserType canonicalUser = new CanonicalUserType(ownerId, displayName); accessControlPolicy.setOwner(canonicalUser); AccessControlListType accessControlList = new AccessControlListType(); ArrayList<Grant> grants = new ArrayList<Grant>(); List<String> permissions = xmlParser.getValues("//AccessControlList/Grant/Permission"); DTMNodeList grantees = xmlParser.getNodes("//AccessControlList/Grant/Grantee"); for (int i = 0; i < grantees.getLength(); ++i) { String id = xmlParser.getValue(grantees.item(i), "ID"); if (id.length() > 0) { String canonicalUserName = xmlParser.getValue(grantees.item(i), "DisplayName"); Grant grant = new Grant(); Grantee grantee = new Grantee(); grantee.setCanonicalUser(new CanonicalUserType(id, canonicalUserName)); grant.setGrantee(grantee); grant.setPermission(permissions.get(i)); grants.add(grant); } else { String groupUri = xmlParser.getValue(grantees.item(i), "URI"); if (groupUri.length() == 0) throw new EucalyptusCloudException("malformed access control list"); Grant grant = new Grant(); Grantee grantee = new Grantee(); grantee.setGroup(new Group(groupUri)); grant.setGrantee(grantee); grant.setPermission(permissions.get(i)); grants.add(grant); } } accessControlList.setGrants(grants); accessControlPolicy.setAccessControlList(accessControlList); } } catch (Exception ex) { LOG.warn(ex); throw new EucalyptusCloudException(ex.getMessage()); } return accessControlPolicy; } private AccessControlListType getAccessControlList(InputStream in) throws EucalyptusCloudException { AccessControlListType accessControlList = new AccessControlListType(); try { BufferedInputStream bufferedIn = new BufferedInputStream(in); byte[] bytes = new byte[DATA_MESSAGE_SIZE]; int bytesRead; String aclString = ""; while ((bytesRead = bufferedIn.read(bytes)) > 0) { aclString += new String(bytes, 0, bytesRead); } if (aclString.length() > 0) { XMLParser xmlParser = new XMLParser(aclString); String ownerId = xmlParser.getValue("//Owner/ID"); String displayName = xmlParser.getValue("//Owner/DisplayName"); ArrayList<Grant> grants = new ArrayList<Grant>(); List<String> permissions = xmlParser.getValues("/AccessControlList/Grant/Permission"); DTMNodeList grantees = xmlParser.getNodes("/AccessControlList/Grant/Grantee"); for (int i = 0; i < grantees.getLength(); ++i) { String canonicalUserName = xmlParser.getValue(grantees.item(i), "DisplayName"); if (canonicalUserName.length() > 0) { String id = xmlParser.getValue(grantees.item(i), "ID"); Grant grant = new Grant(); Grantee grantee = new Grantee(); grantee.setCanonicalUser(new CanonicalUserType(id, canonicalUserName)); grant.setGrantee(grantee); grant.setPermission(permissions.get(i)); grants.add(grant); } else { String groupUri = xmlParser.getValue(grantees.item(i), "URI"); if (groupUri.length() == 0) throw new EucalyptusCloudException("malformed access control list"); Grant grant = new Grant(); Grantee grantee = new Grantee(); grantee.setGroup(new Group(groupUri)); grant.setGrantee(grantee); grant.setPermission(permissions.get(i)); grants.add(grant); } } accessControlList.setGrants(grants); } } catch (Exception ex) { LOG.warn(ex); throw new EucalyptusCloudException(ex.getMessage()); } return accessControlList; } public QuerySecurityHandler getSecurityHandler() { return new WalrusQuerySecurityHandler(); } public QueryBinding getBinding() { return new WalrusQueryBinding(); } public String getNamespace() { return S3_NAMESPACE; } public void initDispatcher() { init(new HandlerDescription(NAME)); } public static synchronized WalrusDataMessenger getReadMessenger() { if (getMessenger == null) { getMessenger = new WalrusDataMessenger(); } return getMessenger; } public static synchronized WalrusDataMessenger getWriteMessenger() { if (putMessenger == null) { putMessenger = new WalrusDataMessenger(); } return putMessenger; } class Writer extends Thread { private InputStream in; private long dataLength; private LinkedBlockingQueue<WalrusDataMessage> putQueue; public Writer(InputStream in, long dataLength, LinkedBlockingQueue<WalrusDataMessage> putQueue) { this.in = in; this.dataLength = dataLength; this.putQueue = putQueue; } public void run() { byte[] bytes = new byte[DATA_MESSAGE_SIZE]; try { LOG.info("Starting upload"); putQueue.put(WalrusDataMessage.StartOfData(dataLength)); int bytesRead; while ((bytesRead = in.read(bytes)) > 0) { putQueue.put(WalrusDataMessage.DataMessage(bytes, bytesRead)); } putQueue.put(WalrusDataMessage.EOF()); } catch (Exception ex) { LOG.warn(ex, ex); } } } private String toUpperFirst(String string) { return string.substring(0, 1).toUpperCase().concat(string.substring(1)); } }