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