Block Rockin’ Codes

back with another one of those block rockin' codes

なぜ html の form は PUT / DELETE をサポートしないのか?

注意

内容については一切保証しません。

ここでは、主に W3C ML での議論や各種仕様などに基づいて書いています。 ここに書かれていることが正しいかどうかは、自身で判断して下さい。 事実としておかしいところなどは、コメントでどんどん指摘して下さい。遠慮はいりません。

ただし、このエントリでは「form が PUT/DELETE をサポートするべきかどうか?」の議論はしません。 「REST の是非」や「PUT/DELETE の意義」についても議論する気はありません。 ここでやっているのは、あくまでもどういった議論の末現状があるのかの調査です。 そうした意見がある場合は、 W3C などに投稿するのが最も有益だと思います。

History

  • 2014/03/29: 公開
  • 2014/03/29: XForm と XHTML の関係を明確化(thanx koichik)
  • 2014/03/29: HTTP/1.1 と XHTML1.1 の時間関係を明確化、それにより HTML3.2 の項は大幅修正 (thanx koichik)
  • 2014/04/09: HTML Form Extension のサンプルを追加
  • 2014/04/10: Cameron 氏とのメールやり取りの結果、「今後」がわかったので追記
  • 2014/04/10: 関連エントリをリンク

Intro

HTML の Form は「歴史的経緯」だとか「セキュリティ的な理由」
により GET と POST しかサポートしない、
というよう分かったような分からないような説明はよく見るけど、
実際は何故なのか。

というのが話の始まりで、それを事あるごとに調べようとするけれど、よくわからずにいました。

ということで呟いてみたところ、色々な方から反応を頂きました。 その反応については、以下にまとめています。

なぜ html の form は PUT / DELETE をサポートしないのか? - Togetterまとめ

f:id:Jxck:20140329075224p:plain

わかったことは、過去についてはそこまではっきりと書かれたリソースはなさそうなこと。 そして、色々な条件が重なって、現在の仕様に落ちつているようであること。 また、新しい仕様についての提案はあり、議論はまだ続いているということ。

ここまでの話をあらためて調べて、まとめてみました。

前提

今回話題にしたいのは、 HTML の form の仕様が HTTP のメソッドの "GET", "POST" 部分しかサポートしていない理由です。

具体的には以下の method 属性です。

<form action="http://example.com/users" method="post">
   <label for="name">name: </label>
   <input type="text" id="name">
   <input type="submit" value="send">
</form>

HTTP/1.1 では、メソッドとして以下の 8 つを定義しています。

GET
POST
PUT
DELETE
HEAD
OPTIONS
TRACE
CONNECT

この中で実質リソースの操作に用いられるのは GET, POST, PUT, DELETE の 4 つです。

REST の考え方が普及して以降は、この 4 つのメソッドを用いてリソースの操作を実行する API を提供するサービスも増え、プログラム間の通信や、 Ajax を用いたリクエストでは PUT/DELETE を用いた操作は実際に行われています。

しかし、 HTML の Form は GET/POST 以外をリクエストすることができません。 そこで現状は、 POST リクエストに hidden 属性で _method パラメータを付与したり、 submit イベントを JavaScript でフックして、 Ajax で PUT/DELETE リクエストを代行するなどの方法で回避されています。

時系列

今回の件は、仕様の時系列にも関係があるので、まとめてみました。 各仕様は、 IETF, W3C などそれぞれのワークフローで更新されており、下記はその主だったバージョンのみを載せています。 

仕様(HTTP)

HTTP の各仕様を見てみます。

PUT/DELETE という method が最初に出てきたのは HTTP/1.0 です。

http://tools.ietf.org/html/rfc1945#appendix-D.1

これは、 appendix の Additional Request Methods 扱いです。 ここでは PUT, DELETE, LINK, UNLINK があり、独自拡張としてこれらのメソッドの実装があったため、その注意を促す目的だったようです。(実際どの実装だったのかは、わかりません。)

HTTP/1.1 からは intro で紹介した 8 つのメソッドが定義され、 PUT, DELETE は正式な HTTP メソッドになりました。

仕様(HTML)

HTML の各仕様を見てみます。いずれも Form の method には GET/POST しか定義されていません。

HTML3.2 http://www.w3.org/TR/REC-html32#form

method
When the action attribute specifies an HTTP server,
the method attribute determines which HTTP method
will be used to send the form's contents to the server.
It can be either GET or POST, and defaults to GET.

HTML4.0 http://www.w3.org/TR/1998/REC-html40-19980424/interact/forms.html#adef-method

HTML4.01 http://www.w3.org/TR/html401/interact/forms.html#adef-method

method = get|post [CI]
This attribute specifies which HTTP method
will be used to submit the form data set.
Possible (case-insensitive) values are
"get" (the default) and "post".
See the section on form submission
for usage information.

HTML5 http://www.w3.org/TR/html5/forms.html#attr-fs-method

The method and formmethod content attributes are
enumerated attributes with the following keywords and states:

The keyword get, mapping to the state GET,
indicating the HTTP GET method.

The keyword post, mapping to the state POST,
indicating the HTTP POST method.

HTML3.2

HTML3.2 のドラフトには、参照する HTTP のバージョンは明記されていないようです。 しかし、 HTTP/1.1 が出たのは HTML3.2 のたった 2 週間前であるため、現実的には HTTP/1.0 を参照していたとかんがえるのが妥当でしょう。

少なくとも、その 2 週間の間で PUT/DELETE の存在を意識した上で HTML3.2 の仕様に取り込まなかったというよりは、 PUT/DELETE の存在は一旦おいておき HTTP/1.0 ベースで HTML3.2 の仕様を(ほとんど決まっていたものを)出したという方が自然だと考えられます。

PUT/DELETE にしても、 HTTP/1.0 から存在はしており、それを HTTP/1.1 で採用するかは 1996 年後半ではもう議論に上がっていただろうし、 HTML3.2 の議論をしている側も完全に知らなかったということは無いでしょう。

ここは、 HTML3.2 は HTTP/1.0 をベースとし、 HTTP/1.1 への追従は後のバージョンで行う。 とするのが妥当な判断だっただろうと想像できます。

よって、問題は次のバージョン HTML4 に移ります。

HTML 4.0, 4.01

HTML4.0 からは、 HTTP/1.1(RFC2068) への参照が明示されています。つまりここからが HTTP/1.1 を前提に Form に PUT/DELETE を入れないことを選択したドラフトと言えるでしょう。

http://www.w3.org/TR/1998/REC-html40-19980424/references.html#ref-RFC2068

HTML4.0 は HTTP/1.1 が出てから 11 ヶ月後、 HTML4.01 は 2 年空いています。 しかし、該当部分の仕様はいずれのバージョンも変更がありません。

ここの期間には謎が多く、実際に「Form に PUT, DELETE を入れるべきか?」という議論が、あったのかどうかもわかりません。(見つけられませんでした、見つけた方は教えて下さい)

しかし、この時代(1997~1999) は、まだ WebDAVAjax、 REST の論文などは出ておらず、 PUT/DELETE によって何かを行うという需要がそこまで強くなかったのでは無いかと考えられます。

また、1997/4/4 には、 Apache HTTP Server の開発者から Apache HTTP Server に PUT を実装する場合の、セキュリティ的なリスクや、それを回避するために試行錯誤した結果が紹介されています。

Publishing Pages with PUT

ここで紹介されている手法は、あくまで「新規文書をサーバに置く(PUT)」というユースケースであり、Netscape Navigator Gold, AOLPress, Amaya という、オーサリング機能を備えた当時のブラウザが PUT をサポートしたことが読み取れます。

Apache でもまだ、実装の面でそこまでこなれていなかったことや、 Web ページの編集という、今の Ajax などと比べると限定的なユースケースからも、 PUT というものが、まだそこまで広く使われていたものではなかっただろうことが想像できます。

なお、当時ブラウザの開発に携わっていた @ さんにお聞きしたところ、やはり積極的な人がいなかったという雰囲気だったようです。

XForms

HTML では、仕様に取り込まれることがなかった PUT/DELETE ですが、実は XForms という仕様には 1.0 で PUT が、 1.1 で DELETE が追加されていました。(XForms 1.0 には 2nd, 3rd Edition がありますが、該当部は変わっていません。)

  • 2003/11/14: XForms 1.0 (GET, POST, PUT)
  • 2009/10/20: XForms 1.1 (GET, POST, PUT, DELETE)
  • 20xx/xx/xx: XForms 2.0(策定中) (GET, POST, PUT, DELETE)

XFormsXML を用いて、よりリッチな機能を持つ Form を実装するための仕様です。 XHTML2.0 には XForms が含まれる予定だったため、 XHTML2.0 が主流となっていればそれが使えたかもしれません。 しかし、 XHTML2.0 は策定活動が 2012/12/17 で終了しました。また XForms を実装しているブラウザは無いため、これらの機能は使うことができません。

HTML5

2010 年に、 HTML5 の仕様として、以下のスレッドでこの件に関する議論が行われました。 issue は HTTP の策定活動にもコミットしている Julian Reschke 氏です。

Bug 10671 - consider adding support for PUT and DELETE as form methods

これは Ajax が主流になって以降であり、かつ Rails などを中心に REST が普及した後です。 しかし、問題の提起は「Form に PUT/DELETE を入れよう!」という短絡的なものではなく、より慎重なもののようです。 Julian 氏の発言の一部を抜粋します。

#c0(最初の発言)

It seems that we currently do not understand how
PUT and DELETE will be useful for HTML forms.

For DELETE, it's indeed easy to create a useful request.
However, server implementations usually respond with 200
and a minimal response body ("deleted")
or 204 (no content).
So it's not clear how this can be used in a web application.

For PUT, it seems there's no real use case as long as
the web page doesn't have full control
over the payload, and also can set the content type.

Please consider removing this feature until there's a clearer
understanding about what it's good for.

#c5

The tricky question is how to actually *use*
PUT and DELETE with HTML forms.
The bug was raised because I think the spec (as it was back then)
wasn't specific enough to make this work,
and thus early adoption (such as in FF4) would
make it very hard to do the right thing later on.

PUT や DELETE を Form でサポートする前に、サーバとのインタラクションや Form では HTTP ヘッダなどが変更できない点につていて、まだ Form の仕様自体にキチンと解決すべき問題があるという、問題提起が主のようです。

しかし、この議論は Hixie こと Ian Hickson によって突然 Reject されます。

#c16

Status: Rejected
Change Description: no spec change
Rationale: PUT as a form method makes no sense,
you wouldn't want to PUT a form payload.
DELETE only makes sense if there is no payload,
so it doesn't make much sense with forms either.

DELETE はペイロードを必要としないし、 Form のデータを PUT したいわけではない。 Form でこれらをやるのは make no sense であるとしています。いわゆる Wont' Fix という感じです。 2011/12/2 のことでした。

HTML Working Group

ところが、この議論は 2011/12/7 に public-html-comments という別の ML で再発します。

Follow-up about PUT and DELETE in form methods

どうやら ML 初心者のようで「先週のあの議論、どうなったの?」という感じの質問です。 しかも、 bug 10671 で一度も指摘されていなかった Mike Amundsen という人の以下のドラフトが参照されています。書かれたのは 2011/4/1 、つまり 10671 の議論の最中ですね。

Supporting PUT and DELETE with HTML FORMS

この Follow-up about PUT and DELETE in form methods はかなり長い議論になり、そこでは具体的な仕様に落としこむために必要な Form の拡張などについて議論されていたようです。

それがひと通り終わった 2012/1/14 に Julian 氏は HTML Working Group に二つの issue を上げます。

タイトルの通り、 HTML の Form を HTTP のリクエストに対して拡張するための議論と、 HTTP のレスポンスに対するユーザエージェントの挙動についての議論です(こちらは、前段としてブラウザごとの挙動の調査もあります)。

いずれの issue も CLOSE されており、 ISSUE-195 については以下の結果がみつかりました。

前者は Cameron Jones 氏のもので、 Form を拡張する提案(proposal) がなされています。 後者は Edward Oconnor 氏のもので、 Cameron 氏の提案の複雑性や実装時の懸念などを指摘しているようです。

また ISSUE-196 の最後 で Cameron 氏はこの提案をより具体化した Unofficial Draft を 2013/2/22 に作成し Github で公開しています。

HTML Form HTTP Extensions

このドラフトが、現時点で追えた最後の議論の結果です。少し見てみます。

HTML Form HTTP Extensions

http://cameronjones.github.io/form-http-extensions/index.html

このドラフトでは、 Form から、生成される HTTP リクエストをより柔軟に変更できるように Form の拡張を行う仕様です。 PUT/DELETE のサポートという狭い範囲ではなく、本質的に Form に足りていなかった機能を拡張しています。

たとえば payload 属性を追加することで、 Form から HTTP のヘッダ情報を追加できるようにすることで、単に method が PUT/DELETE その他をサポートするだけでは解決できなかった問題にも対応できるようにしています。

ドラフト中の PUT と DELETE のサンプルを見てみます。

<form action="http://www.example.com/cms/hogmanay" method="PUT">
  <input name="If-Unmodified-Since"
         type="hidden"
         value="Tue, 1 Jan 2013 12:00:00 GMT"
         payload="_header"/>
  <textarea name="content">
    // content
  </textarea>
  <button type="submit">Update</button>
</form>
<form action="http://www.example.com/logs" method="DELETE">
  <label for="since">Since</label>
  <input name="since" type="datetime"/>
  <button type="submit">Delete</button>
</form>

DELETE は割りとそのままな感じですが、 PUT は input タグの payload 属性を用いて直接 HTTP ヘッダを追加しています。

他にも、ヘッダを触れるということは Bacis 認証が Form だけで(ブラウザ組み込みの UI ではなく)できます。 実際には、専用の username, password を使用します。

<form action="http://www.example.com/login" method="POST">
    <label for="_username_">Username</label>
    <input name="_username_" type="text"/>
    <label for="_password_">Password</label>
    <input name="_password_" type="password"/>
    <button type="submit">Login</button>
</form>

また、メールの送信も定義されているようです。

<form action="mailto:">
    <label for="to">To</label>
    <input name="to" type="email" payload="_action"/>

    <label for="cc">Cc</label>
    <input name="cc" type="email" payload="_header"/>

    <label for="bcc">Bcc</label>
    <input name="bcc" type="email" payload="_header"/>

    <label for="subject">Subject</label>
    <input name="subject" type="text" payload="_header"/>

    <label>Content</label>
    <textarea size="50"/>

    <button type="submit">Send</button>
</form>

結構な拡張ですね。

今後

Cameron 氏のドラフト以降、この議論は止まっているようで、特に 2013年後半くらいからの議論は見つかりませんでした。 現状どうなっているのかがわからず、 Cameron 氏のドラフトについても扱いがよくわからなかったため、本人にメールで質問をしてみました。

いきなりの質問でもそこは標準化ガイ、快く返してくれました。 それによると、以下のような感じ。

  • このドラフト自体は、完成している(出せる状態である)という認識。
  • HTMLWG への提出はまだしてないけど、もう少し頑張ってそこまでもっていきたい。
  • 近いうちに FPWD(First Public Working Draft) として ML に提出する予定。
  • HTML5.0 の策定プロセスに乗せて、実際には HTML5.1 あたりで入れたい。

ということで、近いうちにこのドラフトが ML に投稿されて、そこでまた今回の話を含めた Form というもの自体の今後についての議論が起こることと予想されます。 Cameron 氏は、投稿時には BBC に自分を入れてくれるとのことなので、動きがあったらまたここにアップデートを書きたいと思います。

まとめ

まとめると、以下のような感じかと思います。

  • HTML4.x 以前: 需要があまりなく、積極的に仕様に追加する人もおらず、 HTTP3.2 からの仕様を引き継いでいた。
  • XForms: 仕様には取り込んだが、それを含む予定だった XHTML2.0 の策定が終了し、普及しなかった。
  • HTML5: 議論は何度かあり、現在 Cameron 氏のドラフトあたりが有力で、これはそのうち ML に投げられる模様。
  • HTML5.1?: Cameron 氏のドラフトが議論され、承認されればこの辺で入るかもしれない。入らない可能性は大いにあると思われる。

Cameron 氏のドラフトについて意見がある場合は、 W3C の ML などを通じて Cameron 氏にフィードバックすることで、今後の議論に寄与することができると思います。

最後に、再度書きますが、もし何か間違いなどがあったら遠慮なく指摘して下さい。 必要なものについては追記し、アップデートします。

今回の調査にご協力いただいた皆様、本当にありがとうございました!

関連リンク

Jxck

「Web を支える技術」記念トークセッション行ってきました

(編集:ご本人のブコメによりサインの写真を自重)

RESTを知ったきっかけが、http://yohei-y.blogspot.com/:yoheiさんだった人は少なくないと思います。
その山本陽平さんによる、WEB関連の技術の本が出版されまして、そのトークイベントに参加させて頂きました。


本はこれ
amazon:Web を支える技術 -HTTP、URI、HTML、そしてREST


場所は池袋のジュンク堂です。
yoheiさんとid:t_wadaさんによるトークショーであった訳ですが、和田さんのトークの運びがとてもうまく、陽平さんの興味深い話が色々聞けました。
ustもやっていたので、今見られるか分かりませんが、あったら是非見てみると、その場限り(ustしてたらそうはならんが)の裏話やt_wadaの名言(迷言)も聞くことが出来ます。


自分は、あらかじめ一読してから行くということが出来なかったので、ぱらぱらと捲った程度の予備知識での参加だったため、とりあえずメモりながら聞いていました。


トークセッションでは、本全体のコンセプトを和田さんの作成したマインドマップで俯瞰し、そのあと各章について和田さんが要約し、それについて陽平さんに問いかけながら進められました。


自分はまだ読みたかった2,3,4,6,15章の途中、までしか読んでいませんが、トークで出た話も会わせて少し紹介します。

レビュアとして胸を張って言えることは、この本はこれからの時代の教科書になるだろうということです。

引用ですが、そのまま見出しにしました。山本陽平著『Webを支える技術 ── HTTP、URI、HTML、そしてREST』刊行記念トークセッションのおしらせ - t-wadaの日記の中で、和田さんが書いている言葉です。


上記の言葉の通り、この本は色んな意味で「技術者のためのWebについての教科書」だなぁと思います。


"Web"という言葉がつく本ですが、後ろに"2.0"とか"デザイン"とか"アプリケーション"ではなく、"支える技術"とついているところからも分かるように、Webの上での話じゃなくてその"Web"という土台についての技術や概念等がまとめられた本です。


その代表として「HTTP,URI,HTML, そしてREST」が選ばれ、5部17章にまとめられたという感じでしょうか。
もちろん陽平さんの本なのでRESTの話は随所に出てきます。ただトークショーでも言ってましたが「全体に一貫してRESTがあるので、特に部立てはしていない。」ということで、RESTという部はなく、1部3章にアーキテクチャスタイルとして紹介されている形になっています。


ただし5部の「Webサービスの設計」はリソース指向のアプローチが中心になっているので、その部の内容は陽平さんをご存知なら想像には難くないかと思います。


この章はそこまでの知識をまとめて応用する上での実践的な内容なので、その意味でもただのリファレンスで終わらない「教科書」って感じがします。

キーワード

twitterにつぶやいたりメモを取ったなかから、いくつかキーワードから抜き出してみます。

ハイパーメディア

和田「ハイパーメディアって何ときかれたら?」
陽平「リンクが重要なんだ!」

Webは分散システム

「恐らく世界一巨大で、もっとも成功した分散システムなのに、案外その点が意識されていない。」

URI

URIがすばらしかったのは、アドレス可能性」

Cool URI

「シンプルな名詞にする。メソッド名を入れない。拡張子は使っちゃいけ無い訳じゃ無い。そして変わらないこと。」

HTTP

バッドノウハウの固まり、特に文字コード


T氏 「常識的なFire WallはPOST,GET以外のメソッドを弾くだろ?」
陽平「それが出来るのもHTTPの良いところ。」

WebサービスとWeb APIは分けて考えない

この話は、正直なんとなく理解していたつもりでしたが、今回直接和田さんが陽平さんに問いかけたことで、やっとちゃんと分かった気がしました。
大事なことなので3回書かれていて、索引もされています。

JSON

JSONをデータコンテナとして使って満足していてはいけない。ハイパーメディアとしての側面を考えるなら"リンク"を現すメンバを入れるべき。」
和田「その場合、キーの名前は何がいい?」
陽平「hrefやsrc、あと書き忘れたけどrelも」

ブログ

陽平「帰ってブログに書くまでがイベントです。」
 

まとめ

例えば以前聞いた話にあった

Strutsで開発いっぱいしてきたし、設計もできる、趣味でwicketも触ってる。」
という人が面接に来た時、
「GETとPOSTの違い分かりますか?」
ときいたら黙り込んでしまった。

こういう人にも是非読んでもらえれば、この人が不幸にも「それは別に気にしなくても動くよ」と教えられてしまってきたソース上の呪文たちがどういう意味を持っていたのか分かるのかな、なんて思ったりもしました。

本当はWebやる上で常識であるべきはずなのに、ちゃんと教えてくれる(教えられる)人が中々いなくて、しかも後回しにされがちな分野を、陽平さんが分かりやすくまとめて教えてくれた本という感じですかね。

リファレンスの面としては、付録として「ステータスコード一覧」と「HTTPヘッダ一覧」が載っていて、これも重宝しそうです。

懇親会

多方面の人たちが集まって色々お話しさせていただきました。


id:ryushiさんが持ってた医学書、あの話は面白かった。
患者の状態をもとに、次にどの診断をしていくかを特殊な図で書いた本。この方法で障害対策マニュアル書いたらいいねって話でしたが、本の名前もあの表の書き方もわからないんでここでは全く上手く説明できない。


あと、和田さんにTDDについて思ってることを色々聞いてもらった。やるやる詐欺にならないようにしたい。しかしどうするか。


名刺入れを大きくしてもっと持ってないと、大事なときに無くなる。

サイン

懇親会では陽平さんと和田さんのサインを頂きました。


(陽平さんがブコメでNGをだされていたので、写真は自重しました。)


ということで本当に楽しかったです。
陽平さん、和田さん、編集者のみなさん。本当にお疲れさまでした。