Skip to content

Commit

Permalink
Bump to v8.6.0 (#264)
Browse files Browse the repository at this point in the history
* feat: reorder default query regions hosts

* feat: add `VerifyRequest` to check if request signed by qn

* feat: more fop support

- add idle-time fop support
- add getting fop status
- add configurable for pfop api host config

* chore: bump version info to v8.6.0 and update changelog

* feat: change default uc host
  • Loading branch information
lihsai0 authored Sep 20, 2024
1 parent 6b250fe commit b70f8f2
Show file tree
Hide file tree
Showing 14 changed files with 230 additions and 20 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
**2024-09-05**

v8.6.0

新增:验证 Qbox, Qiniu 签名的辅助方法

新增:持久化处理,支持闲时任务

更改:对象存储,默认空间管理域名,查询区域主备域名

**2024-08-23**

v8.5.1
Expand Down
2 changes: 1 addition & 1 deletion src/Qiniu/Qiniu.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<PostBuildEvent>
</PostBuildEvent>
<ProjectId>Qiniu</ProjectId>
<Version>8.5.1</Version>
<Version>8.6.0</Version>
<Authors>Rong Zhou, Qiniu SDK</Authors>
<Company>Shanghai Qiniu Information Technology Co., Ltd.</Company>
<Description>Qiniu Resource (Cloud) Storage SDK for C#</Description>
Expand Down
2 changes: 1 addition & 1 deletion src/Qiniu/QiniuCSharpSDK.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ public class QiniuCSharpSDK
/// <summary>
/// SDK版本号
/// </summary>
public const string VERSION = "8.5.1";
public const string VERSION = "8.6.0";

}
8 changes: 4 additions & 4 deletions src/Qiniu/Storage/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ public class Config
/// <summary>
/// 默认空间管理域名
/// </summary>
public static string DefaultUcHost = "uc.qbox.me";
public static string DefaultUcHost = "uc.qiniuapi.com";
/// <summary>
/// 默认查询区域域名
/// </summary>
public static string DefaultQueryRegionHost = "kodo-config.qiniuapi.com";
public static string DefaultQueryRegionHost = "uc.qiniuapi.com";
/// <summary>
/// 默认备用查询区域域名
/// </summary>
public static List<string> DefaultBackupQueryRegionHosts = new List<string>
{
"uc.qbox.me",
"api.qiniu.com"
"kodo-config.qiniuapi.com",
"uc.qbox.me"
};

/// <summary>
Expand Down
15 changes: 14 additions & 1 deletion src/Qiniu/Storage/OperationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,17 @@ public OperationManager(Mac mac, Config config)
/// <param name="pipeline">私有队列</param>
/// <param name="notifyUrl">通知url</param>
/// <param name="force">forece参数</param>
/// <param name="persistentType">为 1 时开启闲时任务</param>
/// <returns>pfop操作返回结果,正确返回结果包含persistentId</returns>
public PfopResult Pfop(string bucket, string key, string fops, string pipeline, string notifyUrl, bool force)
public PfopResult Pfop(
string bucket,
string key,
string fops,
string pipeline,
string notifyUrl,
bool force,
int type = 0
)
{
PfopResult result = new PfopResult();

Expand All @@ -65,6 +74,10 @@ public PfopResult Pfop(string bucket, string key, string fops, string pipeline,
{
sb.AppendFormat("&pipeline={0}", pipeline);
}
if (type > 0)
{
sb.AppendFormat("&type={0}", type);
}
byte[] data = Encoding.UTF8.GetBytes(sb.ToString());
string token = auth.CreateManageToken(pfopUrl, data);

Expand Down
10 changes: 10 additions & 0 deletions src/Qiniu/Storage/PfopInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public class PfopInfo
[JsonProperty("id")]
public string Id;
/// <summary>
/// 任务类型,为 1 代表为闲时任务
/// </summary>
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
public int? Type;
/// <summary>
/// 任务创建时间
/// </summary>
[JsonProperty("creationDate", NullValueHandling = NullValueHandling.Ignore)]
public string CreationDate;
/// <summary>
/// 任务结果状态码
/// </summary>
[JsonProperty("code")]
Expand Down
2 changes: 1 addition & 1 deletion src/Qiniu/Storage/PrefopResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public PfopInfo Result

if ((Code == (int)HttpCode.OK) && (!string.IsNullOrEmpty(Text)))
{
info= JsonConvert.DeserializeObject<PfopInfo>(Text);
info= JsonConvert.DeserializeObject<PfopInfo>(Text);
}
return info;
}
Expand Down
7 changes: 7 additions & 0 deletions src/Qiniu/Storage/PutPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ public class PutPolicy
[JsonProperty("persistentPipeline", NullValueHandling = NullValueHandling.Ignore)]
public string PersistentPipeline { get; set; }

/// <summary>
/// [可选]持久化任务类型,为 1 时开启闲时任务
/// </summary>
[JsonProperty("persistentType", NullValueHandling = NullValueHandling.Ignore)]
public int? PersistentType { get; set; }


/// <summary>
/// [可选]上传文件大小限制:最小值,单位Byte
/// </summary>
Expand Down
45 changes: 45 additions & 0 deletions src/Qiniu/Util/Signature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -200,5 +200,50 @@ public string SignRequestV2(string method, string url, StringDictionary headers,
{
return SignRequestV2(method, url, headers, Encoding.UTF8.GetString(body));
}

public bool VerifyRequest(
string method,
string url,
StringDictionary headers,
string body = null
)
{
byte[] bodyBytes = null;
if (!string.IsNullOrEmpty(body)) {
bodyBytes = Encoding.UTF8.GetBytes(body);
}
return VerifyRequest(
method,
url,
headers,
bodyBytes
);
}

public bool VerifyRequest(
string method,
string url,
StringDictionary headers,
byte[] body = null
)
{
if (!headers.ContainsKey("Authorization"))
{
return false;
}

string authString = headers["Authorization"];
if (authString.StartsWith("QBox "))
{
return authString == "QBox " + SignRequest(url, body);
}

if (authString.StartsWith("Qiniu "))
{
return authString == "Qiniu " + SignRequestV2(method, url, headers, body);
}

return false;
}
}
}
4 changes: 2 additions & 2 deletions src/QiniuTests/Storage/ConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ public void UcHostTest()
{
Config config = new Config();
string ucHost = config.UcHost();
Assert.AreEqual("http://uc.qbox.me", ucHost);
Assert.AreEqual("http://uc.qiniuapi.com", ucHost);
config.SetUcHost("uc.example.com");
ucHost = config.UcHost();
Assert.AreEqual("http://uc.example.com", ucHost);

config = new Config();
config.UseHttps = true;
ucHost = config.UcHost();
Assert.AreEqual("https://uc.qbox.me", ucHost);
Assert.AreEqual("https://uc.qiniuapi.com", ucHost);
config.SetUcHost("uc.example.com");
ucHost = config.UcHost();
Assert.AreEqual("https://uc.example.com", ucHost);
Expand Down
51 changes: 51 additions & 0 deletions src/QiniuTests/Storage/FormUploaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using NUnit.Framework;
using Qiniu.Http;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Qiniu.Util;
using Qiniu.Tests;

Expand Down Expand Up @@ -80,5 +82,54 @@ public void UploadFileV2Test()
System.IO.File.Delete(filePath);
}

[Test]
public void UploadFileWithPersistTypeTest()
{
Mac mac = new Mac(AccessKey, SecretKey);
Random rand = new Random();
string key = string.Format("UploadFileTest_{0}.dat", rand.Next());

string tempPath = System.IO.Path.GetTempPath();
int rnd = new Random().Next(1, 100000);
string filePath = tempPath + "resumeFile" + rnd.ToString();
char[] testBody = new char[4 * 1024 * 1024];
System.IO.FileStream stream = new System.IO.FileStream(filePath, System.IO.FileMode.Create);
System.IO.StreamWriter sw = new System.IO.StreamWriter(stream, System.Text.Encoding.Default);
sw.Write(testBody);
sw.Close();
stream.Close();

PutPolicy putPolicy = new PutPolicy();
putPolicy.Scope = Bucket + ":" + key;
putPolicy.SetExpires(3600);
putPolicy.DeleteAfterDays = 1;
string saveEntry = Base64.UrlSafeBase64Encode(Bucket + ":pfop-test_avinfo");
putPolicy.PersistentOps = "avinfo|saveas/" + saveEntry;
putPolicy.PersistentType = 1;
string token = Auth.CreateUploadToken(mac, putPolicy.ToJsonString());
Config config = new Config();
config.Zone = Zone.ZONE_CN_East;
config.UseHttps = true;
config.UseCdnDomains = true;
FormUploader target = new FormUploader(config);
PutExtra extra = new PutExtra();
extra.Version = "v2";
HttpResult result = target.UploadFile(filePath, key, token, extra);
Console.WriteLine("form upload result: " + result.ToString());
Assert.AreEqual((int)HttpCode.OK, result.Code);
System.IO.File.Delete(filePath);

Dictionary<string, object> dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(result.Text.ToString());
Assert.IsTrue(dict.ContainsKey("persistentId"));
OperationManager manager = new OperationManager(mac, config);
PrefopResult prefopRet = manager.Prefop(dict["persistentId"].ToString());
if (prefopRet.Code != (int)HttpCode.OK)
{
Assert.Fail("prefop error: " + prefopRet.ToString());
}
Assert.AreEqual(1, prefopRet.Result.Type);
Assert.IsNotNull(prefopRet.Result.CreationDate);
Assert.IsNotEmpty(prefopRet.Result.CreationDate);
}
}
}
52 changes: 43 additions & 9 deletions src/QiniuTests/Storage/OperationManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,30 @@ namespace Qiniu.Storage.Tests
[TestFixture]
public class OperationManagerTests :TestEnv
{
private OperationManager getOperationManager()
{
Mac mac = new Mac(AccessKey, SecretKey);
Config config = new Config();
// config.UseHttps = true;

OperationManager manager = new OperationManager(mac, config);
return manager;
}

[Test]
public void PfopTest()
public void PfopAndPrefopTest()
{
string key = "qiniu.mp4";
bool force = true;
string pipeline = "sdktest";
string notifyUrl = "http://api.example.com/qiniu/pfop/notify";
string saveMp4Entry = Base64.UrlSafeBase64Encode(Bucket + ":avthumb_test_target.mp4");
string saveJpgEntry = Base64.UrlSafeBase64Encode(Bucket + ":vframe_test_target.jpg");
string avthumbMp4Fop = "avthumb/mp4|saveas/" + saveMp4Entry;
string vframeJpgFop = "vframe/jpg/offset/1|saveas/" + saveJpgEntry;
string fops = string.Join(";", new string[] { avthumbMp4Fop, vframeJpgFop });
Mac mac = new Mac(AccessKey, SecretKey);
Config config = new Config();
config.UseHttps = true;
OperationManager manager = new OperationManager(mac, config);
string pipeline = "sdktest";
string notifyUrl = "http://api.example.com/qiniu/pfop/notify";
string key = "qiniu.mp4";
bool force = true;

OperationManager manager = getOperationManager();
PfopResult pfopRet = manager.Pfop(Bucket, key, fops, pipeline, notifyUrl, force);
if (pfopRet.Code != (int)HttpCode.OK)
{
Expand All @@ -42,5 +49,32 @@ public void PfopTest()
}
Console.WriteLine(ret.ToString());
}

[Test]
public void PfopWithIdleTimeTest()
{
string key = "qiniu.mp4";
bool force = true;
int type = 1;
string pipeline = null;
string saveJpgEntry = Base64.UrlSafeBase64Encode(Bucket + ":vframe_test_target.jpg");
string vframeJpgFop = "vframe/jpg/offset/1|saveas/" + saveJpgEntry;

OperationManager manager = getOperationManager();
PfopResult pfopRet = manager.Pfop(Bucket, key, vframeJpgFop, pipeline, null, force, type);
if (pfopRet.Code != (int)HttpCode.OK)
{
Assert.Fail("pfop error: " + pfopRet.ToString());
}

PrefopResult prefopRet = manager.Prefop(pfopRet.PersistentId);
if (prefopRet.Code != (int)HttpCode.OK)
{
Assert.Fail("prefop error: " + prefopRet.ToString());
}
Assert.AreEqual(1, prefopRet.Result.Type);
Assert.IsNotNull(prefopRet.Result.CreationDate);
Assert.IsNotEmpty(prefopRet.Result.CreationDate);
}
}
}
8 changes: 8 additions & 0 deletions src/QiniuTests/Util/Signature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,13 @@ public string SignatureV2ByBytesTest(string method, string url, StringDictionary
{
return string.Format("Qiniu {0}", sign.SignRequestV2(method, url, headers, Encoding.UTF8.GetBytes(body)));
}

[TestCaseSource(typeof(VerifyRequestDataClass), nameof(VerifyRequestDataClass.TestCases))]
public bool VerifyRequestTest(string method, string url, StringDictionary headers, string body)
{
Mac mac = new Mac("abcdefghklmnopq", "1234567890");
Signature mockSign = new Signature(mac);
return mockSign.VerifyRequest(method, url, headers, body);
}
}
}
34 changes: 33 additions & 1 deletion src/QiniuTests/Util/TestCases.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,36 @@ public static IEnumerable TestCases
}
}
}
}

public class VerifyRequestDataClass
{
public static IEnumerable TestCases
{
get
{
yield return new TestCaseData(
"",
"https://test.qiniu.com/callback",
new StringDictionary
{
{"Authorization", "QBox abcdefghklmnopq:T7F-SjxX7X2zI4Fc1vANiNt1AUE="},
{"Content-Type", "application/x-www-form-urlencoded"}
},
"name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123"
).Returns(true);

yield return new TestCaseData(
"GET",
"https://test.qiniu.com/callback",
new StringDictionary
{
{"Authorization", "Qiniu abcdefghklmnopq:ZqS7EZuAKrhZaEIxqNGxDJi41IQ="},
{"X-Qiniu-Bbb", "BBB"},
{"Content-Type", "application/x-www-form-urlencoded"}
},
"name=sunflower.jpg&hash=Fn6qeQi4VDLQ347NiRm-RlQx_4O2&location=Shanghai&price=1500.00&uid=123"
).Returns(true);
}
}
}
}

0 comments on commit b70f8f2

Please sign in to comment.