要約

  • WebDAV binding は複数 URI を一つの資源へ結べる。対象がコレクションなら、別 binding から同じ子孫へ届き、祖先へ戻る循環も作り得る。
  • binding を理解する Depth: infinity PROPFIND では、一つの出現を 200 として展開する。後続経路は 208 Already Reported の response として残るが、その子孫をもう一度列挙しない。
  • DAV:resource-id が経路の下に安定した資源同一性を置く。クライアントは全 binding を保存しつつ、共有コレクションを一度だけ展開する。208 を理解しない相手には、説明不能な省略ではなく 508 による停止が必要になる。

二つの入口と一つの保管庫

同じ保管庫に東西二つの入口があれば、入口は二つとも建物の事実である。しかし中の棚が二組になるわけではない。

経路だけで再帰する目録係は、各入口から同じ棚を数える。通路が上位階へ戻れば、有限の建物から無限の経路名を作る。反対に、同じ部屋だと分かった瞬間に二つ目の入口を記録から消せば、探索は止まるが平面図が嘘になる。

208 は入口と内部展開を分離した。別経路は報告する。共有先の同一性を示す。そして既に済んだ子孫探索だけを繰り返さない。

省略対象は名前空間ではなく、作業である。

207 は既に内訳を読むよう要求していた

2007 年の RFC 4918 は、WebDAV コレクションの状態を、パスセグメントから資源への mapping とコレクション自身の property として定義する。メンバー名は資源そのものではなく、資源へ到達する関係である。

PROPFIND は Depth 0、1、infinity を使う。深さ無限なら全子孫を対象にし、応答は 207 Multi-Status の中に平らな DAV:response の集合として入る。各 href が経路を、各 propstat の内側の status が property の結果を示す。

外側の 207 は全項目の判決ではない。クライアントは本文の内訳を読む必要がある。この入れ子構造が、後に 208 を一つの binding 出現へ割り当てる場所になった。

基礎 WebDAV も一資源を複数 URI が識別し得ると認めていた。クライアントが既存資源への新経路を作る方法は binding 拡張が加えた。

BIND は複製ではなく関係を作った

2010 年 4 月の RFC 5842 は Experimental RFC であり、BIND、UNBIND、REBIND を定める。BIND はコレクション内のパスセグメントを既存資源へ関連付け、新しい URI から同じ対象へ要求を送れるようにする。

新しいのは binding であり、資源ではない。別々の親コレクションが同じ資源を指すなら、それぞれ独立した binding state を持つ。

Binding integrity により、一つの binding を除いても他の binding を壊してはならず、別経路が残るうちに資源を回収してはならない。関係は明示的な削除・変更操作まで存在し、同じ対象を指し続ける。

別名は表示上の重複ではない。管理可能だが、他の経路を支配しない辺である。

コレクションへの別名は子孫 URI も増やした

葉資源への binding は新しい URI を一つ加える。コレクションへの binding は、その内部 binding を複製せずに、子孫を新しい接頭辞から到達可能にする。

そのため資源数が一定でも URI mapping 数は増える。自分自身または祖先へ binding すれば、同じセグメントを何度も繰り返す無限の URI 列が生じ得る。

RFC 5842 は Depth: infinity 処理時の collection bind loop 検出を必須にする。サーバーは循環を作る要求自体を拒否してもよい。循環対応は任意だが、受け入れた後の検出は省略できない。

無限なのは格納物ではない。経路を対象と誤認した再帰の結果である。

resource-id は経路より長く残った

URI の違いだけでは対象の違いを証明できない。内容一致も同一性の証明にならない。二つの独立資源が同じ内容を持つことはある。

RFC 5842 は必須の DAV:resource-id を導入する。資源作成時に割り当て、全資源で永久に一意であり、既存資源の更新や REBIND で変えてはならず、どの URI からも到達不能になった後も再利用できない。

別 binding から得た値が文字単位で同一なら、クライアントは二経路が同一資源へ達すると確認できる。この ID は canonical URI ではなく、URI が増減しても残る対象証拠である。

PROPFIND でこの property を要求すれば、どの経路が共有ノードへ入るのかを復元できる。

辺の台帳と展開の台帳

忠実な探索には二つの visited が要る。一つは binding edge を記録するため、もう一つはどの collection identity の子孫を本応答で既に展開したかを記録するためである。

URI だけで管理すると全辺は残るが、同一ノードを何度も開く。resource-id だけで早期に統合すると循環は止まるが、二つ目の正当な辺が消える。

まず href と親子関係を保存し、その後で対象 ID の展開済み状態を調べる。重複排除は辺ではなく再帰作業に作用しなければならない。

208 は二台帳を結ぶ記録である。この経路は存在するが、その先のコレクションは既に別経路から列挙済みだと伝える。

208 は後続 binding を消さなかった

仕様上、208 は Depth: infinity のとき DAV:propstat 内で使える。同一コレクションへの複数 binding のうち、一つは 200 として報告される。後続 binding の DAV:response は 208 を持ち、その子孫 response は含めない。

重要なのは後続 response 自体が残ることだ。href が別経路を示し、resource-id が先の 200 出現と同一ノードであることを証明する。

RFC の例では /Coll/ と /Coll/Bar が同じ ID を返す。前者でメンバーを展開し、後者は 208 になる。さらに /Coll/Bar/Bar を作らない。

Already Reported はこの Multi-Status 内の展開履歴を指す。URI の価値や存続を否定しない。

最初の 200 は正統経路を決めない

有限な応答には展開担当の一出現が必要だ。しかし、その 200 経路が原本、所有者、永久 canonical になるとは RFC は述べない。

各 binding は親コレクションの独立した状態であり、異なるナビゲーション、権限、監査文脈を持ち得る。208 経路を「重複」として捨てれば、UNBIND を資源削除と誤認したり、一つの親に他の辺まで支配させたりする。

本応答で先に歩いたことと、名前空間上の権限は別である。

木へ戻すために中心経路を発明してはならない。

208 の外側には 207 があった

要求レベルの応答は通常 207 Multi-Status で、208 は本文中の特定 property result に現れる。

従って 208 は「HTTP 要求そのものが重複した」でも「応答全体を以前送った」でもない。一つの collection binding の子孫が本応答中の別 occurrence で既に報告された、という内訳である。

外側は複数結果を読むよう指示し、href は経路を、resource-id は対象を、200/208 は展開位置を示す。

これを成功真偽値一つに変換する中継層は、状態コードを運んでもグラフ証拠を失う。

省略には能力宣言が必要だった

子孫の不在は、既報か欠落か、意味を知らなければ区別できない。そこで binding 対応サーバーは OPTIONS の DAV 応答ヘッダーで bind compliance class を示す。クライアントも DAV: bind を送り、特に 208 を理解する必要がある。

後方互換性のため、クライアントが対応を示さない限り、Multi-Status 本文で 208 を使うべきではない。古い実装は未知 status を失敗と解釈したり、子のない collection と誤認したりする。

省略はサーバーだけの圧縮判断ではない。受信側が、何を省き、どこで既報となり、どの ID で接続するかを理解する共有契約である。

508 は継続不能を表した

binding 非対応クライアントの depth-infinity 探索が循環に出会う場合、仕様は未知の 208 より 508 Loop Detected を選ぶ。送信開始前に分かれば top-level 508、Multi-Status の streaming 中に分かれば内訳での失敗表現が可能になる。

208 なら、対応クライアントは別経路を保持し、重複子孫だけを止め、残りの探索を続けられる。508 は無限ループのため操作を終了し、全体が失敗したことを示す。

両者は成功と失敗の程度差ではない。参照を理解して継続できるか、理解不能なので停止するかの差である。

曖昧な部分成功より明示的失敗の方が互換性を守る場合がある。

binding は攻撃面も増やした

BIND により、クライアントは偶然または悪意で loop を作りやすくなる。深い探索時の検出は必須だが、208 だけで全資源消費を防げるわけではない。

RFC 5842 は cross-server binding による負荷誘導、DAV:parent-set による私的場所の露出、他管理領域から増やされる親一覧の維持コストを指摘する。

208 が抑えるのは一応答内の重複列挙である。CPU、メモリ、ノード、応答サイズの予算や binding 作成権限は別に必要だ。有限グラフも巨大になり得る。

一つの増幅経路を閉じる状態を、完全な安全政策へ膨らませてはならない。

同一資源でも全 property が経路非依存とは限らない

同じ resource-id は対象同一性を示すが、すべての観測値が同じとは限らない。dead property は binding 数や提出経路から独立する一方、live property は個別定義に従い、経路文脈を持つものもある。

ID だけですべてを統合すれば文脈を失う。値が違うたびに別資源とすれば同一性を失う。

資源の事実、binding の事実、経路依存観測を別レイヤーとして保存する必要がある。208 が共有 ID を使うのは展開判断の範囲だけであり、他レイヤーを消す権限ではない。

最小共通層は、証拠が支えられる以上の権力を持たないとき強い。

IANA の登録も意味を一般化しない

現在の IANA HTTP Status Code Registry は 208 Already Reported を RFC 5842 に結び付ける。同じ Experimental RFC が 508 を定義し、207 は RFC 4918 を参照する。

登録は RFC 5842 を Internet Standard にせず、現在の普及率も証明しない。208 はデータベース重複、冪等性、cache hit の汎用コードでもない。

意味は binding-aware な WebDAV、Depth infinity、Multi-Status という狭い組合せから生まれる。

用途の狭さが「既に」という語を過剰な省略許可から守る。

全経路を残し、展開は一度

HTTP 208 はグラフを木に偽装しなかった。経路と対象を別に保ち、作業だけを有限にした。

Binding は実在するので全部報告する。資源は一 URI に属さないので安定 ID を持つ。同一 collection の子孫は再列挙しても構造が増えないので一度だけ展開する。省略には理由が必要なので 208 を置く。

一つの経路が中心権力にならず、alias が copy にならず、cycle が無限資源を作らない。

二つ目の入口は目録に残る。その先の棚をもう一度数える必要はない。