|
39 | 39 | import java.util.Map; |
40 | 40 | import java.util.Map.Entry; |
41 | 41 | import java.util.Objects; |
| 42 | +import java.util.concurrent.ConcurrentHashMap; |
42 | 43 |
|
43 | 44 | import com.fasterxml.jackson.core.Version; |
44 | 45 | import com.fasterxml.jackson.databind.ObjectMapper; |
|
67 | 68 | import com.qcloud.cos.internal.XmlResponsesSaxParser.CompleteMultipartUploadHandler; |
68 | 69 | import com.qcloud.cos.internal.XmlResponsesSaxParser.CopyObjectResultHandler; |
69 | 70 | import com.qcloud.cos.model.*; |
| 71 | +import com.qcloud.cos.model.IntelligentTiering.BucketIntelligentTieringConfiguration; |
70 | 72 | import com.qcloud.cos.model.bucketcertificate.BucketDomainCertificateRequest; |
71 | 73 | import com.qcloud.cos.model.bucketcertificate.BucketGetDomainCertificate; |
72 | 74 | import com.qcloud.cos.model.bucketcertificate.BucketPutDomainCertificate; |
@@ -164,6 +166,8 @@ public class COSClient implements COS { |
164 | 166 |
|
165 | 167 | private CosHttpClient cosHttpClient; |
166 | 168 |
|
| 169 | + private ConcurrentHashMap<String, Long> preflightBuckets = new ConcurrentHashMap<>(); |
| 170 | + |
167 | 171 | public COSClient(COSCredentials cred, ClientConfig clientConfig) { |
168 | 172 | this(new COSStaticCredentialsProvider(cred), clientConfig); |
169 | 173 | } |
@@ -839,6 +843,17 @@ ObjectMetadata uploadObjectInternal(UploadMode uploadMode, UploadObjectRequest u |
839 | 843 | rejectNull(bucketName, |
840 | 844 | "The bucket name parameter must be specified when uploading an object"); |
841 | 845 | rejectNull(key, "The key parameter must be specified when uploading an object"); |
| 846 | + |
| 847 | + try { |
| 848 | + preflightObj(uploadObjectRequest); |
| 849 | + } catch (CosServiceException cse) { |
| 850 | + log.warn("fail to do the preflight request due to the service exception, will not do the upload obj request", cse); |
| 851 | + throw cse; |
| 852 | + } catch (CosClientException cce) { |
| 853 | + log.warn("fail to do the preflight request due to the client exception, will not do the upload obj request", cce); |
| 854 | + throw cce; |
| 855 | + } |
| 856 | + |
842 | 857 | // If a file is specified for upload, we need to pull some additional |
843 | 858 | // information from it to auto-configure a few options |
844 | 859 | if (file == null) { |
@@ -978,6 +993,22 @@ ObjectMetadata uploadObjectInternal(UploadMode uploadMode, UploadObjectRequest u |
978 | 993 | CosDataSource.Utils.cleanupDataSource(uploadObjectRequest, file, isOrig, input, log); |
979 | 994 | } |
980 | 995 |
|
| 996 | + if (returnedMetadata.isNeedPreflight()) { |
| 997 | + Long currentTime = System.currentTimeMillis(); |
| 998 | + if ((preflightBuckets.get(bucketName) == null) || ((currentTime - preflightBuckets.get(bucketName)) > clientConfig.getPreflightStatusUpdateInterval())) { |
| 999 | + String reqMsg = String.format("will update preflight status, bucket[%s]", bucketName); |
| 1000 | + log.info(reqMsg); |
| 1001 | + preflightBuckets.put(bucketName, currentTime); |
| 1002 | + } |
| 1003 | + } else { |
| 1004 | + Long currentTime = System.currentTimeMillis(); |
| 1005 | + if ((preflightBuckets.get(bucketName) != null) && ((currentTime - preflightBuckets.get(bucketName)) > clientConfig.getPreflightStatusUpdateInterval())) { |
| 1006 | + String reqMsg = String.format("will remove bucket[%s] from preflight lists", bucketName); |
| 1007 | + log.info(reqMsg); |
| 1008 | + preflightBuckets.remove(bucketName); |
| 1009 | + } |
| 1010 | + } |
| 1011 | + |
981 | 1012 | String contentMd5 = metadata.getContentMD5(); |
982 | 1013 | if (md5DigestStream != null) { |
983 | 1014 | contentMd5 = Base64.encodeAsString(md5DigestStream.getMd5Digest()); |
@@ -1542,11 +1573,25 @@ public List<Bucket> listBuckets() throws CosClientException, CosServiceException |
1542 | 1573 | @Override |
1543 | 1574 | public List<Bucket> listBuckets(ListBucketsRequest listBucketsRequest) |
1544 | 1575 | throws CosClientException, CosServiceException { |
| 1576 | + ListBucketsResult result = getService(listBucketsRequest); |
| 1577 | + return result.getBuckets(); |
| 1578 | + } |
| 1579 | + |
| 1580 | + public ListBucketsResult getService(ListBucketsRequest listBucketsRequest) |
| 1581 | + throws CosClientException, CosServiceException { |
1545 | 1582 | rejectNull(listBucketsRequest, |
1546 | 1583 | "The request object parameter listBucketsRequest must be specified."); |
1547 | 1584 | CosHttpRequest<ListBucketsRequest> request = |
1548 | 1585 | createRequest(null, null, listBucketsRequest, HttpMethodName.GET); |
1549 | | - return invoke(request, new Unmarshallers.ListBucketsUnmarshaller()); |
| 1586 | + if (!listBucketsRequest.getMarker().isEmpty()) { |
| 1587 | + request.addParameter("marker", listBucketsRequest.getMarker()); |
| 1588 | + } |
| 1589 | + |
| 1590 | + if (listBucketsRequest.getMaxKeys() != null && listBucketsRequest.getMaxKeys() > 0) { |
| 1591 | + request.addParameter("max-keys", listBucketsRequest.getMaxKeys().toString()); |
| 1592 | + } |
| 1593 | + |
| 1594 | + return invoke(request, new Unmarshallers.GetServiceUnmarshaller()); |
1550 | 1595 | } |
1551 | 1596 |
|
1552 | 1597 | @Override |
@@ -1627,7 +1672,8 @@ public InitiateMultipartUploadResult initiateMultipartUpload( |
1627 | 1672 | // xml payload unmarshaller |
1628 | 1673 | new Unmarshallers.InitiateMultipartUploadResultUnmarshaller(), |
1629 | 1674 | // header handlers |
1630 | | - new ServerSideEncryptionHeaderHandler<InitiateMultipartUploadResult>()); |
| 1675 | + new ServerSideEncryptionHeaderHandler<InitiateMultipartUploadResult>(), |
| 1676 | + new VIDResultHandler<InitiateMultipartUploadResult>()); |
1631 | 1677 | return invoke(request, responseHandler); |
1632 | 1678 | } |
1633 | 1679 |
|
@@ -1740,6 +1786,7 @@ private UploadPartResult doUploadPart(final String bucketName, final String key, |
1740 | 1786 | result.setSSECustomerAlgorithm(metadata.getSSECustomerAlgorithm()); |
1741 | 1787 | result.setSSECustomerKeyMd5(metadata.getSSECustomerKeyMd5()); |
1742 | 1788 | result.setCrc64Ecma(metadata.getCrc64Ecma()); |
| 1789 | + result.setRequestId(metadata.getRequestId()); |
1743 | 1790 |
|
1744 | 1791 | return result; |
1745 | 1792 | } catch (Throwable t) { |
@@ -2226,7 +2273,8 @@ public CopyPartResult copyPart(CopyPartRequest copyPartRequest) |
2226 | 2273 | new Unmarshallers.CopyObjectUnmarshaller(), |
2227 | 2274 | // header handlers |
2228 | 2275 | new ServerSideEncryptionHeaderHandler<CopyObjectResultHandler>(), |
2229 | | - new COSVersionHeaderHandler()); |
| 2276 | + new COSVersionHeaderHandler(), |
| 2277 | + new VIDResultHandler<CopyObjectResultHandler>()); |
2230 | 2278 | copyObjectResultHandler = invoke(request, handler); |
2231 | 2279 | } catch (CosServiceException cse) { |
2232 | 2280 | /* |
@@ -2287,6 +2335,7 @@ public CopyPartResult copyPart(CopyPartRequest copyPartRequest) |
2287 | 2335 | copyPartResult.setSSECustomerAlgorithm(copyObjectResultHandler.getSSECustomerAlgorithm()); |
2288 | 2336 | copyPartResult.setSSECustomerKeyMd5(copyObjectResultHandler.getSSECustomerKeyMd5()); |
2289 | 2337 | copyPartResult.setCrc64Ecma(copyObjectResultHandler.getCrc64Ecma()); |
| 2338 | + copyPartResult.setRequestId(copyObjectResultHandler.getRequestId()); |
2290 | 2339 |
|
2291 | 2340 | return copyPartResult; |
2292 | 2341 | } |
@@ -3874,6 +3923,24 @@ public void setBucketIntelligentTieringConfiguration(SetBucketIntelligentTierCon |
3874 | 3923 | invoke(request, voidCosResponseHandler); |
3875 | 3924 | } |
3876 | 3925 |
|
| 3926 | + public List<BucketIntelligentTieringConfiguration> listBucketIntelligentTieringConfiguration(String bucketName) throws CosServiceException, CosClientException { |
| 3927 | + rejectEmpty(bucketName, |
| 3928 | + "The bucket name parameter must be specified when listing bucket IntelligentTieringConfiguration"); |
| 3929 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, null, new CosServiceRequest(), HttpMethodName.GET); |
| 3930 | + request.addParameter("intelligent-tiering", null); |
| 3931 | + |
| 3932 | + try { |
| 3933 | + return invoke(request, new Unmarshallers.ListBucketTieringConfigurationUnmarshaller()); |
| 3934 | + } catch (CosServiceException cse) { |
| 3935 | + switch (cse.getStatusCode()) { |
| 3936 | + case 404: |
| 3937 | + return null; |
| 3938 | + default: |
| 3939 | + throw cse; |
| 3940 | + } |
| 3941 | + } |
| 3942 | + } |
| 3943 | + |
3877 | 3944 | @Override |
3878 | 3945 | public MediaJobResponse createMediaJobs(MediaJobsRequest req) { |
3879 | 3946 | this.rejectStartWith(req.getCallBack(),"http","The CallBack parameter mush start with http or https"); |
@@ -5367,5 +5434,130 @@ private String buildPrivateM3U8Url(CosHttpRequest<PrivateM3U8Request> request) |
5367 | 5434 | URL url = generatePresignedUrl(request.getBucketName(), request.getResourcePath(), expiredTime, HttpMethodName.GET, new HashMap<String, String>(), params, false, false); |
5368 | 5435 | return url.toString(); |
5369 | 5436 | } |
| 5437 | + |
| 5438 | + public void putBucketEncryptionConfiguration(String bucketName, BucketEncryptionConfiguration bucketEncryptionConfiguration) |
| 5439 | + throws CosClientException, CosServiceException { |
| 5440 | + rejectEmpty(bucketName, |
| 5441 | + "The bucket name parameter must be specified when putting bucket encryption"); |
| 5442 | + |
| 5443 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, null, new CosServiceRequest(), HttpMethodName.PUT); |
| 5444 | + request.addParameter("encryption", null); |
| 5445 | + |
| 5446 | + rejectEmpty(bucketEncryptionConfiguration.getSseAlgorithm(), |
| 5447 | + "The SseAlgorithm parameter must be specified when putting bucket encryption"); |
| 5448 | + |
| 5449 | + byte[] bytes = new BucketConfigurationXmlFactory().convertToXmlByteArray(bucketEncryptionConfiguration); |
| 5450 | + request.setContent(new ByteArrayInputStream(bytes)); |
| 5451 | + request.addHeader(Headers.CONTENT_LENGTH, String.valueOf(bytes.length)); |
| 5452 | + |
| 5453 | + invoke(request, voidCosResponseHandler); |
| 5454 | + } |
| 5455 | + |
| 5456 | + public BucketEncryptionConfiguration getBucketEncryptionConfiguration(String bucketName) throws CosClientException, CosServiceException { |
| 5457 | + rejectEmpty(bucketName, |
| 5458 | + "The bucket name parameter must be specified when getting bucket encryption"); |
| 5459 | + |
| 5460 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, null, new CosServiceRequest(), HttpMethodName.GET); |
| 5461 | + request.addParameter("encryption", null); |
| 5462 | + |
| 5463 | + return invoke(request, new Unmarshallers.BucketEncryptionConfigurationUnmarshaller()); |
| 5464 | + } |
| 5465 | + |
| 5466 | + public void deleteBucketEncryptionConfiguration(String bucketName) throws CosClientException, CosServiceException { |
| 5467 | + rejectEmpty(bucketName, |
| 5468 | + "The bucket name parameter must be specified when deleting bucket encryption"); |
| 5469 | + |
| 5470 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, null, new CosServiceRequest(), HttpMethodName.DELETE); |
| 5471 | + request.addParameter("encryption", null); |
| 5472 | + |
| 5473 | + invoke(request, voidCosResponseHandler); |
| 5474 | + } |
| 5475 | + |
| 5476 | + public BucketObjectLockConfiguration getBucketObjectLockConfiguration(String bucketName) throws CosClientException, CosServiceException { |
| 5477 | + rejectEmpty(bucketName, |
| 5478 | + "The bucket name parameter must be specified when getting bucket object lock configuration"); |
| 5479 | + |
| 5480 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, null, new CosServiceRequest(), HttpMethodName.GET); |
| 5481 | + request.addParameter("object-lock", null); |
| 5482 | + |
| 5483 | + try { |
| 5484 | + return invoke(request, new Unmarshallers.BucketObjectLockConfigurationUnmarshaller()); |
| 5485 | + } catch (CosServiceException cse) { |
| 5486 | + switch (cse.getStatusCode()) { |
| 5487 | + case 404: |
| 5488 | + return null; |
| 5489 | + default: |
| 5490 | + throw cse; |
| 5491 | + } |
| 5492 | + } |
| 5493 | + } |
| 5494 | + |
| 5495 | + public BucketGetMetadataResult getBucketMetadata(String bucketName) throws CosClientException, CosServiceException { |
| 5496 | + rejectEmpty(bucketName, |
| 5497 | + "The bucket name parameter must be specified when getting bucket metadata"); |
| 5498 | + BucketGetMetadataResult result = new BucketGetMetadataResult(); |
| 5499 | + HeadBucketResult headBucketResult = headBucket(new HeadBucketRequest(bucketName)); |
| 5500 | + result.bucketName = bucketName; |
| 5501 | + StringBuilder strBuilder = new StringBuilder(); |
| 5502 | + strBuilder.append(clientConfig.getHttpProtocol().toString()).append("://"); |
| 5503 | + strBuilder.append(clientConfig.getEndpointBuilder() |
| 5504 | + .buildGeneralApiEndpoint(formatBucket(bucketName, null))); |
| 5505 | + result.bucketUrl = strBuilder.toString(); |
| 5506 | + result.isMaz = headBucketResult.isMazBucket(); |
| 5507 | + result.isOFS = headBucketResult.isMergeBucket(); |
| 5508 | + result.location = headBucketResult.getBucketRegion(); |
| 5509 | + |
| 5510 | + try { |
| 5511 | + BucketEncryptionConfiguration encryptionConfiguration = getBucketEncryptionConfiguration(bucketName); |
| 5512 | + result.encryptionConfiguration = encryptionConfiguration; |
| 5513 | + } catch (CosServiceException cse) { |
| 5514 | + if (cse.getStatusCode() != 404) { |
| 5515 | + throw cse; |
| 5516 | + } |
| 5517 | + } |
| 5518 | + |
| 5519 | + result.accessControlList = getBucketAcl(bucketName); |
| 5520 | + result.websiteConfiguration = getBucketWebsiteConfiguration(bucketName); |
| 5521 | + result.loggingConfiguration = getBucketLoggingConfiguration(bucketName); |
| 5522 | + result.crossOriginConfiguration = getBucketCrossOriginConfiguration(bucketName); |
| 5523 | + result.versioningConfiguration = getBucketVersioningConfiguration(bucketName); |
| 5524 | + result.lifecycleConfiguration = getBucketLifecycleConfiguration(bucketName); |
| 5525 | + |
| 5526 | + try { |
| 5527 | + result.replicationConfiguration = getBucketReplicationConfiguration(bucketName); |
| 5528 | + } catch (CosServiceException cse) { |
| 5529 | + if (cse.getStatusCode() != 404) { |
| 5530 | + throw cse; |
| 5531 | + } |
| 5532 | + } |
| 5533 | + |
| 5534 | + result.taggingConfiguration = getBucketTaggingConfiguration(bucketName); |
| 5535 | + result.tieringConfigurations = listBucketIntelligentTieringConfiguration(bucketName); |
| 5536 | + result.bucketObjectLockConfiguration = getBucketObjectLockConfiguration(bucketName); |
| 5537 | + |
| 5538 | + return result; |
| 5539 | + } |
| 5540 | + |
| 5541 | + private void preflightObj(PutObjectRequest putObjectRequest) throws CosClientException, CosServiceException { |
| 5542 | + String bucketName = putObjectRequest.getBucketName(); |
| 5543 | + String key = putObjectRequest.getKey(); |
| 5544 | + rejectEmpty(bucketName, |
| 5545 | + "The bucket name parameter must be specified when doing preflight request"); |
| 5546 | + rejectEmpty(key, |
| 5547 | + "The key parameter must be specified when doing preflight request"); |
| 5548 | + if (clientConfig.isCheckPreflightStatus() && preflightBuckets.containsKey(bucketName)) { |
| 5549 | + String reqMsg = String.format("will do preflight request for put object[%s] to the bucket[%s]", key, bucketName); |
| 5550 | + log.debug(reqMsg); |
| 5551 | + CosServiceRequest serviceRequest = new CosServiceRequest(); |
| 5552 | + CosHttpRequest<CosServiceRequest> request = createRequest(bucketName, key, serviceRequest, HttpMethodName.HEAD); |
| 5553 | + if (putObjectRequest.getFixedEndpointAddr() != null) { |
| 5554 | + request.setEndpoint(putObjectRequest.getFixedEndpointAddr()); |
| 5555 | + } |
| 5556 | + request.addParameter("preflight", null); |
| 5557 | + request.addHeader("x-cos-next-action", "PutObject"); |
| 5558 | + |
| 5559 | + invoke(request, voidCosResponseHandler); |
| 5560 | + } |
| 5561 | + } |
5370 | 5562 | } |
5371 | 5563 |
|
0 commit comments