ブログ執筆中 このページをアンテナに追加

2008-02-13

[]C#ではてなブックマークのポストができなくて参ってる

まさかこんな所で詰まるとは思ってなかった。C#でWSSE認証クライアントで見たGET用のソースを元に、はてなブックマークに投稿するコードを組んでみたんですが、ステータスコード 417を返しやがりました。417 Expectation Failedってなんだよぉ・・・

ブログを見てくださっている方で、C#に詳しい方がいらっしゃるならば、どこが間違っているか教えていただけないでしょうか。

以下がエラー吐くコードです。

using System;
           using System.Collections.Generic;
using System.Text;
using System.Net;
            using System.Security.Cryptography;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            string username = "user" ;
            string password = "pass";
            string postURI = "http://b.hatena.ne.jp/atom/post";
            string uri = "http://d.hatena.ne.jp/tomity/20080213/1202883980";
            string comment = "comment";

            string entry = "<entry xmlns=\"http://purl.org/atom/ns#\">"
+ "<title>dummy</title>"
+ "<link rel=\"related\" type=\"text/html\" href=\"" + uri + " \" />"
+ "<summary type=\"text/plain\">" + comment + "</summary>"
+ "</entry>";
            byte[] data = Encoding.ASCII.GetBytes(entry);

            // nonce(HTTPリクエスト毎に生成したセキュリティ・トークン)の作成 <- ランダムな文字
            byte[] nonceB = new byte[8];
            new Random().NextBytes(nonceB);


            // Created(Nonceが作成された日時をISO-8601表記で記述したもの)
            string created = DateTime.Now.ToString("u").Replace(' ', 'T');
            byte[] createdB = Encoding.UTF8.GetBytes(created);

            // PasswordDigest(Nonce, Created, パスワードを文字列連結し
            // SHA1アルゴリズムでダイジェスト化して生成された文字列を、
            // Base64エンコードした文字列)
            byte[] passwordB = Encoding.UTF8.GetBytes(password);
            SHA1Managed sha1 = new SHA1Managed();
            sha1.Initialize();
            byte[] v = new byte[nonceB.Length + createdB.Length + passwordB.Length];
            Array.Copy(nonceB, 0, v, 0, nonceB.Length);
            Array.Copy(createdB, 0, v, nonceB.Length, createdB.Length);
            Array.Copy(passwordB, 0, v, nonceB.Length + createdB.Length, passwordB.Length);
            byte[] digest = sha1.ComputeHash(v);

            // WSSE認証用のヘッダを作成
            string format = "UsernameToken Username=\"{0}\", PasswordDigest=\"{1}\", Nonce=\"{2}\", Created=\"{3}\"";
            string wsseHeader = string.Format(format, username, Convert.ToBase64String(digest), Convert.ToBase64String(nonceB), created);

            // リクエストの送信と結果の取得
            string res = string.Empty;
            System.Net.HttpWebRequest webreq = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(postURI);
            webreq.Method = "POST";
            webreq.Headers.Add("Authorization", "WSSE profile=\"UsernameToken\"");
            webreq.Headers.Add("X-WSSE", wsseHeader);
            webreq.Accept = "application/x.atom+xml, application/xml, text/xml, */*";
            webreq.ContentType = "application/x.atom+xml, application/xml, text/xml, */*";
            webreq.ContentLength = data.Length;

            //2008/02/15追記
            ServicePoint currentServicePoint = webreq.ServicePoint;
            if (currentServicePoint == null) {
               WebProxy proxy = WebProxy.GetDefaultProxy();
               currentServicePoint = ServicePointManager.FindServicePoint(postURI, proxy);
            }
            currentServicePoint.Expect100Continue = false;
            //追記分ここまで

            Stream reqStream = webreq.GetRequestStream();
            reqStream.Write(data, 0, data.Length);
            reqStream.Close();

            System.Net.HttpWebResponse webres = (System.Net.HttpWebResponse)webreq.GetResponse();
            System.IO.Stream st = webres.GetResponseStream();
            System.IO.StreamReader sr = new System.IO.StreamReader(st);
            res = sr.ReadToEnd();
            sr.Close();
            st.Close();
        }
    }
}

追記

http://q.hatena.ne.jp/1202997886 で回答を募集しています。正しければはてなポイント500ポイントを進呈します。

追記2

原因は、はてながステータスコード100 continueをサポートしていないことでした。上記ソースに手を加え動くようにしました。

kazuki_cchokazuki_ccho 2008/11/08 22:22 参考にさせて頂きました。ありがとうございました。

私が組み込んだ時に1点うまくいかなかった部分がありましたので連絡します。

byte[] data = Encoding.ASCII.GetBytes(entry);

ではなく、

byte[] data = Encoding.UTF8.GetBytes(entry);

ではないでしょうか?

ASCIIだと、コメントが???になってしまいました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証