123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using COSXML.Common;
- using System.IO;
- using COSXML.Utils;
- using COSXML.CosException;
- using COSXML.Auth;
- using COSXML.Log;
- using COSXML.Network;
- namespace COSXML.Model.Object
- {
- /// <summary>
- /// 使用者用表单的形式将文件(Object)上传至指定 Bucket 中.
- /// <see href="https://cloud.tencent.com/document/product/436/14690"/>
- /// </summary>
- public sealed class PostObjectRequest : ObjectRequest
- {
- /// <summary>
- /// 表单字段
- /// <see href="FormStruct"/>
- /// </summary>
- private FormStruct formStruct;
- private PostObjectRequest(string bucket, string key)
- : base(bucket, "/")
- {
- this.method = CosRequestMethod.POST;
- formStruct = new FormStruct();
- formStruct.key = key;
- this.SetHeader(CosRequestHeaderKey.CONTENT_TYPE, "multipart/form-data; boundary=" + MultipartRequestBody.BOUNDARY);
- this.needMD5 = false;
- }
- /// <summary>
- /// 上传文件
- /// </summary>
- /// <param name="bucket"></param>
- /// <param name="key"></param>
- /// <param name="srcPath"></param>
- public PostObjectRequest(string bucket, string key, string srcPath)
- : this(bucket, key, srcPath, -1L, -1L)
- {
- }
- /// <summary>
- /// 上传文件的指定部分
- /// </summary>
- /// <param name="bucket"></param>
- /// <param name="key"></param>
- /// <param name="srcPath"></param>
- /// <param name="fileOffset">指定文件内容的起始位置</param>
- /// <param name="sendContentLength">指定文件内容的大小</param>
- public PostObjectRequest(string bucket, string key, string srcPath, long fileOffset, long sendContentLength)
- : this(bucket, key)
- {
- formStruct.srcPath = srcPath;
- formStruct.fileOffset = fileOffset < 0 ? 0 : fileOffset;
- formStruct.contentLength = sendContentLength < 0L ? -1L : sendContentLength;
- }
- /// <summary>
- /// 上传data数据
- /// </summary>
- /// <param name="bucket"></param>
- /// <param name="key"></param>
- /// <param name="data"></param>
- public PostObjectRequest(string bucket, string key, byte[] data)
- : this(bucket, key)
- {
- formStruct.data = data;
- }
- /// <summary>
- /// 设置进度回调
- /// </summary>
- /// <param name="progressCallback"></param>
- public void SetCosProgressCallback(COSXML.Callback.OnProgressCallback progressCallback)
- {
- formStruct.progressCallback = progressCallback;
- }
- /// <summary>
- /// 定义 Object 的 acl 属性。有效值:private,public-read-write,public-read;默认值:private
- /// <see href="Common.CosACL"/>
- /// </summary>
- /// <param name="cosACL"></param>
- public void SetCosACL(CosACL cosACL)
- {
- SetCosACL(EnumUtils.GetValue(cosACL));
- }
- /// <summary>
- /// 定义 Object 的 acl 属性。有效值:private,public-read-write,public-read;默认值:private
- /// <see href="Common.CosACL"/>
- /// </summary>
- /// <param name="cosACL"></param>
- public void SetCosACL(string cosACL)
- {
- if (cosACL != null)
- {
- formStruct.acl = cosACL;
- }
- }
- /// <summary>
- /// 设置对象的 cacheControl
- /// </summary>
- /// <param name="cacheControl"></param>
- public void SetCacheControl(string cacheControl)
- {
- SetHeader("Cache-Control", cacheControl);
- }
- /// <summary>
- /// 设置对象的contentType
- /// </summary>
- /// <param name="contentType"></param>
- public void SetContentType(string contentType)
- {
- SetHeader("Content-Type", contentType);
- }
- /// <summary>
- /// 设置对象的contentDisposition
- /// </summary>
- /// <param name="contentDisposition"></param>
- public void SetContentDisposition(string contentDisposition)
- {
- SetHeader("Content-Disposition", contentDisposition);
- }
- /// <summary>
- /// 设置对象的contentEncoding
- /// </summary>
- /// <param name="contentEncoding"></param>
- public void SetContentEncoding(string contentEncoding)
- {
- SetHeader("Content-Encoding", contentEncoding);
- }
- /// <summary>
- /// 设置对象 Expire
- /// </summary>
- /// <param name="expires"></param>
- public void SetExpires(string expires)
- {
- SetHeader("Expires", expires);
- }
- /// <summary>
- /// 设置对象header属性
- /// </summary>
- /// <param name="key"></param>
- /// <param name="value"></param>
- public void SetHeader(string key, string value)
- {
- try
- {
- formStruct.headers.Add(key, value);
- }
- catch (ArgumentException)
- {
- formStruct.headers[key] = value;
- }
- }
- /// <summary>
- /// 设置对象自定义的header属性
- /// </summary>
- /// <param name="key"></param>
- /// <param name="value"></param>
- public void SetCustomerHeader(string key, string value)
- {
- try
- {
- formStruct.customHeaders.Add(key, value);
- }
- catch (ArgumentException)
- {
- formStruct.customHeaders[key] = value;
- }
- }
- /// <summary>
- /// 设置对象的存储类型
- /// <see href="Common.CosStorageClass"/>
- /// </summary>
- /// <param name="cosStorageClass"></param>
- public void SetCosStorageClass(string cosStorageClass)
- {
- formStruct.xCosStorageClass = cosStorageClass;
- }
- /// <summary>
- /// 最大上传速度,单位是 bit/s
- /// </summary>
- /// <param name="rate"></param>
- public void LimitTraffic(long rate)
- {
- formStruct.xCOSTrafficLimit = rate.ToString();
- }
- /// <summary>
- /// 若设置优先生效,返回 303 并提供 Location 头部,
- /// 会在 URL 尾部加上 bucket={bucket}<key={key}>etag={%22etag%22} 参数。
- /// </summary>
- /// <param name="redirectHost"></param>
- public void SetSuccessActionRedirect(string redirectHost)
- {
- formStruct.successActionRedirect = redirectHost;
- }
- /// <summary>
- /// successHttpCode can be 200, 201, 204, default value 204
- /// 若填写 success_action_redirect 则会略此设置。
- /// </summary>
- /// <param name="successHttpCode"></param>
- public void SetSuccessActionStatus(int successHttpCode)
- {
- formStruct.successActionStatus = successHttpCode.ToString();
- }
- /// <summary>
- /// 用于做请求检查,如果请求的内容和 Policy 指定的条件不符,返回 403 AccessDenied。
- /// <see href="Policy"/>
- /// </summary>
- /// <param name="policy"></param>
- public void SetPolicy(Policy policy)
- {
- formStruct.policy = policy;
- }
- public override void CheckParameters()
- {
- formStruct.CheckParameter();
- base.CheckParameters();
- }
- public override CosXmlSignSourceProvider GetSignSourceProvider()
- {
- var signSourceProvider = base.GetSignSourceProvider();
-
- if (signSourceProvider != null)
- {
- signSourceProvider.RemoveHeaderKey("content-type");
- signSourceProvider.RemoveHeaderKey("content-length");
- signSourceProvider.RemoveHeaderKey("content-md5");
- signSourceProvider.onGetSign = delegate (Request request, string sign)
- {
- //添加参数 sign
- ((MultipartRequestBody)request.Body).AddParameter("Signature", sign);
- };
- }
- return signSourceProvider;
- }
- public override RequestBody GetRequestBody()
- {
- MultipartRequestBody requestBody = new MultipartRequestBody();
- requestBody.AddParamters(formStruct.GetFormParameters());
- if (formStruct.data != null)
- {
- requestBody.AddData(formStruct.data, "file", "tmp");
- }
- else if (formStruct.srcPath != null)
- {
- FileInfo fileInfo = new FileInfo(this.formStruct.srcPath);
- string fileName = fileInfo.Name;
- if (formStruct.contentLength == -1L || formStruct.contentLength + formStruct.fileOffset > fileInfo.Length)
- {
- formStruct.contentLength = fileInfo.Length - formStruct.fileOffset;
- }
- requestBody.AddData(formStruct.srcPath, formStruct.fileOffset, formStruct.contentLength, "file", fileName);
- }
- requestBody.ProgressCallback = formStruct.progressCallback;
- return requestBody;
- }
- private class FormStruct
- {
- /// <summary>
- /// 对象的ACL
- /// </summary>
- public string acl;
- /// <summary>
- /// 对象的header元数据
- /// </summary>
- public Dictionary<string, string> headers;
- /// <summary>
- /// 上传后的文件名,使用 ${filename} 则会进行替换。
- /// 例如a/b/${filename},上传文件 a1.txt,那么最终的上传路径就是 a/b/a1.txt
- /// </summary>
- public string key;
- /// <summary>
- /// 若设置优先生效,返回 303 并提供 Location 头部
- /// </summary>
- public string successActionRedirect;
- /// <summary>
- /// 可选 200,201,204 默认返回 204。若填写 success_action_redirect 则会略此设置。
- /// </summary>
- public string successActionStatus;
- /// <summary>
- /// 对象的自定义元数据
- /// </summary>
- public Dictionary<string, string> customHeaders;
- /// <summary>
- /// 对象存储类型
- /// </summary>
- public string xCosStorageClass;
- /// <summary>
- /// 速度限制
- /// </summary>
- public string xCOSTrafficLimit;
- /// <summary>
- /// 请求检查策略
- /// <see href="Policy"/>
- /// </summary>
- public Policy policy;
- /// <summary>
- /// 上传文件的本地路径
- /// </summary>
- public string srcPath;
- /// <summary>
- /// 上传文件指定起始位置
- /// </summary>
- public long fileOffset = 0L;
- /// <summary>
- /// 上传文件指定内容大小
- /// </summary>
- public long contentLength = -1L;
- /// <summary>
- /// 上传data数据
- /// </summary>
- public byte[] data;
- /// <summary>
- /// 上传回调
- /// </summary>
- public COSXML.Callback.OnProgressCallback progressCallback;
- public FormStruct()
- {
- headers = new Dictionary<string, string>();
- customHeaders = new Dictionary<string, string>();
- }
- public Dictionary<string, string> GetFormParameters()
- {
- Dictionary<string, string> formParameters = new Dictionary<string, string>();
- if (acl != null)
- {
- formParameters.Add("Acl", acl);
- }
- foreach (KeyValuePair<string, string> pair in headers)
- {
- formParameters.Add(pair.Key, pair.Value);
- }
- formParameters.Add("key", key);
- if (successActionRedirect != null)
- {
- formParameters.Add("success_action_redirect", successActionRedirect);
- }
- if (successActionStatus != null)
- {
- formParameters.Add("success_action_status", successActionStatus);
- }
- foreach (KeyValuePair<string, string> pair in customHeaders)
- {
- formParameters.Add(pair.Key, pair.Value);
- }
- if (xCosStorageClass != null)
- {
- formParameters.Add("x-cos-storage-class", xCosStorageClass);
- }
- if (xCOSTrafficLimit != null)
- {
- formParameters.Add(CosRequestHeaderKey.X_COS_TRAFFIC_LIMIT, xCOSTrafficLimit);
- }
- if (policy != null)
- {
- formParameters.Add("policy", DigestUtils.GetBase64(policy.Content(), Encoding.UTF8));
- }
- return formParameters;
- }
- public void CheckParameter()
- {
- if (String.IsNullOrEmpty(key))
- {
- throw new CosClientException((int)CosClientError.InvalidArgument, "FormStruct.key(null or empty) is invalid");
- }
- if (srcPath == null && data == null)
- {
- throw new CosClientException((int)CosClientError.InvalidArgument, "data source = null");
- }
- if (srcPath != null)
- {
- if (!File.Exists(srcPath))
- {
- throw new CosClientException((int)CosClientError.InvalidArgument, "srcPath not exist");
- }
- }
- }
- }
- public class Policy
- {
- /// <summary>
- /// 过期时间
- /// </summary>
- private string expiration;
- /// <summary>
- /// 检查条件
- /// </summary>
- private StringBuilder conditions = new StringBuilder();
- public void SetExpiration(long endTimeMills)
- {
- this.expiration = TimeUtils_QCloud.GetFormatTime("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", endTimeMills, TimeUnit.Milliseconds);
- }
- public void AddConditions(string key, string value, bool isPrefixMatch)
- {
- if (conditions.Length > 0)
- {
- conditions.Append(',');
- }
- if (isPrefixMatch)
- {
- conditions.Append('[')
- .Append("\"starts-with\"")
- .Append(",\"")
- .Append(key)
- .Append("\",\"")
- .Append(value)
- .Append("\"]");
- }
- else
- {
- conditions.Append("{\"")
- .Append(key)
- .Append("\":\"")
- .Append(value)
- .Append("\"}");
- }
- }
- public void AddContentConditions(int start, int end)
- {
- if (conditions.Length > 0)
- {
- conditions.Append(',');
- }
-
- conditions.Append('[')
- .Append("\"content-length-range\"")
- .Append(',')
- .Append(start)
- .Append(',')
- .Append(end)
- .Append(']');
- }
- public string Content()
- {
- StringBuilder content = new StringBuilder();
- content.Append('{');
- if (expiration != null)
- {
- content.Append(String.Format("\"expiration\":\"{0}\"", expiration));
- }
- if (conditions.Length > 0)
- {
- if (expiration != null)
- {
- content.Append(",");
- }
- content.Append(String.Format("\"conditions\":[{0}]", conditions));
- }
- content.Append('}');
- return content.ToString();
- }
- }
- }
- }
|