├── .gitignore
├── BlobService.cs
├── LICENSE
├── README.md
├── StorageServiceClient.cs
├── http
├── StorageRequest.cs
├── auth
│ ├── Auth.cs
│ └── headers
│ │ ├── AuthorizationHeaders.cs
│ │ └── CanonicalizedHeaders.cs
└── query
│ └── ResType.cs
└── model
├── BlobResults.cs
├── ContainerResults.cs
└── ErrorResult.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | /[Ll]ibrary/
2 | /[Tt]emp/
3 | /[Oo]bj/
4 | /[Bb]uild/
5 | /[Bb]uilds/
6 | /Assets/AssetStoreTools*
7 |
8 | # Visual Studio 2015 cache directory
9 | /.vs/
10 |
11 | # Autogenerated VS/MD/Consulo solution and project files
12 | ExportedObj/
13 | .consulo/
14 | *.csproj
15 | *.unityproj
16 | *.sln
17 | *.suo
18 | *.tmp
19 | *.user
20 | *.userprefs
21 | *.pidb
22 | *.booproj
23 | *.svd
24 | *.pdb
25 |
26 | # Unity3D generated meta files
27 | *.pidb.meta
28 | *.meta
29 |
30 | # Unity3D Generated File On Crash Reports
31 | sysinfo.txt
32 |
33 | # Builds
34 | *.apk
35 | *.unitypackage
36 |
37 | # IDEs
38 | /.vscode
39 | omnisharp.json
40 | .editorconfig
41 |
--------------------------------------------------------------------------------
/BlobService.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using RESTClient;
5 | using System.Collections;
6 | using System;
7 | using System.Collections.Generic;
8 | using UnityEngine;
9 | using System.IO;
10 | using System.Text;
11 |
12 | namespace Azure.StorageServices {
13 | public class BlobService {
14 | private StorageServiceClient client;
15 |
16 | public BlobService(StorageServiceClient client) {
17 | this.client = client;
18 | }
19 |
20 | ///
21 | /// Lists all of the containers in a storage account.
22 | ///
23 | /// The containers.
24 | /// .
25 | public IEnumerator ListContainers(Action> callback) {
26 | Dictionary queryParams = new Dictionary();
27 | queryParams.Add("comp", "list");
28 | queryParams.Add("restype", ResType.container.ToString());
29 | StorageRequest request = Auth.CreateAuthorizedStorageRequest(client, Method.GET, "", queryParams);
30 | yield return request.Send();
31 | request.ParseXML(callback);
32 | }
33 |
34 | ///
35 | /// Lists all of the blobs in a container.
36 | ///
37 | /// The containers.
38 | /// .
39 | public IEnumerator ListBlobs(Action> callback, string resourcePath = "") {
40 | Dictionary queryParams = new Dictionary();
41 | queryParams.Add("comp", "list");
42 | queryParams.Add("restype", ResType.container.ToString());
43 | StorageRequest request = Auth.CreateAuthorizedStorageRequest(client, Method.GET, resourcePath, queryParams);
44 | yield return request.Send();
45 | request.ParseXML(callback);
46 | }
47 |
48 | #region Download blobs
49 |
50 | public IEnumerator GetTextBlob(Action callback, string resourcePath = "") {
51 | StorageRequest request = Auth.GetAuthorizedStorageRequest(client, resourcePath);
52 | yield return request.Send();
53 | request.GetText(callback);
54 | }
55 |
56 | public IEnumerator GetJsonBlob(Action> callback, string resourcePath = "") {
57 | StorageRequest request = Auth.GetAuthorizedStorageRequest(client, resourcePath);
58 | yield return request.Send();
59 | request.ParseJson(callback);
60 | }
61 |
62 | public IEnumerator GetJsonArrayBlob(Action> callback, string resourcePath = "") {
63 | StorageRequest request = Auth.GetAuthorizedStorageRequest(client, resourcePath);
64 | yield return request.Send();
65 | request.ParseJsonArray(callback);
66 | }
67 |
68 | public IEnumerator GetXmlBlob(Action> callback, string resourcePath = "") {
69 | StorageRequest request = Auth.GetAuthorizedStorageRequest(client, resourcePath);
70 | yield return request.Send();
71 | request.ParseXML(callback);
72 | }
73 |
74 | public IEnumerator GetImageBlob(Action> callback, string resourcePath = "") {
75 | StorageRequest request = Auth.GetAuthorizedStorageRequestTexture(client, resourcePath);
76 | yield return request.Send();
77 | request.GetTexture(callback);
78 | }
79 |
80 | public IEnumerator GetAudioBlob(Action> callback, string resourcePath = "") {
81 | StorageRequest request = Auth.GetAuthorizedStorageRequestAudioClip(client, resourcePath);
82 | yield return request.Send();
83 | request.GetAudioClip(callback);
84 | }
85 |
86 | public IEnumerator GetAssetBundle(Action> callback, string resourcePath = "") {
87 | StorageRequest request = Auth.GetAuthorizedStorageRequestAssetBundle(client, resourcePath);
88 | yield return request.Send();
89 | request.GetAssetBundle(callback);
90 | }
91 |
92 | public IEnumerator GetBlob(Action> callback, string resourcePath = "") {
93 | StorageRequest request = Auth.GetAuthorizedStorageRequest(client, resourcePath);
94 | yield return request.Send();
95 | request.GetBytes(callback);
96 | }
97 |
98 | #endregion
99 |
100 | #region Upload blobs
101 |
102 | public IEnumerator PutTextBlob(Action callback, string text, string resourcePath, string filename, string contentType = "text/plain; charset=UTF-8") {
103 | byte[] bytes = Encoding.UTF8.GetBytes(text);
104 | return PutBlob(callback, bytes, resourcePath, filename, contentType);
105 | }
106 |
107 | public IEnumerator PutImageBlob(Action callback, byte[] bytes, string resourcePath, string filename, string contentType = "image/png") {
108 | return PutBlob(callback, bytes, resourcePath, filename, contentType);
109 | }
110 |
111 | public IEnumerator PutAudioBlob(Action callback, byte[] bytes, string resourcePath, string filename, string contentType = "audio/wav") {
112 | return PutBlob(callback, bytes, resourcePath, filename, contentType);
113 | }
114 |
115 | public IEnumerator PutAssetBundle(Action callback, byte[] bytes, string resourcePath, string filename, string contentType = "application/octet-stream") {
116 | return PutBlob(callback, bytes, resourcePath, filename, contentType);
117 | }
118 |
119 | public IEnumerator PutBlob(Action callback, byte[] bytes, string resourcePath, string filename, string contentType, Method method = Method.PUT) {
120 | int contentLength = bytes.Length; // TODO: check size is ok?
121 | Dictionary headers = new Dictionary();
122 | string file = Path.GetFileName(filename);
123 |
124 | headers.Add("Content-Type", contentType);
125 | headers.Add("x-ms-blob-content-disposition", string.Format("attachment; filename=\"{0}\"", file));
126 | headers.Add("x-ms-blob-type", "BlockBlob");
127 |
128 | string filePath = resourcePath.Length > 0 ? resourcePath + "/" + file : file;
129 | StorageRequest request = Auth.CreateAuthorizedStorageRequest(client, method, filePath, null, headers, contentLength);
130 | request.AddBody(bytes, contentType);
131 | yield return request.Send();
132 | request.Result(callback);
133 | }
134 |
135 | #endregion
136 |
137 | public IEnumerator DeleteBlob(Action callback, string resourcePath, string filename) {
138 | string filePath = resourcePath.Length > 0 ? resourcePath + "/" + filename : filename;
139 | StorageRequest request = Auth.CreateAuthorizedStorageRequest(client, Method.DELETE, filePath);
140 | yield return request.Send();
141 | request.Result(callback);
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Unity3dAzure
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Azure Storage Services for Unity3d
2 |
3 | Save and load image textures, audio files, json or xml data files for use in
4 | Unity. You can also store Unity Asset Bundles to load Prefabs with referenced
5 | scripts to work in your game / application.
6 |
7 | ## External dependencies
8 |
9 | **First download the shared
10 | [REST Client library for Unity](https://github.com/Unity3dAzure/RESTClient) and
11 | extract the contents into your Unity project "Assets" folder.**
12 |
13 | * [RESTClient](https://github.com/Unity3dAzure/RESTClient)
14 |
15 | ## Requirements
16 |
17 | Unity 2017.2 recommended. Unity v5.3 or greater required as
18 | [UnityWebRequest](https://docs.unity3d.com/Manual/UnityWebRequest.html) and
19 | [JsonUtility](https://docs.unity3d.com/ScriptReference/JsonUtility.html)
20 | features are used. Unity will be extending platform support for UnityWebRequest
21 | so keep Unity up to date if you need to support these additional platforms.
22 |
23 | ## Azure Blob Storage Demos for Unity 2017.2
24 |
25 | Try the
26 | [Azure Storage Services Demos](https://github.com/Unity3dAzure/StorageServicesDemo)
27 | project for Unity on Mac / Windows. (The demo project has got everything already
28 | bundled in and does not require any additional assets to work. Just wire it up
29 | with your Azure Storage Service and public Blob container and run it right
30 | inside the Unity Editor.)
31 |
32 | ## How to setup Storage Services with a new Unity project
33 |
34 | 1. [Download StorageServices](https://github.com/Unity3dAzure/StorageServices/archive/master.zip)
35 | and
36 | [REST Client](https://github.com/Unity3dAzure/RESTClient/archive/master.zip)
37 | for Unity.
38 | * Copy 'StorageServices' and 'RESTClient' into your Unity project's `Assets`
39 | folder.
40 | 2. Create [Azure](https://portal.azure.com) Storage Service
41 |
42 | ## Supported platforms
43 |
44 | Intended to work on all the platforms
45 | [UnityWebRequest](https://docs.unity3d.com/Manual/UnityWebRequest.html) supports
46 | including:
47 |
48 | * Unity Editor and Standalone players
49 | * iOS
50 | * Android
51 | * Windows
52 |
53 | ## Notice
54 |
55 | This library is in beta so not all APIs are supported yet and some things may
56 | change.
57 |
58 | Questions or tweet [@deadlyfingers](https://twitter.com/deadlyfingers)
59 |
--------------------------------------------------------------------------------
/StorageServiceClient.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using RESTClient;
5 | using System;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace Azure.StorageServices {
9 | public sealed class StorageServiceClient : RestClient {
10 | private string account;
11 |
12 | public string Account {
13 | get {
14 | return account;
15 | }
16 | }
17 |
18 | private byte[] key;
19 |
20 | public byte[] Key {
21 | get {
22 | return key;
23 | }
24 | }
25 |
26 | // https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/versioning-for-the-azure-storage-services
27 | private string version;
28 |
29 | public string Version {
30 | get {
31 | return version;
32 | }
33 | }
34 |
35 | public StorageServiceClient(string url, string accessKey, string version = "2017-04-17", string account = "") : base(url) {
36 | this.version = version;
37 | if (!string.IsNullOrEmpty(accessKey)) {
38 | this.key = Convert.FromBase64String(accessKey);
39 | }
40 | if (!string.IsNullOrEmpty(account)) {
41 | this.account = account;
42 | } else {
43 | this.account = GetAccountName(url);
44 | }
45 | }
46 |
47 | ///
48 | /// Creates a new instance of the class.
49 | ///
50 | /// Storage account name.
51 | /// Access key.
52 | public static StorageServiceClient Create(string account, string accessKey, string version = "2017-04-17") {
53 | string url = GetPrimaryEndpoint(account);
54 | return new StorageServiceClient(url, accessKey, version, account);
55 | }
56 |
57 | public BlobService GetBlobService() {
58 | return new BlobService(this);
59 | }
60 |
61 | public string PrimaryEndpoint() {
62 | return GetPrimaryEndpoint(account);
63 | }
64 |
65 | public string SecondaryEndpoint() {
66 | return GetSecondaryEndpoint(account);
67 | }
68 |
69 | private static string GetPrimaryEndpoint(string account) {
70 | return "https://" + account + ".blob.core.windows.net/";
71 | }
72 |
73 | private static string GetSecondaryEndpoint(string account) {
74 | return "https://" + account + ".blob.core.windows.net/";
75 | }
76 |
77 | private string GetAccountName(string url) {
78 | var match = Regex.Match(url, @"^https?:\/\/([a-z0-9]+)", RegexOptions.IgnoreCase);
79 | if (match.Groups.Count == 2 && match.Groups[1].Value.Length > 0) {
80 | return match.Groups[1].Value;
81 | }
82 | return url;
83 | }
84 |
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/http/StorageRequest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using RESTClient;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 | using UnityEngine;
9 | using UnityEngine.Networking;
10 |
11 | namespace Azure.StorageServices {
12 | public sealed class StorageRequest : RestRequest {
13 | public StorageRequest(string url, Method method) : base(url, method) {
14 | }
15 |
16 | public StorageRequest(UnityWebRequest request) : base(request) {
17 | }
18 |
19 | public void AuthorizeRequest(StorageServiceClient client, Method method, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
20 | AuthorizationHeaders authHeaders = new AuthorizationHeaders(client, method, resourcePath, queryParams, headers, contentLength);
21 | string stringToSign = authHeaders.ToString();
22 | string signature = GetSignature(client.Key, stringToSign);
23 | string authorization = GetAuthorizationHeader(client.Account, signature);
24 |
25 | this.AddHeader("Authorization", authorization);
26 | this.AddHeader("x-ms-date", authHeaders.MSDate());
27 | this.AddHeader("x-ms-version", authHeaders.MSVersion());
28 |
29 | if (headers != null) {
30 | this.AddHeaders(headers);
31 | }
32 |
33 | Debug.Log("Authorized request url:" + this.Request.url + "\n\nauthorization: \"" + authorization + "\"\nx-ms-date: " + authHeaders.MSDate() + "\nstringToSign:'" + stringToSign + "'");
34 | }
35 |
36 | ///
37 | /// Creates Signature using format Base64(HMAC-SHA256(UTF8(StringToSign)))
38 | ///
39 | /// The signature.
40 | /// String to sign.
41 | private string GetSignature(byte[] key, string stringToSign) {
42 | return SignatureHelper.Sign(key, stringToSign);
43 | }
44 |
45 | ///
46 | /// Authorization header value
47 | ///
48 | /// Account.
49 | /// Signature.
50 | private string GetAuthorizationHeader(string account, string signature) {
51 | return string.Format("SharedKey {0}:{1}", account, signature);
52 | }
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/http/auth/Auth.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using RESTClient;
5 | using System.Collections.Generic;
6 | using System.Security.Cryptography;
7 | using UnityEngine;
8 | using System.Text;
9 | using System;
10 | using UnityEngine.Networking;
11 |
12 | namespace Azure.StorageServices {
13 | public static class Auth {
14 | ///
15 | /// Factory method to generate an authorized request URL using query params. (valid up to 15 minutes)
16 | ///
17 | /// The authorized request.
18 | /// StorageServiceClient
19 | /// Http method.
20 | public static StorageRequest CreateAuthorizedStorageRequest(StorageServiceClient client, Method method, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
21 | string requestUrl = RequestUrl(client, queryParams, resourcePath);
22 | StorageRequest request = new StorageRequest(requestUrl, method);
23 | request.AuthorizeRequest(client, method, resourcePath, queryParams, headers, contentLength);
24 | return request;
25 | }
26 |
27 | public static StorageRequest GetAuthorizedStorageRequest(StorageServiceClient client, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
28 | return CreateAuthorizedStorageRequest(client, Method.GET, resourcePath, queryParams, headers, contentLength);
29 | }
30 |
31 | public static StorageRequest GetAuthorizedStorageRequestTexture(StorageServiceClient client, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
32 | string requestUrl = RequestUrl(client, queryParams, resourcePath);
33 | StorageRequest request = new StorageRequest(UnityWebRequestTexture.GetTexture(requestUrl));
34 | request.AuthorizeRequest(client, Method.GET, resourcePath, queryParams, headers, contentLength);
35 | return request;
36 | }
37 |
38 | public static StorageRequest GetAuthorizedStorageRequestAudioClip(StorageServiceClient client, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0, AudioType audioType = AudioType.WAV) {
39 | string requestUrl = RequestUrl(client, queryParams, resourcePath);
40 | StorageRequest request = new StorageRequest(UnityWebRequestMultimedia.GetAudioClip(requestUrl, audioType));
41 | request.AuthorizeRequest(client, Method.GET, resourcePath, queryParams, headers, contentLength);
42 | return request;
43 | }
44 |
45 | public static StorageRequest GetAuthorizedStorageRequestAssetBundle(StorageServiceClient client, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
46 | string requestUrl = RequestUrl(client, queryParams, resourcePath);
47 | StorageRequest request = new StorageRequest(UnityWebRequest.GetAssetBundle(requestUrl));
48 | request.AuthorizeRequest(client, Method.GET, resourcePath, queryParams, headers, contentLength);
49 | return request;
50 | }
51 |
52 | private static string RequestUrl(StorageServiceClient client, Dictionary queryParams = null, string resourcePath = "") {
53 | string baseUrl = client.PrimaryEndpoint();
54 | return UrlHelper.BuildQuery(baseUrl, queryParams, resourcePath);
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/http/auth/headers/AuthorizationHeaders.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using RESTClient;
5 | using System.Text;
6 | using System.Collections.Generic;
7 | using System;
8 |
9 | namespace Azure.StorageServices {
10 | public class AuthorizationHeaders {
11 | private string method;
12 | private CanonicalizedHeaders canonicalizedHeaders;
13 | private string canonicalizedResource;
14 |
15 | private Dictionary authHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase) {
16 | { "Content-Encoding", "" },
17 | { "Content-Language", "" },
18 | { "Content-Length", "" },
19 | { "Content-MD5", "" },
20 | { "Content-Type", "" },
21 | { "Date", "" },
22 | { "If-Modified-Since", "" },
23 | { "If-Match", "" },
24 | { "If-None-Match", "" },
25 | { "If-Unmodified-Since", "" },
26 | { "Range", "" }
27 | };
28 |
29 | public AuthorizationHeaders(StorageServiceClient client, Method method, string resourcePath = "", Dictionary queryParams = null, Dictionary headers = null, int contentLength = 0) {
30 | string path = resourcePath;
31 | this.method = method.ToString();
32 | this.canonicalizedHeaders = new CanonicalizedHeaders(client.Version, headers);
33 |
34 | if (queryParams != null) {
35 | path = resourcePath + BuildQueryString(queryParams);
36 | }
37 |
38 | if (headers != null) {
39 | UpdateHeaderValues(headers);
40 | }
41 |
42 | if (contentLength > 0) {
43 | authHeaders["Content-Length"] = contentLength.ToString();
44 | }
45 |
46 | // account followed by url encoded resource path, and query params
47 | this.canonicalizedResource = string.Format("/{0}/{1}", client.Account, path);
48 | }
49 |
50 | private string BuildQueryString(Dictionary queryParams) {
51 | StringBuilder q = new StringBuilder();
52 | foreach (KeyValuePair param in queryParams) {
53 | q.Append("\n" + param.Key + ":" + param.Value);
54 | }
55 | return q.ToString();
56 | }
57 |
58 | private void UpdateHeaderValues(Dictionary headers) {
59 | foreach (KeyValuePair header in headers) {
60 | if (authHeaders.ContainsKey(header.Key)) {
61 | authHeaders[header.Key] = header.Value;
62 | }
63 | }
64 | }
65 |
66 | public string MSDate() {
67 | return canonicalizedHeaders.MSDate;
68 | }
69 |
70 | public string MSVersion() {
71 | return canonicalizedHeaders.MSVersion;
72 | }
73 |
74 | ///
75 | /// Returns string to sign
76 | /// https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/authentication-for-the-azure-storage-services
77 | ///
78 | public override string ToString() {
79 | StringBuilder sb = new StringBuilder();
80 | sb.Append(method + "\n");
81 | foreach (KeyValuePair authHeader in authHeaders) {
82 | sb.Append(authHeader.Value + "\n");
83 | }
84 | sb.Append(canonicalizedHeaders);
85 | sb.Append(canonicalizedResource);
86 | return sb.ToString();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/http/auth/headers/CanonicalizedHeaders.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace Azure.StorageServices {
9 | public class CanonicalizedHeaders {
10 | private string xMSDate;
11 |
12 | public string MSDate {
13 | get {
14 | return xMSDate;
15 | }
16 | }
17 |
18 | private string xMSVersion;
19 |
20 | public string MSVersion {
21 | get {
22 | return xMSVersion;
23 | }
24 | }
25 |
26 | private List canonicalHeaders;
27 |
28 | public CanonicalizedHeaders(string version, Dictionary headers = null) {
29 | this.xMSDate = DateTime.UtcNow.ToString("R");
30 | this.xMSVersion = version;
31 |
32 | canonicalHeaders = new List();
33 | AddCanonicalHeaderKeyValue("x-ms-date", MSDate);
34 | AddCanonicalHeaderKeyValue("x-ms-version", MSVersion);
35 |
36 | if (headers == null) {
37 | return;
38 | }
39 |
40 | foreach (KeyValuePair header in headers) {
41 | if (header.Key.StartsWith("x-ms", StringComparison.OrdinalIgnoreCase)) {
42 | AddCanonicalHeaderKeyValue(header.Key, header.Value);
43 | }
44 | }
45 | }
46 |
47 | private void AddCanonicalHeaderKeyValue(string key, string value) {
48 | canonicalHeaders.Add(FormatKeyValue(key, value));
49 | }
50 |
51 | private string FormatKeyValue(string key, string value) {
52 | return string.Format("{0}:{1}", key, value);
53 | }
54 |
55 | public override string ToString() {
56 | //return string.Format ("x-ms-date:{0}\nx-ms-version:{1}\n", MSDate, MSVersion);
57 | canonicalHeaders.Sort();
58 | StringBuilder sb = new StringBuilder();
59 | foreach (string canonicalHeader in canonicalHeaders) {
60 | sb.Append(canonicalHeader + "\n");
61 | }
62 | return sb.ToString();
63 | }
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/http/query/ResType.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | namespace Azure.StorageServices {
5 | public enum ResType {
6 | container,
7 | blob
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/model/BlobResults.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Xml;
6 | using System.Xml.Serialization;
7 |
8 | namespace Azure.StorageServices {
9 | [Serializable]
10 | [XmlRoot("EnumerationResults")]
11 |
12 | public class BlobResults {
13 | [XmlAttribute("ServiceEndpoint")]
14 | public string ServiceEndpoint;
15 |
16 | [XmlAttribute("ContainerName")]
17 | public string ContainerName;
18 |
19 | [XmlArray("Blobs")]
20 | public Blob[] Blobs;
21 | }
22 |
23 | [Serializable]
24 | public class Blob {
25 | public string Name;
26 |
27 | [XmlElement("Properties")]
28 | public BlobProperties Properties;
29 | }
30 |
31 | [Serializable]
32 | public class BlobProperties {
33 | [XmlElement("Last-Modified")]
34 | public string LastModified;
35 |
36 | public string Etag;
37 |
38 | [XmlElement("Content-Length")]
39 | public string ContentLength;
40 |
41 | [XmlElement("Content-Type")]
42 | public string ContentType;
43 |
44 | [XmlElement("Content-Encoding")]
45 | public string ContentEncoding;
46 |
47 | [XmlElement("Content-Language")]
48 | public string ContentLanguage;
49 |
50 | [XmlElement("Content-MD5")]
51 | public string ContentMD5;
52 |
53 | [XmlElement("Cache-Control")]
54 | public string CacheControl;
55 |
56 | [XmlElement("Content-Disposition")]
57 | public string ContentDisposition;
58 |
59 | public string BlobType;
60 | public string LeaseStatus;
61 | public string LeaseState;
62 | public bool ServerEncrypted;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/model/ContainerResults.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Xml;
6 | using System.Xml.Serialization;
7 |
8 | namespace Azure.StorageServices {
9 | [Serializable]
10 | [XmlRoot("EnumerationResults")]
11 | public class ContainerResults {
12 | [XmlAttribute("ServiceEndpoint")]
13 | public string ServiceEndpoint;
14 |
15 | [XmlArray("Containers")]
16 | public Container[] Containers;
17 | }
18 |
19 | [Serializable]
20 | public class Container {
21 | public string Name;
22 |
23 | [XmlElement("Properties")]
24 | public ContainerProperties Properties;
25 | }
26 |
27 | [Serializable]
28 | public class ContainerProperties {
29 | [XmlElement("Last-Modified")]
30 | public string LastModified;
31 |
32 | public string Etag;
33 | public string LeaseStatus;
34 | public string LeaseState;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/model/ErrorResult.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3 |
4 | using System;
5 | using System.Xml;
6 | using System.Xml.Serialization;
7 |
8 | namespace Azure.StorageServices {
9 | [Serializable]
10 | [XmlRoot("Error")]
11 | public class ErrorResult {
12 | public string Code;
13 | public string Message;
14 | public string AuthenticationErrorDetail;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------