From 156503c01f0439e8751b0a15ff13e5be4cac0f82 Mon Sep 17 00:00:00 2001 From: zzq996 Date: Tue, 30 Apr 2024 15:55:29 +0800 Subject: [PATCH] Version 3.24.3 Resolved issues: 1. Optimized log info of some exception stack 2. Added log when client closed 3. Fixed the issue of hostname verifying 4. Optimized Security of client encryption 5. Optimized the retry logic 6. Fixed issue of setObjectMetadata not working while copyObject 7. Optimized object key coding of temporary url 8. Optimized performance of parsing and generating time string 9. Optimized logic of xml generating 10. Fixed several issues of null pointer Third-party dependence: 1. Replace okhttp 4.12.0 with okhttp 4.11.0 2. Replace okio 3.6.0 with okio 3.5.0 3. Replace jackson-core 2.15.2 with jackson-core 2.13.3 4. Replace jackson-databind 2.15.2 with jackson-databind 2.13.4.1 5. Replace jackson-annotations 2.15.2 with jackson-annotations 2.13.3 --- README-Android.md | 20 ++++ README-Java.md | 20 ++++ README.MD | 20 ++++ README_CN.MD | 20 ++++ .../java/com/obs/log/AbstractLog4jLogger.java | 23 ++++- .../java/com/obs/services/AbstractClient.java | 6 +- .../com/obs/services/ObsConfiguration.java | 14 +++ .../services/crypto/CTRCipherGenerator.java | 34 +++++-- .../obs/services/crypto/CryptoObsClient.java | 10 +- .../crypto/CtrRSACipherGenerator.java | 75 +++++++++++++-- .../com/obs/services/internal/Constants.java | 2 +- .../internal/RestConnectionService.java | 5 +- .../services/internal/RestStorageService.java | 95 +++++++++++++------ .../service/ObsBucketBaseService.java | 4 + .../internal/service/RequestConvertor.java | 7 ++ .../internal/utils/AccessLoggerUtils.java | 5 +- .../services/internal/utils/RestUtils.java | 71 ++++++++------ .../services/internal/utils/ServiceUtils.java | 27 ++++-- .../services/internal/xml/OBSXMLBuilder.java | 44 +++++++-- .../model/BucketDirectColdAccess.java | 6 +- pom-android.xml | 12 +-- pom-java-optimization.xml | 8 +- pom-java.xml | 12 +-- pom.xml | 12 +-- 24 files changed, 432 insertions(+), 120 deletions(-) diff --git a/README-Android.md b/README-Android.md index 63e7a48..b45965d 100644 --- a/README-Android.md +++ b/README-Android.md @@ -1,3 +1,23 @@ +Version 3.24.3 +Resolved issues: +1. Optimized log info of some exception stack +2. Added log when client closed +3. Fixed the issue of hostname verifying +4. Optimized Security of client encryption +5. Optimized the retry logic +6. Fixed issue of setObjectMetadata not working while copyObject +7. Optimized object key coding of temporary url +8. Optimized performance of parsing and generating time string +9. Optimized logic of xml generating +10. Fixed several issues of null pointer + +Third-party dependence: +1. Replace okhttp 4.12.0 with okhttp 4.11.0 +2. Replace okio 3.6.0 with okio 3.5.0 +3. Replace jackson-core 2.15.2 with jackson-core 2.13.3 +4. Replace jackson-databind 2.15.2 with jackson-databind 2.13.4.1 +5. Replace jackson-annotations 2.15.2 with jackson-annotations 2.13.3 +----------------------------------------------------------------------------------- Version 3.23.9.1 New features: 1. Allow you set custom dns resolver diff --git a/README-Java.md b/README-Java.md index b48ecab..d724f2c 100644 --- a/README-Java.md +++ b/README-Java.md @@ -1,3 +1,23 @@ +Version 3.24.3 +Resolved issues: +1. Optimized log info of some exception stack +2. Added log when client closed +3. Fixed the issue of hostname verifying +4. Optimized Security of client encryption +5. Optimized the retry logic +6. Fixed issue of setObjectMetadata not working while copyObject +7. Optimized object key coding of temporary url +8. Optimized performance of parsing and generating time string +9. Optimized logic of xml generating +10. Fixed several issues of null pointer + +Third-party dependence: +1. Replace okhttp 4.12.0 with okhttp 4.11.0 +2. Replace okio 3.6.0 with okio 3.5.0 +3. Replace jackson-core 2.15.2 with jackson-core 2.13.3 +4. Replace jackson-databind 2.15.2 with jackson-databind 2.13.4.1 +5. Replace jackson-annotations 2.15.2 with jackson-annotations 2.13.3 +----------------------------------------------------------------------------------- Version 3.23.9.1 New features: 1. Allow you set custom dns resolver diff --git a/README.MD b/README.MD index 67b98eb..afdba28 100644 --- a/README.MD +++ b/README.MD @@ -1,3 +1,23 @@ +Version 3.24.3 +Resolved issues: +1. Optimized log info of some exception stack +2. Added log when client closed +3. Fixed the issue of hostname verifying +4. Optimized Security of client encryption +5. Optimized the retry logic +6. Fixed issue of setObjectMetadata not working while copyObject +7. Optimized object key coding of temporary url +8. Optimized performance of parsing and generating time string +9. Optimized logic of xml generating +10. Fixed several issues of null pointer + +Third-party dependence: +1. Replace okhttp 4.12.0 with okhttp 4.11.0 +2. Replace okio 3.6.0 with okio 3.5.0 +3. Replace jackson-core 2.15.2 with jackson-core 2.13.3 +4. Replace jackson-databind 2.15.2 with jackson-databind 2.13.4.1 +5. Replace jackson-annotations 2.15.2 with jackson-annotations 2.13.3 +----------------------------------------------------------------------------------- Version 3.23.9.1 New features: 1. Allow you set custom dns resolver diff --git a/README_CN.MD b/README_CN.MD index 180466c..b5ccca1 100644 --- a/README_CN.MD +++ b/README_CN.MD @@ -1,3 +1,23 @@ +Version 3.24.3 +Resolved issues: +1. 优化某些堆栈的日志打印 +2. 增加client close时的日志打印 +3. 修复域名校验不正确的问题 +4. 客户端加密功能的安全整改 +5. 优化重试逻辑 +6. 修复拷贝对象时的元数据设置不生效的问题 +7. 优化临时url的路径编码逻辑 +8. 优化解析、生成时间字符串的性能 +9. 优化xml生成逻辑 +10. 修复部分空指针问题 + +Third-party dependence: +1. 使用 okhttp 4.12.0 替代 okhttp 4.11.0 +2. 使用 okio 3.6.0 替代 okio 3.5.0 +3. 使用 jackson-core 2.15.2 替代 jackson-core 2.13.3 +4. 使用 jackson-databind 2.15.2 替代 jackson-databind 2.13.4.1 +5. 使用 jackson-annotations 2.15.2 替代 jackson-annotations 2.13.3 +----------------------------------------------------------------------------------- Version 3.23.9.1 New features: 1. 支持设置自定义dns解析器 diff --git a/app/src/main/java/com/obs/log/AbstractLog4jLogger.java b/app/src/main/java/com/obs/log/AbstractLog4jLogger.java index 4ff4a21..fa6a4b6 100644 --- a/app/src/main/java/com/obs/log/AbstractLog4jLogger.java +++ b/app/src/main/java/com/obs/log/AbstractLog4jLogger.java @@ -15,10 +15,13 @@ package com.obs.log; -import java.util.logging.Logger; - import com.obs.services.internal.utils.AccessLoggerUtils; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.logging.Logger; + public abstract class AbstractLog4jLogger { private static final Logger ILOG = Logger.getLogger(AbstractLog4jLogger.class.getName()); @@ -55,6 +58,7 @@ public void info(Object obj, Throwable e) { try { LoggerMethodHolder.info.invoke(this.logger, obj, e); AccessLoggerUtils.appendLog(obj, "info"); + appendLogForThrowable(e,"info"); } catch (Exception ex) { ILOG.warning(ex.getMessage()); } @@ -88,6 +92,7 @@ public void warn(Object obj, Throwable e) { try { LoggerMethodHolder.warn.invoke(this.logger, obj, e); AccessLoggerUtils.appendLog(obj, "warn"); + appendLogForThrowable(e,"warn"); } catch (Exception ex) { ILOG.warning(ex.getMessage()); } @@ -121,6 +126,7 @@ public void error(Object obj, Throwable e) { try { LoggerMethodHolder.error.invoke(this.logger, obj, e); AccessLoggerUtils.appendLog(obj, "error"); + appendLogForThrowable(e,"error"); } catch (Exception ex) { ILOG.warning(ex.getMessage()); } @@ -154,6 +160,7 @@ public void debug(Object obj, Throwable e) { try { LoggerMethodHolder.debug.invoke(this.logger, obj, e); AccessLoggerUtils.appendLog(obj, "debug"); + appendLogForThrowable(e,"debug"); } catch (Exception ex) { ILOG.warning(ex.getMessage()); } @@ -187,6 +194,7 @@ public void trace(Object obj, Throwable e) { try { LoggerMethodHolder.trace.invoke(this.logger, obj, e); AccessLoggerUtils.appendLog(obj, "trace"); + appendLogForThrowable(e,"trace"); } catch (Exception ex) { ILOG.warning(ex.getMessage()); } @@ -202,4 +210,15 @@ public void accessRecord(Object obj) { } } } + + protected void appendLogForThrowable(Throwable e, String level) { + AccessLoggerUtils.appendLog("Throwable Message:" + e.getMessage(), level); + try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { + e.printStackTrace(pw); + AccessLoggerUtils.appendLog("Throwable printStackTrace:" + sw, level); + } catch (IOException ex) + { + AccessLoggerUtils.appendLog("Throwable printStackTrace failed:" + ex.getMessage(), level); + } + } } diff --git a/app/src/main/java/com/obs/services/AbstractClient.java b/app/src/main/java/com/obs/services/AbstractClient.java index 51a1d5b..b290937 100644 --- a/app/src/main/java/com/obs/services/AbstractClient.java +++ b/app/src/main/java/com/obs/services/AbstractClient.java @@ -68,7 +68,7 @@ protected void init(String accessKey, String secretKey, String securityToken, Ob if (this.isAuthTypeNegotiation()) { this.getProviderCredentials().setIsAuthTypeNegotiation(true); } - this.initHttpClient(config.getHttpDispatcher(), config.getCustomizedDnsImpl()); + this.initHttpClient(config.getHttpDispatcher(), config.getCustomizedDnsImpl(), config.getHostnameVerifier()); OBSXMLBuilder.setXmlDocumentBuilderFactoryClass(config.getXmlDocumentBuilderFactoryClass()); reqBean.setRespTime(new Date()); reqBean.setResultCode(Constants.RESULTCODE_SUCCESS); @@ -435,7 +435,11 @@ public void refresh(String accessKey, String secretKey, String securityToken) { */ @Override public void close() throws IOException { + ILOG.warn("client closing"); + AccessLoggerUtils.printLog(); this.shutdown(); + ILOG.warn("client closed"); + AccessLoggerUtils.printLog(); } public String base64Md5(InputStream is, long length, long offset) throws NoSuchAlgorithmException, IOException { diff --git a/app/src/main/java/com/obs/services/ObsConfiguration.java b/app/src/main/java/com/obs/services/ObsConfiguration.java index d2d6fcb..49d1ca8 100644 --- a/app/src/main/java/com/obs/services/ObsConfiguration.java +++ b/app/src/main/java/com/obs/services/ObsConfiguration.java @@ -14,6 +14,7 @@ package com.obs.services; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; @@ -99,6 +100,8 @@ public class ObsConfiguration implements Cloneable { private Dispatcher httpDispatcher; private Dns customizedDnsImpl; + + private HostnameVerifier hostnameVerifier; private String xmlDocumentBuilderFactoryClass; @@ -901,6 +904,17 @@ public Dns getCustomizedDnsImpl() { public void setCustomizedDnsImpl(Dns customizedDnsImpl) { this.customizedDnsImpl = customizedDnsImpl; } + + public HostnameVerifier getHostnameVerifier() + { + return hostnameVerifier; + } + + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) + { + this.hostnameVerifier = hostnameVerifier; + } + public String getXmlDocumentBuilderFactoryClass() { return xmlDocumentBuilderFactoryClass; } diff --git a/app/src/main/java/com/obs/services/crypto/CTRCipherGenerator.java b/app/src/main/java/com/obs/services/crypto/CTRCipherGenerator.java index ce07fcb..605908a 100644 --- a/app/src/main/java/com/obs/services/crypto/CTRCipherGenerator.java +++ b/app/src/main/java/com/obs/services/crypto/CTRCipherGenerator.java @@ -27,6 +27,7 @@ import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -52,6 +53,16 @@ public class CTRCipherGenerator { static int sha256BufferLen = 65536; + private static String AesCipherProvider = ""; + + public static String getAesCipherProvider() { + return AesCipherProvider; + } + + public static void setAesCipherProvider(String aesCipherProvider) { + AesCipherProvider = aesCipherProvider; + } + public SecureRandom getSecureRandom() { return secureRandom; } @@ -87,6 +98,7 @@ public byte[] getCryptoKeyBytes() { public byte[] getRandomCryptoKeyBytes() { return getRandomBytes(CRYPTO_KEY_BYTES_LEN); } + public byte[] getRandomBytes(int randomBytesLen) { byte[] randomBytes; randomBytes = new byte[randomBytesLen]; @@ -130,10 +142,10 @@ public CTRCipherGenerator( public CipherInputStream getAES256DecryptedStream( InputStream ciphertextInput, byte[] object_CryptoIvBytes, byte[] object_CryptoKeyBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, - InvalidKeyException { + InvalidKeyException, NoSuchProviderException { SecretKeySpec keySpec = new SecretKeySpec(object_CryptoKeyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(object_CryptoIvBytes); - Cipher cipher = Cipher.getInstance(AES_ALGORITHM); + Cipher cipher = getAesCipher(); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); return new CipherInputStream(ciphertextInput, cipher); } @@ -141,12 +153,11 @@ public CipherInputStream getAES256DecryptedStream( public CipherInputStream getAES256EncryptedStream( InputStream plaintextInput, byte[] object_CryptoIvBytes, byte[] object_CryptoKeyBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, - InvalidKeyException { + InvalidKeyException, NoSuchProviderException { SecretKeySpec keySpec = new SecretKeySpec(object_CryptoKeyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(object_CryptoIvBytes); - Cipher cipher = Cipher.getInstance(AES_ALGORITHM); + Cipher cipher = getAesCipher(); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); - return new CipherInputStream(plaintextInput, cipher); } @@ -161,10 +172,10 @@ public static byte[] getBytesFromBase64(String cryptoInfo) throws UnsupportedEnc public static byte[] getAESEncryptedBytes( byte[] plainText, int plainTextOffset, int plainTextLength, byte[] aesKeyBytes, byte[] aesIvBytes) throws IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, - InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException { + InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException { SecretKeySpec keySpec = new SecretKeySpec(aesKeyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(aesIvBytes); - Cipher cipher = Cipher.getInstance(AES_ALGORITHM); + Cipher cipher = getAesCipher(); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); return cipher.doFinal(plainText, plainTextOffset, plainTextLength); } @@ -225,6 +236,13 @@ public static byte[] getFileSha256Bytes(String filePath) throws IOException, NoS return fileSha256Digest.digest(); } + public static Cipher getAesCipher() + throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException { + return AesCipherProvider.equals("") + ? Cipher.getInstance(AES_ALGORITHM) + : Cipher.getInstance(AES_ALGORITHM, AesCipherProvider); + } + public SHA256Info computeSHA256HashAES( InputStream plainTextStream, byte[] object_CryptoIvBytes, @@ -235,7 +253,7 @@ public SHA256Info computeSHA256HashAES( try { SecretKeySpec keySpec = new SecretKeySpec(object_CryptoKeyBytes, "AES"); IvParameterSpec ivSpec = new IvParameterSpec(object_CryptoIvBytes); - Cipher cipher = Cipher.getInstance(AES_ALGORITHM); + Cipher cipher = getAesCipher(); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); bis = new BufferedInputStream(plainTextStream); MessageDigest plainTextSha256 = MessageDigest.getInstance("SHA-256"); diff --git a/app/src/main/java/com/obs/services/crypto/CryptoObsClient.java b/app/src/main/java/com/obs/services/crypto/CryptoObsClient.java index 394e036..b2afe24 100644 --- a/app/src/main/java/com/obs/services/crypto/CryptoObsClient.java +++ b/app/src/main/java/com/obs/services/crypto/CryptoObsClient.java @@ -58,6 +58,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.Objects; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -257,7 +258,8 @@ protected ObsFSFile putObjectImpl(PutObjectRequest request) throws ServiceExcept | NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException - | BadPaddingException e) { + | BadPaddingException + | NoSuchProviderException e) { throw new ServiceException(e); } finally { if (result != null && result.getBody() != null && request.isAutoClose()) { @@ -373,7 +375,8 @@ protected ObsObject getObjectImpl(GetObjectRequest request) throws ServiceExcept | UnsupportedEncodingException | NoSuchAlgorithmException | BadPaddingException - | InvalidKeyException e) { + | InvalidKeyException + | NoSuchProviderException e) { throw new ServiceException(e); } } @@ -389,7 +392,8 @@ protected ObsObject getObjectImpl(GetObjectRequest request) throws ServiceExcept | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException - | InvalidKeyException e) { + | InvalidKeyException + | NoSuchProviderException e) { throw new ServiceException(e); } } else { diff --git a/app/src/main/java/com/obs/services/crypto/CtrRSACipherGenerator.java b/app/src/main/java/com/obs/services/crypto/CtrRSACipherGenerator.java index be6c6b5..184df70 100644 --- a/app/src/main/java/com/obs/services/crypto/CtrRSACipherGenerator.java +++ b/app/src/main/java/com/obs/services/crypto/CtrRSACipherGenerator.java @@ -13,15 +13,21 @@ */ package com.obs.services.crypto; +import com.obs.services.exception.ObsException; + import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.security.InvalidKeyException; +import java.security.Key; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -33,10 +39,14 @@ public class CtrRSACipherGenerator extends CTRCipherGenerator { public static final String ENCRYPTED_AES_KEY_META_NAME = "encrypted-object-key"; - public static final String ENCRYPTED_ALGORITHM = "AES256-Ctr/RSA-Object-Key/NoPadding"; + protected static final String CIPHER_RSA_ALGORITHM = "RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING"; + protected static final String KEY_FACTORY_RSA_ALGORITHM = "RSA"; + private static String RsaCipherProvider = ""; + public static final String ENCRYPTED_ALGORITHM = + CTRCipherGenerator.ENCRYPTED_ALGORITHM + " " + CIPHER_RSA_ALGORITHM; + public static final int MIN_RSA_KEY_LENGTH = 3072; private PrivateKey privateKey; private PublicKey publicKey; - protected static final String RSA_ALGORITHM = "RSA"; public CtrRSACipherGenerator( String masterKeyInfo, @@ -44,12 +54,43 @@ public CtrRSACipherGenerator( SecureRandom secureRandom, PrivateKey privateKey, PublicKey publicKey) - throws NoSuchAlgorithmException, InvalidKeySpecException { + throws NoSuchAlgorithmException, InvalidKeySpecException, ObsException { super(masterKeyInfo, null, null, needSha256, secureRandom); + checkKeyLength(privateKey); + checkKeyLength(publicKey); this.privateKey = privateKey; this.publicKey = publicKey; } + public static void checkKeyLength(Key key) throws ObsException { + if (key instanceof RSAPrivateKey) { + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) key; + int rsaPrivateKeyBitLength = rsaPrivateKey.getModulus().bitLength(); + if (rsaPrivateKeyBitLength < MIN_RSA_KEY_LENGTH) { + String errorMsg = + "Your RSAPrivateKey bitLength is " + + rsaPrivateKeyBitLength + + ", for data safety, please use RSAKeyPair with at least " + + MIN_RSA_KEY_LENGTH + + " bitLength"; + throw new ObsException(errorMsg); + } + } + if (key instanceof RSAPublicKey) { + RSAPublicKey rsaPublicKey = (RSAPublicKey) key; + int rsaPublicKeyBitLength = rsaPublicKey.getModulus().bitLength(); + if (rsaPublicKeyBitLength < MIN_RSA_KEY_LENGTH) { + String errorMsg = + "Your RSAPublicKey bitLength is " + + rsaPublicKeyBitLength + + ", for data safety, please use RSAKeyPair with at least " + + MIN_RSA_KEY_LENGTH + + " bitLength"; + throw new ObsException(errorMsg); + } + } + } + public static PrivateKey importPKCS8PrivateKey(String filePath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { StringBuilder sb = new StringBuilder(); @@ -70,7 +111,7 @@ public static PrivateKey importPKCS8PrivateKey(String filePath) byte[] keyBytes = Base64.getDecoder().decode(sb.toString()); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance(RSA_ALGORITHM); + KeyFactory kf = KeyFactory.getInstance(KEY_FACTORY_RSA_ALGORITHM); return kf.generatePrivate(spec); } @@ -94,14 +135,14 @@ public static PublicKey importPublicKey(String filename) byte[] keyBytes = Base64.getDecoder().decode(sb.toString()); X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance(RSA_ALGORITHM); + KeyFactory kf = KeyFactory.getInstance(KEY_FACTORY_RSA_ALGORITHM); return kf.generatePublic(spec); } public byte[] RSAEncrypted(byte[] plaintext) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, - BadPaddingException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + BadPaddingException, NoSuchProviderException { + Cipher cipher = getRsaCipher(); // 加密 cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(plaintext); @@ -109,13 +150,21 @@ public byte[] RSAEncrypted(byte[] plaintext) public byte[] RSADecrypted(byte[] cipherInfo) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, - BadPaddingException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + BadPaddingException, NoSuchProviderException { + Cipher cipher = getRsaCipher(); // 解密 cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(cipherInfo); } + public static Cipher getRsaCipher() + throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException + { + return RsaCipherProvider.equals("") + ? Cipher.getInstance(CIPHER_RSA_ALGORITHM) + : Cipher.getInstance(CIPHER_RSA_ALGORITHM, RsaCipherProvider); + } + public void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } @@ -123,4 +172,12 @@ public void setPrivateKey(PrivateKey privateKey) { public void setPublicKey(PublicKey publicKey) { this.publicKey = publicKey; } + + public static String getRsaCipherProvider() { + return RsaCipherProvider; + } + + public static void setRsaCipherProvider(String rsaCipherProvider) { + RsaCipherProvider = rsaCipherProvider; + } } diff --git a/app/src/main/java/com/obs/services/internal/Constants.java b/app/src/main/java/com/obs/services/internal/Constants.java index 5295eb1..048009b 100644 --- a/app/src/main/java/com/obs/services/internal/Constants.java +++ b/app/src/main/java/com/obs/services/internal/Constants.java @@ -213,7 +213,7 @@ public static class ObsRequestParams { public static final TimeZone GMT_TIMEZONE = TimeZone.getTimeZone("GMT"); - public static final String OBS_SDK_VERSION = "3.23.9.1"; + public static final String OBS_SDK_VERSION = "3.24.3"; public static final String USER_AGENT_VALUE = "obs-sdk-java/" + Constants.OBS_SDK_VERSION; diff --git a/app/src/main/java/com/obs/services/internal/RestConnectionService.java b/app/src/main/java/com/obs/services/internal/RestConnectionService.java index 384c506..ee6f3e4 100644 --- a/app/src/main/java/com/obs/services/internal/RestConnectionService.java +++ b/app/src/main/java/com/obs/services/internal/RestConnectionService.java @@ -21,6 +21,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; @@ -56,10 +57,10 @@ public class RestConnectionService { protected volatile ProviderCredentials credentials; - protected void initHttpClient(Dispatcher httpDispatcher, Dns customizedDnsImpl) { + protected void initHttpClient(Dispatcher httpDispatcher, Dns customizedDnsImpl, HostnameVerifier hostnameVerifier) { OkHttpClient.Builder builder = RestUtils.initHttpClientBuilder(obsProperties, keyManagerFactory, - trustManagerFactory, httpDispatcher, customizedDnsImpl, credentials.getSecureRandom()); + trustManagerFactory, httpDispatcher, customizedDnsImpl, hostnameVerifier, credentials.getSecureRandom()); if (this.obsProperties.getBoolProperty(ObsConstraint.PROXY_ISABLE, true)) { String proxyHostAddress = this.obsProperties.getStringProperty(ObsConstraint.PROXY_HOST, null); diff --git a/app/src/main/java/com/obs/services/internal/RestStorageService.java b/app/src/main/java/com/obs/services/internal/RestStorageService.java index b4165c6..e313bda 100644 --- a/app/src/main/java/com/obs/services/internal/RestStorageService.java +++ b/app/src/main/java/com/obs/services/internal/RestStorageService.java @@ -38,12 +38,10 @@ import okhttp3.Request; import okhttp3.Response; -import javax.net.ssl.SSLException; import java.io.IOException; import java.io.InterruptedIOException; import java.net.ConnectException; import java.net.URI; -import java.net.UnknownHostException; import java.text.ParseException; import java.util.Date; import java.util.HashMap; @@ -61,7 +59,7 @@ public abstract class RestStorageService extends RestConnectionService { private static final ILogger log = LoggerBuilder.getLogger(RestStorageService.class); - private static final Set> NON_RETRIABLE_CLASSES = + private static final Set> NON_RETRIEVABLE_CLASSES = new HashSet<>(); private static final String REQUEST_TIMEOUT_CODE = "RequestTimeout"; @@ -70,9 +68,16 @@ public abstract class RestStorageService extends RestConnectionService { // Connection{...} private static final String UNEXPECTED_END_OF_STREAM_EXCEPTION = "unexpected end of stream"; - static { - NON_RETRIABLE_CLASSES.add(UnknownHostException.class); - NON_RETRIABLE_CLASSES.add(SSLException.class); + public static Set> getNonRetrievableClasses(){ + return NON_RETRIEVABLE_CLASSES; + } + + public static void addNonRetrievableClass(Class nonRetrievableClass){ + NON_RETRIEVABLE_CLASSES.add(nonRetrievableClass); + } + + public static void removeNonRetrievableClass(Class nonRetrievableClass){ + NON_RETRIEVABLE_CLASSES.remove(nonRetrievableClass); } private static ThreadLocal> userHeaders = new ThreadLocal<>(); @@ -165,10 +170,10 @@ protected boolean retryRequest(IOException exception, RetryCounter retryCounter, if (retryCounter.getErrorCount() > retryCounter.getRetryMaxCount()) { return false; } - if (NON_RETRIABLE_CLASSES.contains(exception.getClass())) { + if (NON_RETRIEVABLE_CLASSES.contains(exception.getClass())) { return false; } else { - for (final Class rejectException : NON_RETRIABLE_CLASSES) { + for (final Class rejectException : NON_RETRIEVABLE_CLASSES) { if (rejectException.isInstance(exception)) { return false; } @@ -449,9 +454,10 @@ private void tryRequest(Map requestParameters, String bucketName ExtObsConstraint.DEFAULT_MAX_RETRY_ON_UNEXPECTED_END_EXCEPTION)), false); + StringBuilder stringToSignToReturn = new StringBuilder(""); do { if (!retryController.isWasRecentlyRedirected()) { - requestInfo.setRequest(addBaseHeaders(requestInfo.getRequest(), bucketName, doSignature)); + requestInfo.setRequest(addBaseHeaders(requestInfo.getRequest(), bucketName, doSignature, stringToSignToReturn)); } else { retryController.setWasRecentlyRedirected(false); } @@ -487,9 +493,9 @@ private void tryRequest(Map requestParameters, String bucketName if (responseCode >= 300 && responseCode < 400 && responseCode != 304) { requestInfo.setRequest(handleRedirectResponse(requestInfo.getRequest(), requestParameters, bucketName, doSignature, isOEF, - requestInfo.getReqBean(), requestInfo.getResponse(), retryController)); + requestInfo.getReqBean(), requestInfo.getResponse(), retryController, stringToSignToReturn)); } else if ((responseCode >= 400 && responseCode < 500) || responseCode == 304) { - handleRequestErrorResponse(requestInfo.getResponse(), retryController); + handleRequestErrorResponse(requestInfo.getResponse(), retryController, stringToSignToReturn); } else if (responseCode >= 500) { handleServerErrorResponse(requestInfo.getReqBean(), requestInfo.getResponse(), retryController, responseCode); @@ -501,8 +507,9 @@ private void tryRequest(Map requestParameters, String bucketName } while (true); } - private void handleRequestErrorResponse(Response response, RetryController retryController) { - ServiceException exception = createServiceException("Request Error.", response); + private void handleRequestErrorResponse(Response response, RetryController retryController, + StringBuilder stringToSignToReturn) { + ServiceException exception = createServiceException("Request Error.", response, stringToSignToReturn); if (!REQUEST_TIMEOUT_CODE.equals(exception.getErrorCode())) { throw exception; @@ -544,7 +551,8 @@ private void handleServerErrorResponse(InterfaceLogBean reqBean, Response respon private Request handleRedirectResponse(Request request, Map requestParameters, String bucketName, boolean doSignature, boolean isOEF, InterfaceLogBean reqBean, - Response response, RetryController retryController) { + Response response, RetryController retryController, + StringBuilder stringToSignToReturn) { int responseCode = response.code(); String location = response.header(CommonHeaders.LOCATION); if (!ServiceUtils.isValid(location)) { @@ -555,7 +563,7 @@ private Request handleRedirectResponse(Request request, Map requ } request = createRedirectRequest(request, requestParameters, bucketName, doSignature, isOEF, - responseCode, location); + responseCode, location, stringToSignToReturn); retryController.setWasRecentlyRedirected(true); @@ -635,14 +643,42 @@ private void retryOnIOException(IOException e, private void doRetry(Response response, String message, RetryCounter retryCounter) { retryCounter.addErrorCount(); if (retryCounter.getErrorCount() > retryCounter.getRetryMaxCount()) { - throw createServiceException(message, response); + throw createServiceException(message, response, null); } ServiceUtils.closeStream(response); } - private ServiceException createServiceException(String message, Response response) { + private ServiceException createServiceException(String message, Response response, + StringBuilder stringToSignToReturn) { String xmlMessage = readResponseMessage(response); - return new ServiceException(message, xmlMessage); + if(stringToSignToReturn != null){ + String errorMessageForSignatureDoesNotMatch = + createErrorMessageForSignatureDoesNotMatch(xmlMessage, message, stringToSignToReturn); + ServiceException serviceException = new ServiceException(errorMessageForSignatureDoesNotMatch, xmlMessage); + serviceException.setErrorMessage(serviceException.getErrorMessage()+"\n"+errorMessageForSignatureDoesNotMatch); + return serviceException; + } else { + return new ServiceException(message, xmlMessage); + } + } + + private String createErrorMessageForSignatureDoesNotMatch(String xmlMessage, String message, StringBuilder stringToSignToReturn){ + if (!xmlMessage.contains("SignatureDoesNotMatch")) { + return message; + } + int startStringToSign = xmlMessage.lastIndexOf("") + "".length(); + if(startStringToSign < 0){ + return message; + } + int endStringToSign = xmlMessage.lastIndexOf(""); + + StringBuilder ErrorStringToSignMessage = new StringBuilder(); + ErrorStringToSignMessage.append("your local StringToSign is (between\"---\"):\n---\n"); + ErrorStringToSignMessage.append(stringToSignToReturn); + ErrorStringToSignMessage.append("\n---\nPlease compare it to Server's StringToSign (between\"---\"):\n---\n"); + ErrorStringToSignMessage.append(xmlMessage, startStringToSign, endStringToSign); + ErrorStringToSignMessage.append("\n---\n"); + return ErrorStringToSignMessage.toString(); } private String readResponseMessage(Response response) { @@ -658,13 +694,14 @@ private String readResponseMessage(Response response) { } private Request createRedirectRequest(Request request, Map requestParameters, String bucketName, - boolean doSignature, boolean isOEF, int responseCode, String location) { + boolean doSignature, boolean isOEF, int responseCode, String location, + StringBuilder stringToSignToReturn) { if (!location.contains("?")) { location = addRequestParametersToUrlPath(location, requestParameters, isOEF); } if (doSignature && isLocationHostOnly(location)) { - request = authorizeHttpRequest(request, bucketName, location); + request = authorizeHttpRequest(request, bucketName, location, stringToSignToReturn); } else { Request.Builder builder = request.newBuilder(); @@ -703,13 +740,13 @@ private void transOEFResponse(Response response, InterfaceLogBean reqBean, } throw createServiceException("Encountered too many 5xx errors (" + internalErrorCount + "), aborting request.", - response); + response, null); } } - private Request addBaseHeaders(Request request, String bucketName, boolean doSignature) { + private Request addBaseHeaders(Request request, String bucketName, boolean doSignature, StringBuilder stringToSignToReturn) { if (doSignature) { - request = authorizeHttpRequest(request, bucketName, null); + request = authorizeHttpRequest(request, bucketName, null, stringToSignToReturn); } else { Request.Builder builder = request.newBuilder(); builder.headers(request.headers().newBuilder().removeAll(CommonHeaders.AUTHORIZATION).build()); @@ -795,7 +832,7 @@ private Date parseDate(String bucketName, Request request, boolean isV4) { } } - protected Request authorizeHttpRequest(Request request, String bucketName, String url) throws ServiceException { + protected Request authorizeHttpRequest(Request request, String bucketName, String url, StringBuilder stringToSignToReturn) throws ServiceException { Headers headers = request.headers().newBuilder().removeAll(CommonHeaders.AUTHORIZATION).build(); Request.Builder builder = request.newBuilder(); @@ -867,6 +904,10 @@ protected Request authorizeHttpRequest(Request request, String bucketName, Strin .makeAuthorizationString(request.method(), convertHeadersToMap(builder.build().headers()), fullUrl, Constants.ALLOWED_RESOURCE_PARAMTER_NAMES, securityKey); } + if (stringToSignToReturn != null){ + stringToSignToReturn.setLength(0); + stringToSignToReturn.append(iauthentication.getStringToSign()); + } log.debug("StringToSign ('|' is a newline): " + iauthentication.getStringToSign().replace('\n', '|')); @@ -1016,10 +1057,8 @@ protected Response performRestForApiVersion(String bucketName, String objectKey, private void sleepBeforeRetry(int internalErrorCount) { long delayMs = 50L * (int) Math.pow(2, internalErrorCount); - if (log.isWarnEnabled()) { - log.warn("Encountered " + internalErrorCount + " Internal Server error(s), will retry in " + delayMs - + "ms"); - } + log.warn("Encountered " + internalErrorCount + " Internal Server error(s), will retry in " + delayMs + + "ms"); try { Thread.sleep(delayMs); } catch (InterruptedException e) { diff --git a/app/src/main/java/com/obs/services/internal/service/ObsBucketBaseService.java b/app/src/main/java/com/obs/services/internal/service/ObsBucketBaseService.java index 82232e1..84b52b0 100644 --- a/app/src/main/java/com/obs/services/internal/service/ObsBucketBaseService.java +++ b/app/src/main/java/com/obs/services/internal/service/ObsBucketBaseService.java @@ -43,6 +43,7 @@ import com.obs.services.model.BucketVersioningConfiguration; import com.obs.services.model.CreateBucketRequest; import com.obs.services.model.HeaderResponse; +import com.obs.services.model.HttpMethodEnum; import com.obs.services.model.ListBucketsRequest; import com.obs.services.model.ListBucketsResult; import com.obs.services.model.ListObjectsRequest; @@ -66,6 +67,7 @@ import com.obs.services.model.inventory.GetInventoryConfigurationResult; import com.obs.services.model.inventory.ListInventoryConfigurationResult; import okhttp3.Response; +import okhttp3.internal.http.HttpMethod; public abstract class ObsBucketBaseService extends RequestConvertor { @@ -206,6 +208,7 @@ protected HeaderResponse setBucketFSStatusImpl(SetBucketFSStatusRequest request) Map headers = transRequestPaymentHeaders(request, null, this.getIHeaders(request.getBucketName())); + headers = headers == null ? new HashMap<>() : headers; String xml = this.getIConvertor(request.getBucketName()).transBucketFileInterface(request.getStatus()); headers.put(CommonHeaders.CONTENT_LENGTH, String.valueOf(xml.length())); @@ -214,6 +217,7 @@ protected HeaderResponse setBucketFSStatusImpl(SetBucketFSStatusRequest request) NewTransResult result = transRequest(request); result.setParams(requestParams); result.setHeaders(headers); + result.setHttpMethod(HttpMethodEnum.PUT); result.setBody(createRequestBody(Mimetypes.MIMETYPE_XML, xml)); Response response = performRequest(result); diff --git a/app/src/main/java/com/obs/services/internal/service/RequestConvertor.java b/app/src/main/java/com/obs/services/internal/service/RequestConvertor.java index 382593a..5ff42fa 100644 --- a/app/src/main/java/com/obs/services/internal/service/RequestConvertor.java +++ b/app/src/main/java/com/obs/services/internal/service/RequestConvertor.java @@ -515,6 +515,13 @@ protected TransResult transCopyObjectRequest(CopyObjectRequest request) throws S } headers.put(key, entry.getValue() == null ? "" : entry.getValue().toString()); } + + Object contentType = objectMetadata.getContentType() == null + ? objectMetadata.getValue(CommonHeaders.CONTENT_TYPE) : objectMetadata.getContentType(); + if (contentType == null) { + contentType = Mimetypes.getInstance().getMimetype(request.getObjectKey()); + } + headers.put(CommonHeaders.CONTENT_TYPE, contentType.toString().trim()); } setBaseHeaderFromMetadata(request.getBucketName(), headers, objectMetadata); diff --git a/app/src/main/java/com/obs/services/internal/utils/AccessLoggerUtils.java b/app/src/main/java/com/obs/services/internal/utils/AccessLoggerUtils.java index 7b99e1c..5f6d140 100644 --- a/app/src/main/java/com/obs/services/internal/utils/AccessLoggerUtils.java +++ b/app/src/main/java/com/obs/services/internal/utils/AccessLoggerUtils.java @@ -72,7 +72,10 @@ public static void appendLog(Object log, String level) { } if (isLog) { StringBuilder sb = new StringBuilder(getFormat().format(new Date())); - sb.append("|").append(AccessLoggerUtils.getLogPrefix()).append(log.toString()).append("\n"); + sb.append("|").append(Thread.currentThread().getName()) + .append("|").append(level) + .append("|").append(AccessLoggerUtils.getLogPrefix()) + .append(log.toString()).append("\n"); getLog().append(sb.toString()); } } diff --git a/app/src/main/java/com/obs/services/internal/utils/RestUtils.java b/app/src/main/java/com/obs/services/internal/utils/RestUtils.java index 8c477fc..642b90a 100644 --- a/app/src/main/java/com/obs/services/internal/utils/RestUtils.java +++ b/app/src/main/java/com/obs/services/internal/utils/RestUtils.java @@ -37,6 +37,7 @@ import org.jetbrains.annotations.NotNull; import javax.net.SocketFactory; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; @@ -161,15 +162,8 @@ public static String encodeUrlString(String path) throws ServiceException { } public static String encodeUrlPath(String path, String delimiter) throws ServiceException { - StringBuilder result = new StringBuilder(); - String[] tokens = path.split(delimiter); - for (int i = 0; i < tokens.length; i++) { - result.append(encodeUrlString(tokens[i])); - if (i < tokens.length - 1) { - result.append(delimiter); - } - } - return result.toString(); + String allEncoded = encodeUrlString(path); + return allEncoded.replaceAll(encodeUrlString(delimiter),delimiter); } private static SSLContext createSSLContext(KeyManager[] km, TrustManager[] tm, String provider, @@ -215,18 +209,23 @@ private static SSLContext createSSLContext(KeyManager[] km, TrustManager[] tm, private static class WrapperedSocketFactory extends SocketFactory { private SocketFactory delegate; - private int socketReadWriteBufferSize; + private int socketReadBufferSize; + private int socketWriteBufferSize; - WrapperedSocketFactory(SocketFactory delegate, int socketReadWriteBufferSize) { + WrapperedSocketFactory(SocketFactory delegate, + int socketReadBufferSize, int socketWriteBufferSize) { this.delegate = delegate; - this.socketReadWriteBufferSize = socketReadWriteBufferSize; + this.socketReadBufferSize = socketReadBufferSize; + this.socketWriteBufferSize = socketWriteBufferSize; } private Socket doWrap(Socket s) throws SocketException { if (s != null) { - if (socketReadWriteBufferSize > 0) { - s.setReceiveBufferSize(socketReadWriteBufferSize); - s.setReceiveBufferSize(socketReadWriteBufferSize); + if (socketReadBufferSize > 0) { + s.setReceiveBufferSize(socketReadBufferSize); + } + if (socketWriteBufferSize > 0) { + s.setSendBufferSize(socketWriteBufferSize); } s.setTcpNoDelay(true); } @@ -265,18 +264,23 @@ public Socket createSocket(InetAddress address, int port, InetAddress localAddre private static class WrapperedSSLSocketFactory extends SSLSocketFactory { private SSLSocketFactory delegate; - private int socketReadWriteBufferSize; + private int socketReadBufferSize; + private int socketWriteBufferSize; - WrapperedSSLSocketFactory(SSLSocketFactory delegate, int socketReadWriteBufferSize) { + WrapperedSSLSocketFactory(SSLSocketFactory delegate, + int socketReadBufferSize, int socketWriteBufferSize) { this.delegate = delegate; - this.socketReadWriteBufferSize = socketReadWriteBufferSize; + this.socketReadBufferSize = socketReadBufferSize; + this.socketWriteBufferSize = socketWriteBufferSize; } private Socket doWrap(Socket s) throws SocketException { if (s != null) { - if (socketReadWriteBufferSize > 0) { - s.setReceiveBufferSize(socketReadWriteBufferSize); - s.setReceiveBufferSize(socketReadWriteBufferSize); + if (socketReadBufferSize > 0) { + s.setReceiveBufferSize(socketReadBufferSize); + } + if (socketWriteBufferSize > 0) { + s.setSendBufferSize(socketWriteBufferSize); } s.setTcpNoDelay(true); } @@ -329,7 +333,7 @@ public Socket createSocket(InetAddress address, int port, InetAddress localAddre public static OkHttpClient.Builder initHttpClientBuilder(ObsProperties obsProperties, KeyManagerFactory keyManagerFactory, TrustManagerFactory trustManagerFactory, - Dispatcher httpDispatcher, Dns customizedDnsImpl, SecureRandom secureRandom) { + Dispatcher httpDispatcher, Dns customizedDnsImpl, HostnameVerifier userHostnameVerifier, SecureRandom secureRandom) { List protocols = new ArrayList(2); protocols.add(Protocol.HTTP_1_1); @@ -351,6 +355,20 @@ public static OkHttpClient.Builder initHttpClientBuilder(ObsProperties obsProper TimeUnit.MILLISECONDS); Dns dns = customizedDnsImpl == null ? new DefaultObsDns() : customizedDnsImpl; + HostnameVerifier hostnameVerifier = (s, sslSession) -> { + if(obsProperties.getBoolProperty( + ObsConstraint.HTTP_STRICT_HOSTNAME_VERIFICATION, false)) { + if(userHostnameVerifier == null) { + return HttpsURLConnection.getDefaultHostnameVerifier().verify + (obsProperties.getStringProperty(ObsConstraint.END_POINT, ""), sslSession); + } else { + return userHostnameVerifier.verify(s, sslSession); + } + } else { + // no hostnameVerify + return true; + } + }; builder.protocols(protocols).followRedirects(false).followSslRedirects(false) .retryOnConnectionFailure( @@ -363,16 +381,13 @@ public static OkHttpClient.Builder initHttpClientBuilder(ObsProperties obsProper .readTimeout(obsProperties.getIntProperty(ObsConstraint.HTTP_SOCKET_TIMEOUT, ObsConstraint.HTTP_SOCKET_TIMEOUT_VALUE), TimeUnit.MILLISECONDS) .connectionPool(pool) - .hostnameVerifier((hostname, session) -> !obsProperties.getBoolProperty(ObsConstraint.HTTP_STRICT_HOSTNAME_VERIFICATION, false) - || HttpsURLConnection.getDefaultHostnameVerifier().verify(obsProperties.getStringProperty(ObsConstraint.END_POINT, ""), session)) + .hostnameVerifier(hostnameVerifier) .dns(dns); int socketReadBufferSize = obsProperties.getIntProperty(ObsConstraint.SOCKET_READ_BUFFER_SIZE, -1); int socketWriteBufferSize = obsProperties.getIntProperty(ObsConstraint.SOCKET_WRITE_BUFFER_SIZE, -1); - int socketReadWriteBufferSize = Math.max(socketReadBufferSize, socketWriteBufferSize); - - builder.socketFactory(new WrapperedSocketFactory(SocketFactory.getDefault(), socketReadWriteBufferSize)); + builder.socketFactory(new WrapperedSocketFactory(SocketFactory.getDefault(), socketReadBufferSize, socketWriteBufferSize)); try { KeyManager[] km = null; @@ -406,7 +421,7 @@ public static OkHttpClient.Builder initHttpClientBuilder(ObsProperties obsProper sslContext = createSSLContext(km, tm, secureRandom); } SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); - builder.sslSocketFactory(new WrapperedSSLSocketFactory(sslSocketFactory, socketReadWriteBufferSize), + builder.sslSocketFactory(new WrapperedSSLSocketFactory(sslSocketFactory, socketReadBufferSize, socketWriteBufferSize), trustManager); } catch (Exception e) { if (log.isErrorEnabled()) { diff --git a/app/src/main/java/com/obs/services/internal/utils/ServiceUtils.java b/app/src/main/java/com/obs/services/internal/utils/ServiceUtils.java index 9d94289..7edfed1 100644 --- a/app/src/main/java/com/obs/services/internal/utils/ServiceUtils.java +++ b/app/src/main/java/com/obs/services/internal/utils/ServiceUtils.java @@ -47,6 +47,9 @@ import java.security.NoSuchAlgorithmException; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -71,6 +74,7 @@ public class ServiceUtils { private static Pattern pattern = Pattern .compile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$"); + private static DateTimeFormatter rfc822DateTimeFormatter = DateTimeFormatter.ofPattern(RFC_822_TIME_PARSER_STRING, Locale.US).withZone(ZoneId.of("GMT")); public static boolean isValid(String s) { return s != null && !s.equals(""); @@ -147,17 +151,26 @@ public static String formatIso8601MidnightDate(Date date) { iso8601TimeParser.setTimeZone(Constants.GMT_TIMEZONE); return iso8601TimeParser.format(date); } - public static Date parseRfc822Date(String dateString) throws ParseException { - SimpleDateFormat rfc822TimeParser = new SimpleDateFormat(RFC_822_TIME_PARSER_STRING, Locale.US); - rfc822TimeParser.setTimeZone(Constants.GMT_TIMEZONE); - return rfc822TimeParser.parse(dateString); + try { + return Date.from(ZonedDateTime.parse(dateString, rfc822DateTimeFormatter).toInstant()); + } catch (Exception e) { + log.warn("parseRfc822Date with DateTimeFormatter failed, using SimpleDateFormat instead, error detail :", e); + SimpleDateFormat rfc822TimeParser = new SimpleDateFormat(RFC_822_TIME_PARSER_STRING, Locale.US); + rfc822TimeParser.setTimeZone(Constants.GMT_TIMEZONE); + return rfc822TimeParser.parse(dateString); + } } public static String formatRfc822Date(Date date) { - SimpleDateFormat rfc822TimeParser = new SimpleDateFormat(RFC_822_TIME_PARSER_STRING, Locale.US); - rfc822TimeParser.setTimeZone(Constants.GMT_TIMEZONE); - return rfc822TimeParser.format(date); + try { + return rfc822DateTimeFormatter.format(date.toInstant()); + } catch (Exception e) { + log.warn("formatRfc822Date with DateTimeFormatter failed, using SimpleDateFormat instead, error detail :", e); + SimpleDateFormat rfc822TimeParser = new SimpleDateFormat(RFC_822_TIME_PARSER_STRING, Locale.US); + rfc822TimeParser.setTimeZone(Constants.GMT_TIMEZONE); + return rfc822TimeParser.format(date); + } } public static String signWithHmacSha1(String sk, String canonicalString) throws ServiceException { diff --git a/app/src/main/java/com/obs/services/internal/xml/OBSXMLBuilder.java b/app/src/main/java/com/obs/services/internal/xml/OBSXMLBuilder.java index 44c4b97..33bb6e7 100644 --- a/app/src/main/java/com/obs/services/internal/xml/OBSXMLBuilder.java +++ b/app/src/main/java/com/obs/services/internal/xml/OBSXMLBuilder.java @@ -13,6 +13,8 @@ */ package com.obs.services.internal.xml; +import com.obs.log.ILogger; +import com.obs.log.LoggerBuilder; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -41,6 +43,11 @@ public class OBSXMLBuilder { private static String xmlDocumentBuilderFactoryClass = "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"; + private static String xmlTransformerFactoryClass = + ""; + + private static final ILogger log = LoggerBuilder.getLogger(OBSXMLBuilder.class); + private Document xmlDocument; private Node xmlNode; @@ -49,6 +56,11 @@ public static void setXmlDocumentBuilderFactoryClass(String className) { xmlDocumentBuilderFactoryClass = className; } } + public static void setXmlTransformerFactoryClass(String className) { + if (null != className && !className.trim().equals("")) { + xmlTransformerFactoryClass = className; + } + } protected OBSXMLBuilder(Document xmlDocument) { this.xmlDocument = xmlDocument; @@ -76,14 +88,27 @@ private static DocumentBuilderFactory findDocumentBuilderFactory() { return newInstance(DocumentBuilderFactory.class, xmlDocumentBuilderFactoryClass, null, true, false); } + private static TransformerFactory findTransformerFactory() { + if (xmlTransformerFactoryClass == null || xmlTransformerFactoryClass.equals("")) { + return TransformerFactory.newInstance(); + } else { + return TransformerFactory.newInstance(xmlTransformerFactoryClass, null); + } + + } + protected static Document createDocumentImpl( String name, String namespaceURI, boolean isNamespaceAware) throws ParserConfigurationException, FactoryConfigurationError { DocumentBuilderFactory factory = OBSXMLBuilder.findDocumentBuilderFactory(); - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + try { + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (Throwable e) { + log.debug("setFeature not supported, detail:", e); + } factory.setNamespaceAware(isNamespaceAware); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.newDocument(); @@ -302,9 +327,14 @@ public Document getDocument() { } public String asString() throws TransformerException { - TransformerFactory tf = TransformerFactory.newInstance(); - tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); - tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + + TransformerFactory tf = findTransformerFactory(); + try { + tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + } catch (Throwable e) { + log.debug("setAttribute not supported, detail:", e); + } Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); StringWriter writer = new StringWriter(); diff --git a/app/src/main/java/com/obs/services/model/BucketDirectColdAccess.java b/app/src/main/java/com/obs/services/model/BucketDirectColdAccess.java index 6f27ee8..38f4c6e 100644 --- a/app/src/main/java/com/obs/services/model/BucketDirectColdAccess.java +++ b/app/src/main/java/com/obs/services/model/BucketDirectColdAccess.java @@ -59,7 +59,11 @@ public void setStatus(RuleStatusEnum status) { @Override public String toString() { - return "BucketDirectColdAccess [Status=" + status.getCode() + "]"; + String statusStr = "null"; + if (status != null) { + statusStr = status.getCode(); + } + return "BucketDirectColdAccess [Status=" + statusStr + "]"; } } diff --git a/pom-android.xml b/pom-android.xml index 5edf591..d6a4b6c 100644 --- a/pom-android.xml +++ b/pom-android.xml @@ -4,7 +4,7 @@ com.huaweicloud esdk-obs-android - 3.23.9.1 + 3.24.3 jar OBS SDK for Android @@ -19,28 +19,28 @@ com.squareup.okhttp3 okhttp - 4.11.0 + 4.12.0 com.squareup.okio okio - 3.5.0 + 3.6.0 com.fasterxml.jackson.core jackson-core - 2.13.3 + 2.15.2 com.fasterxml.jackson.core jackson-databind - 2.13.4.1 + 2.15.2 com.fasterxml.jackson.core jackson-annotations - 2.13.3 + 2.15.2 diff --git a/pom-java-optimization.xml b/pom-java-optimization.xml index 0eb819d..fe410d6 100644 --- a/pom-java-optimization.xml +++ b/pom-java-optimization.xml @@ -4,7 +4,7 @@ com.huaweicloud esdk-obs-java-optimised - 3.23.9.1 + 3.24.3 jar OBS SDK for Java Optimised @@ -29,17 +29,17 @@ com.fasterxml.jackson.core jackson-core - 2.13.3 + 2.15.2 com.fasterxml.jackson.core jackson-databind - 2.13.4.1 + 2.15.2 com.fasterxml.jackson.core jackson-annotations - 2.13.2 + 2.15.2 diff --git a/pom-java.xml b/pom-java.xml index 01f63a7..5ae9b6f 100644 --- a/pom-java.xml +++ b/pom-java.xml @@ -4,7 +4,7 @@ com.huaweicloud esdk-obs-java - 3.23.9.1 + 3.24.3 jar OBS SDK for Java @@ -18,28 +18,28 @@ com.squareup.okhttp3 okhttp - 4.11.0 + 4.12.0 com.squareup.okio okio - 3.5.0 + 3.6.0 com.fasterxml.jackson.core jackson-core - 2.13.3 + 2.15.2 com.fasterxml.jackson.core jackson-databind - 2.13.4.1 + 2.15.2 com.fasterxml.jackson.core jackson-annotations - 2.13.3 + 2.15.2 diff --git a/pom.xml b/pom.xml index 8753994..60f9cc5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.huaweicloud esdk-obs-java - 3.23.9.1 + 3.24.3 jar OBS SDK for Java @@ -18,28 +18,28 @@ com.squareup.okhttp3 okhttp - 4.11.0 + 4.12.0 com.squareup.okio okio - 3.5.0 + 3.6.0 com.fasterxml.jackson.core jackson-core - 2.13.3 + 2.15.2 com.fasterxml.jackson.core jackson-databind - 2.13.4.1 + 2.15.2 com.fasterxml.jackson.core jackson-annotations - 2.13.3 + 2.15.2