unoh.github.com

ウェブアプリ開発を助けるGETコマンドを使ってハックしてみよう!!

Tue Feb 13 03:09:24 -0800 2007

2GBのSDカード買って意気揚々と歓迎会に突撃したらカメラごと持って帰るのを忘れて生きていくのがつらくなったjokagiです. ガジェットには名前と連絡先をお忘れなく.

さてウェブアプリケーションの開発をしていると当然ですがブラウザーで画面の確認をしたりしますが,ブラウザーで確認をしているとキャッシュに悩んだり面倒くさいことが少なくありません. 普通そういう時はtelnetなどで直接HTTPプロトコルでウェブサーバーと会話するわけですが面倒くさいですよね.

$ telnet www.yahoo.co.jp 80
Trying 203.216.231.160...
Connected to www.yahoo.co.jp.
Escape character is '^]'.
GET / HTTP/1.1
Host: www.yahoo.co.jp

HTTP/1.1 200 OK
Date: Tue, 13 Feb 2007 10:10:41 GMT
P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
Expires: -1
Pragma: no-cache
Cache-Control: no-cache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=euc-jp

10fff  
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
<!---->
(略)

jokagiは何年か前に偶然見つけたGETというコマンド(HEADもよく使う)を使用していますので,このコマンドの紹介と超簡単なハックをひとつ紹介したいと思います.

GETコマンドの使い方

GETコマンドの使い方は--helpしてみましょう.

$ GET --help
Unknown option: help
Usage: GET [-options] <url>...
    -m <method>   use method for the request (default is 'GET')
    -f            make request even if GET believes method is illegal
    -b <base>     Use the specified URL as base
    -t <timeout>  Set timeout value
    -i <time>     Set the If-Modified-Since header on the request
    -c <conttype> use this content-type for POST, PUT, CHECKIN
    -a            Use text mode for content I/O
    -p <proxyurl> use this as a proxy
    -P            don't load proxy settings from environment
    -H <header>   send this HTTP header (you can specify several)

    -u            Display method and URL before any response
    -U            Display request headers (implies -u)
    -s            Display response status code
    -S            Display response status chain
    -e            Display response headers
    -d            Do not display content
    -o <format>   Process HTML content in various ways

    -v            Show program version
    -h            Print this message

    -x            Extra debugging output

大体で言うと-m,-c,-p,-Hを覚えておくとよいです.後はDisplay~となっている系のオプション. 例えばhttp://www.yahoo.co.jp/のコンテンツを取得するのはこんな感じで行います.

$ GET 'http://yahoo.co.jp/' | head
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=euc-jp">
<!---->
<title>Yahoo! JAPAN</title>
<meta name="description" content="80??">
<style type="text/css" media="all">
<!--
.spacer { line-height: 110%; }
.spacer1 {line-height: 115%; }
URLを指定するときに「&」などが含まれるとshellの特殊記号として扱われるので注意してください. 大体はシングルクォートで囲む癖をつければ問題ないと思います.

GETを使うと簡単にコマンドラインでいろんなウェブ関連の処理ができます. 下記はgo-pear.org(pear.php.net)からPEARのインストーラーをダウンロードしてインストール作業を行う例です.

$ GET 'http://go-pear.org/' | php -q
Welcome to go-pear!

Go-pear will install the 'pear' command and all the files needed by
it.  This command is your tool for PEAR installation and maintenance.

Go-pear also lets you download and install the PEAR packages bundled
with PHP: MDB2.


If you wish to abort, press Control-C now, or press Enter to continue: 

ウェブサービスへのアクセスも簡単です. 下記はフォト蔵からキーワードmasatoで検索をする例です.

$ GET 'http://api.photozou.jp/rest/search_public?type=photo&order=date&keyword=masato' | head
<?xml version="1.0" encoding="UTF-8" ?>
<rsp stat="ok"
><info
><photo
><photo_id>2166156</photo_id
><user_id>137</user_id
><album_id>220281</album_id
><photo_title>P1140118</photo_title
><favorite_num>0</favorite_num
><comment_num>0</comment_num
指定URLにアクセスしてコンテンツを標準出力に出力する程度ならwgetでもできますが,標準ではファイルが作られるため,オプションを覚えなければいけません. 筆者はとても物覚えが悪いので,GETコマンドを覚える道を選択しました.

-m覚えようぜ!!といいつつ,実は-mに相当するコマンドがそれぞれHEAD,POSTとして用意されています.

$ rpm -qlf /usr/bin/GET | grep bin
/usr/bin/GET
/usr/bin/HEAD
/usr/bin/POST
/usr/bin/lwp-download
/usr/bin/lwp-mirror
/usr/bin/lwp-request
/usr/bin/lwp-rget

ようするにコマンド名イコールHTTPリクエスト方法(-mオプション)になります. ウェブアプリケーションでは通常GET,POST,HEADしか使わないので(HEADも開発中でもなければ使う機会は少ないかも),これだけで十分作業ができます(以後これらのコマンド群はまとめてGETコマンドとします).

GETコマンドはBasic認証に対応しているので,いちいちBasic認証情報をBase64エンコードしたりしなくてもいいことも特徴のひとつでしょう(ただし毎回認証情報を質問されるので,うっとおしければ-Hで自分で指定する必要があるかもしれません).また,基本的にキャッシュなどの機構はないので,ブラウザーで確認するほどキャッシュに振り回されることがありません.

また,HEADコマンドを使えば(HEADじゃなくてもできるけど)簡単にサーバー側からの送られてくるHTTPレスポンスヘッダーを確認することができます.

$ HEAD 'http://www.yahoo.co.jp/'
200 OK
Cache-Control: no-cache
Connection: close
Date: Tue, 13 Feb 2007 09:24:38 GMT
Pragma: no-cache
Content-Type: text/html; charset=euc-jp
Expires: -1
Client-Date: Tue, 13 Feb 2007 09:24:38 GMT
Client-Peer: 203.216.247.225:80
Client-Response-Num: 1
P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"

残念ながらGETコマンドも注意点があります.

この辺をうまく使うことでウェブサーバーを経由したユニットテストも可能になるかもしれません. またちょっとしたハックでWebDAVなどで必要なPROPFINDなどの対応もできるようになります. やり方はいくつかあると思いますが,jokagiは下記の手順でやってみました.

これでPROPFINDとして使用できるようになります. 下記はその実行例です.

$ PROPFIND http://192.168.0.1/webdav/foo.txt
Enter username for Authorization at 192.168.0.1:80: user
Password: 
<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:ns0="DAV:" xmlns:ns1="urn:schemas-microsoft-com:" xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
<D:href>/webdav/foo.txt</D:href>
<D:propstat>
<D:prop>
<ns1:Win32CreationTime>Wed, 13 Dec 2006 07:06:38 GMT</ns1:Win32CreationTime>
<ns1:Win32LastAccessTime>Wed, 13 Dec 2006 07:06:38 GMT</ns1:Win32LastAccessTime>
<ns1:Win32LastModifiedTime>Wed, 13 Dec 2006 07:06:38 GMT</ns1:Win32LastModifiedTime>
<ns1:Win32FileAttributes>00000000</ns1:Win32FileAttributes>
<lp1:resourcetype/>
<lp1:creationdate>2006-12-13T07:07:42Z</lp1:creationdate>
<lp1:getcontentlength>0</lp1:getcontentlength>
<lp1:getlastmodified>Wed, 13 Dec 2006 07:07:42 GMT</lp1:getlastmodified>
<lp1:getetag>"1ed52e-0-e08ab80"</lp1:getetag>
<lp2:executable>F</lp2:executable>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>text/plain</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>

コピーでなくシンボリックリンクでもいいのですが,パッケージのアップデートの影響をもろ受けること,/usr/bin/直下を直接いじりたくないと思ったからです. perlがわかる人はそんなことしなくてもさくさくうまいやりかたでやると思います(コメントとかトラックバックとかで情報ください).

通常はwgetやcurlでも問題ないかもしれませんが,GETコマンドはできることがシンプルなのですぐに使いこなせると思います. また,WebDAVを使う人は今回のハックはちょっと開発効率アップに貢献するかもしれません. 一度使うと常用するようになってしまうのでぜひお試しください. それではあでゅー.