PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/aspclassiccompiler/AzureStoreAsp/Assets/StorageClient/RestHelpers.cs

#
C# | 503 lines | 367 code | 48 blank | 88 comment | 21 complexity | 82d8824207a53c85ec7713cc7cbef00c MD5 | raw file
Possible License(s): Apache-2.0, AGPL-3.0
  1. // ----------------------------------------------------------------------------------
  2. // Microsoft Developer & Platform Evangelism
  3. //
  4. // Copyright (c) Microsoft Corporation. All rights reserved.
  5. //
  6. // THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
  7. // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
  8. // OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
  9. // ----------------------------------------------------------------------------------
  10. // The example companies, organizations, products, domain names,
  11. // e-mail addresses, logos, people, places, and events depicted
  12. // herein are fictitious. No association with any real company,
  13. // organization, product, domain name, email address, logo, person,
  14. // places, or events is intended or should be inferred.
  15. // ----------------------------------------------------------------------------------
  16. //
  17. // <copyright file="RestHelpers.cs" company="Microsoft">
  18. // Copyright (c) Microsoft Corporation. All rights reserved.
  19. // </copyright>
  20. //
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Linq;
  24. using System.Text;
  25. using System.IO;
  26. using System.Net;
  27. using System.Diagnostics;
  28. using System.Globalization;
  29. using System.Collections.Specialized;
  30. using System.Web;
  31. using System.Xml;
  32. using System.Text.RegularExpressions;
  33. namespace Microsoft.Samples.ServiceHosting.StorageClient
  34. {
  35. namespace StorageHttpConstants
  36. {
  37. internal static class ConstChars
  38. {
  39. internal const string Linefeed = "\n";
  40. internal const string CarriageReturnLinefeed = "\r\n";
  41. internal const string Colon = ":";
  42. internal const string Comma = ",";
  43. internal const string Slash = "/";
  44. internal const string BackwardSlash = @"\";
  45. internal const string Space = " ";
  46. internal const string Ampersand = "&";
  47. internal const string QuestionMark = "?";
  48. internal const string Equal = "=";
  49. internal const string Bang = "!";
  50. internal const string Star = "*";
  51. internal const string Dot = ".";
  52. }
  53. internal static class RequestParams
  54. {
  55. internal const string NumOfMessages = "numofmessages";
  56. internal const string VisibilityTimeout = "visibilitytimeout";
  57. internal const string PeekOnly = "peekonly";
  58. internal const string MessageTtl = "messagettl";
  59. internal const string Messages = "messages";
  60. internal const string PopReceipt = "popreceipt";
  61. }
  62. internal static class QueryParams
  63. {
  64. internal const string SeparatorForParameterAndValue = "=";
  65. internal const string QueryParamTimeout = "timeout";
  66. internal const string QueryParamComp = "comp";
  67. // Other query string parameter names
  68. internal const string QueryParamBlockId = "blockid";
  69. internal const string QueryParamPrefix = "prefix";
  70. internal const string QueryParamMarker = "marker";
  71. internal const string QueryParamMaxResults = "maxresults";
  72. internal const string QueryParamDelimiter = "delimiter";
  73. internal const string QueryParamModifiedSince = "modifiedsince";
  74. }
  75. internal static class CompConstants
  76. {
  77. internal const string Metadata = "metadata";
  78. internal const string List = "list";
  79. internal const string BlobList = "bloblist";
  80. internal const string BlockList = "blocklist";
  81. internal const string Block = "block";
  82. internal const string Acl = "acl";
  83. }
  84. internal static class XmlElementNames
  85. {
  86. internal const string BlockList = "BlockList";
  87. internal const string Block = "Block";
  88. internal const string EnumerationResults = "EnumerationResults";
  89. internal const string Prefix = "Prefix";
  90. internal const string Marker = "Marker";
  91. internal const string MaxResults = "MaxResults";
  92. internal const string Delimiter = "Delimiter";
  93. internal const string NextMarker = "NextMarker";
  94. internal const string Containers = "Containers";
  95. internal const string Container = "Container";
  96. internal const string ContainerName = "Name";
  97. internal const string ContainerNameAttribute = "ContainerName";
  98. internal const string AccountNameAttribute = "AccountName";
  99. internal const string LastModified = "LastModified";
  100. internal const string Etag = "Etag";
  101. internal const string Url = "Url";
  102. internal const string CommonPrefixes = "CommonPrefixes";
  103. internal const string ContentType = "ContentType";
  104. internal const string ContentEncoding = "ContentEncoding";
  105. internal const string ContentLanguage = "ContentLanguage";
  106. internal const string Size = "Size";
  107. internal const string Blobs = "Blobs";
  108. internal const string Blob = "Blob";
  109. internal const string BlobName = "Name";
  110. internal const string BlobPrefix = "BlobPrefix";
  111. internal const string BlobPrefixName = "Name";
  112. internal const string Name = "Name";
  113. internal const string Queues = "Queues";
  114. internal const string Queue = "Queue";
  115. internal const string QueueName = "QueueName";
  116. internal const string QueueMessagesList = "QueueMessagesList";
  117. internal const string QueueMessage = "QueueMessage";
  118. internal const string MessageId = "MessageId";
  119. internal const string PopReceipt = "PopReceipt";
  120. internal const string InsertionTime = "InsertionTime";
  121. internal const string ExpirationTime = "ExpirationTime";
  122. internal const string TimeNextVisible = "TimeNextVisible";
  123. internal const string MessageText = "MessageText";
  124. // Error specific constants
  125. internal const string ErrorRootElement = "Error";
  126. internal const string ErrorCode = "Code";
  127. internal const string ErrorMessage = "Message";
  128. internal const string ErrorException = "ExceptionDetails";
  129. internal const string ErrorExceptionMessage = "ExceptionMessage";
  130. internal const string ErrorExceptionStackTrace = "StackTrace";
  131. internal const string AuthenticationErrorDetail = "AuthenticationErrorDetail";
  132. //The following are for table error messages
  133. internal const string DataWebMetadataNamespace = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
  134. internal const string TableErrorCodeElement = "code";
  135. internal const string TableErrorMessageElement = "message";
  136. }
  137. internal static class HeaderNames
  138. {
  139. internal const string PrefixForStorageProperties = "x-ms-prop-";
  140. internal const string PrefixForMetadata = "x-ms-meta-";
  141. internal const string PrefixForStorageHeader = "x-ms-";
  142. internal const string PrefixForTableContinuation = "x-ms-continuation-";
  143. //
  144. // Standard headers...
  145. //
  146. internal const string ContentLanguage = "Content-Language";
  147. internal const string ContentLength = "Content-Length";
  148. internal const string ContentType = "Content-Type";
  149. internal const string ContentEncoding = "Content-Encoding";
  150. internal const string ContentMD5 = "Content-MD5";
  151. internal const string ContentRange = "Content-Range";
  152. internal const string LastModifiedTime = "Last-Modified";
  153. internal const string Server = "Server";
  154. internal const string Allow = "Allow";
  155. internal const string ETag = "ETag";
  156. internal const string Range = "Range";
  157. internal const string Date = "Date";
  158. internal const string Authorization = "Authorization";
  159. internal const string IfModifiedSince = "If-Modified-Since";
  160. internal const string IfUnmodifiedSince = "If-Unmodified-Since";
  161. internal const string IfMatch = "If-Match";
  162. internal const string IfNoneMatch = "If-None-Match";
  163. internal const string IfRange = "If-Range";
  164. internal const string NextPartitionKey = "NextPartitionKey";
  165. internal const string NextRowKey = "NextRowKey";
  166. internal const string NextTableName = "NextTableName";
  167. //
  168. // Storage specific custom headers...
  169. //
  170. internal const string StorageDateTime = PrefixForStorageHeader + "date";
  171. internal const string PublicAccess = PrefixForStorageProperties + "publicaccess";
  172. internal const string StorageRange = PrefixForStorageHeader + "range";
  173. internal const string CreationTime = PrefixForStorageProperties + "creation-time";
  174. internal const string ForceUpdate = PrefixForStorageHeader + "force-update";
  175. internal const string ApproximateMessagesCount = PrefixForStorageHeader + "approximate-messages-count";
  176. internal const string Version = PrefixForStorageHeader + "version";
  177. }
  178. internal static class HeaderValues
  179. {
  180. internal const string ContentTypeXml = "application/xml";
  181. /// <summary>
  182. /// This is the default content-type xStore uses when no content type is specified
  183. /// </summary>
  184. internal const string DefaultContentType = "application/octet-stream";
  185. // The Range header value is "bytes=start-end", both start and end can be empty
  186. internal const string RangeHeaderFormat = "bytes={0}-{1}";
  187. }
  188. internal static class AuthenticationSchemeNames
  189. {
  190. internal const string SharedKeyAuthSchemeName = "SharedKey";
  191. internal const string SharedKeyLiteAuthSchemeName = "SharedKeyLite";
  192. }
  193. internal static class HttpMethod
  194. {
  195. internal const string Get = "GET";
  196. internal const string Put = "PUT";
  197. internal const string Post = "POST";
  198. internal const string Head = "HEAD";
  199. internal const string Delete = "DELETE";
  200. internal const string Trace = "TRACE";
  201. internal const string Options = "OPTIONS";
  202. internal const string Connect = "CONNECT";
  203. }
  204. internal static class BlobBlockConstants
  205. {
  206. internal const int KB = 1024;
  207. internal const int MB = 1024 * KB;
  208. /// <summary>
  209. /// When transmitting a blob that is larger than this constant, this library automatically
  210. /// transmits the blob as individual blocks. I.e., the blob is (1) partitioned
  211. /// into separate parts (these parts are called blocks) and then (2) each of the blocks is
  212. /// transmitted separately.
  213. /// The maximum size of this constant as supported by the real blob storage service is currently
  214. /// 64 MB; the development storage tool currently restricts this value to 2 MB.
  215. /// Setting this constant can have a significant impact on the performance for uploading or
  216. /// downloading blobs.
  217. /// As a general guideline: If you run in a reliable environment increase this constant to reduce
  218. /// the amount of roundtrips. In an unreliable environment keep this constant low to reduce the
  219. /// amount of data that needs to be retransmitted in case of connection failures.
  220. /// </summary>
  221. internal const long MaximumBlobSizeBeforeTransmittingAsBlocks = 2 * MB;
  222. /// <summary>
  223. /// The size of a single block when transmitting a blob that is larger than the
  224. /// MaximumBlobSizeBeforeTransmittingAsBlocks constant (see above).
  225. /// The maximum size of this constant is currently 4 MB; the development storage
  226. /// tool currently restricts this value to 1 MB.
  227. /// Setting this constant can have a significant impact on the performance for uploading or
  228. /// downloading blobs.
  229. /// As a general guideline: If you run in a reliable environment increase this constant to reduce
  230. /// the amount of roundtrips. In an unreliable environment keep this constant low to reduce the
  231. /// amount of data that needs to be retransmitted in case of connection failures.
  232. /// </summary>
  233. internal const long BlockSize = 1 * MB;
  234. }
  235. internal static class ListingConstants
  236. {
  237. internal const int MaxContainerListResults = 100;
  238. internal const int MaxBlobListResults = 100;
  239. internal const int MaxQueueListResults = 50;
  240. internal const int MaxTableListResults = 50;
  241. }
  242. /// <summary>
  243. /// Contains regular expressions for checking whether container and table names conform
  244. /// to the rules of the storage REST protocols.
  245. /// </summary>
  246. public static class RegularExpressionStrings
  247. {
  248. /// <summary>
  249. /// Container or queue names that match against this regular expression are valid.
  250. /// </summary>
  251. public const string ValidContainerNameRegex = @"^([a-z]|\d){1}([a-z]|-|\d){1,61}([a-z]|\d){1}$";
  252. /// <summary>
  253. /// Table names that match against this regular expression are valid.
  254. /// </summary>
  255. public const string ValidTableNameRegex = @"^([a-z]|[A-Z]){1}([a-z]|[A-Z]|\d){2,62}$";
  256. }
  257. internal static class StandardPortalEndpoints
  258. {
  259. internal const string BlobStorage = "blob";
  260. internal const string QueueStorage = "queue";
  261. internal const string TableStorage = "table";
  262. internal const string StorageHostSuffix = ".core.windows.net";
  263. internal const string BlobStorageEndpoint = BlobStorage + StorageHostSuffix;
  264. internal const string QueueStorageEndpoint = QueueStorage + StorageHostSuffix;
  265. internal const string TableStorageEndpoint = TableStorage + StorageHostSuffix;
  266. }
  267. }
  268. internal static partial class Utilities
  269. {
  270. internal static HttpWebRequest CreateHttpRequest(Uri uri, string httpMethod, TimeSpan timeout)
  271. {
  272. HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
  273. request.Timeout = (int)timeout.TotalMilliseconds;
  274. request.ReadWriteTimeout = (int)timeout.TotalMilliseconds;
  275. request.Method = httpMethod;
  276. request.ContentLength = 0;
  277. request.Headers.Add(StorageHttpConstants.HeaderNames.StorageDateTime,
  278. Utilities.ConvertDateTimeToHttpString(DateTime.UtcNow));
  279. return request;
  280. }
  281. /// <summary>
  282. /// Converts the date time to a valid string form as per HTTP standards
  283. /// </summary>
  284. internal static string ConvertDateTimeToHttpString(DateTime dateTime)
  285. {
  286. // On the wire everything should be represented in UTC. This assert will catch invalid callers who
  287. // are violating this rule.
  288. Debug.Assert(dateTime == DateTime.MaxValue || dateTime == DateTime.MinValue || dateTime.Kind == DateTimeKind.Utc);
  289. // 'R' means rfc1123 date which is what our server uses for all dates...
  290. // It will be in the following format:
  291. // Sun, 28 Jan 2008 12:11:37 GMT
  292. return dateTime.ToString("R", CultureInfo.InvariantCulture);
  293. }
  294. /// <summary>
  295. /// Parse a string having the date time information in acceptable formats according to HTTP standards
  296. /// </summary>
  297. internal static bool TryGetDateTimeFromHttpString(string dateString, out DateTime? result)
  298. {
  299. DateTime dateTime;
  300. result = null;
  301. // 'R' means rfc1123 date which is the preferred format used in HTTP
  302. bool parsed = DateTime.TryParseExact(dateString, "R", null, DateTimeStyles.None, out dateTime);
  303. if (parsed)
  304. {
  305. // For some reason, format string "R" makes the DateTime.Kind as Unspecified while it's actually
  306. // Utc. Specifying DateTimeStyles.AssumeUniversal also doesn't make the difference. If we also
  307. // specify AdjustToUniversal it works as expected but we don't really want Parse to adjust
  308. // things automatically.
  309. result = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
  310. return true;
  311. }
  312. return false;
  313. }
  314. /// <summary>
  315. /// Copies from one stream to another
  316. /// </summary>
  317. /// <param name="sourceStream">The stream to copy from</param>
  318. /// <param name="destinationStream">The stream to copy to</param>
  319. internal static long CopyStream(Stream sourceStream, Stream destinationStream)
  320. {
  321. const int BufferSize = 0x10000;
  322. byte[] buffer = new byte[BufferSize];
  323. int n = 0;
  324. long totalRead = 0;
  325. do
  326. {
  327. n = sourceStream.Read(buffer, 0, BufferSize);
  328. if (n > 0)
  329. {
  330. totalRead += n;
  331. destinationStream.Write(buffer, 0, n);
  332. }
  333. } while (n > 0);
  334. return totalRead;
  335. }
  336. internal static void CopyStream(Stream sourceStream, Stream destinationStream, long length)
  337. {
  338. const int BufferSize = 0x10000;
  339. byte[] buffer = new byte[BufferSize];
  340. int n = 0;
  341. long amountLeft = length;
  342. do
  343. {
  344. amountLeft -= n;
  345. n = sourceStream.Read(buffer, 0, (int)Math.Min(BufferSize, amountLeft));
  346. if (n > 0)
  347. {
  348. destinationStream.Write(buffer, 0, n);
  349. }
  350. } while (n > 0);
  351. }
  352. internal static int CopyStreamToBuffer(Stream sourceStream, byte[] buffer, int bytesToRead)
  353. {
  354. int n = 0;
  355. int amountLeft = bytesToRead;
  356. do
  357. {
  358. n = sourceStream.Read(buffer, bytesToRead - amountLeft, amountLeft);
  359. amountLeft -= n;
  360. } while (n > 0);
  361. return bytesToRead - amountLeft;
  362. }
  363. internal static Uri CreateRequestUri(
  364. Uri baseUri,
  365. bool usePathStyleUris,
  366. string accountName,
  367. string containerName,
  368. string blobName,
  369. TimeSpan Timeout,
  370. NameValueCollection queryParameters,
  371. out ResourceUriComponents uriComponents
  372. )
  373. {
  374. uriComponents =
  375. new ResourceUriComponents(accountName, containerName, blobName);
  376. Uri uri = HttpRequestAccessor.ConstructResourceUri(baseUri, uriComponents, usePathStyleUris);
  377. if (queryParameters != null)
  378. {
  379. UriBuilder builder = new UriBuilder(uri);
  380. if (queryParameters.Get(StorageHttpConstants.QueryParams.QueryParamTimeout) == null)
  381. {
  382. queryParameters.Add(StorageHttpConstants.QueryParams.QueryParamTimeout,
  383. Timeout.TotalSeconds.ToString(CultureInfo.InvariantCulture));
  384. }
  385. StringBuilder sb = new StringBuilder();
  386. bool firstParam = true;
  387. foreach (string queryKey in queryParameters.AllKeys)
  388. {
  389. if (!firstParam)
  390. sb.Append("&");
  391. sb.Append(HttpUtility.UrlEncode(queryKey));
  392. sb.Append('=');
  393. sb.Append(HttpUtility.UrlEncode(queryParameters[queryKey]));
  394. firstParam = false;
  395. }
  396. if (sb.Length > 0)
  397. {
  398. builder.Query = sb.ToString();
  399. }
  400. return builder.Uri;
  401. }
  402. else
  403. {
  404. return uri;
  405. }
  406. }
  407. internal static bool StringIsIPAddress(string address)
  408. {
  409. IPAddress outIPAddress;
  410. return IPAddress.TryParse(address, out outIPAddress);
  411. }
  412. internal static void AddMetadataHeaders(HttpWebRequest request, NameValueCollection metadata)
  413. {
  414. foreach (string key in metadata.Keys)
  415. {
  416. request.Headers.Add(
  417. StorageHttpConstants.HeaderNames.PrefixForMetadata + key,
  418. metadata[key]
  419. );
  420. }
  421. }
  422. internal static bool IsValidTableName(string name)
  423. {
  424. if (string.IsNullOrEmpty(name))
  425. {
  426. return false;
  427. }
  428. Regex reg = new Regex(StorageHttpConstants.RegularExpressionStrings.ValidTableNameRegex);
  429. if (reg.IsMatch(name))
  430. {
  431. return true;
  432. }
  433. else
  434. {
  435. return false;
  436. }
  437. }
  438. internal static bool IsValidContainerOrQueueName(string name)
  439. {
  440. if (string.IsNullOrEmpty(name))
  441. {
  442. return false;
  443. }
  444. Regex reg = new Regex(StorageHttpConstants.RegularExpressionStrings.ValidContainerNameRegex);
  445. if (reg.IsMatch(name))
  446. {
  447. return true;
  448. }
  449. else
  450. {
  451. return false;
  452. }
  453. }
  454. }
  455. }