vital.vim の Web.Http.request を使ってみた その2

  • ヘルプには記述が見当たらないが, 実行環境に curlwget がインストールされている必要がある.

get/post/request

get({url}, {param}, {header})           Vital.Web.Http.get()
post({url}, {param}, {header})          Vital.Web.Http.post()
request(...)                   Vital.Web.Http.request()

get/post に関しては request のラッパであり, request() が使えるようになればいい.

function! s:get(url, ...)
  let settings = {
  \    'url': a:url,
  \    'param': a:0 > 0 ? a:1 : {},
  \    'headers': a:0 > 1 ? a:2 : {},
  \ }
  return s:request(settings)
endfunction

function! s:post(url, ...)
  let settings = {
  \    'url': a:url,
  \    'data': a:0 > 0 ? a:1 : {},
  \    'headers': a:0 > 1 ? a:2 : {},
  \    'method': a:0 > 2 ? a:3 : 'POST',
  \ }
  return s:request(settings)
endfunction
client/command
        "client"        Default: "curl" or "wget" (executable one)
                HTTP client used for a request.

        "command"
                Command name for client.  You should use with "client".
  • 現状, "client" には "curl" か "wget" しか設定できない.
  • "command" は使い道がわからない. たとえば "curl" と全く同じ引数をとるコマンド "hoge" が存在するなら, 以下のように設定すればいいはずだが...
  • "command" は "client" へのフルパスを指定するのを想定しているらしい.
  {"client" : "curl", "command" : "hoge"} 
"maxRedirect"

manpage of curl
リダイレクト追跡回数の上限を指示します

    • wget は指定方法が間違っている気がする.
-   let command .= ' --max-redirect ' . a:settings.maxRedirect
+   let command .= ' --max-redirect=' . a:settings.maxRedirect
"param"

manpage of curl
指定したデータを GET リクエストとして HTTP サーバに送信します。

    • dictionary or string と書いてあるが, string は動作しない.
	"param"		Default: (None)
		Get parameters.  This is a string or a dictionary.
		If dictionary, it is converted to a string by
		|Vital.Web.Http.encodeURI()|.
    • "data" は対応しているのでバグだとおもう
-	let getdatastr = s:encodeURI(settings.param)
+	if s:Prelude.is_dict(settings.param)
+		let getdatastr = s:encodeURI(settings.param)
+	else
+		let getdatastr = settings.param
+	endif
"data"

manpage of curl
指定したデータを POST リクエストとして HTTP サーバに送信します。

    • curl で -d @filename のような @指定ができない?
    • PukiWiki.vim でのファイル添付はどうすんべよ
元のコマンドとの対応
Vital curl wget
maxRedirect --max-redirs --max-redirect
timeout --max-time --timeout
username/password --anyauth --user --http-user, --http-password
data --data-binary --post-file?
headers -H --header
復帰値

ヘルプに復帰値に関しての説明はほとんどない. 実行結果での比較

let g:VITAL = vital#of('vital')
let HTTP = g:VITAL.import('Web.Http')
echo HTTP.get("localhost")
{
   'status': 200, 
   'success': 1, 
   'header': [
       'Date: Tue, 07 May 2013 06:24:47 GMT', 
       'Server: Apache/2.2.22 (Ubuntu)', 
       'Last-Modified: Fri, 26 Feb 2010 10:31:14 GMT', 
       'ETag: "64d92-2d-4807e66192080"', 
       'Accept-Ranges: bytes', 
       'Content-Length: 45', 
       'Content-Type: text/html'
   ], 
   'statusText': 'OK', 
   'content': '<html><body><h1>It works!</h1></body></html>
'}
% telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 200 OK                             <== status, statusText
Date: Tue, 07 May 2013 06:30:25 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Fri, 26 Feb 2010 10:31:14 GMT
ETag: "64d92-2d-4807e66192080"
Accept-Ranges: bytes
Content-Length: 45
Connection: close
Content-Type: text/html

<html><body><h1>It works!</h1></body></html>
Connection closed by foreign host.
  • 一番問題なのは正常終了か異常終了かの確認方法が記述されていないこと.
    • HTTP から復帰がある場合には, "success", "status", "statusText" に値が設定される.
      • HTTP の status コードをみて, "success" に 0 (異常)または 1 (正常/200番台)が設定される.
    • たとえばネットワークエラーで web サーバに接続できなかったときには "success" は設定されない.
      • エラーメッセージも得られない. 何か異常があったことだけはわかる.
    • たとえば 302 が返ってきた場合にも 0 (異常)が設定される
      • あとから追加された "maxRedirect" の考慮不足かな. うちのせい?
  • "header" はヘッダ部の情報が一行ずつ文字列としてリストに格納される.
    • 解析には parseHeader を使うと良い

parseHeader

parseHeader({headers})                  Vital.Web.Http.parseHeader()
  • request/get/post 関数で得られるヘッダ部は「文字列のリスト」でそれを解析して辞書に変形する.
    • requst() 関数の処理を軽くするために別にしてあるのだと思う.
let g:VITAL = vital#of('vital')
let HTTP = g:VITAL.import('Web.Http')
let RET = HTTP.get("localhost")
echo HTTP.parseHeader(RET.header)
{
	'ETag': '"64d92-2d-4807e66192080"', 
	'Content-Type': 'text/html', 
	'Date': 'Tue, 07 May 2013 06:39:55 GMT', 
	'Accept-Ranges': 'bytes', 
	'Content-Length': '45', 
	'Last-Modified': 'Fri, 26 Feb 2010 10:31:14 GMT', 
	'Server': 'Apache/2.2.22 (Ubuntu)'
}

encodeURI/decodeURI

encodeURI({param})                      Vital.Web.Http.encodeURI()
decodeURI({str})                        Vital.Web.Http.decodeURI()

URL エンコード/デコードをする. まだ使っていない. ローカルの関数を呼び出し中. そのうち使う

encodeURIComponent

encodeURIComponent({str})               Vital.Web.Http.encodeURIComponent()

まだ使っていない. 使い道もしらない.

まとめ

差分

--- autoload/vital/__latest__/web/http.vim	2013-05-05 23:55:12.000000000 +0900
+++ autoload/vital/_3370e3e/web/http.vim	2013-05-07 22:12:02.000000000 +0900
@@ -116,7 +116,11 @@
     let settings.headers['Content-Type'] = settings.contentType
   endif
   if has_key(settings, 'param')
-    let getdatastr = s:encodeURI(settings.param)
+	if s:Prelude.is_dict(settings.param)
+		let getdatastr = s:encodeURI(settings.param)
+	else
+		let getdatastr = settings.param
+	endif
     if strlen(getdatastr)
       let settings.url .= '?' . getdatastr
     endif
@@ -194,7 +198,7 @@
   let command .= ' -O ' . a:quote . a:settings._file.content . a:quote
   let command .= ' --server-response -q -L '
   if has_key(a:settings, 'maxRedirect')
-    let command .= ' --max-redirect ' . a:settings.maxRedirect
+    let command .= ' --max-redirect=' . a:settings.maxRedirect
   endif
   let command .= s:_make_header_args(a:settings.headers, '--header=', a:quote)
   let timeout = get(a:settings, 'timeout', '')
@@ -210,7 +214,7 @@
   let command .= ' ' . a:quote . a:settings.url . a:quote
   if has_key(a:settings._file, 'post')
     let file = a:settings._file.post
-    let command .= ' --post-data @' . a:quote . file . a:quote
+    let command .= ' --post-file ' . a:quote . file . a:quote
   endif
 
   call s:Prelude.system(command)