- blogs:
- cles::blog
XML-RPCを使ってTracのチケットに添付ファイルを投げ込む(Ruby編)
以前に間に合わせで書いたTracにXML-RPCを投げるスクリプトがPerlだったのでRubyに書き換えようと思って作業を始めてみたら思ったより手間がかかってしまいました。
ブラウザはどちらも同じように認証用のダイアログを出してくるので分かりにくいのですが、TracLightningを使ってTracをインストールすると、認証はBasic認証ではなくてDigest認証になっています。このDigest認証をXML-RPC時にやるというのがかなりの曲者です。初めこれをすっかり忘れていて、XMLRPC::Clientを使って実装した後に認証が通らなくて色々調べる羽目になりました。
/usr/lib/ruby/1.8/xmlrpc/client.rb
If ((|user|)) and ((|password|)) are given, each time a request is send, a Authorization header is send. Currently only Basic Authentification is implemented no Digest.
上記の通り、rubyのXML-RPCライブラリであるXMLRPC::ClientはDigest認証に対応していません。
というか、僕の調べた限りではnet/httpなどのRubyの標準添付のライブラリでDigest認証に対応しているものはないようです。
† MechanizeはDigest認証できるようだ
とりあえず自分でDigest認証のルーチンを書きたくはないので、何か良いものがないかと思って検索して見ると下記のエントリを見つけました。
RubyのMechanizeでBASIC認証・Digest認証
require 'mechanize'
agent = WWW::Mechanize.new
require 'logger' # ログ出力用
agent.log = Logger.new($stdout) # ログ出力用
agent.auth('hogeuser','hogepasswd')
agent.get('http://www.example.com/authdir/')
とりあえずMechanizeがDigest認証できることは分かりましたが、MechanizeはPostのペイロードを任意の形式にするためのAPIがないので、「WWW::MechanizeでPOSTするデータを直接書くための野良拡張 - にたまごほうれん草」を参考にMechanizeにメソッドを追加してしまうことにしました。あと、XMLRPC::Clientで書いてしまった部分をそのまま使いたかったので、XMLRPC::ClientからリクエストのXMLを取り出すためのメソッドをXMLRPC::Clientに追加することにしました。
† 完成したコード
以前Perlで実装したtracAttachmentPost.plと同様の機能をRubyで書いてみたのが下記のスクリプト。
メソッドをアドホックに追加しているので、ちょっと汚いですが、とりあえず問題なく動作はします。
tracAttachmentPost.rb
require 'xmlrpc/client'
require 'logger'
require 'rubygems'
require 'mechanize'
require 'hpricot'
WWW::Mechanize.html_parser = Hpricot if WWW::Mechanize.html_parser
class XMLRPC::Client
def get_request(method, *args)
create().methodCall(method, *args)
end
end
module WWW
class Mechanize
def post_xmlrpc(url, data)
cur_page = Page.new( nil, {'content-type'=>'text/html'})
log.debug("data: #{ data.inspect }") if log
# fetch the page
page = fetch_page( :uri => url,
:referer => cur_page,
:verb => :post,
:params => [data],
:headers => {
'Content-Type' => 'text/xml',
'Content-Length' => data.size.to_s,
})
page
end
end
end
(ARGV[0] && ARGV[1] && ARGV[2]) || puts('usage: tracAttachPost.rb ##TicketID## ##AttachmentFile## ##Comment##') || exit(1)
ticket_id = ARGV[0].to_i
file_path = ARGV[1]
comment = ARGV[2]
user = 'username'
password = 'password'
uri = 'http://trachost/trac/project_name/login/xmlrpc'
client = XMLRPC::Client.new2( uri )
if File.exists?(file_path) then
basename = File.basename(file_path)
base64_content = XMLRPC::Base64.new(File.read(file_path))
begin
request = client.get_request "ticket.putAttachment", ticket_id, basename, comment, base64_content
agent = WWW::Mechanize.new
agent.auth(user, password)
page = agent.post_xmlrpc(uri, request)
# p page.body
rescue WWW::Mechanize::ResponseCodeError => e
p e
# p e.page
# p e.page.header
end
else
puts "#{file_path} not found"
end
† さらにDigest認証のバグにハマった
Mechanizeを使っているので、Digest認証がすんなり通るのかとおもいきや、それでもサーバから401が帰ってくるのでちょっと参りました。仕方がないので、Mechanizeが送信しているヘッダを眺めてみると、WWW-Authenticateヘッダのrealmとncの間にカンマが入っていないというバグでした。問題の部分については下記のようにちょっと書き換えています。
/usr/lib64/ruby/gems/1.8/gems/mechanize-0.9.0/lib/www/mechanize/chain
+++ auth_headers.rb 2009-12-12 05:17:07.000000000 +0900
@@ -68,7 +68,7 @@
"#{field}=\"#{params[field]}\""
}.compact.join(', ')
- header << "nc=#{'%08x' % @@nonce_count}, "
+ header << ", nc=#{'%08x' % @@nonce_count}, "
header << "cnonce=\"#{CNONCE}\", "
header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\""
ちなみにこのバグは、僕の使っているMechanizeが0.9.0だったのが原因のようです。
0.9.1のリリースノートには下記のような記述があるので、gemで最新板をインストールしていれば特に書き換えを行う必要はありません。
RubyのWWW::Mechanize 0.9.1 が出ました - きたももんががきたん。
Nonce count fixed for digest auth requests. Thanks Adrian Slapa!
このエントリへのTrackbackにはこのURLが必要です→http://blog.cles.jp/item/3330
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。
sp-20100319094743644595554@cles.net
- trac xmlrpc
- Yahoo! - 10/02/24 15:32:17
- ruby xml rpc
- Yahoo! - 10/02/19 09:35:32
- mechanize fetch_page 401
- Google - 10/02/18 18:09:27
- おめでとうございます (4)
- 知恵の輪 サターン編 (3)
- SourceForge.JPのSubversion... (3)
- サーバセットアップ (3)
- Thanks ! 10000 Hit ! (3)
- 和食 小錦 (3)
- .inはインドのccTLDなのか (3)
- 散髪しました (3)
- やっと髪をきりました (3)
- Waterfallプロセスに返れ? (3)
2 . やっぱりあった!パクれる読書感想文! [7583x]
3 . Echofon for Firefox [6355x]
4 . 急性胃腸炎 [5718x]
5 . OpenIDで自分のサイトのURLを使う [5717x]
- CD-ROM起動で、HDDを完全消去
- NP_Moblog v1.16
- pinzoro 01/15
- hsur 12/29
- and more...
- 耳がおかしいと思ったら突発..
- baca 01/13
- hsur 01/13
- and more...
★はてな認証APIをつかってログインすることができます。




