/*************************************************************************
* Copyright 2009-2014 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; version 3 of the License.
*
* This program 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., 6755 Hollister Ave., Goleta
* CA 93117, 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.
*
* This file may incorporate work covered under the following copyright
* and permission notice:
*
* Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights
* Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
************************************************************************/
package com.eucalyptus.objectstorage.util;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import com.eucalyptus.component.Topology;
import com.eucalyptus.objectstorage.ObjectStorage;
import com.eucalyptus.system.BaseDirectory;
import com.google.common.base.CharMatcher;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public class ObjectStorageProperties {
private static Logger LOG = Logger.getLogger(ObjectStorageProperties.class);
public static final long G = 1024 * 1024 * 1024;
public static final long M = 1024 * 1024;
public static final long K = 1024;
public static int IO_CHUNK_SIZE = 4096;
public static boolean enableTorrents = false;
public static final String NAMESPACE_VERSION = "2006-03-01";
public static int MAX_KEYS = 1000;
public static int MIN_PART_NUMBER = 1;
public static int MAX_PART_NUMBER = 10000;
public static final String AMZ_META_HEADER_PREFIX = "x-amz-meta-";
public static final String AMZ_ACL = "x-amz-acl";
public static final String AMZ_REQUEST_ID = "x-amz-request-id";
public static final String LEGACY_WALRUS_SERVICE_PATH = "/services/Walrus";
public static final long OBJECT_CREATION_EXPIRATION_INTERVAL_SEC = 30;
// TODO: zhill - these should be replaced by references to the actual Accounts lookup. May need to add these as valid groups/accounts
public static enum S3_GROUP {
ALL_USERS_GROUP {
public String toString() {
return "http://acs.amazonaws.com/groups/global/AllUsers";
}
},
AUTHENTICATED_USERS_GROUP {
public String toString() {
return "http://acs.amazonaws.com/groups/global/AuthenticatedUsers";
}
},
LOGGING_GROUP {
public String toString() {
return "http://acs.amazonaws.com/groups/s3/LogDelivery";
}
},
// TODO: this is wrong. za-team is a user, not a group. Should use canonicalId: 6aa5a366c34c1cbe25dc49211496e913e0351eb0e8c37aa3477e40942ec6b97c
AWS_EXEC_READ {
public String toString() {
return "http://acs.amazonaws.com/groups/s3/zateam";
}
}, // Used for the system for vm images
// This is a made-up group in place of the ec2-bundled-image
EC2_BUNDLE_READ {
public String toString() {
return "http://acs.amazonaws.com/groups/s3/ec2-bundle";
}
} // Used for the system for vm images
}
public static final String IGNORE_PREFIX = "x-ignore-";
public static final String COPY_SOURCE = "x-amz-copy-source";
public static final String METADATA_DIRECTIVE = "x-amz-metadata-directive";
public static final String X_AMZ_VERSION_ID = "x-amz-version-id";
public static final String NULL_VERSION_ID = "null";
public static final String X_AMZ_DELETE_MARKER = "x-amz-delete-marker";
public static final String TRACKER_BINARY = "bttrack";
public static final String TORRENT_CREATOR_BINARY = "btmakemetafile";
public static final String TORRENT_CLIENT_BINARY = "btdownloadheadless";
public static String TRACKER_DIR = BaseDirectory.VAR.toString() + "/bt";
public static String TRACKER_URL = "http://localhost:6969/announce";
public static String TRACKER_PORT = "6969";
public static long MAX_INLINE_DATA_SIZE = 10 * M;
// public static String FORM_BOUNDARY_FIELD = IGNORE_PREFIX + "euca-form-boundary"; //internal header value for passing info
// public static String FIRST_CHUNK_FIELD = IGNORE_PREFIX + "FirstDataChunk";
// public static String UPLOAD_LENGTH_FIELD = IGNORE_PREFIX + "FileContentLength";
public static long MPU_PART_MIN_SIZE = 5 * 1024 * 1024; // 5MB
// 15 minutes
public final static long EXPIRATION_LIMIT = 900000;
public static final Pattern RANGE_HEADER_PATTERN = Pattern.compile("^bytes=(\\d*)-(\\d*)$");
public static final Pattern GRANT_HEADER_PATTERN = Pattern
.compile("^(\\s*(emailAddress|id|uri)=['\"]?[^,'\"]+['\"]?\\s*)(,\\s*(emailAddress|id|uri)=['\"]?[^,'\"]+['\"]?\\s*)*$");
public enum CannedACL {
private_only {
public String toString() {
return "private";
}
},
public_read {
public String toString() {
return "public-read";
}
},
public_read_write {
public String toString() {
return "public-read-write";
}
},
authenticated_read {
public String toString() {
return "authenticated-read";
}
},
bucket_owner_read {
public String toString() {
return "bucket-owner-read";
}
},
bucket_owner_full_control {
public String toString() {
return "bucket-owner-full-control";
}
},
log_delivery_write {
public String toString() {
return "log-delivery-write";
}
},
aws_exec_read {
public String toString() {
return "aws-exec-read";
}
},
ec2_bundle_read {
public String toString() {
return "ec2-bundle-read";
}
}
}
public enum STORAGE_CLASS {
STANDARD, REDUCED_REDUNDANCY;
}
public enum Permission {
READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL
}
public enum Resource {
bucket, object
}
public enum X_AMZ_GRANT {
READ("x-amz-grant-read"), WRITE("x-amz-grant-write"), READ_ACP("x-amz-grant-read-acp"), WRITE_ACP("x-amz-grant-write-acp"), FULL_CONTROL(
"x-amz-grant-full-control");
private final String header;
private X_AMZ_GRANT(String header) {
this.header = header;
}
@Override
public String toString() {
return this.header;
}
}
public static final Map<X_AMZ_GRANT, Permission> HEADER_PERMISSION_MAP = ImmutableMap.<X_AMZ_GRANT, Permission>builder()
.put(X_AMZ_GRANT.READ, Permission.READ).put(X_AMZ_GRANT.WRITE, Permission.WRITE).put(X_AMZ_GRANT.READ_ACP, Permission.READ_ACP)
.put(X_AMZ_GRANT.WRITE_ACP, Permission.WRITE_ACP).put(X_AMZ_GRANT.FULL_CONTROL, Permission.FULL_CONTROL).build();
/**
* Splitting function for parsing x-amz-grant-* headers into a list of [key,value] string arrays</p>
*
* Input to the function, header value: <code>x-amz-grant-read: emailAddress="xyz@amazon.com", uri="http://some-uri",id="canonical-id"</code></p>
*
* Output from the function, list of string arrays: <code>{[emailAddress, xyz@amazon.com],[uri, http://some-uri],[id, canonical-id]}</code> </p>
*/
// Tried using MapSplitter which does the same thing. However, it does not allow duplicate keys in the key-value output. So if the grant has two or
// more of the same identity elements (uri, id, emailAddress), only one of them gets through
public static final Function<String, List<String[]>> GRANT_HEADER_PARSER = new Function<String, List<String[]>>() {
private final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
private final Splitter KEY_VALUE_SPLITTER = Splitter.on('=').limit(2).omitEmptyStrings()
.trimResults(CharMatcher.anyOf("'\"").or(CharMatcher.WHITESPACE));
@Override
public List<String[]> apply(String arg0) {
List<String[]> returnvalue = Lists.newArrayList();
for (String gpString : COMMA_SPLITTER.split(arg0)) {
Iterator<String> gpIterator = KEY_VALUE_SPLITTER.split(gpString).iterator();
String idType = null;
String idValue = null;
if (gpIterator != null && gpIterator.hasNext()) {
idType = gpIterator.next();
} else {
continue; // drop the header
}
if (gpIterator.hasNext()) {
idValue = gpIterator.next();
} else {
continue; // drop the header
}
if (StringUtils.isNotBlank(idType) && StringUtils.isNotBlank(idValue)) {
returnvalue.add(new String[] {idType, idValue});
} else {
continue; // drop the header
}
}
return returnvalue;
}
};
public enum VersioningStatus {
Enabled, Disabled, Suspended
}
public enum Headers {
Bucket, Key, RandomKey, VolumeId, S3UploadPolicy, S3UploadPolicySignature
}
public enum SubResource {
// Per the S3 Dev guide, these must be included in the canonicalized resource:
acl(true), lifecycle, location, logging, notification, partNumber, policy, requestPayment, torrent(true), uploadId, uploads,
versionId, versioning, versions, website, cors, tagging, delete, accelerate, metrics, analytics, inventory, replication;
/** Indicates whether the SubResource is of this <a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/ObjectAndSoubResource.html">type</a> */
public final boolean isObjectSubResource;
SubResource(){
isObjectSubResource = false;
}
SubResource(boolean isObjectSubResource) {
this.isObjectSubResource = isObjectSubResource;
}
}
public enum ExtendedGetHeaders {
IfModifiedSince, IfUnmodifiedSince, IfMatch, IfNoneMatch, Range
}
public enum ExtendedHeaderDateTypes {
IfModifiedSince, IfUnmodifiedSince, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince;
public static boolean contains(String value) {
for (ExtendedHeaderDateTypes type : values()) {
if (type.toString().equals(value)) {
return true;
}
}
return false;
}
}
public enum ExtendedHeaderRangeTypes {
ByteRangeStart, ByteRangeEnd
}
public enum GetOptionalParameters {
IsCompressed
}
public enum FormField {
AWSAccessKeyId, key, bucket, acl, Policy, redirect, success_action_redirect, success_action_status, x_amz_security_token {
public String toString() {
return "x-amz-security-token";
}
},
Signature, file, Cache_Control {
public String toString() {
return HttpHeaders.Names.CACHE_CONTROL;
}
},
Content_Type {
public String toString() {
return HttpHeaders.Names.CONTENT_TYPE;
}
},
Content_Disposition {
public String toString() {
return "Content-Disposition";
}
},
Content_Encoding {
public String toString() {
return HttpHeaders.Names.CONTENT_ENCODING;
}
},
Expires, x_ignore_firstdatachunk {
public String toString() {
return "x-ignore-firstdatachunk";
}
},
x_ignore_filecontentlength {
public String toString() {
return "x-ignore-filecontentlength";
}
},
x_ignore_formboundary {
public String toString() {
return "x-ignore-formboundary";
}
};
private static Set<FormField> HTTPHeaderFields = Sets.newHashSet(FormField.Content_Type, FormField.Cache_Control, FormField.Content_Disposition,
FormField.Content_Encoding, FormField.Expires);
public static boolean isHttpField(String value) {
try {
return HTTPHeaderFields.contains(FormField.valueOf(value.replace('-', '_')));
} catch (IllegalArgumentException e) {
return false;
}
}
}
public enum IgnoredFields {
AWSAccessKeyId, Signature, file, Policy, submit
}
public enum PolicyHeaders {
expiration, conditions
}
public enum CopyHeaders {
CopySourceIfMatch, CopySourceIfNoneMatch, CopySourceIfUnmodifiedSince, CopySourceIfModifiedSince
}
public enum MetadataDirective {
COPY, REPLACE
}
public enum ResponseHeaderOverrides {
response_content_type {
public String toString() {
return "response-content-type";
}
},
response_content_language {
public String toString() {
return "response-content-language";
}
},
response_expires {
public String toString() {
return "response-expires";
}
},
response_cache_control {
public String toString() {
return "response-cache-control";
}
},
response_content_disposition {
public String toString() {
return "response-content-disposition";
}
},
response_content_encoding {
public String toString() {
return "response-content-encoding";
}
};
public static ResponseHeaderOverrides fromString(String value) {
if (value != null && "response-content-type".equals(value)) {
return response_content_type;
}
if (value != null && "response-content-language".equals(value)) {
return response_content_language;
}
if (value != null && "response-expires".equals(value)) {
return response_expires;
}
if (value != null && "response-cache-control".equals(value)) {
return response_cache_control;
}
if (value != null && "response-content-disposition".equals(value)) {
return response_content_disposition;
}
if (value != null && "response-content-encoding".equals(value)) {
return response_content_encoding;
}
return null;
}
}
public static final Map<String, String> RESPONSE_OVERRIDE_HTTP_HEADER_MAP = ImmutableMap.<String, String>builder()
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_content_type.toString(), HttpHeaders.Names.CONTENT_TYPE)
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_content_language.toString(), HttpHeaders.Names.CONTENT_LANGUAGE)
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_expires.toString(), HttpHeaders.Names.EXPIRES)
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_cache_control.toString(), HttpHeaders.Names.CACHE_CONTROL)
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_content_disposition.toString(), "Content-Disposition")
.put(ObjectStorageProperties.ResponseHeaderOverrides.response_content_encoding.toString(), HttpHeaders.Names.CONTENT_ENCODING).build();
public enum HTTPVerb {
GET, PUT, DELETE, POST, HEAD, OPTIONS;
}
public enum ServiceParameter {
}
public enum BucketParameter {
acl, location, prefix, maxkeys, delimiter, marker, torrent, logging, versioning, versions, versionidmarker,
keymarker, cors, lifecycle, policy, notification, tagging, requestPayment, website, uploads, maxUploads,
uploadIdMarker, delete, accelerate, metrics, analytics, inventory, replication
}
public enum ObjectParameter {
acl, torrent, versionId, uploads, partNumber, uploadId, maxParts, partNumberMarker;
}
public enum RequiredQueryParams {
Date
}
public static String getTrackerUrl() {
try {
TRACKER_URL = "http://" + Topology.lookup(ObjectStorage.class).getUri().getHost() + ":" + TRACKER_PORT + "/announce";
} catch (Exception e) {
LOG.error(e);
}
return TRACKER_URL;
}
}