190 lines
8.0 KiB
C#
190 lines
8.0 KiB
C#
/*
|
|
* MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020, 2021 MinIO, Inc.
|
|
*
|
|
* Licensed 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.
|
|
*/
|
|
|
|
using Minio.DataModel.ObjectLock;
|
|
using Minio.DataModel.Result;
|
|
using Minio.Helper;
|
|
|
|
namespace Minio.DataModel.Args;
|
|
|
|
internal class CopyObjectRequestArgs : ObjectWriteArgs<CopyObjectRequestArgs>
|
|
{
|
|
internal CopyObjectRequestArgs()
|
|
{
|
|
RequestMethod = HttpMethod.Put;
|
|
Headers = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
CopyOperationObjectType = typeof(CopyObjectResult);
|
|
}
|
|
|
|
internal CopySourceObjectArgs SourceObject { get; set; }
|
|
internal ObjectStat SourceObjectInfo { get; set; }
|
|
internal Type CopyOperationObjectType { get; set; }
|
|
internal bool ReplaceTagsDirective { get; set; }
|
|
internal bool ReplaceMetadataDirective { get; set; }
|
|
internal string StorageClass { get; set; }
|
|
internal Dictionary<string, string> QueryMap { get; set; }
|
|
internal CopyConditions CopyCondition { get; set; }
|
|
internal ObjectRetentionMode ObjectLockRetentionMode { get; set; }
|
|
internal DateTime RetentionUntilDate { get; set; }
|
|
internal bool ObjectLockSet { get; set; }
|
|
|
|
internal CopyObjectRequestArgs WithQueryMap(IDictionary<string, string> queryMap)
|
|
{
|
|
QueryMap = new Dictionary<string, string>(queryMap, StringComparer.Ordinal);
|
|
return this;
|
|
}
|
|
|
|
internal CopyObjectRequestArgs WithPartCondition(CopyConditions partCondition)
|
|
{
|
|
CopyCondition = partCondition.Clone();
|
|
Headers ??= new Dictionary<string, string>(StringComparer.Ordinal);
|
|
Headers["x-amz-copy-source-range"] = "bytes=" + partCondition.byteRangeStart + "-" + partCondition.byteRangeEnd;
|
|
|
|
return this;
|
|
}
|
|
|
|
internal CopyObjectRequestArgs WithReplaceMetadataDirective(bool replace)
|
|
{
|
|
ReplaceMetadataDirective = replace;
|
|
return this;
|
|
}
|
|
|
|
internal CopyObjectRequestArgs WithReplaceTagsDirective(bool replace)
|
|
{
|
|
ReplaceTagsDirective = replace;
|
|
return this;
|
|
}
|
|
|
|
public CopyObjectRequestArgs WithCopyObjectSource(CopySourceObjectArgs cs)
|
|
{
|
|
if (cs is null)
|
|
throw new InvalidOperationException("The copy source object needed for copy operation is not initialized.");
|
|
|
|
SourceObject ??= new CopySourceObjectArgs();
|
|
SourceObject.RequestMethod = HttpMethod.Put;
|
|
SourceObject.BucketName = cs.BucketName;
|
|
SourceObject.ObjectName = cs.ObjectName;
|
|
SourceObject.VersionId = cs.VersionId;
|
|
SourceObject.SSE = cs.SSE;
|
|
SourceObject.Headers = new Dictionary<string, string>(cs.Headers, StringComparer.Ordinal);
|
|
SourceObject.MatchETag = cs.MatchETag;
|
|
SourceObject.ModifiedSince = cs.ModifiedSince;
|
|
SourceObject.NotMatchETag = cs.NotMatchETag;
|
|
SourceObject.UnModifiedSince = cs.UnModifiedSince;
|
|
SourceObject.CopySourceObjectPath = $"{cs.BucketName}/{Utils.UrlEncode(cs.ObjectName)}";
|
|
SourceObject.CopyOperationConditions = cs.CopyOperationConditions?.Clone();
|
|
return this;
|
|
}
|
|
|
|
public CopyObjectRequestArgs WithSourceObjectInfo(ObjectStat stat)
|
|
{
|
|
SourceObjectInfo = stat;
|
|
return this;
|
|
}
|
|
|
|
internal override HttpRequestMessageBuilder BuildRequest(HttpRequestMessageBuilder requestMessageBuilder)
|
|
{
|
|
var sourceObjectPath = SourceObject.BucketName + "/" + Utils.UrlEncode(SourceObject.ObjectName);
|
|
if (!string.IsNullOrEmpty(SourceObject.VersionId)) sourceObjectPath += "?versionId=" + SourceObject.VersionId;
|
|
// Set the object source
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-copy-source", sourceObjectPath);
|
|
|
|
if (QueryMap is not null)
|
|
foreach (var query in QueryMap)
|
|
requestMessageBuilder.AddQueryParameter(query.Key, query.Value);
|
|
|
|
if (SourceObject.CopyOperationConditions is not null)
|
|
foreach (var item in SourceObject.CopyOperationConditions.Conditions)
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter(item.Key, item.Value);
|
|
|
|
if (!string.IsNullOrEmpty(MatchETag))
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-copy-source-if-match", MatchETag);
|
|
if (!string.IsNullOrEmpty(NotMatchETag))
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-copy-source-if-none-match", NotMatchETag);
|
|
if (ModifiedSince != default)
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-copy-source-if-unmodified-since",
|
|
Utils.To8601String(ModifiedSince));
|
|
|
|
if (UnModifiedSince != default)
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-copy-source-if-modified-since",
|
|
Utils.To8601String(UnModifiedSince));
|
|
|
|
if (ObjectTags?.TaggingSet?.Tag.Count > 0)
|
|
{
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-tagging", ObjectTags.GetTagString());
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-tagging-directive",
|
|
ReplaceTagsDirective ? "REPLACE" : "COPY");
|
|
if (ReplaceMetadataDirective)
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-tagging-directive", "REPLACE");
|
|
}
|
|
|
|
if (ReplaceMetadataDirective)
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-metadata-directive", "REPLACE");
|
|
if (!string.IsNullOrEmpty(StorageClass))
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-storage-class", StorageClass);
|
|
if (ObjectLockSet)
|
|
{
|
|
if (!RetentionUntilDate.Equals(default))
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-object-lock-retain-until-date",
|
|
Utils.To8601String(RetentionUntilDate));
|
|
|
|
requestMessageBuilder.AddOrUpdateHeaderParameter("x-amz-object-lock-mode",
|
|
ObjectLockRetentionMode == ObjectRetentionMode.GOVERNANCE ? "GOVERNANCE" : "COMPLIANCE");
|
|
}
|
|
|
|
if (!RequestBody.IsEmpty) requestMessageBuilder.SetBody(RequestBody);
|
|
return requestMessageBuilder;
|
|
}
|
|
|
|
internal CopyObjectRequestArgs WithCopyOperationObjectType(Type cp)
|
|
{
|
|
CopyOperationObjectType = cp;
|
|
return this;
|
|
}
|
|
|
|
public CopyObjectRequestArgs WithObjectLockMode(ObjectRetentionMode mode)
|
|
{
|
|
ObjectLockSet = true;
|
|
ObjectLockRetentionMode = mode;
|
|
return this;
|
|
}
|
|
|
|
public CopyObjectRequestArgs WithObjectLockRetentionDate(DateTime untilDate)
|
|
{
|
|
ObjectLockSet = true;
|
|
RetentionUntilDate = new DateTime(untilDate.Year, untilDate.Month, untilDate.Day,
|
|
untilDate.Hour, untilDate.Minute, untilDate.Second, untilDate.Kind);
|
|
return this;
|
|
}
|
|
|
|
internal override void Validate()
|
|
{
|
|
Utils.ValidateBucketName(BucketName); //Object name can be same as that of source.
|
|
if (SourceObject is null) throw new InvalidOperationException(nameof(SourceObject) + " has not been assigned.");
|
|
Populate();
|
|
}
|
|
|
|
internal void Populate()
|
|
{
|
|
ObjectName = string.IsNullOrEmpty(ObjectName) ? SourceObject.ObjectName : ObjectName;
|
|
// Opting for concat as Headers may have byte range info .etc.
|
|
if (!ReplaceMetadataDirective && SourceObjectInfo.MetaData is not null)
|
|
Headers = SourceObjectInfo.MetaData.Concat(Headers).GroupBy(item => item.Key, StringComparer.Ordinal)
|
|
.ToDictionary(item => item.Key, item => item.First().Value, StringComparer.Ordinal);
|
|
else if (ReplaceMetadataDirective) Headers ??= new Dictionary<string, string>(StringComparer.Ordinal);
|
|
}
|
|
}
|