Azureの小ネタ (改)

~Azureネタを中心に、色々とその他の技術的なことなどを~

REST API でBlob 操作

Windows Azure Storage APIのベースはREST API なのですが、直接触ったことがなかったのちょっとトライしてみました。試してみたのは、一番簡単なファイルダウンロードというか取得。もちろんPublicコンテナではなく、PrivateコンテナなのでKeyのやりとりをしなくていけません。

API

ファイルをダウンロードするには、的には、以下のURLに書かれているGet Blobを行います。

リクエストはGETで、以下のURLに対して行います。

Method URI
GET http://myaccount.blob.core.windows.net/mycontainer/myblob

いくつか、リクエストヘッダを付けなければいけません。必死なのは、上から3つで、あとは任意です。

Request Header Description
Authorization 必須
Data or x-ms-date どちらか必須。こんな形式、Sun, 09 May 2011 22:36:25 GMT
x-ms-version 必須。Versioning for the Blob, Queue, and Table services in Windows Azure
Range 任意
x-ms-range 任意
x-ms-lease-id: 任意
x-ms-range-get-content-md5: true 任意

それらを1つのリクエストとして、Blobに投げてやるとファイルが取得できます。

取得部分

        static void Main(string[] args)
        {
            // BlobのURI
            string url = "http://xxx.blob.core.windows.net/hoge/fuga.txt";
            var req = (HttpWebRequest)WebRequest.Create(url);

            // GETする
            req.Method = "GET";

            // 必須ヘッダを付ける
            req.Headers.Add("x-ms-version", "2009-09-19");
            req.Headers.Add("x-ms-date" , DateTime.UtcNow.ToString("R", 
                             System.Globalization.CultureInfo.InvariantCulture));

            // ヘッダにサインする
            string authHeader = SignRequest(req);
            req.Headers.Add("Authorization", "SharedKeyLite " + AccountName + ":" + authHeader);

            // レスポンスを取得して、コンソールに表示。
            try
            {
                var res = req.GetResponse();
                var con = new System.IO.StreamReader(res.GetResponseStream()).ReadToEnd();
                Console.WriteLine(con);
            }
            catch (WebException e)
            {
                Console.WriteLine(e);
                Console.WriteLine(((HttpWebResponse)e.Response).StatusDescription);

            }
            Console.Write("Press ENTER to exit.");
            Console.ReadLine();
        }

Authorization

Authorizationヘッダを付加しなくてなりませんがコレが面倒くさい。スキーマの説明は以下のURL。

どうやら2つ付加する方法がって、普通の方法と、Liteな方法。

  • Shared Key Authentication
  • Shared Key Lite Authentication

普通の方法は、以下のヘッダをに対して署名する方法。必須ヘッダでないところは単に改行で構わない。


StringToSign = VERB + "\n" +
Content-Encoding + "\n"
Content-Language + "\n"
Content-Length + "\n"
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
If-Modified-Since + "\n"
If-Match + "\n"
If-None-Match + "\n"
If-Unmodified-Since + "\n"
Range + "\n"
CanonicalizedHeaders +
CanonicalizedResource;

もうちょとわかりやすくすると以下。\nと、/* */によるコメントは実際つかない。任意のヘッダは付けなくてもいいが改行が必要。


GET\n /*HTTP Verb*/
\n /*Content-Encoding*/
\n /*Content-Language*/
\n /*Content-Length*/
\n /*Content-MD5*/
\n /*Content-Type*/
\n /*Date*/
\n /*If-Modified-Since */
\n /*If-Match*/
\n /*If-None-Match*/
\n /*If-Unmodified-Since*/
\n /*Range*/
x-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\n
x-ms-version:2009-09-19\n /*CanonicalizedHeaders*/
/myaccount/myaccount/mycontainered\
ncomp:metadata\n
restype:container\n
timeout:20 /*CanonicalizedResource*/

Liteな方法は以下。署名に必要なヘッダが少なくなっている。


StringToSign = VERB + "\n" +
Content-MD5 + "\n" +
Content-Type + "\n" +
Date + "\n" +
CanonicalizedHeaders +
CanonicalizedResource;

以下、HttpWebRequestを入力して、署名するメソッド。Programming Windows Azure (洋書)を参考にさせていただいた。詳細は原著を当っていただきたい。

        static string SignRequest(HttpWebRequest request)
        {
            StringBuilder stringToSign = new StringBuilder();
            //1行目 Verbを付ける。  GET/PUT/POST
            stringToSign.Append(request.Method + "\n");

            //2行目。Content-MD5 を付ける。任意なので、無ければ改行
            stringToSign.Append("\n");

            //3行目。Content-Typeを付ける。リクエストから取り出す
            stringToSign.Append(request.ContentType + "\n");

            //4行目 Date。x-ms-dateがあるので、改行だけでかまわない。
            stringToSign.Append("\n");


            // x-ms で始るも取り出す
            List<string> httpStorageHeaderNameArray = new List<string>();
            foreach (string key in request.Headers.Keys)
            {
                if (key.ToLowerInvariant().StartsWith("x-ms", StringComparison.Ordinal))
                {
                    httpStorageHeaderNameArray.Add(key.ToLowerInvariant());
                }
            }

            // ソートする
            httpStorageHeaderNameArray.Sort();

            // key : value の形式
            foreach (string key in httpStorageHeaderNameArray)
            {
                stringToSign.Append(key + ":" + request.Headers[key] + "\n");
            }

            // 最後に CanonicatlPathを付ける。/アカウント名/リクエストURI 
            stringToSign.Append("/" + AccountName + request.RequestUri.AbsolutePath);

            // UTF8 => Byte変換
            byte[] dataToMAC = System.Text.Encoding.UTF8.GetBytes(stringToSign.ToString());
            var skey = Convert.FromBase64String(AccountKey);
            Console.WriteLine(stringToSign);
            using (var hmacsha256 = new System.Security.Cryptography.HMACSHA256(skey))
            {
                return Convert.ToBase64String(hmacsha256.ComputeHash(dataToMAC));
            }
        }

実際に、stringToSignには、以下のような値がはいり、それに対して署名が行われます。


GET



x-ms-date:Tue, 05 Apr 2011 14:22:59 GMT
x-ms-version:2009-09-19
/xxx/hoge/fuga.txt

結局は、以下の計算を行って署名を作らなければならないということになります。


Signature=Base64(HMAC-SHA256(UTF8(StringToSign)))

実行結果

実行結果をFiddlerでキャプチャすると正しく動いているのか否かが切り分けしやすい。

まとめ

REST APIは面倒くさい。.NETな人は、素直にStorage Client Libraryを使った方がよいと思われる。
これをC++でというのは、ちょいとハードル高いのだろうな(ぼそっ)

参考にしたよう洋書はコレ。電子版を安くかいました。

Programming Azure

Programming Azure

和書は、最近でたこれですかね。

プログラミング Windows Azure

プログラミング Windows Azure

  • 作者: Sriram Krishnan,安納順一(監訳),砂金信一郎(監訳),佐藤直樹(監訳),関田文雄(監訳),野村一行(監訳),玉川竜司
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2011/02/28
  • メディア: 大型本
  • 購入: 2人 クリック: 27回
  • この商品を含むブログ (1件) を見る