diff --git a/pom.xml b/pom.xml
index 51f7dabc..c65cebcc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
com.aliyun.oss
aliyun-sdk-oss
- 3.3.0-SNAPSHOT
+ 3.4.0
jar
Aliyun OSS SDK for Java
The Aliyun OSS SDK for Java used for accessing Aliyun Object Storage Service
diff --git a/src/main/java/com/aliyun/oss/ClientConfiguration.java b/src/main/java/com/aliyun/oss/ClientConfiguration.java
index ed5ea4e9..d4780b24 100644
--- a/src/main/java/com/aliyun/oss/ClientConfiguration.java
+++ b/src/main/java/com/aliyun/oss/ClientConfiguration.java
@@ -31,6 +31,7 @@
import com.aliyun.oss.common.auth.RequestSigner;
import com.aliyun.oss.common.comm.IdleConnectionReaper;
import com.aliyun.oss.common.comm.Protocol;
+import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.common.utils.ResourceManager;
import com.aliyun.oss.common.utils.VersionInfoUtils;
import com.aliyun.oss.internal.OSSConstants;
@@ -59,6 +60,8 @@ public class ClientConfiguration {
public static final String DEFAULT_CNAME_EXCLUDE_LIST = "aliyuncs.com,aliyun-inc.com,aliyun.com";
+ public static final SignVersion DEFAULT_SIGNATURE_VERSION = SignVersion.V1;
+
protected String userAgent = DEFAULT_USER_AGENT;
protected int maxErrorRetry = DEFAULT_MAX_RETRIES;
protected int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
@@ -94,9 +97,11 @@ public class ClientConfiguration {
protected List signerHandlers = new LinkedList();
+ protected SignVersion signatureVersion = DEFAULT_SIGNATURE_VERSION;
+
/**
* Gets the user agent string.
- *
+ *
* @return The user agent string.
*/
public String getUserAgent() {
@@ -105,7 +110,7 @@ public String getUserAgent() {
/**
* Sets the user agent string.
- *
+ *
* @param userAgent
* The user agent string.
*/
@@ -115,7 +120,7 @@ public void setUserAgent(String userAgent) {
/**
* Gets proxy host.
- *
+ *
* @return The proxy host in string.
*/
public String getProxyHost() {
@@ -124,7 +129,7 @@ public String getProxyHost() {
/**
* Sets the proxy host.
- *
+ *
* @param proxyHost
* The proxy host in string.
*/
@@ -134,7 +139,7 @@ public void setProxyHost(String proxyHost) {
/**
* Gets the proxy host's port.
- *
+ *
* @return The proxy host.
*/
public int getProxyPort() {
@@ -143,7 +148,7 @@ public int getProxyPort() {
/**
* Sets proxy port.
- *
+ *
* @param proxyPort
* The proxy port.
* @throws ClientException
@@ -159,7 +164,7 @@ public void setProxyPort(int proxyPort) throws ClientException {
/**
* Gets the proxy user name.
- *
+ *
* @return The user name.
*/
public String getProxyUsername() {
@@ -168,7 +173,7 @@ public String getProxyUsername() {
/**
* Sets the proxy user name.
- *
+ *
* @param proxyUsername
* The user name.
*/
@@ -178,7 +183,7 @@ public void setProxyUsername(String proxyUsername) {
/**
* Gets the proxy user password.
- *
+ *
* @return The proxy user password.
*/
public String getProxyPassword() {
@@ -187,7 +192,7 @@ public String getProxyPassword() {
/**
* Sets the proxy user password.
- *
+ *
* @param proxyPassword
* The proxy user password.
*/
@@ -198,7 +203,7 @@ public void setProxyPassword(String proxyPassword) {
/**
* Gets the proxy server's domain, which could do the NTLM authentiation
* (optional).
- *
+ *
* @return The proxy domain name.
*/
public String getProxyDomain() {
@@ -208,7 +213,7 @@ public String getProxyDomain() {
/**
* Sets the proxy server's domain, which could do the NTLM authentication
* (optional).
- *
+ *
* @param proxyDomain
* The proxy domain name.
*/
@@ -218,7 +223,7 @@ public void setProxyDomain(String proxyDomain) {
/**
* Gets the proxy host's NTLM authentication server.
- *
+ *
* @return The NTLM authentication server name.
*/
public String getProxyWorkstation() {
@@ -228,7 +233,7 @@ public String getProxyWorkstation() {
/**
* Sets the proxy host's NTLM authentication server(optional, if the proxy
* server does not require NTLM authentication, then it's not needed).
- *
+ *
* @param proxyWorkstation
* The proxy host's NTLM authentication server name.
*/
@@ -238,7 +243,7 @@ public void setProxyWorkstation(String proxyWorkstation) {
/**
* Gets the max connection count.
- *
+ *
* @return The max connection count. By default it's 1024.
*/
public int getMaxConnections() {
@@ -247,7 +252,7 @@ public int getMaxConnections() {
/**
* Sets the max connection count.
- *
+ *
* @param maxConnections
* The max connection count.
*/
@@ -258,7 +263,7 @@ public void setMaxConnections(int maxConnections) {
/**
* Gets the socket timeout in millisecond. 0 means infinite timeout, not
* recommended.
- *
+ *
* @return The socket timeout in millisecond.
*/
public int getSocketTimeout() {
@@ -268,7 +273,7 @@ public int getSocketTimeout() {
/**
* Sets the socket timeout in millisecond. 0 means infinite timeout, not
* recommended.
- *
+ *
* @param socketTimeout
* The socket timeout in millisecond.
*/
@@ -278,7 +283,7 @@ public void setSocketTimeout(int socketTimeout) {
/**
* Gets the socket connection timeout in millisecond.
- *
+ *
* @return The socket connection timeout in millisecond.
*/
public int getConnectionTimeout() {
@@ -287,7 +292,7 @@ public int getConnectionTimeout() {
/**
* Sets the socket connection timeout in millisecond.
- *
+ *
* @param connectionTimeout
* The socket connection timeout in millisecond.
*/
@@ -299,7 +304,7 @@ public void setConnectionTimeout(int connectionTimeout) {
* Gets the timeout in millisecond for retrieving an available connection
* from the connection manager. 0 means infinite and -1 means not defined.
* By default it's -1.
- *
+ *
* @return The timeout in millisecond.
*/
public int getConnectionRequestTimeout() {
@@ -309,7 +314,7 @@ public int getConnectionRequestTimeout() {
/**
* Sets the timeout in millisecond for retrieving an available connection
* from the connection manager.
- *
+ *
* @param connectionRequestTimeout
* The timeout in millisecond.
*/
@@ -319,7 +324,7 @@ public void setConnectionRequestTimeout(int connectionRequestTimeout) {
/**
* Gets the max retry count upon a retryable error. By default it's 3.
- *
+ *
* @return The max retry count.
*/
public int getMaxErrorRetry() {
@@ -328,7 +333,7 @@ public int getMaxErrorRetry() {
/**
* Sets the max retry count upon a retryable error. By default it's 3.
- *
+ *
* @param maxErrorRetry
* The max retry count.
*/
@@ -339,7 +344,7 @@ public void setMaxErrorRetry(int maxErrorRetry) {
/**
* Gets the connection TTL (time to live). Http connection is cached by the
* connection manager with a TTL.
- *
+ *
* @return The connection TTL in millisecond.
*/
public long getConnectionTTL() {
@@ -349,7 +354,7 @@ public long getConnectionTTL() {
/**
* Sets the connection TTL (time to live). Http connection is cached by the
* connection manager with a TTL.
- *
+ *
* @param connectionTTL
* The connection TTL in millisecond.
*/
@@ -376,7 +381,7 @@ public void setUseReaper(boolean useReaper) {
/**
* Gets the connection's max idle time. If a connection has been idle for
* more than this number, it would be closed.
- *
+ *
* @return The connection's max idle time in millisecond.
*/
public long getIdleConnectionTime() {
@@ -386,7 +391,7 @@ public long getIdleConnectionTime() {
/**
* Sets the connection's max idle time. If a connection has been idle for
* more than this number, it would be closed.
- *
+ *
* @param idleConnectionTime
* The connection's max idle time in millisecond.
*/
@@ -411,7 +416,7 @@ public void setProtocol(Protocol protocol) {
/**
* Gets the immutable excluded CName list----any domain ends with an item in
* this list will not do Cname resolution.
- *
+ *
* @return The excluded CName list, immutable.
*/
public List getCnameExcludeList() {
@@ -428,7 +433,7 @@ public List getCnameExcludeList() {
/**
* Sets the immutable excluded CName list----any domain ends with an item in
* this list will not do Cname resolution.
- *
+ *
* @param cnameExcludeList
* The excluded CName list, immutable.
*/
@@ -449,7 +454,7 @@ public void setCnameExcludeList(List cnameExcludeList) {
/**
* Append default excluded CName list.
- *
+ *
* @param excludeList
* The excluded CName list.
*/
@@ -464,7 +469,7 @@ private static void AppendDefaultExcludeList(List excludeList) {
/**
* Gets the flag if supporting Cname in the endpoint. By default it's true.
- *
+ *
* @return True if supporting Cname; False if not.
*/
public boolean isSupportCname() {
@@ -473,7 +478,7 @@ public boolean isSupportCname() {
/**
* Sets the flag if supporting Cname in the endpoint. By default it's true.
- *
+ *
*
* If this value is set true, when building a canonical url, the host would
* be checked against the Cname excluded list. If that host is found in the
@@ -481,7 +486,7 @@ public boolean isSupportCname() {
* domain). If the host is found, then it's thought as CName. If this value
* is set false, then always uses TLD to access the endpoint.
*
- *
+ *
* @param supportCname
* The flag if supporting CName.
*/
@@ -494,7 +499,7 @@ public ClientConfiguration setSupportCname(boolean supportCname) {
* Gets the flag of using SLD (Second Level Domain) style to access the
* endpoint. By default it's false. When using SLD, then the bucket endpoint
* would be: http://host/bucket. Otherwise, it will be http://bucket.host
- *
+ *
* @return True if it's enabled; False if it's disabled.
*/
public boolean isSLDEnabled() {
@@ -504,7 +509,7 @@ public boolean isSLDEnabled() {
/**
* Sets the flag of using SLD (Second Level Domain) style to access the
* endpoint. By default it's false.
- *
+ *
* @param enabled
* True if it's enabled; False if it's disabled.
*/
@@ -516,7 +521,7 @@ public ClientConfiguration setSLDEnabled(boolean enabled) {
/**
* The connection idle time threshold in millisecond that triggers the
* validation. By default it's 2000.
- *
+ *
* @return The connection idle time threshold.
*/
public int getValidateAfterInactivity() {
@@ -525,7 +530,7 @@ public int getValidateAfterInactivity() {
/**
* Gets the flag of enabling request timeout. By default it's disabled.
- *
+ *
* @return true enabled; false disabled.
*/
public boolean isRequestTimeoutEnabled() {
@@ -534,7 +539,7 @@ public boolean isRequestTimeoutEnabled() {
/**
* Gets the flag of enabling request timeout. By default it's disabled.
- *
+ *
* @param requestTimeoutEnabled
* true to enable; false to disable.
*/
@@ -585,7 +590,7 @@ public Map getDefaultHeaders() {
* Sets the default http headers. All these headers would be automatically
* added in every request. And if a header is also specified in the request,
* the default one will be overwritten.
- *
+ *
* @param defaultHeaders
* Default http headers.
*/
@@ -595,7 +600,7 @@ public void setDefaultHeaders(Map defaultHeaders) {
/**
* Add a default header into the default header list.
- *
+ *
* @param key
* The default header name.
* @param value
@@ -608,7 +613,7 @@ public void addDefaultHeader(String key, String value) {
/**
* Gets the flag of enabling CRC checksum on upload and download. By default
* it's true.
- *
+ *
* @return true enable CRC;false disable CRC.
*/
public boolean isCrcCheckEnabled() {
@@ -618,7 +623,7 @@ public boolean isCrcCheckEnabled() {
/**
* Sets the flag of enabling CRC checksum on upload and download. By default
* it's true.
- *
+ *
* @param crcCheckEnabled
* True to enable CRC; False to disable CRC.
*/
@@ -628,7 +633,7 @@ public void setCrcCheckEnabled(boolean crcCheckEnabled) {
/**
* Gets signer handlers
- *
+ *
* @return signer handlers
*/
public List getSignerHandlers() {
@@ -637,7 +642,7 @@ public List getSignerHandlers() {
/**
* Sets signer handlers using for authentication of the proxy server.
- *
+ *
* @param signerHandlers
*/
public void setSignerHandlers(List signerHandlers) {
@@ -652,4 +657,21 @@ public void setSignerHandlers(List signerHandlers) {
}
}
+ /**
+ * Gets signature version
+ *
+ * @return signature version
+ */
+ public SignVersion getSignatureVersion() {
+ return signatureVersion;
+ }
+
+ /**
+ * Sets signature version for all request.
+ *
+ * @param signatureVersion
+ */
+ public void setSignatureVersion(SignVersion signatureVersion) {
+ this.signatureVersion = signatureVersion;
+ }
}
diff --git a/src/main/java/com/aliyun/oss/OSS.java b/src/main/java/com/aliyun/oss/OSS.java
index 8dd43568..007c3e2d 100644
--- a/src/main/java/com/aliyun/oss/OSS.java
+++ b/src/main/java/com/aliyun/oss/OSS.java
@@ -28,6 +28,7 @@
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.comm.ResponseMessage;
+import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import com.aliyun.oss.model.SetBucketCORSRequest.CORSRule;
@@ -52,6 +53,14 @@ public interface OSS {
*/
public void switchCredentials(Credentials creds);
+ /**
+ * Switches to another signature version
+ *
+ * @param signatureVersion
+ * the signature version to switch to。
+ */
+ public void switchSignatureVersion(SignVersion signatureVersion);
+
/**
* Shuts down the OSS instance (release all resources) The OSS instance is
* not usable after its shutdown() is called.
@@ -706,6 +715,28 @@ public SimplifiedObjectMeta getSimplifiedObjectMeta(GenericRequest genericReques
*/
public SelectObjectMetadata createSelectObjectMetadata(CreateSelectObjectMetadataRequest createSelectObjectMetadataRequest) throws OSSException, ClientException;
+ /**
+ * Gets all the head data of {@link OSSObject}.
+ *
+ * @param bucketName
+ * Bucket name.
+ * @param key
+ * Object key.
+ *
+ * @return The {@link ObjectMetadata} instance.
+ */
+ public ObjectMetadata headObject(String bucketName, String key) throws OSSException, ClientException;
+
+ /**
+ * Gets all the head data of {@link OSSObject}.
+ *
+ * @param headObjectRequest
+ * A {@link HeadObjectRequest} instance which specifies the
+ * bucket name and object key, and some constraint information can be set.
+ * @return The {@link ObjectMetadata} instance.
+ */
+ public ObjectMetadata headObject(HeadObjectRequest headObjectRequest) throws OSSException, ClientException;
+
/**
* Append the data to the appendable object specified in
* {@link AppendObjectRequest}. It's not applicable to normal OSS object.
@@ -2142,6 +2173,45 @@ public void generateVodPlaylist(String bucketName, String liveChannelName, Strin
public void generateVodPlaylist(GenerateVodPlaylistRequest generateVodPlaylistRequest)
throws OSSException, ClientException;
+ /**
+ * Generates and returns a VOD playlist (m3u8 format) for the *.ts files with specified
+ * time range under the Live Channel, but this VOD playlist would not be stored in OSS Server.
+ *
+ * @param bucketName
+ * Bucket name.
+ * @param liveChannelName
+ * Live Channel name.
+ * @param startTime
+ * The start time of the playlist in epoch time (means *.ts files
+ * time is same or later than it)
+ * @param endTime
+ * The end time of the playlist in epoch time(means *.ts files
+ * time is no later than it).
+ * @return A {@link OSSObject} instance.
+ * @throws OSSException
+ * OSS Server side exception.
+ * @throws ClientException
+ * OSS Client side exception.
+ */
+ public OSSObject getVodPlaylist(String bucketName, String liveChannelName, long startTime,
+ long endTime) throws OSSException, ClientException;
+
+ /**
+ * Generates and returns a VOD playlist (m3u8 format) for the *.ts files with specified
+ * time range under the Live Channel, but this VOD playlist would not be stored in OSS Server.
+ *
+ * @param getVodPlaylistRequest
+ * A {@link GetVodPlaylistRequest} instance the specifies
+ * the bucket name and the Live Channel name.
+ * @return A {@link OSSObject} instance.
+ * @throws OSSException
+ * OSS Server side exception.
+ * @throws ClientException
+ * OSS Client side exception.
+ */
+ public OSSObject getVodPlaylist(GetVodPlaylistRequest getVodPlaylistRequest)
+ throws OSSException, ClientException;
+
/**
* Generates a RTMP pushing streaming address in the Live Channel.
*
diff --git a/src/main/java/com/aliyun/oss/OSSClient.java b/src/main/java/com/aliyun/oss/OSSClient.java
index bee1e83b..f8a4c8a4 100644
--- a/src/main/java/com/aliyun/oss/OSSClient.java
+++ b/src/main/java/com/aliyun/oss/OSSClient.java
@@ -26,10 +26,6 @@
import static com.aliyun.oss.internal.OSSConstants.DEFAULT_OSS_ENDPOINT;
import static com.aliyun.oss.internal.OSSUtils.OSS_RESOURCE_MANAGER;
import static com.aliyun.oss.internal.OSSUtils.ensureBucketNameValid;
-import static com.aliyun.oss.internal.OSSUtils.populateResponseHeaderParameters;
-import static com.aliyun.oss.internal.RequestParameters.OSS_ACCESS_KEY_ID;
-import static com.aliyun.oss.internal.RequestParameters.SECURITY_TOKEN;
-import static com.aliyun.oss.internal.RequestParameters.SIGNATURE;
import java.io.File;
import java.io.FileInputStream;
@@ -44,8 +40,6 @@
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -53,27 +47,10 @@
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.auth.ServiceSignature;
-import com.aliyun.oss.common.comm.DefaultServiceClient;
-import com.aliyun.oss.common.comm.RequestMessage;
-import com.aliyun.oss.common.comm.ResponseMessage;
-import com.aliyun.oss.common.comm.ServiceClient;
-import com.aliyun.oss.common.comm.TimeoutServiceClient;
+import com.aliyun.oss.common.comm.*;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.common.utils.DateUtil;
-import com.aliyun.oss.common.utils.HttpHeaders;
-import com.aliyun.oss.common.utils.HttpUtil;
-import com.aliyun.oss.internal.CORSOperation;
-import com.aliyun.oss.internal.LiveChannelOperation;
-import com.aliyun.oss.internal.OSSBucketOperation;
-import com.aliyun.oss.internal.OSSDownloadOperation;
-import com.aliyun.oss.internal.OSSHeaders;
-import com.aliyun.oss.internal.OSSMultipartOperation;
-import com.aliyun.oss.internal.OSSObjectOperation;
-import com.aliyun.oss.internal.OSSUdfOperation;
-import com.aliyun.oss.internal.OSSUploadOperation;
-import com.aliyun.oss.internal.OSSUtils;
-import com.aliyun.oss.internal.RequestParameters;
-import com.aliyun.oss.internal.SignUtils;
+import com.aliyun.oss.internal.*;
import com.aliyun.oss.model.*;
import com.aliyun.oss.model.SetBucketCORSRequest.CORSRule;
@@ -320,6 +297,15 @@ public void switchCredentials(Credentials creds) {
this.credsProvider.setCredentials(creds);
}
+ @Override
+ public void switchSignatureVersion(SignVersion signatureVersion) {
+ if (signatureVersion == null) {
+ throw new IllegalArgumentException("signatureVersion should not be null.");
+ }
+
+ this.getClientConfiguration().setSignatureVersion(signatureVersion);
+ }
+
public CredentialsProvider getCredentialsProvider() {
return this.credsProvider;
}
@@ -593,6 +579,16 @@ public ObjectMetadata getObjectMetadata(GenericRequest genericRequest) throws OS
return objectOperation.getObjectMetadata(genericRequest);
}
+ @Override
+ public ObjectMetadata headObject(String bucketName, String key) throws OSSException, ClientException {
+ return this.headObject(new HeadObjectRequest(bucketName, key));
+ }
+
+ @Override
+ public ObjectMetadata headObject(HeadObjectRequest headObjectRequest) throws OSSException, ClientException {
+ return objectOperation.headObject(headObjectRequest);
+ }
+
@Override
public AppendObjectResult appendObject(AppendObjectRequest appendObjectRequest)
throws OSSException, ClientException {
@@ -691,7 +687,6 @@ public URL generatePresignedUrl(GeneratePresignedUrlRequest request) throws Clie
assertParameterNotNull(request, "request");
- String bucketName = request.getBucketName();
if (request.getBucketName() == null) {
throw new IllegalArgumentException(OSS_RESOURCE_MANAGER.getString("MustSetBucketName"));
}
@@ -700,74 +695,13 @@ public URL generatePresignedUrl(GeneratePresignedUrlRequest request) throws Clie
if (request.getExpiration() == null) {
throw new IllegalArgumentException(OSS_RESOURCE_MANAGER.getString("MustSetExpiration"));
}
+ String url;
- Credentials currentCreds = credsProvider.getCredentials();
- String accessId = currentCreds.getAccessKeyId();
- String accessKey = currentCreds.getSecretAccessKey();
- boolean useSecurityToken = currentCreds.useSecurityToken();
- HttpMethod method = request.getMethod() != null ? request.getMethod() : HttpMethod.GET;
-
- String expires = String.valueOf(request.getExpiration().getTime() / 1000L);
- String key = request.getKey();
- ClientConfiguration config = serviceClient.getClientConfiguration();
- String resourcePath = OSSUtils.determineResourcePath(bucketName, key, config.isSLDEnabled());
-
- RequestMessage requestMessage = new RequestMessage(bucketName, key);
- requestMessage.setEndpoint(OSSUtils.determineFinalEndpoint(endpoint, bucketName, config));
- requestMessage.setMethod(method);
- requestMessage.setResourcePath(resourcePath);
- requestMessage.setHeaders(request.getHeaders());
-
- requestMessage.addHeader(HttpHeaders.DATE, expires);
- if (request.getContentType() != null && !request.getContentType().trim().equals("")) {
- requestMessage.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType());
- }
- if (request.getContentMD5() != null && request.getContentMD5().trim().equals("")) {
- requestMessage.addHeader(HttpHeaders.CONTENT_MD5, request.getContentMD5());
- }
- for (Map.Entry h : request.getUserMetadata().entrySet()) {
- requestMessage.addHeader(OSSHeaders.OSS_USER_METADATA_PREFIX + h.getKey(), h.getValue());
- }
-
- Map responseHeaderParams = new HashMap();
- populateResponseHeaderParameters(responseHeaderParams, request.getResponseHeaders());
- if (responseHeaderParams.size() > 0) {
- requestMessage.setParameters(responseHeaderParams);
- }
-
- if (request.getQueryParameter() != null && request.getQueryParameter().size() > 0) {
- for (Map.Entry entry : request.getQueryParameter().entrySet()) {
- requestMessage.addParameter(entry.getKey(), entry.getValue());
- }
- }
-
- if (request.getProcess() != null && !request.getProcess().trim().equals("")) {
- requestMessage.addParameter(RequestParameters.SUBRESOURCE_PROCESS, request.getProcess());
- }
-
- if (useSecurityToken) {
- requestMessage.addParameter(SECURITY_TOKEN, currentCreds.getSecurityToken());
- }
-
- String canonicalResource = "/" + ((bucketName != null) ? bucketName : "") + ((key != null ? "/" + key : ""));
- String canonicalString = SignUtils.buildCanonicalString(method.toString(), canonicalResource, requestMessage,
- expires);
- String signature = ServiceSignature.create().computeSignature(accessKey, canonicalString);
-
- Map params = new LinkedHashMap();
- params.put(HttpHeaders.EXPIRES, expires);
- params.put(OSS_ACCESS_KEY_ID, accessId);
- params.put(SIGNATURE, signature);
- params.putAll(requestMessage.getParameters());
-
- String queryString = HttpUtil.paramToQueryString(params, DEFAULT_CHARSET_NAME);
-
- /* Compse HTTP request uri. */
- String url = requestMessage.getEndpoint().toString();
- if (!url.endsWith("/")) {
- url += "/";
+ if (serviceClient.getClientConfiguration().getSignatureVersion() != null && serviceClient.getClientConfiguration().getSignatureVersion() == SignVersion.V2) {
+ url = SignV2Utils.buildSignedURL(request, credsProvider.getCredentials(), serviceClient.getClientConfiguration(), endpoint);
+ } else {
+ url = SignUtils.buildSignedURL(request, credsProvider.getCredentials(), serviceClient.getClientConfiguration(), endpoint);
}
- url += resourcePath + "?" + queryString;
try {
return new URL(url);
@@ -1278,6 +1212,19 @@ public void generateVodPlaylist(GenerateVodPlaylistRequest generateVodPlaylistRe
liveChannelOperation.generateVodPlaylist(generateVodPlaylistRequest);
}
+ @Override
+ public OSSObject getVodPlaylist(String bucketName, String liveChannelName, long startTime,
+ long endTime) throws OSSException, ClientException {
+ return this.getVodPlaylist(
+ new GetVodPlaylistRequest(bucketName, liveChannelName, startTime, endTime));
+ }
+
+ @Override
+ public OSSObject getVodPlaylist(GetVodPlaylistRequest getVodPlaylistRequest)
+ throws OSSException, ClientException {
+ return liveChannelOperation.getVodPlaylist(getVodPlaylistRequest);
+ }
+
@Override
public String generateRtmpUri(String bucketName, String liveChannelName, String PlaylistName, long expires)
throws OSSException, ClientException {
diff --git a/src/main/java/com/aliyun/oss/common/auth/HmacSHA1Signature.java b/src/main/java/com/aliyun/oss/common/auth/HmacSHA1Signature.java
index 2579eac7..588dd727 100644
--- a/src/main/java/com/aliyun/oss/common/auth/HmacSHA1Signature.java
+++ b/src/main/java/com/aliyun/oss/common/auth/HmacSHA1Signature.java
@@ -20,11 +20,7 @@
package com.aliyun.oss.common.auth;
import java.io.UnsupportedEncodingException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
import com.aliyun.oss.common.utils.BinaryUtil;
@@ -57,39 +53,12 @@ public String getVersion() {
public String computeSignature(String key, String data) {
try {
- byte[] signData = sign(key.getBytes(DEFAULT_ENCODING), data.getBytes(DEFAULT_ENCODING));
+ byte[] signData = sign(key.getBytes(DEFAULT_ENCODING), data.getBytes(DEFAULT_ENCODING), macInstance,
+ LOCK, ALGORITHM);
return BinaryUtil.toBase64String(signData);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
}
}
- private byte[] sign(byte[] key, byte[] data) {
- try {
- // Because Mac.getInstance(String) calls a synchronized method, it
- // could block on
- // invoked concurrently, so use prototype pattern to improve perf.
- if (macInstance == null) {
- synchronized (LOCK) {
- if (macInstance == null) {
- macInstance = Mac.getInstance(ALGORITHM);
- }
- }
- }
-
- Mac mac = null;
- try {
- mac = (Mac) macInstance.clone();
- } catch (CloneNotSupportedException e) {
- // If it is not clonable, create a new one.
- mac = Mac.getInstance(ALGORITHM);
- }
- mac.init(new SecretKeySpec(key, ALGORITHM));
- return mac.doFinal(data);
- } catch (NoSuchAlgorithmException ex) {
- throw new RuntimeException("Unsupported algorithm: " + ALGORITHM, ex);
- } catch (InvalidKeyException ex) {
- throw new RuntimeException("Invalid key: " + key, ex);
- }
- }
}
\ No newline at end of file
diff --git a/src/main/java/com/aliyun/oss/common/auth/HmacSHA256Signature.java b/src/main/java/com/aliyun/oss/common/auth/HmacSHA256Signature.java
new file mode 100644
index 00000000..d7d2dd10
--- /dev/null
+++ b/src/main/java/com/aliyun/oss/common/auth/HmacSHA256Signature.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License 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.aliyun.oss.common.auth;
+
+import java.io.UnsupportedEncodingException;
+import javax.crypto.Mac;
+
+import com.aliyun.oss.common.utils.BinaryUtil;
+
+/**
+ * Used for computing Hmac-SHA256 signature.
+ */
+public class HmacSHA256Signature extends ServiceSignature {
+
+ /* The default encoding. */
+ private static final String DEFAULT_ENCODING = "UTF-8";
+
+ /* Signature method. */
+ private static final String ALGORITHM = "HmacSHA256";
+
+ /* Signature version. */
+ private static final String VERSION = "1";
+
+ private static final Object LOCK = new Object();
+
+ /* Prototype of the Mac instance. */
+ private static Mac macInstance;
+
+ public String getAlgorithm() {
+ return ALGORITHM;
+ }
+
+ public String getVersion() {
+ return VERSION;
+ }
+
+ public String computeSignature(String key, String data) {
+ try {
+ byte[] signData = sign(key.getBytes(DEFAULT_ENCODING), data.getBytes(DEFAULT_ENCODING), macInstance,
+ LOCK, ALGORITHM);
+ return BinaryUtil.toBase64String(signData);
+ } catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException("Unsupported algorithm: " + DEFAULT_ENCODING, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/aliyun/oss/common/auth/ServiceSignature.java b/src/main/java/com/aliyun/oss/common/auth/ServiceSignature.java
index a26b8f37..d34da79d 100644
--- a/src/main/java/com/aliyun/oss/common/auth/ServiceSignature.java
+++ b/src/main/java/com/aliyun/oss/common/auth/ServiceSignature.java
@@ -19,6 +19,11 @@
package com.aliyun.oss.common.auth;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
/**
* The interface to compute the signature of the data.
*/
@@ -59,4 +64,34 @@ public abstract class ServiceSignature {
public static ServiceSignature create() {
return new HmacSHA1Signature();
}
+
+ protected byte[] sign(byte[] key, byte[] data, Mac macInstance, Object lock, String algorithm) {
+ try {
+ // Because Mac.getInstance(String) calls a synchronized method, it
+ // could block on
+ // invoked concurrently, so use prototype pattern to improve perf.
+ if (macInstance == null) {
+ synchronized (lock) {
+ if (macInstance == null) {
+ macInstance = Mac.getInstance(algorithm);
+ }
+ }
+ }
+
+ Mac mac;
+ try {
+ mac = (Mac) macInstance.clone();
+ } catch (CloneNotSupportedException e) {
+ // If it is not clonable, create a new one.
+ mac = Mac.getInstance(algorithm);
+ }
+ mac.init(new SecretKeySpec(key, algorithm));
+ return mac.doFinal(data);
+ } catch (NoSuchAlgorithmException ex) {
+ throw new RuntimeException("Unsupported algorithm: " + algorithm, ex);
+ } catch (InvalidKeyException ex) {
+ throw new RuntimeException("Invalid key: " + key, ex);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/com/aliyun/oss/common/comm/SignVersion.java b/src/main/java/com/aliyun/oss/common/comm/SignVersion.java
new file mode 100644
index 00000000..31d0b0f9
--- /dev/null
+++ b/src/main/java/com/aliyun/oss/common/comm/SignVersion.java
@@ -0,0 +1,6 @@
+package com.aliyun.oss.common.comm;
+
+public enum SignVersion {
+ V1,
+ V2
+}
diff --git a/src/main/java/com/aliyun/oss/common/utils/StringUtils.java b/src/main/java/com/aliyun/oss/common/utils/StringUtils.java
index 9dcb38a6..b64691fb 100644
--- a/src/main/java/com/aliyun/oss/common/utils/StringUtils.java
+++ b/src/main/java/com/aliyun/oss/common/utils/StringUtils.java
@@ -23,6 +23,7 @@
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.text.Collator;
+import java.util.Collection;
import java.util.Locale;
/**
@@ -148,6 +149,25 @@ public static String join(String joiner, String... parts) {
return builder.toString();
}
+ /**
+ * Joins the strings in collection with joiner between each string
+ * @param joiner the string to insert between the strings in collection
+ * @param collection the collection to join
+ */
+ public static String join(String joiner, Collection collection) {
+ StringBuilder builder = new StringBuilder();
+ int i = 0;
+
+ for (String part : collection) {
+ builder.append(part);
+ if (i < collection.size() - 1) {
+ builder.append(joiner);
+ }
+ i++;
+ }
+ return builder.toString();
+ }
+
/**
* A null-safe trim method. If the input string is null, returns null;
* otherwise returns a trimmed version of the input.
diff --git a/src/main/java/com/aliyun/oss/internal/LiveChannelOperation.java b/src/main/java/com/aliyun/oss/internal/LiveChannelOperation.java
index ca2805ed..b3e7a533 100644
--- a/src/main/java/com/aliyun/oss/internal/LiveChannelOperation.java
+++ b/src/main/java/com/aliyun/oss/internal/LiveChannelOperation.java
@@ -32,6 +32,7 @@
import static com.aliyun.oss.internal.ResponseParsers.getLiveChannelInfoResponseParser;
import static com.aliyun.oss.internal.ResponseParsers.getLiveChannelStatResponseParser;
import static com.aliyun.oss.internal.ResponseParsers.listLiveChannelsReponseParser;
+import static com.aliyun.oss.internal.ResponseParsers.GetObjectResponseParser;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
@@ -65,6 +66,8 @@
import com.aliyun.oss.model.LiveChannelStat;
import com.aliyun.oss.model.LiveRecord;
import com.aliyun.oss.model.SetLiveChannelRequest;
+import com.aliyun.oss.model.GetVodPlaylistRequest;
+import com.aliyun.oss.model.OSSObject;
/**
* Live channel operation.
@@ -268,7 +271,7 @@ public void generateVodPlaylist(GenerateVodPlaylistRequest generateVodPlaylistRe
String bucketName = generateVodPlaylistRequest.getBucketName();
String liveChannelName = generateVodPlaylistRequest.getLiveChannelName();
String playlistName = generateVodPlaylistRequest.getPlaylistName();
- Long startTime = generateVodPlaylistRequest.getStratTime();
+ Long startTime = generateVodPlaylistRequest.getStartTime();
Long endTime = generateVodPlaylistRequest.getEndTime();
assertParameterNotNull(bucketName, "bucketName");
@@ -276,7 +279,7 @@ public void generateVodPlaylist(GenerateVodPlaylistRequest generateVodPlaylistRe
assertParameterNotNull(liveChannelName, "liveChannelName");
ensureLiveChannelNameValid(liveChannelName);
assertParameterNotNull(playlistName, "playlistName");
- assertParameterNotNull(startTime, "stratTime");
+ assertParameterNotNull(startTime, "startTime");
assertParameterNotNull(endTime, "endTime");
Map parameters = new HashMap();
@@ -293,6 +296,34 @@ public void generateVodPlaylist(GenerateVodPlaylistRequest generateVodPlaylistRe
doOperation(request, emptyResponseParser, bucketName, key);
}
+ public OSSObject getVodPlaylist(GetVodPlaylistRequest getVodPlaylistRequest) throws OSSException, ClientException {
+
+ assertParameterNotNull(getVodPlaylistRequest, "getVodPlaylistRequest");
+
+ String bucketName = getVodPlaylistRequest.getBucketName();
+ String liveChannelName = getVodPlaylistRequest.getLiveChannelName();
+ Long startTime = getVodPlaylistRequest.getStartTime();
+ Long endTime = getVodPlaylistRequest.getEndTime();
+
+ assertParameterNotNull(bucketName, "bucketName");
+ ensureBucketNameValid(bucketName);
+ assertParameterNotNull(liveChannelName, "liveChannelName");
+ ensureLiveChannelNameValid(liveChannelName);
+ assertParameterNotNull(startTime, "startTime");
+ assertParameterNotNull(endTime, "endTime");
+
+ Map parameters = new HashMap();
+ parameters.put(RequestParameters.SUBRESOURCE_VOD, null);
+ parameters.put(RequestParameters.SUBRESOURCE_START_TIME, startTime.toString());
+ parameters.put(RequestParameters.SUBRESOURCE_END_TIME, endTime.toString());
+
+ RequestMessage request = new OSSRequestMessageBuilder(getInnerClient()).setEndpoint(getEndpoint())
+ .setMethod(HttpMethod.GET).setBucket(bucketName).setKey(liveChannelName).setParameters(parameters)
+ .setOriginalRequest(getVodPlaylistRequest).build();
+
+ return doOperation(request, new GetObjectResponseParser(bucketName, liveChannelName), bucketName, liveChannelName, true);
+ }
+
public String generateRtmpUri(GenerateRtmpUriRequest request) throws OSSException, ClientException {
assertParameterNotNull(request, "request");
diff --git a/src/main/java/com/aliyun/oss/internal/OSSConstants.java b/src/main/java/com/aliyun/oss/internal/OSSConstants.java
index ff4186cf..30067677 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSConstants.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSConstants.java
@@ -42,9 +42,6 @@ public final class OSSConstants {
public static final int OBJECT_NAME_MAX_LENGTH = 1024;
- public static final String OSS_AUTHORIZATION_PREFIX = "OSS ";
- public static final String OSS_AUTHORIZATION_SEPERATOR = ":";
-
public static final String LOGGER_PACKAGE_NAME = "com.aliyun.oss";
public static final String PROTOCOL_HTTP = "http://";
diff --git a/src/main/java/com/aliyun/oss/internal/OSSDownloadOperation.java b/src/main/java/com/aliyun/oss/internal/OSSDownloadOperation.java
index dce8c350..6df8eccd 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSDownloadOperation.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSDownloadOperation.java
@@ -48,6 +48,9 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import com.aliyun.oss.InconsistentException;
+import com.aliyun.oss.common.utils.CRC64;
+import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.event.ProgressPublisher;
@@ -58,6 +61,7 @@
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.SimplifiedObjectMeta;
+import com.aliyun.oss.model.HeadObjectRequest;
/**
* OSSDownloadOperation
@@ -201,13 +205,16 @@ public int hashCode() {
result = prime * result + (isCompleted ? 1231 : 1237);
result = prime * result + (int) (end ^ (end >>> 32));
result = prime * result + (int) (start ^ (start >>> 32));
+ result = prime * result + (int) (crc ^ (crc >>> 32));
return result;
}
public int index; // part index (starting from 0).
public long start; // start index;
public long end; // end index;
- public boolean isCompleted; // flag of part download finished or not.
+ public boolean isCompleted; // flag of part download finished or not;
+ public long length; // length of part
+ public long crc; // part crc.
}
static class PartResult {
@@ -218,6 +225,14 @@ public PartResult(int number, long start, long end) {
this.end = end;
}
+ public PartResult(int number, long start, long end, long length, long clientCRC) {
+ this.number = number;
+ this.start = start;
+ this.end = end;
+ this.length = length;
+ this.clientCRC = clientCRC;
+ }
+
public long getStart() {
return start;
}
@@ -254,11 +269,34 @@ public void setException(Exception exception) {
this.exception = exception;
}
+ public Long getClientCRC() { return clientCRC; }
+
+ public void setClientCRC(Long clientCRC) { this.clientCRC = clientCRC; }
+
+ public Long getServerCRC() {
+ return serverCRC;
+ }
+
+ public void setServerCRC(Long serverCRC) {
+ this.serverCRC = serverCRC;
+ }
+
+ public long getLength() {
+ return length;
+ }
+
+ public void setLength(long length) {
+ this.length = length;
+ }
private int number; // part number, starting from 1.
private long start; // start index in the part.
private long end; // end index in the part.
private boolean failed; // flag of part upload failure.
private Exception exception; // Exception during part upload.
+ private Long clientCRC; // client crc of this part
+ private Long serverCRC; // server crc of this file
+
+ private long length;
}
static class DownloadResult {
@@ -347,13 +385,29 @@ private DownloadFileResult downloadFileWithCheckpoint(DownloadFileRequest downlo
// Concurrently download parts.
DownloadResult downloadResult = download(downloadCheckPoint, downloadFileRequest);
+ Long serverCRC = null;
for (PartResult partResult : downloadResult.getPartResults()) {
+ if (partResult.getServerCRC() != null) {
+ serverCRC = partResult.getServerCRC();
+ }
if (partResult.isFailed()) {
ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_PART_FAILED_EVENT);
throw partResult.getException();
}
}
+ // check crc64
+ if(objectOperation.getInnerClient().getClientConfiguration().isCrcCheckEnabled()) {
+ Long clientCRC = calcObjectCRCFromParts(downloadResult.getPartResults());
+ try {
+ OSSUtils.checkChecksum(clientCRC, serverCRC, downloadResult.getObjectMetadata().getRequestId());
+ } catch (Exception e) {
+ ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
+ throw new InconsistentException(clientCRC, serverCRC, downloadResult.getObjectMetadata().getRequestId());
+ }
+ }
+
+
// Publish the complete status.
ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_COMPLETED_EVENT);
@@ -398,6 +452,18 @@ public static void createFixedFile(String filePath, long length) throws IOExcept
}
}
+ private static Long calcObjectCRCFromParts(List partResults) {
+ long crc = 0;
+
+ for (PartResult partResult : partResults) {
+ if (partResult.getClientCRC() == null || partResult.getLength() <= 0) {
+ return null;
+ }
+ crc = CRC64.combine(crc, partResult.getClientCRC(), partResult.getLength());
+ }
+ return new Long(crc);
+ }
+
private DownloadResult download(DownloadCheckPoint downloadCheckPoint, DownloadFileRequest downloadFileRequest)
throws Throwable {
DownloadResult downloadResult = new DownloadResult();
@@ -428,7 +494,8 @@ private DownloadResult download(DownloadCheckPoint downloadCheckPoint, DownloadF
tasks.add(task);
} else {
taskResults.add(new PartResult(i + 1, downloadCheckPoint.downloadParts.get(i).start,
- downloadCheckPoint.downloadParts.get(i).end));
+ downloadCheckPoint.downloadParts.get(i).end, downloadCheckPoint.downloadParts.get(i).length,
+ downloadCheckPoint.downloadParts.get(i).crc));
}
}
service.shutdown();
@@ -509,6 +576,14 @@ public PartResult call() throws Exception {
output.write(buffer, 0, bytesRead);
}
+ if (objectOperation.getInnerClient().getClientConfiguration().isCrcCheckEnabled()) {
+ Long clientCRC = IOUtils.getCRCValue(content);
+ tr.setClientCRC(clientCRC);
+ tr.setServerCRC(objectMetadata.getServerCRC());
+ tr.setLength(objectMetadata.getContentLength());
+ downloadPart.length = objectMetadata.getContentLength();
+ downloadPart.crc = clientCRC;
+ }
downloadCheckPoint.update(partIndex, true);
if (downloadFileRequest.isEnableCheckpoint()) {
downloadCheckPoint.dump(downloadFileRequest.getCheckpointFile());
diff --git a/src/main/java/com/aliyun/oss/internal/OSSHeaders.java b/src/main/java/com/aliyun/oss/internal/OSSHeaders.java
index 6700d09d..9470f3e6 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSHeaders.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSHeaders.java
@@ -31,6 +31,7 @@ public interface OSSHeaders extends HttpHeaders {
static final String OSS_VERSION_ID = "x-oss-version-id";
static final String OSS_SERVER_SIDE_ENCRYPTION = "x-oss-server-side-encryption";
+ static final String OSS_SERVER_SIDE_ENCRYPTION_KEY_ID = "x-oss-server-side-encryption-key-id";
static final String GET_OBJECT_IF_MODIFIED_SINCE = "If-Modified-Since";
static final String GET_OBJECT_IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
diff --git a/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java b/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java
index 20c18a1d..f7b8f4e7 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSObjectOperation.java
@@ -62,6 +62,7 @@
import static com.aliyun.oss.internal.ResponseParsers.putObjectProcessReponseParser;
import static com.aliyun.oss.internal.ResponseParsers.getSimplifiedObjectMetaResponseParser;
import static com.aliyun.oss.internal.ResponseParsers.getSymbolicLinkResponseParser;
+import static com.aliyun.oss.internal.ResponseParsers.headObjectResponseParser;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -526,9 +527,9 @@ public DeleteObjectsResult deleteObjects(DeleteObjectsRequest deleteObjectsReque
}
/**
- * Check if the object key exists under the specified bucket.
+ * Get head information.
*/
- public void headObject(HeadObjectRequest headObjectRequest) throws OSSException, ClientException {
+ public ObjectMetadata headObject(HeadObjectRequest headObjectRequest) throws OSSException, ClientException {
assertParameterNotNull(headObjectRequest, "headObjectRequest");
@@ -554,7 +555,7 @@ public void headObject(HeadObjectRequest headObjectRequest) throws OSSException,
.setMethod(HttpMethod.HEAD).setBucket(bucketName).setKey(key).setHeaders(headers)
.setOriginalRequest(headObjectRequest).build();
- doOperation(request, emptyResponseParser, bucketName, key);
+ return doOperation(request, headObjectResponseParser, bucketName, key);
}
public void setObjectAcl(SetObjectAclRequest setObjectAclRequest) throws OSSException, ClientException {
@@ -930,6 +931,7 @@ private static void populateCopyObjectHeaders(CopyObjectRequest copyObjectReques
copyObjectRequest.getNonmatchingEtagConstraints());
addHeader(headers, OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, copyObjectRequest.getServerSideEncryption());
+ addHeader(headers, OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, copyObjectRequest.getServerSideEncryptionKeyId());
ObjectMetadata newObjectMetadata = copyObjectRequest.getNewObjectMetadata();
if (newObjectMetadata != null) {
diff --git a/src/main/java/com/aliyun/oss/internal/OSSOperation.java b/src/main/java/com/aliyun/oss/internal/OSSOperation.java
index 57ce32e9..939c6e14 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSOperation.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSOperation.java
@@ -33,18 +33,7 @@
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.RequestSigner;
-import com.aliyun.oss.common.comm.ExecutionContext;
-import com.aliyun.oss.common.comm.NoRetryStrategy;
-import com.aliyun.oss.common.comm.RequestChecksumHanlder;
-import com.aliyun.oss.common.comm.RequestHandler;
-import com.aliyun.oss.common.comm.RequestMessage;
-import com.aliyun.oss.common.comm.RequestProgressHanlder;
-import com.aliyun.oss.common.comm.ResponseChecksumHandler;
-import com.aliyun.oss.common.comm.ResponseHandler;
-import com.aliyun.oss.common.comm.ResponseMessage;
-import com.aliyun.oss.common.comm.ResponseProgressHandler;
-import com.aliyun.oss.common.comm.RetryStrategy;
-import com.aliyun.oss.common.comm.ServiceClient;
+import com.aliyun.oss.common.comm.*;
import com.aliyun.oss.common.parser.ResponseParseException;
import com.aliyun.oss.common.parser.ResponseParser;
import com.aliyun.oss.common.utils.ExceptionFactory;
@@ -165,16 +154,16 @@ protected T doOperation(RequestMessage request, ResponseParser parser, St
}
}
- private static RequestSigner createSigner(HttpMethod method, String bucketName, String key, Credentials creds) {
+ private static RequestSigner createSigner(HttpMethod method, String bucketName, String key, Credentials creds, SignVersion signatureVersion) {
String resourcePath = "/" + ((bucketName != null) ? bucketName + "/" : "") + ((key != null ? key : ""));
- return new OSSRequestSigner(method.toString(), resourcePath, creds);
+ return new OSSRequestSigner(method.toString(), resourcePath, creds, signatureVersion);
}
protected ExecutionContext createDefaultContext(HttpMethod method, String bucketName, String key) {
ExecutionContext context = new ExecutionContext();
context.setCharset(DEFAULT_CHARSET_NAME);
- context.setSigner(createSigner(method, bucketName, key, credsProvider.getCredentials()));
+ context.setSigner(createSigner(method, bucketName, key, credsProvider.getCredentials(), client.getClientConfiguration().getSignatureVersion()));
context.addResponseHandler(errorResponseHandler);
if (method == HttpMethod.POST) {
context.setRetryStrategy(noRetryStrategy);
diff --git a/src/main/java/com/aliyun/oss/internal/OSSRequestSigner.java b/src/main/java/com/aliyun/oss/internal/OSSRequestSigner.java
index e2d8f54a..67c8be85 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSRequestSigner.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSRequestSigner.java
@@ -22,8 +22,8 @@
import com.aliyun.oss.ClientException;
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.RequestSigner;
-import com.aliyun.oss.common.auth.ServiceSignature;
import com.aliyun.oss.common.comm.RequestMessage;
+import com.aliyun.oss.common.comm.SignVersion;
public class OSSRequestSigner implements RequestSigner {
@@ -31,12 +31,16 @@ public class OSSRequestSigner implements RequestSigner {
/* Note that resource path should not have been url-encoded. */
private String resourcePath;
+
private Credentials creds;
- public OSSRequestSigner(String httpMethod, String resourcePath, Credentials creds) {
+ private SignVersion signatureVersion;
+
+ public OSSRequestSigner(String httpMethod, String resourcePath, Credentials creds, SignVersion signatureVersion) {
this.httpMethod = httpMethod;
this.resourcePath = resourcePath;
this.creds = creds;
+ this.signatureVersion = signatureVersion;
}
@Override
@@ -45,9 +49,15 @@ public void sign(RequestMessage request) throws ClientException {
String secretAccessKey = creds.getSecretAccessKey();
if (accessKeyId.length() > 0 && secretAccessKey.length() > 0) {
- String canonicalString = SignUtils.buildCanonicalString(httpMethod, resourcePath, request, null);
- String signature = ServiceSignature.create().computeSignature(secretAccessKey, canonicalString);
- request.addHeader(OSSHeaders.AUTHORIZATION, OSSUtils.composeRequestAuthorization(accessKeyId, signature));
+ String signature;
+
+ if (signatureVersion == SignVersion.V2) {
+ signature = SignV2Utils.buildSignature(secretAccessKey, httpMethod, resourcePath, request);
+ request.addHeader(OSSHeaders.AUTHORIZATION, SignV2Utils.composeRequestAuthorization(accessKeyId,signature, request));
+ } else {
+ signature = SignUtils.buildSignature(secretAccessKey, httpMethod, resourcePath, request);
+ request.addHeader(OSSHeaders.AUTHORIZATION, SignUtils.composeRequestAuthorization(accessKeyId, signature));
+ }
}
}
}
diff --git a/src/main/java/com/aliyun/oss/internal/OSSUploadOperation.java b/src/main/java/com/aliyun/oss/internal/OSSUploadOperation.java
index 4a924db0..d6a9dbfe 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSUploadOperation.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSUploadOperation.java
@@ -43,6 +43,8 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import com.aliyun.oss.InconsistentException;
+import com.aliyun.oss.common.utils.CRC64;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.event.ProgressPublisher;
@@ -203,6 +205,7 @@ public int hashCode() {
result = prime * result + number;
result = prime * result + (int) (offset ^ (offset >>> 32));
result = prime * result + (int) (size ^ (size >>> 32));
+ result = prime * result + (int) (crc ^ (crc >>> 32));
return result;
}
@@ -210,6 +213,7 @@ public int hashCode() {
public long offset; // the offset in the file
public long size; // part size
public boolean isCompleted; // upload completeness flag.
+ public long crc; //part crc
}
static class PartResult {
@@ -220,6 +224,13 @@ public PartResult(int number, long offset, long length) {
this.length = length;
}
+ public PartResult(int number, long offset, long length, long partCRC) {
+ this.number = number;
+ this.offset = offset;
+ this.length = length;
+ this.partCRC = partCRC;
+ }
+
public int getNumber() {
return number;
}
@@ -260,11 +271,20 @@ public void setException(Exception exception) {
this.exception = exception;
}
+ public Long getPartCRC() {
+ return partCRC;
+ }
+
+ public void setPartCRC(Long partCRC) {
+ this.partCRC = partCRC;
+ }
+
private int number; // part number
private long offset; // offset in the file
private long length; // part size
private boolean failed; // part upload failure flag
private Exception exception; // part upload exception
+ private Long partCRC;
}
public OSSUploadOperation(OSSMultipartOperation multipartOperation) {
@@ -340,6 +360,18 @@ private UploadFileResult uploadFileWithCheckpoint(UploadFileRequest uploadFileRe
CompleteMultipartUploadResult multipartUploadResult = complete(uploadCheckPoint, uploadFileRequest);
uploadFileResult.setMultipartUploadResult(multipartUploadResult);
+ // check crc64
+ if (multipartOperation.getInnerClient().getClientConfiguration().isCrcCheckEnabled()) {
+ Long clientCRC = calcObjectCRCFromParts(partResults);
+ multipartUploadResult.setClientCRC(clientCRC);
+ try {
+ OSSUtils.checkChecksum(clientCRC, multipartUploadResult.getServerCRC(), multipartUploadResult.getRequestId());
+ } catch (Exception e) {
+ ProgressPublisher.publishProgress(listener, ProgressEventType.TRANSFER_FAILED_EVENT);
+ throw new InconsistentException(clientCRC, multipartUploadResult.getServerCRC(), multipartUploadResult.getRequestId());
+ }
+ }
+
// The checkpoint is enabled and upload the checkpoint file.
if (uploadFileRequest.isEnableCheckpoint()) {
remove(uploadFileRequest.getCheckpointFile());
@@ -348,6 +380,18 @@ private UploadFileResult uploadFileWithCheckpoint(UploadFileRequest uploadFileRe
return uploadFileResult;
}
+ private static Long calcObjectCRCFromParts(List partResults) {
+ long crc = 0;
+
+ for (PartResult partResult : partResults) {
+ if (partResult.getPartCRC() == null || partResult.getLength() <= 0) {
+ return null;
+ }
+ crc = CRC64.combine(crc, partResult.getPartCRC(), partResult.getLength());
+ }
+ return new Long(crc);
+ }
+
private void prepare(UploadCheckPoint uploadCheckPoint, UploadFileRequest uploadFileRequest) {
uploadCheckPoint.magic = UploadCheckPoint.UPLOAD_MAGIC;
uploadCheckPoint.uploadFile = uploadFileRequest.getUploadFile();
@@ -397,7 +441,7 @@ private ArrayList upload(UploadCheckPoint uploadCheckPoint, UploadFi
multipartOperation, listener)));
} else {
taskResults.add(new PartResult(i + 1, uploadCheckPoint.uploadParts.get(i).offset,
- uploadCheckPoint.uploadParts.get(i).size));
+ uploadCheckPoint.uploadParts.get(i).size, uploadCheckPoint.uploadParts.get(i).crc));
}
}
service.shutdown();
@@ -462,6 +506,12 @@ public PartResult call() throws Exception {
UploadPartResult uploadPartResult = multipartOperation.uploadPart(uploadPartRequest);
+ if(multipartOperation.getInnerClient().getClientConfiguration().isCrcCheckEnabled()) {
+ OSSUtils.checkChecksum(uploadPartResult.getClientCRC(), uploadPartResult.getServerCRC(), uploadPartResult.getRequestId());
+ tr.setPartCRC(uploadPartResult.getClientCRC());
+ tr.setLength(uploadPartResult.getPartSize());
+ uploadPart.crc = uploadPartResult.getClientCRC();
+ }
PartETag partETag = new PartETag(uploadPartResult.getPartNumber(), uploadPartResult.getETag());
uploadCheckPoint.update(partIndex, partETag, true);
if (uploadFileRequest.isEnableCheckpoint()) {
diff --git a/src/main/java/com/aliyun/oss/internal/OSSUtils.java b/src/main/java/com/aliyun/oss/internal/OSSUtils.java
index 450945bd..ad509961 100644
--- a/src/main/java/com/aliyun/oss/internal/OSSUtils.java
+++ b/src/main/java/com/aliyun/oss/internal/OSSUtils.java
@@ -21,8 +21,6 @@
import static com.aliyun.oss.internal.OSSConstants.DEFAULT_CHARSET_NAME;
import static com.aliyun.oss.internal.OSSConstants.OBJECT_NAME_MAX_LENGTH;
-import static com.aliyun.oss.internal.OSSConstants.OSS_AUTHORIZATION_PREFIX;
-import static com.aliyun.oss.internal.OSSConstants.OSS_AUTHORIZATION_SEPERATOR;
import static com.aliyun.oss.internal.OSSConstants.RESOURCE_NAME_COMMON;
import static com.aliyun.oss.internal.OSSConstants.RESOURCE_NAME_OSS;
@@ -393,10 +391,6 @@ public static String joinETags(List eTags) {
return sb.toString();
}
- public static String composeRequestAuthorization(String accessKeyId, String signature) {
- return OSS_AUTHORIZATION_PREFIX + accessKeyId + OSS_AUTHORIZATION_SEPERATOR + signature;
- }
-
/**
* Encode the callback with JSON.
*/
diff --git a/src/main/java/com/aliyun/oss/internal/RequestParameters.java b/src/main/java/com/aliyun/oss/internal/RequestParameters.java
index 05f80830..589869e2 100644
--- a/src/main/java/com/aliyun/oss/internal/RequestParameters.java
+++ b/src/main/java/com/aliyun/oss/internal/RequestParameters.java
@@ -79,9 +79,6 @@ public final class RequestParameters {
public static final String PART_NUMBER_MARKER = "part-number-marker";
public static final String RULE_ID = "rule-id";
- public static final String SIGNATURE = "Signature";
- public static final String OSS_ACCESS_KEY_ID = "OSSAccessKeyId";
-
public static final String SECURITY_TOKEN = "security-token";
public static final String POSITION = "position";
@@ -99,4 +96,15 @@ public final class RequestParameters {
public static final String SINCE = "since";
public static final String TAIL = "tail";
+ /* V1 signature params */
+ public static final String SIGNATURE = "Signature";
+ public static final String OSS_ACCESS_KEY_ID = "OSSAccessKeyId";
+
+ /* V2 signature params */
+ public static final String OSS_SIGNATURE_VERSION = "x-oss-signature-version";
+ public static final String OSS_EXPIRES = "x-oss-expires";
+ public static final String OSS_ACCESS_KEY_ID_PARAM = "x-oss-access-key-id";
+ public static final String OSS_ADDITIONAL_HEADERS = "x-oss-additional-headers";
+ public static final String OSS_SIGNATURE = "x-oss-signature";
+
}
diff --git a/src/main/java/com/aliyun/oss/internal/ResponseParsers.java b/src/main/java/com/aliyun/oss/internal/ResponseParsers.java
index 5a39b6b2..3cb712ed 100644
--- a/src/main/java/com/aliyun/oss/internal/ResponseParsers.java
+++ b/src/main/java/com/aliyun/oss/internal/ResponseParsers.java
@@ -151,6 +151,7 @@ public final class ResponseParsers {
public static final GetSimplifiedObjectMetaResponseParser getSimplifiedObjectMetaResponseParser = new GetSimplifiedObjectMetaResponseParser();
public static final RestoreObjectResponseParser restoreObjectResponseParser = new RestoreObjectResponseParser();
public static final ProcessObjectResponseParser processObjectResponseParser = new ProcessObjectResponseParser();
+ public static final HeadObjectResponseParser headObjectResponseParser = new HeadObjectResponseParser();
public static final CompleteMultipartUploadResponseParser completeMultipartUploadResponseParser = new CompleteMultipartUploadResponseParser();
public static final CompleteMultipartUploadProcessResponseParser completeMultipartUploadProcessResponseParser = new CompleteMultipartUploadProcessResponseParser();
@@ -734,6 +735,18 @@ public ObjectMetadata parse(ResponseMessage response) throws ResponseParseExcept
}
+ public static final class HeadObjectResponseParser implements ResponseParser {
+
+ @Override
+ public ObjectMetadata parse(ResponseMessage response) throws ResponseParseException {
+ try {
+ return parseObjectMetadata(response.getHeaders());
+ } finally {
+ safeCloseResponse(response);
+ }
+ }
+ }
+
public static final class CopyObjectResponseParser implements ResponseParser {
@Override
diff --git a/src/main/java/com/aliyun/oss/internal/SignParameters.java b/src/main/java/com/aliyun/oss/internal/SignParameters.java
new file mode 100644
index 00000000..30fbb321
--- /dev/null
+++ b/src/main/java/com/aliyun/oss/internal/SignParameters.java
@@ -0,0 +1,45 @@
+package com.aliyun.oss.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static com.aliyun.oss.common.utils.CodingUtils.assertTrue;
+import static com.aliyun.oss.internal.RequestParameters.*;
+import static com.aliyun.oss.internal.RequestParameters.SUBRESOURCE_RESTORE;
+import static com.aliyun.oss.internal.RequestParameters.SUBRESOURCE_UDF_LOG;
+import static com.aliyun.oss.model.ResponseHeaderOverrides.*;
+import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_TYPE;
+import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_EXPIRES;
+
+public class SignParameters {
+
+ public static final String AUTHORIZATION_PREFIX = "OSS ";
+
+ public static final String AUTHORIZATION_PREFIX_V2 = "OSS2 ";
+
+ public static final String AUTHORIZATION_V2 = "OSS2";
+
+ public static final String AUTHORIZATION_ACCESS_KEY_ID = "AccessKeyId";
+
+ public static final String AUTHORIZATION_ADDITIONAL_HEADERS = "AdditionalHeaders";
+
+ public static final String AUTHORIZATION_SIGNATURE = "Signature";
+
+ public static final String NEW_LINE = "\n";
+
+ public static final List SIGNED_PARAMTERS = Arrays.asList(new String[] { SUBRESOURCE_ACL,
+ SUBRESOURCE_UPLOADS, SUBRESOURCE_LOCATION, SUBRESOURCE_CORS, SUBRESOURCE_LOGGING, SUBRESOURCE_WEBSITE,
+ SUBRESOURCE_REFERER, SUBRESOURCE_LIFECYCLE, SUBRESOURCE_DELETE, SUBRESOURCE_APPEND, SUBRESOURCE_TAGGING,
+ SUBRESOURCE_OBJECTMETA, UPLOAD_ID, PART_NUMBER, SECURITY_TOKEN, POSITION, RESPONSE_HEADER_CACHE_CONTROL,
+ RESPONSE_HEADER_CONTENT_DISPOSITION, RESPONSE_HEADER_CONTENT_ENCODING, RESPONSE_HEADER_CONTENT_LANGUAGE,
+ RESPONSE_HEADER_CONTENT_TYPE, RESPONSE_HEADER_EXPIRES, SUBRESOURCE_IMG, SUBRESOURCE_STYLE, STYLE_NAME,
+ SUBRESOURCE_REPLICATION, SUBRESOURCE_REPLICATION_PROGRESS, SUBRESOURCE_REPLICATION_LOCATION,
+ SUBRESOURCE_CNAME, SUBRESOURCE_BUCKET_INFO, SUBRESOURCE_COMP, SUBRESOURCE_QOS, SUBRESOURCE_LIVE,
+ SUBRESOURCE_STATUS, SUBRESOURCE_VOD, SUBRESOURCE_START_TIME, SUBRESOURCE_END_TIME, SUBRESOURCE_PROCESS,
+ SUBRESOURCE_PROCESS_CONF, SUBRESOURCE_SYMLINK, SUBRESOURCE_STAT, SUBRESOURCE_UDF, SUBRESOURCE_UDF_NAME,
+ SUBRESOURCE_UDF_IMAGE, SUBRESOURCE_UDF_IMAGE_DESC, SUBRESOURCE_UDF_APPLICATION, SUBRESOURCE_UDF_LOG,
+ SUBRESOURCE_RESTORE, });
+
+
+}
diff --git a/src/main/java/com/aliyun/oss/internal/SignUtils.java b/src/main/java/com/aliyun/oss/internal/SignUtils.java
index 3202078e..6dacb9e5 100644
--- a/src/main/java/com/aliyun/oss/internal/SignUtils.java
+++ b/src/main/java/com/aliyun/oss/internal/SignUtils.java
@@ -21,44 +21,38 @@
import static com.aliyun.oss.common.utils.CodingUtils.assertTrue;
import static com.aliyun.oss.internal.RequestParameters.*;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CACHE_CONTROL;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_DISPOSITION;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_ENCODING;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_LANGUAGE;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_CONTENT_TYPE;
-import static com.aliyun.oss.model.ResponseHeaderOverrides.RESPONSE_HEADER_EXPIRES;
import java.util.Arrays;
-import java.util.List;
import java.util.Map;
+import static com.aliyun.oss.internal.OSSConstants.DEFAULT_CHARSET_NAME;
+import static com.aliyun.oss.internal.OSSUtils.populateResponseHeaderParameters;
+import static com.aliyun.oss.internal.RequestParameters.SIGNATURE;
+import static com.aliyun.oss.internal.SignParameters.AUTHORIZATION_PREFIX;
+
+import java.net.URI;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.TreeMap;
+import com.aliyun.oss.ClientConfiguration;
+import com.aliyun.oss.HttpMethod;
+import com.aliyun.oss.common.auth.Credentials;
+import com.aliyun.oss.common.auth.ServiceSignature;
import com.aliyun.oss.common.comm.RequestMessage;
import com.aliyun.oss.common.utils.HttpHeaders;
+import com.aliyun.oss.common.utils.HttpUtil;
+import com.aliyun.oss.model.GeneratePresignedUrlRequest;
public class SignUtils {
- private static final String NEW_LINE = "\n";
-
- private static final List SIGNED_PARAMTERS = Arrays.asList(new String[] { SUBRESOURCE_ACL,
- SUBRESOURCE_UPLOADS, SUBRESOURCE_LOCATION, SUBRESOURCE_CORS, SUBRESOURCE_LOGGING, SUBRESOURCE_WEBSITE,
- SUBRESOURCE_REFERER, SUBRESOURCE_LIFECYCLE, SUBRESOURCE_DELETE, SUBRESOURCE_APPEND, SUBRESOURCE_TAGGING,
- SUBRESOURCE_OBJECTMETA, UPLOAD_ID, PART_NUMBER, SECURITY_TOKEN, POSITION, RESPONSE_HEADER_CACHE_CONTROL,
- RESPONSE_HEADER_CONTENT_DISPOSITION, RESPONSE_HEADER_CONTENT_ENCODING, RESPONSE_HEADER_CONTENT_LANGUAGE,
- RESPONSE_HEADER_CONTENT_TYPE, RESPONSE_HEADER_EXPIRES, SUBRESOURCE_IMG, SUBRESOURCE_STYLE, STYLE_NAME,
- SUBRESOURCE_REPLICATION, SUBRESOURCE_REPLICATION_PROGRESS, SUBRESOURCE_REPLICATION_LOCATION,
- SUBRESOURCE_CNAME, SUBRESOURCE_BUCKET_INFO, SUBRESOURCE_COMP, SUBRESOURCE_QOS, SUBRESOURCE_LIVE,
- SUBRESOURCE_STATUS, SUBRESOURCE_VOD, SUBRESOURCE_START_TIME, SUBRESOURCE_END_TIME, SUBRESOURCE_PROCESS,
- SUBRESOURCE_PROCESS_CONF, SUBRESOURCE_SYMLINK, SUBRESOURCE_STAT, SUBRESOURCE_UDF, SUBRESOURCE_UDF_NAME,
- SUBRESOURCE_UDF_IMAGE, SUBRESOURCE_UDF_IMAGE_DESC, SUBRESOURCE_UDF_APPLICATION, SUBRESOURCE_UDF_LOG,
- SUBRESOURCE_RESTORE, SUBRESOURCE_CSV_SELECT, SUBRESOURCE_CSV_META, SUBRESOURCE_SQL});
+ public static String composeRequestAuthorization(String accessKeyId, String signature) {
+ return AUTHORIZATION_PREFIX + accessKeyId + ":" + signature;
+ }
public static String buildCanonicalString(String method, String resourcePath, RequestMessage request,
String expires) {
StringBuilder canonicalString = new StringBuilder();
- canonicalString.append(method + NEW_LINE);
+ canonicalString.append(method).append(SignParameters.NEW_LINE);
Map headers = request.getHeaders();
TreeMap headersToSign = new TreeMap();
@@ -97,7 +91,7 @@ public static String buildCanonicalString(String method, String resourcePath, Re
canonicalString.append(value);
}
- canonicalString.append(NEW_LINE);
+ canonicalString.append(SignParameters.NEW_LINE);
}
// Append canonical resource to canonical string
@@ -112,14 +106,14 @@ public static String buildRtmpCanonicalString(String canonicalizedResource, Requ
StringBuilder canonicalString = new StringBuilder();
// Append expires
- canonicalString.append(expires + NEW_LINE);
+ canonicalString.append(expires + SignParameters.NEW_LINE);
// Append canonicalized parameters
for (Map.Entry entry : request.getParameters().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
canonicalString.append(key).append(':').append(value);
- canonicalString.append(NEW_LINE);
+ canonicalString.append(SignParameters.NEW_LINE);
}
// Append canonicalized resource
@@ -128,8 +122,77 @@ public static String buildRtmpCanonicalString(String canonicalizedResource, Requ
return canonicalString.toString();
}
- private static String buildCanonicalizedResource(String resourcePath, Map parameters) {
+ public static String buildSignedURL(GeneratePresignedUrlRequest request, Credentials currentCreds, ClientConfiguration config, URI endpoint) {
+ String bucketName = request.getBucketName();
+ String accessId = currentCreds.getAccessKeyId();
+ String accessKey = currentCreds.getSecretAccessKey();
+ boolean useSecurityToken = currentCreds.useSecurityToken();
+ HttpMethod method = request.getMethod() != null ? request.getMethod() : HttpMethod.GET;
+
+ String expires = String.valueOf(request.getExpiration().getTime() / 1000L);
+ String key = request.getKey();
+ String resourcePath = OSSUtils.determineResourcePath(bucketName, key, config.isSLDEnabled());
+
+ RequestMessage requestMessage = new RequestMessage(bucketName, key);
+ requestMessage.setEndpoint(OSSUtils.determineFinalEndpoint(endpoint, bucketName, config));
+ requestMessage.setMethod(method);
+ requestMessage.setResourcePath(resourcePath);
+ requestMessage.setHeaders(request.getHeaders());
+
+ requestMessage.addHeader(HttpHeaders.DATE, expires);
+ if (request.getContentType() != null && !request.getContentType().trim().equals("")) {
+ requestMessage.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType());
+ }
+ if (request.getContentMD5() != null && !request.getContentMD5().trim().equals("")) {
+ requestMessage.addHeader(HttpHeaders.CONTENT_MD5, request.getContentMD5());
+ }
+ for (Map.Entry h : request.getUserMetadata().entrySet()) {
+ requestMessage.addHeader(OSSHeaders.OSS_USER_METADATA_PREFIX + h.getKey(), h.getValue());
+ }
+
+ Map responseHeaderParams = new HashMap();
+ populateResponseHeaderParameters(responseHeaderParams, request.getResponseHeaders());
+ if (responseHeaderParams.size() > 0) {
+ requestMessage.setParameters(responseHeaderParams);
+ }
+
+ if (request.getQueryParameter() != null && request.getQueryParameter().size() > 0) {
+ for (Map.Entry entry : request.getQueryParameter().entrySet()) {
+ requestMessage.addParameter(entry.getKey(), entry.getValue());
+ }
+ }
+
+ if (request.getProcess() != null && !request.getProcess().trim().equals("")) {
+ requestMessage.addParameter(RequestParameters.SUBRESOURCE_PROCESS, request.getProcess());
+ }
+
+ if (useSecurityToken) {
+ requestMessage.addParameter(SECURITY_TOKEN, currentCreds.getSecurityToken());
+ }
+
+ String canonicalResource = "/" + ((bucketName != null) ? bucketName : "") + ((key != null ? "/" + key : ""));
+ String canonicalString = buildCanonicalString(method.toString(), canonicalResource, requestMessage,
+ expires);
+ String signature = ServiceSignature.create().computeSignature(accessKey, canonicalString);
+
+ Map params = new LinkedHashMap();
+ params.put(HttpHeaders.EXPIRES, expires);
+ params.put(OSS_ACCESS_KEY_ID, accessId);
+ params.put(SIGNATURE, signature);
+ params.putAll(requestMessage.getParameters());
+
+ String queryString = HttpUtil.paramToQueryString(params, DEFAULT_CHARSET_NAME);
+ /* Compse HTTP request uri. */
+ String url = requestMessage.getEndpoint().toString();
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+ url += resourcePath + "?" + queryString;
+ return url;
+ }
+
+ public static String buildCanonicalizedResource(String resourcePath, Map parameters) {
assertTrue(resourcePath.startsWith("/"), "Resource path should start with slash character");
StringBuilder builder = new StringBuilder();
@@ -139,23 +202,28 @@ private static String buildCanonicalizedResource(String resourcePath, Map headerNames, Set additionalHeaderNames) {
+ Set ts = buildSortedAdditionalHeaderNames(headerNames, additionalHeaderNames);
+ StringBuilder sb = new StringBuilder();
+ String separator = "";
+
+ for (String header : ts) {
+ sb.append(separator);
+ sb.append(header);
+ separator = ";";
+ }
+ return sb.toString();
+ }
+
+ private static Set buildSortedAdditionalHeaderNames(Set headerNames, Set additionalHeaderNames) {
+ Set ts = new TreeSet();
+
+ if (headerNames != null && additionalHeaderNames != null) {
+ for (String additionalHeaderName : additionalHeaderNames) {
+ if (headerNames.contains(additionalHeaderName)) {
+ ts.add(additionalHeaderName.toLowerCase());
+ }
+ }
+ }
+ return ts;
+ }
+
+ private static Set buildRawAdditionalHeaderNames(Set headerNames, Set additionalHeaderNames) {
+ Set hs = new HashSet();
+
+ if (headerNames != null && additionalHeaderNames != null) {
+ for (String additionalHeaderName : additionalHeaderNames) {
+ if (headerNames.contains(additionalHeaderName)) {
+ hs.add(additionalHeaderName);
+ }
+ }
+ }
+ return hs;
+ }
+
+ public static String buildCanonicalString(String method, String resourcePath, RequestMessage request, Set additionalHeaderNames) {
+ StringBuilder canonicalString = new StringBuilder();
+ canonicalString.append(method).append(SignParameters.NEW_LINE);
+ Map headers = request.getHeaders();
+ TreeMap fixedHeadersToSign = new TreeMap();
+ TreeMap canonicalizedOssHeadersToSign = new TreeMap();
+
+ if (headers != null) {
+ for (Map.Entry header : headers.entrySet()) {
+ if (header.getKey() != null) {
+ String lowerKey = header.getKey().toLowerCase();
+ if (lowerKey.equals(HttpHeaders.CONTENT_TYPE.toLowerCase())
+ || lowerKey.equals(HttpHeaders.CONTENT_MD5.toLowerCase())
+ || lowerKey.equals(HttpHeaders.DATE.toLowerCase())) {
+ fixedHeadersToSign.put(lowerKey, header.getValue().trim());
+ } else if (lowerKey.startsWith(OSSHeaders.OSS_PREFIX)){
+ canonicalizedOssHeadersToSign.put(lowerKey, header.getValue().trim());
+ }
+ }
+ }
+ }
+
+ if (!fixedHeadersToSign.containsKey(HttpHeaders.CONTENT_TYPE.toLowerCase())) {
+ fixedHeadersToSign.put(HttpHeaders.CONTENT_TYPE.toLowerCase(), "");
+ }
+ if (!fixedHeadersToSign.containsKey(HttpHeaders.CONTENT_MD5.toLowerCase())) {
+ fixedHeadersToSign.put(HttpHeaders.CONTENT_MD5.toLowerCase(), "");
+ }
+
+ for (String additionalHeaderName : additionalHeaderNames) {
+ if (additionalHeaderName != null && headers.get(additionalHeaderName) != null) {
+ canonicalizedOssHeadersToSign.put(additionalHeaderName.toLowerCase(), headers.get(additionalHeaderName).trim());
+ }
+ }
+
+ // Append fixed headers to sign to canonical string
+ for (Map.Entry entry : fixedHeadersToSign.entrySet()) {
+ Object value = entry.getValue();
+
+ canonicalString.append(value);
+ canonicalString.append(SignParameters.NEW_LINE);
+ }
+
+ // Append canonicalized oss headers to sign to canonical string
+ for (Map.Entry entry : canonicalizedOssHeadersToSign.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+
+ canonicalString.append(key).append(':').append(value).append(SignParameters.NEW_LINE);
+ }
+
+
+ // Append additional header names
+ TreeSet ts = new TreeSet();
+ for (String additionalHeaderName : additionalHeaderNames) {
+ ts.add(additionalHeaderName.toLowerCase());
+ }
+ String separator = "";
+
+ for (String additionalHeaderName : ts) {
+ canonicalString.append(separator).append(additionalHeaderName);
+ separator = ";";
+ }
+ canonicalString.append(SignParameters.NEW_LINE);
+
+ // Append canonical resource to canonical string
+ canonicalString.append(buildCanonicalizedResource(resourcePath, request.getParameters()));
+
+ return canonicalString.toString();
+ }
+
+ public static String buildSignedURL(GeneratePresignedUrlRequest request, Credentials currentCreds, ClientConfiguration config, URI endpoint) {
+ String bucketName = request.getBucketName();
+ String accessId = currentCreds.getAccessKeyId();
+ String accessKey = currentCreds.getSecretAccessKey();
+ boolean useSecurityToken = currentCreds.useSecurityToken();
+ HttpMethod method = request.getMethod() != null ? request.getMethod() : HttpMethod.GET;
+
+ String expires = String.valueOf(request.getExpiration().getTime() / 1000L);
+ String key = request.getKey();
+ String resourcePath = OSSUtils.determineResourcePath(bucketName, key, config.isSLDEnabled());
+
+ RequestMessage requestMessage = new RequestMessage(bucketName, key);
+ requestMessage.setEndpoint(OSSUtils.determineFinalEndpoint(endpoint, bucketName, config));
+ requestMessage.setMethod(method);
+ requestMessage.setResourcePath(resourcePath);
+ requestMessage.setHeaders(request.getHeaders());
+
+ requestMessage.addHeader(HttpHeaders.DATE, expires);
+ if (request.getContentType() != null && !request.getContentType().trim().equals("")) {
+ requestMessage.addHeader(HttpHeaders.CONTENT_TYPE, request.getContentType());
+ }
+ if (request.getContentMD5() != null && !request.getContentMD5().trim().equals("")) {
+ requestMessage.addHeader(HttpHeaders.CONTENT_MD5, request.getContentMD5());
+ }
+ for (Map.Entry h : request.getUserMetadata().entrySet()) {
+ requestMessage.addHeader(OSSHeaders.OSS_USER_METADATA_PREFIX + h.getKey(), h.getValue());
+ }
+ Map responseHeaderParams = new HashMap();
+ populateResponseHeaderParameters(responseHeaderParams, request.getResponseHeaders());
+ if (responseHeaderParams.size() > 0) {
+ requestMessage.setParameters(responseHeaderParams);
+ }
+
+ if (request.getQueryParameter() != null && request.getQueryParameter().size() > 0) {
+ for (Map.Entry entry : request.getQueryParameter().entrySet()) {
+ requestMessage.addParameter(entry.getKey(), entry.getValue());
+ }
+ }
+
+ if (request.getProcess() != null && !request.getProcess().trim().equals("")) {
+ requestMessage.addParameter(SUBRESOURCE_PROCESS, request.getProcess());
+ }
+
+ if (useSecurityToken) {
+ requestMessage.addParameter(SECURITY_TOKEN, currentCreds.getSecurityToken());
+ }
+
+ String canonicalResource = "/" + ((bucketName != null) ? bucketName : "") + ((key != null ? "/" + key : ""));
+ requestMessage.addParameter(OSS_SIGNATURE_VERSION, SignParameters.AUTHORIZATION_V2);
+ requestMessage.addParameter(OSS_EXPIRES, expires);
+ requestMessage.addParameter(OSS_ACCESS_KEY_ID_PARAM, accessId);
+ String additionalHeaderNameStr = buildSortedAdditionalHeaderNameStr(requestMessage.getHeaders().keySet(),
+ request.getAdditionalHeaderNames());
+
+ if (!additionalHeaderNameStr.isEmpty()) {
+ requestMessage.addParameter(OSS_ADDITIONAL_HEADERS, additionalHeaderNameStr);
+ }
+ Set rawAdditionalHeaderNames = buildRawAdditionalHeaderNames(request.getHeaders().keySet(), request.getAdditionalHeaderNames());
+ String canonicalString = buildCanonicalString(method.toString(), canonicalResource, requestMessage, rawAdditionalHeaderNames);
+ String signature = new HmacSHA256Signature().computeSignature(accessKey, canonicalString);
+
+ Map params = new LinkedHashMap();
+
+ if (!additionalHeaderNameStr.isEmpty()) {
+ params.put(OSS_ADDITIONAL_HEADERS, additionalHeaderNameStr);
+ }
+ params.put(OSS_SIGNATURE, signature);
+ params.putAll(requestMessage.getParameters());
+
+ String queryString = HttpUtil.paramToQueryString(params, DEFAULT_CHARSET_NAME);
+
+ /* Compose HTTP request uri. */
+ String url = requestMessage.getEndpoint().toString();
+ if (!url.endsWith("/")) {
+ url += "/";
+ }
+ url += resourcePath + "?" + queryString;
+ return url;
+ }
+
+ private static String buildCanonicalizedResource(String resourcePath, Map parameters) {
+ assertTrue(resourcePath.startsWith("/"), "Resource path should start with slash character");
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(uriEncoding(resourcePath));
+
+ if (parameters != null) {
+ String[] parameterNames = parameters.keySet().toArray(new String[parameters.size()]);
+ Arrays.sort(parameterNames);
+
+ char separator = '?';
+ for (String paramName : parameterNames) {
+ builder.append(separator);
+ builder.append(uriEncoding(paramName));
+ String paramValue = parameters.get(paramName);
+ if (paramValue != null && !paramValue.isEmpty()) {
+ builder.append("=").append(uriEncoding(paramValue));
+ }
+
+ separator = '&';
+ }
+ }
+
+ return builder.toString();
+ }
+
+ public static String uriEncoding(String uri) {
+ String result = "";
+
+ try {
+ for (char c : uri.toCharArray()) {
+ if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
+ || (c >= '0' && c <= '9') || c == '_' || c == '-'
+ || c == '~' || c == '.') {
+ result += c;
+ } else if (c == '/') {
+ result += "%2F";
+ } else {
+ byte[] b;
+ b = Character.toString(c).getBytes("utf-8");
+
+ for (int i = 0; i < b.length; i++) {
+ int k = b[i];
+
+ if (k < 0) {
+ k += 256;
+ }
+ result += "%" + Integer.toHexString(k).toUpperCase();
+ }
+ }
+ }
+ } catch (UnsupportedEncodingException e) {
+ throw new ClientException(e);
+ }
+ return result;
+ }
+
+ public static String buildSignature(String secretAccessKey, String httpMethod, String resourcePath, RequestMessage request) {
+ String canonicalString = buildCanonicalString(httpMethod, resourcePath, request,
+ buildRawAdditionalHeaderNames(request.getOriginalRequest().getHeaders().keySet(), request.getOriginalRequest().getAdditionalHeaderNames()));
+ return new HmacSHA256Signature().computeSignature(secretAccessKey, canonicalString);
+ }
+
+}
diff --git a/src/main/java/com/aliyun/oss/model/CopyObjectRequest.java b/src/main/java/com/aliyun/oss/model/CopyObjectRequest.java
index f51689b7..f8b2dbc3 100644
--- a/src/main/java/com/aliyun/oss/model/CopyObjectRequest.java
+++ b/src/main/java/com/aliyun/oss/model/CopyObjectRequest.java
@@ -44,6 +44,9 @@ public class CopyObjectRequest extends WebServiceRequest {
// Target server's encryption algorithm.
private String serverSideEncryption;
+ // Target server's encryption key ID.
+ private String serverSideEncryptionKeyID;
+
// Target object's metadata information.
private ObjectMetadata newObjectMetadata;
@@ -297,4 +300,23 @@ public String getServerSideEncryption() {
public void setServerSideEncryption(String serverSideEncryption) {
this.serverSideEncryption = serverSideEncryption;
}
+
+ /**
+ * Gets the target object's server side encryption key ID.
+ *
+ * @return Server side encryption key ID,null if no encryption key ID.
+ */
+ public String getServerSideEncryptionKeyId() {
+ return this.serverSideEncryptionKeyID;
+ }
+
+ /**
+ * Sets the target object's server side encryption key ID.
+ *
+ * @param serverSideEncryptionKeyId
+ * Server side encryption key ID,null if no encryption key ID.
+ */
+ public void setServerSideEncryptionKeyId(String serverSideEncryptionKeyId) {
+ this.serverSideEncryptionKeyID = serverSideEncryptionKeyId;
+ }
}
diff --git a/src/main/java/com/aliyun/oss/model/GeneratePresignedUrlRequest.java b/src/main/java/com/aliyun/oss/model/GeneratePresignedUrlRequest.java
index fc647208..02a9129f 100644
--- a/src/main/java/com/aliyun/oss/model/GeneratePresignedUrlRequest.java
+++ b/src/main/java/com/aliyun/oss/model/GeneratePresignedUrlRequest.java
@@ -19,9 +19,7 @@
package com.aliyun.oss.model;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
import com.aliyun.oss.HttpMethod;
@@ -70,9 +68,11 @@ public class GeneratePresignedUrlRequest {
private Map headers = new HashMap();
+ private Set additionalHeaderNames = new HashSet();
+
/**
* Constructor with GET as the httpMethod
- *
+ *
* @param bucketName
* Bucket name.
* @param key
@@ -84,7 +84,7 @@ public GeneratePresignedUrlRequest(String bucketName, String key) {
/**
* Constructor.
- *
+ *
* @param bucketName
* Bucket name.
* @param key
@@ -100,7 +100,7 @@ public GeneratePresignedUrlRequest(String bucketName, String key, HttpMethod met
/**
* Gets Http method.
- *
+ *
* @return HTTP method.
*/
public HttpMethod getMethod() {
@@ -109,7 +109,7 @@ public HttpMethod getMethod() {
/**
* Sets Http method.
- *
+ *
* @param method
* HTTP method.
*/
@@ -122,7 +122,7 @@ public void setMethod(HttpMethod method) {
/**
* Gets {@link Bucket} name
- *
+ *
* @return Bucket name
*/
public String getBucketName() {
@@ -131,7 +131,7 @@ public String getBucketName() {
/**
* Sets the {@link Bucket} name.
- *
+ *
* @param bucketName
* {@link Bucket} name.
*/
@@ -141,7 +141,7 @@ public void setBucketName(String bucketName) {
/**
* Gets the {@link OSSObject} key.
- *
+ *
* @return Object key.
*/
public String getKey() {
@@ -150,7 +150,7 @@ public String getKey() {
/**
* Sets {@link OSSObject} key.
- *
+ *
* @param key
* {@link OSSObject} key.
*/
@@ -160,7 +160,7 @@ public void setKey(String key) {
/**
* Gets the expiration time of the Url
- *
+ *
* @return The expiration time of the Url.
*/
public Date getExpiration() {
@@ -169,7 +169,7 @@ public Date getExpiration() {
/**
* Sets the expiration time of the Url
- *
+ *
* @param expiration
* The expiration time of the Url.
*/
@@ -179,7 +179,7 @@ public void setExpiration(Date expiration) {
/**
* Sets the content-type header which indicates the file's type.
- *
+ *
* @param contentType
* The file's content type.
*/
@@ -189,7 +189,7 @@ public void setContentType(String contentType) {
/**
* Gets the content type header.
- *
+ *
* @return Content-Type Header
*/
public String getContentType() {
@@ -198,7 +198,7 @@ public String getContentType() {
/**
* Sets the file's MD5 value.
- *
+ *
* @param contentMD5
* The target file's MD5 value.
*/
@@ -208,7 +208,7 @@ public void setContentMD5(String contentMD5) {
/**
* Gets the file's MD5 value.
- *
+ *
* @return Content-MD5
*/
public String getContentMD5() {
@@ -217,7 +217,7 @@ public String getContentMD5() {
/**
* Sets the response headers to override.
- *
+ *
* @param responseHeaders
* The response headers to override.
*/
@@ -227,7 +227,7 @@ public void setResponseHeaders(ResponseHeaderOverrides responseHeaders) {
/**
* Gets the response headers to override.
- *
+ *
* @return The response headers to override.
*/
public ResponseHeaderOverrides getResponseHeaders() {
@@ -246,7 +246,7 @@ public ResponseHeaderOverrides getResponseHeaders() {
* when it's returned from OSS. For example, if the key is MyUserMeta,the
* key returned by this method will be myusermeta.
*
- *
+ *
* @return A {@link Map} instance that contains the user's customized
* metadata.
*/
@@ -257,7 +257,7 @@ public Map getUserMetadata() {
/**
* Gets user's customized metadata. They will be represented in x-oss-meta*
* headers.
- *
+ *
* @param userMetadata
* User's metadata
*/
@@ -270,7 +270,7 @@ public void setUserMetadata(Map userMetadata) {
/**
* Add a user's customized metadata.
- *
+ *
* @param key
* The metadata key. Note: this key should not have prefix of
* 'x-oss-meta-'.
@@ -283,7 +283,7 @@ public void addUserMetadata(String key, String value) {
/**
* Gets the query parameters.
- *
+ *
* @return Query parameters.
*/
public Map getQueryParameter() {
@@ -292,7 +292,7 @@ public Map getQueryParameter() {
/**
* Sets the query parameters.
- *
+ *
* @param queryParam
* Query parameters.
*/
@@ -313,7 +313,7 @@ public void addQueryParameter(String key, String value) {
/**
* Gets the process header.
- *
+ *
* @return The process header.
*/
public String getProcess() {
@@ -322,7 +322,7 @@ public String getProcess() {
/**
* Sets the process header.
- *
+ *
* @param process
* The process header.
*/
@@ -332,7 +332,7 @@ public void setProcess(String process) {
/**
* Gets HTTP Headers
- *
+ *
* @return HTTP Headers
*/
public Map getHeaders() {
@@ -341,7 +341,7 @@ public Map getHeaders() {
/**
* Sets Http headers.
- *
+ *
* @param headers
* HTTP Headers。
*/
@@ -360,4 +360,26 @@ public void addHeader(String key, String value) {
this.headers.put(key, value);
}
+ /**
+ * Gets additional HTTP header names.
+ *
+ * @return Additional HTTP header names.
+ */
+ public Set getAdditionalHeaderNames() {
+ return additionalHeaderNames;
+ }
+
+ /**
+ * Sets additional HTTP header names
+ *
+ * @param additionalHeaderNames
+ * additional http header names.
+ */
+ public void setAdditionalHeaderNames(Set additionalHeaderNames) {
+ this.additionalHeaderNames = additionalHeaderNames;
+ }
+
+ public void addAdditionalHeaderName(String name) {
+ this.additionalHeaderNames.add(name);
+ }
}
diff --git a/src/main/java/com/aliyun/oss/model/GenerateVodPlaylistRequest.java b/src/main/java/com/aliyun/oss/model/GenerateVodPlaylistRequest.java
index 3ea9f248..83c195c0 100644
--- a/src/main/java/com/aliyun/oss/model/GenerateVodPlaylistRequest.java
+++ b/src/main/java/com/aliyun/oss/model/GenerateVodPlaylistRequest.java
@@ -26,11 +26,11 @@ public GenerateVodPlaylistRequest(String bucketName, String liveChannelName, Str
this.playlistName = playlistName;
}
- public GenerateVodPlaylistRequest(String bucketName, String liveChannelName, String playlistName, long stratTime,
+ public GenerateVodPlaylistRequest(String bucketName, String liveChannelName, String playlistName, long startTime,
long endTime) {
super(bucketName, liveChannelName);
this.playlistName = playlistName;
- this.stratTime = stratTime;
+ this.startTime = startTime;
this.endTime = endTime;
}
@@ -42,12 +42,12 @@ public void setPlaylistName(String playlistName) {
this.playlistName = playlistName;
}
- public Long getStratTime() {
- return stratTime;
+ public Long getStartTime() {
+ return startTime;
}
- public void setStratTime(long stratTime) {
- this.stratTime = stratTime;
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
}
public Long getEndTime() {
@@ -59,6 +59,6 @@ public void setEndTime(long endTime) {
}
private String playlistName;
- private Long stratTime;
+ private Long startTime;
private Long endTime;
}
diff --git a/src/main/java/com/aliyun/oss/model/GetVodPlaylistRequest.java b/src/main/java/com/aliyun/oss/model/GetVodPlaylistRequest.java
new file mode 100644
index 00000000..26919b92
--- /dev/null
+++ b/src/main/java/com/aliyun/oss/model/GetVodPlaylistRequest.java
@@ -0,0 +1,30 @@
+package com.aliyun.oss.model;
+
+public class GetVodPlaylistRequest extends LiveChannelGenericRequest {
+
+ public GetVodPlaylistRequest(String bucketName, String liveChannelName, long startTime,
+ long endTime) {
+ super(bucketName, liveChannelName);
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+ public Long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public Long getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(long endTime) {
+ this.endTime = endTime;
+ }
+
+ private Long startTime;
+ private Long endTime;
+}
diff --git a/src/main/java/com/aliyun/oss/model/ObjectMetadata.java b/src/main/java/com/aliyun/oss/model/ObjectMetadata.java
index f00e0069..d858165a 100644
--- a/src/main/java/com/aliyun/oss/model/ObjectMetadata.java
+++ b/src/main/java/com/aliyun/oss/model/ObjectMetadata.java
@@ -19,6 +19,7 @@
package com.aliyun.oss.model;
+import java.math.BigInteger;
import java.text.ParseException;
import java.util.Collections;
import java.util.Date;
@@ -42,6 +43,8 @@ public class ObjectMetadata {
public static final String AES_256_SERVER_SIDE_ENCRYPTION = "AES256";
+ public static final String KMS_SERVER_SIDE_ENCRYPTION = "KMS";
+
/**
*
* Gets the user's custom metadata.
@@ -282,6 +285,25 @@ public void setServerSideEncryption(String serverSideEncryption) {
metadata.put(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, serverSideEncryption);
}
+ /**
+ * Gets the object's server side encryption key ID.
+ *
+ * @return The server side encryption key ID. Null means no encryption key ID.
+ */
+ public String getServerSideEncryptionKeyId() {
+ return (String) metadata.get(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID);
+ }
+
+ /**
+ * Sets the object's server side encryption key ID.
+ *
+ * @param serverSideEncryptionKeyId
+ * The server side encryption key ID.
+ */
+ public void setServerSideEncryptionKeyId(String serverSideEncryptionKeyId) {
+ metadata.put(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, serverSideEncryptionKeyId);
+ }
+
/**
* Gets the object's storage type, which only supports "normal" and
* "appendable" for now.
@@ -322,6 +344,21 @@ public String getRequestId() {
return (String) metadata.get(OSSHeaders.OSS_HEADER_REQUEST_ID);
}
+ /**
+ * Gets the service crc.
+ *
+ * @return service crc.
+ */
+ public Long getServerCRC() {
+ String strSrvCrc = (String) metadata.get(OSSHeaders.OSS_HASH_CRC64_ECMA);
+
+ if (strSrvCrc != null) {
+ BigInteger bi = new BigInteger(strSrvCrc);
+ return bi.longValue();
+ }
+ return null;
+ }
+
/**
* Gets the object's storage class, which is "standard", "IA" or "Archive".
*
diff --git a/src/main/java/com/aliyun/oss/model/PolicyConditions.java b/src/main/java/com/aliyun/oss/model/PolicyConditions.java
index c59491eb..d0640243 100644
--- a/src/main/java/com/aliyun/oss/model/PolicyConditions.java
+++ b/src/main/java/com/aliyun/oss/model/PolicyConditions.java
@@ -153,6 +153,7 @@ public class PolicyConditions {
public final static String COND_SUCCESS_ACTION_REDIRECT = "success_action_redirect";
public final static String COND_SUCCESS_ACTION_STATUS = "success_action_status";
public final static String COND_X_OSS_META_PREFIX = "x-oss-meta-";
+ public final static String COND_X_OSS_SERVER_SIDE_PREFIX = "x-oss-server-side-";
private static Map> _supportedMatchRules = new HashMap>();
private List _conds = new ArrayList();
@@ -176,6 +177,7 @@ public class PolicyConditions {
_supportedMatchRules.put(COND_SUCCESS_ACTION_REDIRECT, ordinaryMatchModes);
_supportedMatchRules.put(COND_SUCCESS_ACTION_STATUS, ordinaryMatchModes);
_supportedMatchRules.put(COND_X_OSS_META_PREFIX, ordinaryMatchModes);
+ _supportedMatchRules.put(COND_X_OSS_SERVER_SIDE_PREFIX, ordinaryMatchModes);
}
/**
diff --git a/src/main/java/com/aliyun/oss/model/WebServiceRequest.java b/src/main/java/com/aliyun/oss/model/WebServiceRequest.java
index 538c8661..48ea5ff8 100644
--- a/src/main/java/com/aliyun/oss/model/WebServiceRequest.java
+++ b/src/main/java/com/aliyun/oss/model/WebServiceRequest.java
@@ -19,8 +19,10 @@
package com.aliyun.oss.model;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
import com.aliyun.oss.event.ProgressListener;
@@ -38,6 +40,8 @@ public abstract class WebServiceRequest {
private Map parameters = new LinkedHashMap();
private Map headers = new LinkedHashMap();
+ private Set additionalHeaderNames = new HashSet();
+
public void setProgressListener(ProgressListener progressListener) {
this.progressListener = (progressListener == null) ? ProgressListener.NOOP : progressListener;
}
@@ -77,6 +81,18 @@ public void addHeader(String key, String value) {
this.headers.put(key, value);
}
+ public Set getAdditionalHeaderNames() {
+ return additionalHeaderNames;
+ }
+
+ public void setAdditionalHeaderNames(Set additionalHeaderNames) {
+ this.additionalHeaderNames = additionalHeaderNames;
+ }
+
+ public void addAdditionalHeaderName(String name) {
+ this.additionalHeaderNames.add(name);
+ }
+
public boolean isLogEnabled() {
return logEnabled;
}
diff --git a/src/main/resources/mime.types b/src/main/resources/mime.types
index 90e65da9..e7fb0c7e 100644
--- a/src/main/resources/mime.types
+++ b/src/main/resources/mime.types
@@ -225,4 +225,6 @@ xml application/xml
xsl application/xml
xslt application/xslt+xml
xul application/vnd.mozilla.xul+xml
-webp image/webp
\ No newline at end of file
+webp image/webp
+csv text/csv
+json application/json
\ No newline at end of file
diff --git a/src/main/resources/versioninfo.properties b/src/main/resources/versioninfo.properties
index 14103c3f..e6640dcd 100644
--- a/src/main/resources/versioninfo.properties
+++ b/src/main/resources/versioninfo.properties
@@ -1 +1 @@
-version=3.3.0
+version=3.4.0
diff --git a/src/samples/ImageSample.java b/src/samples/ImageSample.java
index e61c4a49..54a9f93c 100644
--- a/src/samples/ImageSample.java
+++ b/src/samples/ImageSample.java
@@ -98,7 +98,7 @@ public static void main(String[] args) throws IOException {
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
- System.out.println("Error Message: " + oe.getErrorCode());
+ System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
diff --git a/src/samples/MultipartUploadSample.java b/src/samples/MultipartUploadSample.java
index 2aa0d15a..19bc224d 100644
--- a/src/samples/MultipartUploadSample.java
+++ b/src/samples/MultipartUploadSample.java
@@ -150,7 +150,7 @@ public static void main(String[] args) throws IOException {
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
- System.out.println("Error Message: " + oe.getErrorCode());
+ System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
diff --git a/src/samples/UploadSample.java b/src/samples/UploadSample.java
index a00bc223..cb74effa 100644
--- a/src/samples/UploadSample.java
+++ b/src/samples/UploadSample.java
@@ -66,7 +66,7 @@ public static void main(String[] args) throws IOException {
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
- System.out.println("Error Message: " + oe.getErrorCode());
+ System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
diff --git a/src/test/java/com/aliyun/oss/common/utils/VersionUtilTest.java b/src/test/java/com/aliyun/oss/common/utils/VersionUtilTest.java
index de85df33..edac1f5b 100644
--- a/src/test/java/com/aliyun/oss/common/utils/VersionUtilTest.java
+++ b/src/test/java/com/aliyun/oss/common/utils/VersionUtilTest.java
@@ -28,7 +28,7 @@ public class VersionUtilTest {
@Test
public void testGetDefaultUserAgent() {
String userAgent = VersionInfoUtils.getDefaultUserAgent();
- assertTrue(userAgent.startsWith("aliyun-sdk-java/3.3.0("));
+ assertTrue(userAgent.startsWith("aliyun-sdk-java/3.4.0("));
assertEquals(userAgent.split("/").length, 4);
assertEquals(userAgent.split(";").length, 2);
assertEquals(userAgent.split("\\(").length, 2);
diff --git a/src/test/java/com/aliyun/oss/integrationtests/BucketProcesTest.java b/src/test/java/com/aliyun/oss/integrationtests/BucketProcesTest.java
index ac9699d3..81b44d7f 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/BucketProcesTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/BucketProcesTest.java
@@ -30,6 +30,8 @@
import com.aliyun.oss.model.ImageProcess;
import com.aliyun.oss.model.SetBucketProcessRequest;
+import static com.aliyun.oss.integrationtests.TestUtils.waitForCacheExpiration;
+
public class BucketProcesTest extends TestBase {
@Test
@@ -49,7 +51,9 @@ public void testBucketImageProcessConf() {
ImageProcess imageProcess = new ImageProcess("Img", true, "jpg,png", "/,-");
SetBucketProcessRequest request = new SetBucketProcessRequest(bucketName, imageProcess);
ossClient.setBucketProcess(request);
-
+
+ waitForCacheExpiration(2);
+
// get 1
bucketProcess = ossClient.getBucketProcess(new GenericRequest(bucketName));
Assert.assertEquals(bucketProcess.getImageProcess().getCompliedHost(), "Img");
@@ -64,7 +68,9 @@ public void testBucketImageProcessConf() {
imageProcess = new ImageProcess("Both", false, "gif", "-");
request = new SetBucketProcessRequest(bucketName, imageProcess);
ossClient.setBucketProcess(request);
-
+
+ waitForCacheExpiration(2);
+
// get 2
bucketProcess = ossClient.getBucketProcess(new GenericRequest(bucketName));
Assert.assertEquals(bucketProcess.getImageProcess().getCompliedHost(), "Both");
@@ -79,7 +85,9 @@ public void testBucketImageProcessConf() {
imageProcess = new ImageProcess("Img", true, "*", "/", true);
request = new SetBucketProcessRequest(bucketName, imageProcess);
ossClient.setBucketProcess(request);
-
+
+ waitForCacheExpiration(2);
+
// get 3
bucketProcess = ossClient.getBucketProcess(new GenericRequest(bucketName));
Assert.assertEquals(bucketProcess.getImageProcess().getCompliedHost(), "Img");
diff --git a/src/test/java/com/aliyun/oss/integrationtests/CMKIDTest.java b/src/test/java/com/aliyun/oss/integrationtests/CMKIDTest.java
new file mode 100644
index 00000000..2985078a
--- /dev/null
+++ b/src/test/java/com/aliyun/oss/integrationtests/CMKIDTest.java
@@ -0,0 +1,290 @@
+package com.aliyun.oss.integrationtests;
+
+import com.aliyun.oss.model.*;
+import junit.framework.Assert;
+import org.apache.commons.codec.binary.Base64;
+import org.junit.Test;
+
+import javax.activation.MimetypesFileTypeMap;
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+public class CMKIDTest extends TestBase {
+
+ private String key = "CMKIDTest";
+
+ private String uploadLocalFilePath = "uploadFile";
+
+ private String downloadLocalFilePath = "downloadFile";
+
+ @Test
+ public void testPutObjectWithCMKID() {
+ try {
+ final File sampleFile = createSampleFile(uploadLocalFilePath, 1 * 1024 * 1024);
+
+ final ObjectMetadata metadata = new ObjectMetadata();
+ metadata.setServerSideEncryption(ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
+ metadata.setServerSideEncryptionKeyId(TestConfig.CMK_ID);
+ ossClient.putObject(bucketName, key, sampleFile, metadata);
+ ObjectMetadata objectMetadata = ossClient.getObject(new GetObjectRequest(bucketName, key), new File(downloadLocalFilePath));
+ Assert.assertEquals(TestConfig.CMK_ID, objectMetadata.getServerSideEncryptionKeyId());
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testPostObjectWithCMKID() {
+ HttpURLConnection conn = null;
+
+ try {
+ final File sampleFile = createSampleFile(uploadLocalFilePath, 1 * 1024 * 1024);
+
+ String urlStr = TestConfig.OSS_TEST_ENDPOINT.replace("http://", "http://" + bucketName + ".");
+
+ Map formFields = new LinkedHashMap();
+
+ formFields.put("key", this.key);
+ formFields.put("Content-Disposition", "attachment;filename="
+ + sampleFile.getAbsolutePath());
+ formFields.put("OSSAccessKeyId", TestConfig.OSS_TEST_ACCESS_KEY_ID);
+ formFields.put("x-oss-server-side-encryption", ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
+ formFields.put("x-oss-server-side-encryption-key-id", TestConfig.CMK_ID);
+ String policy
+ = "{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [[\"content-length-range\", 0, 104857600]]}";
+ String encodePolicy = new String(Base64.encodeBase64(policy.getBytes()));
+ formFields.put("policy", encodePolicy);
+ String signaturecom = computeSignature(TestConfig.OSS_TEST_ACCESS_KEY_SECRET, encodePolicy);
+ formFields.put("Signature", signaturecom);
+
+ String boundary = "9431149156168";
+
+ URL url = new URL(urlStr);
+ conn = (HttpURLConnection)url.openConnection();
+ conn.setConnectTimeout(5000);
+ conn.setReadTimeout(30000);
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("User-Agent",
+ "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
+ conn.setRequestProperty("Content-Type",
+ "multipart/form-data; boundary=" + boundary);
+ OutputStream out = new DataOutputStream(conn.getOutputStream());
+
+ if (formFields != null) {
+ StringBuffer strBuf = new StringBuffer();
+ Iterator> iter = formFields.entrySet().iterator();
+ int i = 0;
+
+ while (iter.hasNext()) {
+ Map.Entry entry = iter.next();
+ String inputName = entry.getKey();
+ String inputValue = entry.getValue();
+
+ if (inputValue == null) {
+ continue;
+ }
+
+ if (i == 0) {
+ strBuf.append("--").append(boundary).append("\r\n");
+ strBuf.append("Content-Disposition: form-data; name=\""
+ + inputName + "\"\r\n\r\n");
+ strBuf.append(inputValue);
+ } else {
+ strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
+ strBuf.append("Content-Disposition: form-data; name=\""
+ + inputName + "\"\r\n\r\n");
+ strBuf.append(inputValue);
+ }
+
+ i++;
+ }
+ out.write(strBuf.toString().getBytes());
+ }
+
+ String contentType = new MimetypesFileTypeMap().getContentType(sampleFile.getName());
+ if (contentType == null || contentType.equals("")) {
+ contentType = "application/octet-stream";
+ }
+
+ StringBuffer strBuf = new StringBuffer();
+ strBuf.append("\r\n").append("--").append(boundary)
+ .append("\r\n");
+ strBuf.append("Content-Disposition: form-data; name=\"file\"; "
+ + "filename=\"" + sampleFile.getName() + "\"\r\n");
+ strBuf.append("Content-Type: " + contentType + "\r\n\r\n");
+
+ out.write(strBuf.toString().getBytes());
+
+ DataInputStream in = new DataInputStream(new FileInputStream(sampleFile));
+ int bytes = 0;
+ byte[] bufferOut = new byte[1024];
+ while ((bytes = in.read(bufferOut)) != -1) {
+ out.write(bufferOut, 0, bytes);
+ }
+ in.close();
+
+ byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
+ out.write(endData);
+ out.flush();
+ out.close();
+
+ strBuf = new StringBuffer();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ strBuf.append(line).append("\n");
+ }
+ System.out.println(strBuf.toString());
+ reader.close();
+
+ ObjectMetadata objectMetadata = ossClient.getObject(new GetObjectRequest(bucketName, key), new File(downloadLocalFilePath));
+ Assert.assertEquals(TestConfig.CMK_ID, objectMetadata.getServerSideEncryptionKeyId());
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ }
+
+ private static String computeSignature(String accessKeySecret, String encodePolicy)
+ throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
+ // convert to UTF-8
+ byte[] key = accessKeySecret.getBytes("UTF-8");
+ byte[] data = encodePolicy.getBytes("UTF-8");
+
+ // hmac-sha1
+ Mac mac = Mac.getInstance("HmacSHA1");
+ mac.init(new SecretKeySpec(key, "HmacSHA1"));
+ byte[] sha = mac.doFinal(data);
+
+ // base64
+ return new String(Base64.encodeBase64(sha));
+ }
+
+ @Test
+ public void testInitMultipartUploadWithCMKID() {
+ try {
+ final File sampleFile = createSampleFile(uploadLocalFilePath, 1 * 1024 * 1024);
+ ObjectMetadata metadata = new ObjectMetadata();
+ metadata.setServerSideEncryption(ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
+ metadata.setServerSideEncryptionKeyId(TestConfig.CMK_ID);
+
+ InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key, metadata);
+ InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);
+ String uploadId = result.getUploadId();
+ List partETags = new ArrayList();
+
+ final long partSize = 1 * 1024 * 1024L;
+ long fileLength = sampleFile.length();
+ int partCount = (int) (fileLength / partSize);
+ if (fileLength % partSize != 0) {
+ partCount++;
+ }
+
+ for (int i = 0; i < partCount; i++) {
+ long startPos = i * partSize;
+ long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
+ InputStream instream = new FileInputStream(sampleFile);
+ instream.skip(startPos);
+ UploadPartRequest uploadPartRequest = new UploadPartRequest();
+ uploadPartRequest.setBucketName(bucketName);
+ uploadPartRequest.setKey(key);
+ uploadPartRequest.setUploadId(uploadId);
+ uploadPartRequest.setInputStream(instream);
+ uploadPartRequest.setPartSize(curPartSize);
+ uploadPartRequest.setPartNumber(i + 1);
+ UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
+ partETags.add(uploadPartResult.getPartETag());
+ }
+
+ Collections.sort(partETags, new Comparator() {
+ public int compare(PartETag p1, PartETag p2) {
+ return p1.getPartNumber() - p2.getPartNumber();
+ }
+ });
+ CompleteMultipartUploadRequest completeMultipartUploadRequest =
+ new CompleteMultipartUploadRequest(bucketName, key, uploadId, partETags);
+ ossClient.completeMultipartUpload(completeMultipartUploadRequest);
+
+ ObjectMetadata objectMetadata = ossClient.getObject(new GetObjectRequest(bucketName, key), new File(downloadLocalFilePath));
+
+ Assert.assertEquals(TestConfig.CMK_ID, objectMetadata.getServerSideEncryptionKeyId());
+ } catch (IOException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyObjectWithCMKID() {
+ try {
+ final String sourceBucketName = createBucket();
+ final String sourceKey = "src_key";
+ final File sampleFile = createSampleFile(uploadLocalFilePath, 1 * 1024 * 1024);
+ final CopyObjectRequest request =
+ new CopyObjectRequest(sourceBucketName, sourceKey, bucketName, key);
+
+ ossClient.putObject(sourceBucketName, sourceKey, sampleFile);
+
+ request.setServerSideEncryption(ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
+ request.setServerSideEncryptionKeyId(TestConfig.CMK_ID);
+ ossClient.copyObject(request);
+
+ String copyLocalFilePath = "copy";
+
+ ObjectMetadata metadataCopy = ossClient.getObject(new GetObjectRequest(bucketName, key), new File(copyLocalFilePath));
+
+ Assert.assertEquals(TestConfig.CMK_ID, metadataCopy.getServerSideEncryptionKeyId());
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testAppendObjectWithCMKID() {
+ try {
+ String content1 = "Hello OSS A ";
+ String content2 = "Hello OSS B ";
+
+ ObjectMetadata meta = new ObjectMetadata();
+
+ meta.setContentType("text/plain");
+ meta.setServerSideEncryption(ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
+ meta.setServerSideEncryptionKeyId(TestConfig.CMK_ID);
+
+ AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, key, new ByteArrayInputStream(content1.getBytes()),meta);
+
+ appendObjectRequest.setPosition(0L);
+
+ AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);
+
+ appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
+ appendObjectRequest.setInputStream(new ByteArrayInputStream(content2.getBytes()));
+
+ ossClient.appendObject(appendObjectRequest);
+
+ OSSObject o = ossClient.getObject(bucketName, key);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(o.getObjectContent()));
+ StringBuilder sb = new StringBuilder();
+
+ String line;
+
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ }
+
+ Assert.assertTrue(sb.toString().equals(content1 + content2));
+ } catch (IOException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/aliyun/oss/integrationtests/CRCChecksumTest.java b/src/test/java/com/aliyun/oss/integrationtests/CRCChecksumTest.java
index 44d13300..f36345c4 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/CRCChecksumTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/CRCChecksumTest.java
@@ -48,6 +48,8 @@
import com.aliyun.oss.model.PutObjectResult;
import com.aliyun.oss.model.UploadPartRequest;
import com.aliyun.oss.model.UploadPartResult;
+import com.aliyun.oss.model.UploadFileRequest;
+import com.aliyun.oss.model.UploadFileResult;
public class CRCChecksumTest extends TestBase {
@@ -186,7 +188,26 @@ public void testMutilUploadCRC() {
Assert.fail(e.getMessage());
}
}
-
+
+ @Test
+ public void testUploadFileCRC() {
+ final String key = "upload-file-crc";
+
+ try {
+ File file = createSampleFile(key, 1024 * 500);
+
+ UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
+ uploadFileRequest.setUploadFile(file.getAbsolutePath());
+ uploadFileRequest.setTaskNum(10);
+ uploadFileRequest.setEnableCheckpoint(true);
+
+ UploadFileResult uploadRes = ossClient.uploadFile(uploadFileRequest);
+ Assert.assertEquals(uploadRes.getMultipartUploadResult().getClientCRC(), uploadRes.getMultipartUploadResult().getServerCRC());
+ } catch (Throwable e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
@Test
public void testGetObjectCRC() {
String key = "get-object-crc";
diff --git a/src/test/java/com/aliyun/oss/integrationtests/GetObjectTest.java b/src/test/java/com/aliyun/oss/integrationtests/GetObjectTest.java
index fad8bd61..0ba8f063 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/GetObjectTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/GetObjectTest.java
@@ -529,7 +529,7 @@ public void testGetObjectWithSpecialChars() {
@Test
public void testGetObjectByUrlsignature() {
final String key = "put-object-by-urlsignature";
- final String expirationString = "Sun, 12 Apr 2018 12:00:00 GMT";
+ final String expirationString = "Sun, 12 Apr 2020 12:00:00 GMT";
final long inputStreamLength = 128 * 1024; //128KB
final long firstByte= inputStreamLength / 2;
final long lastByte = inputStreamLength - 1;
diff --git a/src/test/java/com/aliyun/oss/integrationtests/HeadObjectTest.java b/src/test/java/com/aliyun/oss/integrationtests/HeadObjectTest.java
new file mode 100644
index 00000000..f93fdfb7
--- /dev/null
+++ b/src/test/java/com/aliyun/oss/integrationtests/HeadObjectTest.java
@@ -0,0 +1,56 @@
+package com.aliyun.oss.integrationtests;
+
+import com.aliyun.oss.model.HeadObjectRequest;
+import com.aliyun.oss.model.ObjectMetadata;
+import com.aliyun.oss.model.PutObjectRequest;
+import com.aliyun.oss.model.PutObjectResult;
+import junit.framework.Assert;
+import org.junit.Test;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.aliyun.oss.integrationtests.TestUtils.genFixedLengthInputStream;
+
+public class HeadObjectTest extends TestBase {
+
+ @Test
+ public void testHeadObject() {
+ final String key = "head-object";
+ final long inputStreanLength = 1024;
+
+ try {
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key,
+ genFixedLengthInputStream(inputStreanLength), null);
+ PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
+ Assert.assertEquals(putObjectResult.getRequestId().length(), REQUEST_ID_LEN);
+
+ HeadObjectRequest headObjectRequest = new HeadObjectRequest(bucketName, key);
+ List matchingETags = new LinkedList();
+ matchingETags.add(putObjectResult.getETag());
+ headObjectRequest.setMatchingETagConstraints(matchingETags);
+ ObjectMetadata o = ossClient.headObject(headObjectRequest);
+ Assert.assertEquals(o.getETag(), putObjectResult.getETag());
+
+ headObjectRequest = new HeadObjectRequest(bucketName, key);
+ List nonmatchingEtags = new LinkedList();
+ nonmatchingEtags.add("nonmatching");
+ headObjectRequest.setNonmatchingETagConstraints(nonmatchingEtags);
+ o = ossClient.headObject(headObjectRequest);
+ Assert.assertEquals(o.getETag(), putObjectResult.getETag());
+
+ headObjectRequest = new HeadObjectRequest(bucketName, key);
+ headObjectRequest.setModifiedSinceConstraint(new Date(System.currentTimeMillis() - 3600 * 1000));
+ o = ossClient.headObject(headObjectRequest);
+ Assert.assertEquals(o.getETag(), putObjectResult.getETag());
+
+ headObjectRequest = new HeadObjectRequest(bucketName, key);
+ headObjectRequest.setUnmodifiedSinceConstraint(new Date(System.currentTimeMillis() + 3600 * 1000));
+ o = ossClient.headObject(headObjectRequest);
+ Assert.assertEquals(o.getETag(), putObjectResult.getETag());
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/com/aliyun/oss/integrationtests/PostPolicyTest.java b/src/test/java/com/aliyun/oss/integrationtests/PostPolicyTest.java
index f605395d..7e85cb90 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/PostPolicyTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/PostPolicyTest.java
@@ -65,7 +65,8 @@ public void testGenPostPolicy() {
String actualPostSignature = ossClient.calculatePostSignature(actualPostPolicy);
// It has something to do with the local time
Assert.assertTrue((actualPostSignature.equals("88kD3wGu1W5isVAdWSG765DRPKY=") ||
- actualPostSignature.equals("KbUYorFeyyqxntffsNlrRcV50Ds=")));
+ actualPostSignature.equals("KbUYorFeyyqxntffsNlrRcV50Ds=") ||
+ actualPostSignature.equals("oGVOEb+wFKpZMgMqI0NNfSldA6s=")));
} catch (Exception e) {
Assert.fail(e.getMessage());
}
diff --git a/src/test/java/com/aliyun/oss/integrationtests/PutObjectTest.java b/src/test/java/com/aliyun/oss/integrationtests/PutObjectTest.java
index c4776823..de825a1f 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/PutObjectTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/PutObjectTest.java
@@ -348,7 +348,7 @@ public void testPutObjectByUrlSignature() throws Exception {
final String key = "put-object-by-urlsignature";
final String metaKey0 = "author";
final String metaValue0 = "aliy";
- final String expirationString = "Sun, 12 Apr 2018 12:00:00 GMT";
+ final String expirationString = "Sun, 12 Apr 2020 12:00:00 GMT";
final long inputStreamLength = 128 * 1024; //128KB
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.PUT);
@@ -494,5 +494,25 @@ public void testIncorrentSignature() throws Exception {
}
}
}
-
+
+ @Test
+ public void testPutCSVTypeFile() throws Exception {
+ final String key = "1.csv";
+ final int instreamLength = 128 * 1024;
+
+ InputStream instream = null;
+ try {
+ instream = genFixedLengthInputStream(instreamLength);
+ ossClient.putObject(bucketName, key, instream);
+
+ OSSObject o = ossClient.getObject(bucketName, key);
+ Assert.assertEquals(o.getObjectMetadata().getContentType(), "text/csv");
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+
+ if (instream != null) {
+ instream.close();
+ }
+ }
+ }
}
diff --git a/src/test/java/com/aliyun/oss/integrationtests/RtmpTest.java b/src/test/java/com/aliyun/oss/integrationtests/RtmpTest.java
index 18afdd00..559ffdcf 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/RtmpTest.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/RtmpTest.java
@@ -42,6 +42,7 @@
import com.aliyun.oss.model.LiveChannelTarget;
import com.aliyun.oss.model.LiveRecord;
import com.aliyun.oss.model.PushflowStatus;
+import com.aliyun.oss.model.OSSObject;
/**
* Test rtmp
@@ -56,6 +57,7 @@ public void testCreateLiveChannelDefault() {
CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
bucketName, liveChannel);
CreateLiveChannelResult createLiveChannelResult = ossClient.createLiveChannel(createLiveChannelRequest);
+ ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
Assert.assertEquals(createLiveChannelResult.getPublishUrls().size(), 1);
Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).startsWith("rtmp://"));
Assert.assertTrue(createLiveChannelResult.getPublishUrls().get(0).endsWith("live/" + liveChannel));
@@ -553,7 +555,34 @@ public void testGenerateVodPlaylist() {
Assert.fail(e.getMessage());
}
}
-
+
+ @Test
+ public void testGetVodPlaylist() {
+ final String liveChannel = "normal-get-vod-playlist";
+
+ try {
+ CreateLiveChannelRequest createLiveChannelRequest = new CreateLiveChannelRequest(
+ bucketName, liveChannel);
+ ossClient.createLiveChannel(createLiveChannelRequest);
+ ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);
+
+ long startTime = System.currentTimeMillis() / 1000 - 3600;
+ long endTime = System.currentTimeMillis() / 1000 + 3600;
+ try {
+ OSSObject o = ossClient.getVodPlaylist(bucketName, liveChannel, startTime, endTime);
+ Assert.assertEquals(bucketName, o.getBucketName());
+ Assert.assertEquals(liveChannel, o.getKey());
+ } catch (OSSException e) {
+ Assert.assertEquals(e.getErrorCode(), OSSErrorCode.INVALID_ARGUMENT);
+ Assert.assertTrue(e.getMessage().indexOf("No ts file found in specified time span.") > -1);
+ }
+
+ ossClient.deleteLiveChannel(bucketName, liveChannel);
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
@Test
public void testGeneratePushflowUri() {
final String liveChannel = "normal-generate-pushflow-uri";
diff --git a/src/test/java/com/aliyun/oss/integrationtests/SignTest.java b/src/test/java/com/aliyun/oss/integrationtests/SignTest.java
new file mode 100644
index 00000000..732dba23
--- /dev/null
+++ b/src/test/java/com/aliyun/oss/integrationtests/SignTest.java
@@ -0,0 +1,236 @@
+package com.aliyun.oss.integrationtests;
+
+import com.aliyun.oss.ClientBuilderConfiguration;
+import com.aliyun.oss.HttpMethod;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.common.comm.SignVersion;
+import com.aliyun.oss.common.utils.DateUtil;
+import com.aliyun.oss.common.utils.HttpHeaders;
+import com.aliyun.oss.common.utils.IOUtils;
+import com.aliyun.oss.model.GeneratePresignedUrlRequest;
+import com.aliyun.oss.model.OSSObject;
+import com.aliyun.oss.model.PutObjectRequest;
+import junit.framework.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.*;
+
+import static com.aliyun.oss.integrationtests.TestUtils.genFixedLengthFile;
+import static com.aliyun.oss.integrationtests.TestUtils.genFixedLengthInputStream;
+import static com.aliyun.oss.integrationtests.TestUtils.removeFile;
+import static com.aliyun.oss.internal.OSSConstants.DEFAULT_OBJECT_CONTENT_TYPE;
+
+public class SignTest {
+
+ @Test
+ public void testSignV2() {
+ String key = "test-sign-V2";
+ ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+ conf.setSignatureVersion(SignVersion.V2);
+ OSS ossClient = new OSSClientBuilder().build(TestConfig.OSS_TEST_ENDPOINT, TestConfig.OSS_TEST_ACCESS_KEY_ID, TestConfig.OSS_TEST_ACCESS_KEY_SECRET, conf);
+ long ticks = new Date().getTime() / 1000 + new Random().nextInt(5000);
+ String bucket = TestBase.BUCKET_NAME_PREFIX + ticks;
+ ossClient.createBucket(bucket);
+ String filePath = null;
+
+ try {
+ filePath = genFixedLengthFile(1 * 1024 * 1024); //1MB
+ PutObjectRequest request = new PutObjectRequest(bucket, key, new File(filePath));
+ request.addHeader("x-oss-head1", "value");
+ request.addHeader("abc", "value");
+ request.addHeader("ZAbc", "value");
+ request.addHeader("XYZ", "value");
+ request.addAdditionalHeaderName("ZAbc");
+ request.addAdditionalHeaderName("x-oss-head1");
+ request.addAdditionalHeaderName("abc");
+ request.addParameter("param1", "value1");
+
+ ossClient.putObject(request);
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ if (filePath != null) {
+ removeFile(filePath);
+ }
+ }
+ }
+
+ @Test
+ public void testGenerateSignedV2URL() {
+ String key = "test-sign-v2-url";
+ ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+ conf.setSignatureVersion(SignVersion.V2);
+ OSS ossClient = new OSSClientBuilder().build(TestConfig.OSS_TEST_ENDPOINT, TestConfig.OSS_TEST_ACCESS_KEY_ID, TestConfig.OSS_TEST_ACCESS_KEY_SECRET, conf);
+ Date expiration = new Date(new Date().getTime() + 1000 * 60 *10);
+ long ticks = new Date().getTime() / 1000 + new Random().nextInt(5000);
+ String bucket = TestBase.BUCKET_NAME_PREFIX + ticks;
+
+ ossClient.createBucket(bucket);
+ URL url;
+ String filePath;
+
+ try {
+ filePath = genFixedLengthFile(1 * 1024 * 1024); //1MB
+ PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, key, new File(filePath));
+
+ ossClient.putObject(putObjectRequest);
+
+ URI endpointURI = new URI(TestConfig.OSS_TEST_ENDPOINT);
+ GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key);
+ request.setExpiration(expiration);
+ url = ossClient.generatePresignedUrl(request);
+
+ StringBuilder expectedUrlPrefix = new StringBuilder();
+
+ expectedUrlPrefix.append(endpointURI.getScheme()).append("://").append(bucket).append(".").append(endpointURI.getHost()).append("/")
+ .append(key).append("?x-oss-");
+
+ Assert.assertTrue(url.toString().startsWith(expectedUrlPrefix.toString()));
+ Assert.assertTrue(url.toString().contains("x-oss-signature"));
+ Assert.assertTrue(url.toString().contains("x-oss-signature-version"));
+ Assert.assertTrue(url.toString().contains("x-oss-expires"));
+ Assert.assertTrue(url.toString().contains("x-oss-access-key-id"));
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testSwitchSignatureVersion() {
+ String key = "test-switch-signature-version";
+ ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+ conf.setSignatureVersion(SignVersion.V2);
+ OSS ossClient = new OSSClientBuilder().build(TestConfig.OSS_TEST_ENDPOINT, TestConfig.OSS_TEST_ACCESS_KEY_ID, TestConfig.OSS_TEST_ACCESS_KEY_SECRET, conf);
+ long ticks = new Date().getTime() / 1000 + new Random().nextInt(5000);
+ String bucket = TestBase.BUCKET_NAME_PREFIX + ticks;
+ ossClient.createBucket(bucket);
+ String filePath;
+
+ try {
+ filePath = genFixedLengthFile(1 * 1024 * 1024); //1MB
+
+ ossClient.putObject(bucket, key, new File(filePath));
+
+ ossClient.switchSignatureVersion(SignVersion.V1);
+
+ ossClient.putObject(bucket, key, new File(filePath));
+ } catch (Exception e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testPutObjectByUrlSignature() {
+ final String key = "put-object-by-urlSignature";
+ ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+ conf.setSignatureVersion(SignVersion.V2);
+ OSS ossClient = new OSSClientBuilder().build(TestConfig.OSS_TEST_ENDPOINT, TestConfig.OSS_TEST_ACCESS_KEY_ID, TestConfig.OSS_TEST_ACCESS_KEY_SECRET, conf);
+ long ticks = new Date().getTime() / 1000 + new Random().nextInt(5000);
+ String bucket = TestBase.BUCKET_NAME_PREFIX + ticks;
+ ossClient.createBucket(bucket);
+
+ final String expirationString = "Sun, 12 Apr 2020 12:00:00 GMT";
+ final long inputStreamLength = 128 * 1024; //128KB
+
+ GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key, HttpMethod.PUT);
+ try {
+ Date expiration = DateUtil.parseRfc822Date(expirationString);
+ request.setExpiration(expiration);
+ request.setContentType(DEFAULT_OBJECT_CONTENT_TYPE);
+ request.addHeader("x-oss-head1", "value");
+ request.addHeader("abc", "value");
+ request.addHeader("ZAbc", "value");
+ request.addHeader("XYZ", "value");
+ request.addAdditionalHeaderName("ZAbc");
+ request.addAdditionalHeaderName("x-oss-head1");
+ request.addAdditionalHeaderName("abc");
+ request.addQueryParameter("param1", "value1");
+ URL signedUrl = ossClient.generatePresignedUrl(request);
+
+ Map requestHeaders = new HashMap();
+
+ requestHeaders.put("x-oss-head1", "value");
+ requestHeaders.put("abc", "value");
+ requestHeaders.put("ZAbc", "value");
+ requestHeaders.put("XYZ", "value");
+ requestHeaders.put(HttpHeaders.CONTENT_TYPE, DEFAULT_OBJECT_CONTENT_TYPE);
+ InputStream instream = genFixedLengthInputStream(inputStreamLength);
+ // Using url signature & chunked encoding to upload specified inputstream.
+ ossClient.putObject(signedUrl, instream, -1, requestHeaders, true);
+ OSSObject o = ossClient.getObject(bucket, key);
+ Assert.assertEquals(key, o.getKey());
+ Assert.assertEquals(inputStreamLength, o.getObjectMetadata().getContentLength());
+ } catch (Exception ex) {
+ Assert.fail(ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetObjectByUrlsignature() {
+ final String key = "get-object-by-urlsignature";
+ ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+ conf.setSignatureVersion(SignVersion.V2);
+ OSS ossClient = new OSSClientBuilder().build(TestConfig.OSS_TEST_ENDPOINT, TestConfig.OSS_TEST_ACCESS_KEY_ID, TestConfig.OSS_TEST_ACCESS_KEY_SECRET, conf);
+ long ticks = new Date().getTime() / 1000 + new Random().nextInt(5000);
+ String bucket = TestBase.BUCKET_NAME_PREFIX + ticks;
+ ossClient.createBucket(bucket);
+
+ final String expirationString = "Sun, 12 Apr 2020 12:00:00 GMT";
+ final long inputStreamLength = 128 * 1024; //128KB
+ final long firstByte= inputStreamLength / 2;
+ final long lastByte = inputStreamLength - 1;
+
+ try {
+ ossClient.putObject(bucket, key, genFixedLengthInputStream(inputStreamLength), null);
+
+ GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucket, key);
+ Date expiration = DateUtil.parseRfc822Date(expirationString);
+ request.setExpiration(expiration);
+ request.setContentType(DEFAULT_OBJECT_CONTENT_TYPE);
+ request.addHeader(HttpHeaders.RANGE, String.format("bytes=%d-%d", firstByte, lastByte));
+ request.addHeader("x-oss-head1", "value");
+ request.addHeader("abc", "value");
+ request.addHeader("ZAbc", "value");
+ request.addHeader("XYZ", "value");
+ request.addAdditionalHeaderName("ZAbc");
+ request.addAdditionalHeaderName("x-oss-head1");
+ request.addAdditionalHeaderName("abc");
+ request.addQueryParameter("param1", "value1");
+ URL signedUrl = ossClient.generatePresignedUrl(request);
+
+ Map requestHeaders = new HashMap();
+
+ requestHeaders.put("x-oss-head1", "value");
+ requestHeaders.put("abc", "value");
+ requestHeaders.put("ZAbc", "value");
+ requestHeaders.put("XYZ", "value");
+ requestHeaders.put(HttpHeaders.CONTENT_TYPE, DEFAULT_OBJECT_CONTENT_TYPE);
+ requestHeaders.put(HttpHeaders.RANGE, String.format("bytes=%d-%d", firstByte, lastByte));
+
+ OSSObject o = ossClient.getObject(signedUrl, requestHeaders);
+
+ try {
+ int bytesRead = -1;
+ int totalBytes = 0;
+ byte[] buffer = new byte[4096];
+ while ((bytesRead = o.getObjectContent().read(buffer)) != -1) {
+ totalBytes += bytesRead;
+ }
+
+ Assert.assertEquals((lastByte - firstByte + 1), totalBytes);
+ } catch (IOException e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ IOUtils.safeClose(o.getObjectContent());
+ }
+ } catch (Exception ex) {
+ Assert.fail(ex.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/com/aliyun/oss/integrationtests/TestConfig.java b/src/test/java/com/aliyun/oss/integrationtests/TestConfig.java
index 99b78700..047f17eb 100644
--- a/src/test/java/com/aliyun/oss/integrationtests/TestConfig.java
+++ b/src/test/java/com/aliyun/oss/integrationtests/TestConfig.java
@@ -45,4 +45,6 @@ public final class TestConfig {
public static String PROXY_USER = null;
public static String PROXY_PASSWORD = null;
+ // OSS cmk id configuration
+ public static String CMK_ID = null;
}