RFC 5842
Binding Extensions to Web Distributed Authoring and Versioning (WebDAV)
Binding Extensions to Web Distributed Authoring and Versioning (WebDAV) π
Okay bestie, this is RFC 5842, published in April 2010 by the IETF (Internet Engineering Task Force) π¦ It's an Experimental doc (ISSN 2070-1721), so it's for trying things out, not a finished Internet Standard. The authors are G. Clemm (IBM), J. Crawford (IBM Research), J. Reschke, Ed. (greenbytes; the "Ed." means he's the editor π ), and J. Whitehead (U.C. Santa Cruz). The title block doesn't list anything it obsoletes or updates, so this one stands on its own β¨
Abstract
okay so this spec defines bindings and the BIND method, which is how you make multiple bindings to the same resource πΈ Making a new binding gives a resource at least one new URI. And servers have to keep the integrity of any bindings they let people create π«Ά
Status of This Memo
This doc is not an Internet Standards Track spec. It's published so people can look at it, try it out in experimental implementations, and evaluate it π§
It defines an Experimental Protocol for the Internet community. It's a product of the IETF and represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). Not every IESG-approved doc is a candidate for any level of Internet Standard, so check Section 2 of RFC 5741 if you're curious π€
You can find the current status, any errata, and how to send feedback at http://www.rfc-editor.org/info/rfc5842 π
Copyright Notice
Copyright (c) 2010 IETF Trust and the persons identified as the document authors. All rights reserved. π
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they stood on the publication date. Please actually read these, because they explain your rights and restrictions for this doc π Code Components pulled out of this doc must include the Simplified BSD License text described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in that license.
This doc may include material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. Some of the copyright holders for that older material might not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. So unless you get a proper license from those holders, this doc can't be modified outside the IETF Standards Process, and derivative works can't be made outside it either. The exceptions are formatting it for publication as an RFC and translating it into languages other than English π
Table of Contents
1. Introduction ....................................................4
1.1. Terminology ................................................5
1.2. Method Preconditions and Postconditions ....................6
2. Overview of Bindings ............................................7
2.1. Bindings to Collections ....................................7
2.1.1. Bind Loops ..........................................8
2.2. URI Mappings Created by a New Binding ......................8
2.3. COPY and Bindings ..........................................9
2.3.1. Example: COPY with "Depth: infinity" in
Presence of Bind Loops .............................11
2.3.2. Example: COPY Updating Multiple Bindings ...........13
2.3.3. Example: COPY with "Depth: infinity" with
Multiple Bindings to a Leaf Resource ...............14
2.4. DELETE and Bindings .......................................15
2.5. MOVE and Bindings .........................................15
2.5.1. Example: Simple MOVE ...............................16
2.5.2. Example: MOVE Request Causing a Bind Loop ..........16
2.6. PROPFIND and Bindings .....................................18
2.7. Determining Whether Two Bindings Are to the Same
Resource ..................................................18
2.8. Discovering the Bindings to a Resource ....................19
3. Properties .....................................................19
3.1. DAV:resource-id Property ..................................20
3.2. DAV:parent-set Property ...................................20
3.2.1. Example for DAV:parent-set Property ................20
4. BIND Method ....................................................21
4.1. Example: BIND .............................................24
5. UNBIND Method ..................................................24
5.1. Example: UNBIND ...........................................26
6. REBIND Method ..................................................26
6.1. Example: REBIND ...........................................28
6.2. Example: REBIND in Presence of Locks and Bind Loops .......29
7. Additional Status Codes ........................................31
7.1. 208 Already Reported ......................................31
7.1.1. Example: PROPFIND by Bind-Aware Client .............32
7.1.2. Example: PROPFIND by Non-Bind-Aware Client .........34
7.2. 508 Loop Detected .........................................34
8. Capability Discovery ...........................................34
8.1. OPTIONS Method ............................................34
8.2. 'DAV' Request Header ......................................34
9. Relationship to Locking in WebDAV ..............................35
9.1. Example: Locking and Multiple Bindings ....................36
10. Relationship to WebDAV Access Control Protocol ................37
11. Relationship to Versioning Extensions to WebDAV ...............37
12. Security Considerations .......................................40
12.1. Privacy Concerns .........................................40
12.2. Bind Loops ...............................................40
12.3. Bindings and Denial of Service ...........................40
12.4. Private Locations May Be Revealed ........................40
12.5. DAV:parent-set and Denial of Service .....................41
13. Internationalization Considerations ...........................41
14. IANA Considerations ...........................................41
15. Acknowledgements ..............................................41
16. References ....................................................41
16.1. Normative References .....................................41
16.2. Informative References ...................................42
Index .............................................................42
1. Introduction β¨
okay so this spec extends the WebDAV Distributed Authoring Protocol ([RFC4918]) so clients can make new access paths to existing resources π That's useful for a few reasons, and I'm about to explain all of them π
WebDAV resource URIs are hierarchical, and they line up with a hierarchy of collections in resource space. The WebDAV Distributed Authoring Protocol lets you organize resources into groupings called collections, which are way easier to browse and manage than one giant flat collection ποΈ The catch is that hierarchies force categorization decisions, so each resource ends up in exactly one spot. That's a real drawback when a resource fits more than one category. Picture a hierarchy of vehicle descriptions with collections for cars and boats. A description of a car/boat combo could live in either one, but ideally it'd be reachable from both πβ΅ Letting clients create new URIs that point at the existing resource means it can show up in multiple collections. Iconic π
Hierarchies also make sharing resources harder, because resources that are useful across lots of collections still get jammed into just one π€ Say the mathematics department at a university makes a collection about fractals. It has bindings to some local resources, but it also gives access to some resources at other universities π A lot of the time you don't want physical copies of those shared resources on the local server. Maybe you want to save disk space, respect copyright, or have changes in the shared resources show up automatically. So being able to create new access paths to existing resources in other collections, or even on other servers, is super useful for cases like this π
The BIND method, defined here, gives clients a way to create alternative access paths to existing WebDAV resources π¦ HTTP [RFC2616] and WebDAV [RFC4918] methods work because there are mappings between URIs and resources. A method gets addressed to a URI, the server follows the mapping from that URI to a resource, and then it applies the method to that resource. Multiple URIs may be mapped to the same resource, but until now clients had no way to create additional URIs mapped to existing resources. Not me being shocked π
BIND lets a client associate a new URI with an existing WebDAV resource, and then that URI can be used to send requests to the resource πΈ WebDAV URIs are hierarchical and match a hierarchy of collections, so the BIND method also adds the resource to a collection. Every new URI tied to the resource means it appears in more collections β¨
A BIND request doesn't create a new resource. It just makes a new URI available for sending requests to an existing resource π§ The new URI is indistinguishable from any other URI when you send a request to a resource, and only one round trip is needed to reach the intended target. Servers are required to enforce the integrity of the relationships between the new URIs and the resources tied to them. Because of that, it may be very costly for servers to support BIND requests that cross server boundaries π
Here's how this spec is laid out π Section 1.1 defines the terminology used in the rest of the spec, and Section 2 gives an overview of bindings. Section 3 defines the new properties needed to support multiple bindings to the same resource. Section 4 specifies the BIND method, which creates multiple bindings to the same resource. Section 5 specifies the UNBIND method, which removes a binding to a resource. Section 6 specifies the REBIND method, which moves a binding to another collection π«Ά
1.1. Terminology
okay bestie, let's get our vocab straight first π this doc's terms follow and extend the ones from the WebDAV Distributed Authoring Protocol spec [RFC4918] π
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. β¨
this doc writes its XML DTD fragments ([XML]) using the notation rules from Section 17 of [RFC4918] π
URI Mapping
a relation between an absolute URI and a resource π¦ for an absolute URI U and the resource it identifies R, the URI mapping can be thought of as (U => R). a resource can represent stuff that isn't network retrievable as well as stuff that is, so a resource can have zero, one, or many URI mappings. mapping a resource to an "http"-scheme URI makes it possible to submit HTTP requests to the resource using that URI πΈ
Path Segment
informally, it's the characters found between slashes ("/") in a URI π formally, it's defined in Section 3.3 of [RFC3986].
Binding
a relation between a single path segment (in a collection) and a resource π a binding is part of the state of a collection. if two different collections contain a binding between the same path segment and the same resource, those are two distinct bindings. so for a collection C, a path segment S, and a resource R, the binding can be thought of as C:(S -> R). bindings create URI mappings, which means requests can be sent to a single resource from multiple locations in a URI namespace π
for example: say a collection C is accessible through the URI http://www.example.com/CollX, a path segment S is "foo.html", and there's a resource R. creating the binding C: (S -> R) makes it possible to use http://www.example.com/CollX/foo.html to access R π§
Collection
a resource that contains, as part of its state, a set of bindings that identify internal member resources π
Internal Member URI
the URI that identifies an internal member of a collection. it's made of the URI for the collection, then a slash character ('/'), then the path segment of the binding for that internal member π«Ά
Binding Integrity
the property of a binding that says:
- the binding continues to exist, and
- the identity of the resource identified by that binding does not change,
unless an explicit request is executed that is defined to delete that binding. examples of requests that delete a binding are DELETE, MOVE, and (defined later on) UNBIND and REBIND π
1.2. Method Preconditions and Postconditions
see Section 16 of [RFC4918] for the definitions of "precondition" and "postcondition" π
2. Overview of Bindings
bindings are part of the state of a collection π they define the internal members of the collection and the names of those internal members.
bindings get added and removed by a bunch of existing HTTP methods β¨ a method that creates a new resource, like PUT, COPY, and MKCOL, adds a binding. a method that deletes a resource, like DELETE, removes a binding. a method that moves a resource (e.g., MOVE) does both: it adds a binding in the destination collection and removes one in the source collection. the BIND method introduced here is the way to add a second binding to an existing resource π¦ there's no difference between an initial binding added by PUT, COPY, or MKCOL and additional bindings added with BIND π₯
it would be very undesirable if one binding could get destroyed as a side effect of operating on the resource through a different binding π especially, removing one binding to a resource (e.g., with a DELETE or a MOVE) MUST NOT disrupt another binding to that resource, for example by turning that binding into a dangling path segment. the server MUST NOT reclaim system resources after removing one binding while other bindings to the resource remain. in other words, the server MUST maintain the integrity of a binding π«Ά it is permissible, though, for future method definitions (e.g., a DESTROY method) to have semantics that explicitly remove all bindings and/or immediately reclaim system resources π
Note: the collection model described herein is not compatible with systems in which resources inherit properties based solely on the access path, because the ability to create additional bindings will cause a single resource to appear as a member of several different collections at the same time. π
2.1. Bindings to Collections
creating a new binding to a collection makes each resource associated with a binding in that collection accessible via a new URI πΈ so it creates new URI mappings to those resources, but no new bindings π
for example, suppose a new binding CollY is created for collection C1 in the figure below. it immediately becomes possible to access resource R1 using the URI /CollY/x.gif and to access resource R2 using the URI /CollY/y.jpg, but no new bindings for these child resources were created. this is because bindings are part of the state of a collection, and they associate a URI that is relative to that collection with its target resource. no change to the bindings in Collection C1 is needed to make its children accessible using /CollY/x.gif and /CollY/y.jpg π§
+-------------------------+
| Root Collection |
| bindings: |
| CollX CollY |
+-------------------------+
| /
| /
| /
+------------------+
| Collection C1 |
| bindings: |
| x.gif y.jpg |
+------------------+
| \
| \
| \
+-------------+ +-------------+
| Resource R1 | | Resource R2 |
+-------------+ +-------------+
2.1.1. Bind Loops
bindings to collections can result in loops ("cycles"), and servers MUST detect these when processing "Depth: infinity" requests π it's sometimes possible to complete an operation even with a loop around. for instance, a PROPFIND can still succeed if the server uses the new status code 208 (Already Reported) defined in Section 7.1 β¨
however, the 508 (Loop Detected) status code is defined in Section 7.2 for use in contexts where an operation gets terminated because a loop was encountered π
support for loops is OPTIONAL: servers MAY reject requests that would lead to the creation of a bind loop (see the DAV:cycle-allowed precondition defined in Section 4) π
2.2. URI Mappings Created by a New Binding
okay so suppose a binding from "Binding-Name" to resource R is about to be added to a collection, C π¦ if C-MAP is the set of URIs that were mapped to C before the BIND request, then for each URI "C-URI" in C-MAP, the URI "C-URI/Binding-Name" gets mapped to resource R after the BIND request πΈ
for example, if a binding from "foo.html" to R is added to a collection C, and these URIs are mapped to C:
http://www.example.com/A/1/
http://example.com/A/one/
then these new mappings to R are introduced:
http://www.example.com/A/1/foo.html
http://example.com/A/one/foo.html
note that if R is a collection, additional URI mappings get created to the descendents of R π also, if a binding is made in collection C to C itself (or to a parent of C), an infinite number of mappings are introduced π
for example, if a binding from "myself" to C is then added to C, this infinite number of additional mappings to C are introduced:
http://www.example.com/A/1/myself
http://www.example.com/A/1/myself/myself
...
and this infinite number of additional mappings to R are introduced:
http://www.example.com/A/1/myself/foo.html
http://www.example.com/A/1/myself/myself/foo.html
...
2.3. COPY and Bindings
as defined in Section 9.8 of [RFC4918], COPY causes the resource identified by the Request-URI to be duplicated, and it makes the new resource accessible using the URI specified in the Destination header π upon successful completion of a COPY, a new binding gets created between the last path segment of the Destination header and the destination resource. the new binding is added to its parent collection, which is whatever the Destination header is minus its final segment π§
here's the vibe with an example: a COPY is issued to URI-3 for resource R (which is also mapped to URI-1 and URI-2), with the Destination header set to URI-X. after the COPY succeeds, resource R is duplicated to create resource R', and a new binding has been created that creates at least the URI mapping between URI-X and the new resource (although other URI mappings may also have been created too) π
URI-1 URI-2 URI-3 URI-X
| | | |
| | | <---- URI Mappings ----> |
| | | |
+---------------------+ +------------------------+
| Resource R | | Resource R' |
+---------------------+ +------------------------+
it might be thought that a COPY request with "Depth: 0" on a collection would duplicate its bindings, since bindings are part of the collection's state π this is not the case, though. the definition of Depth in [RFC4918] makes it clear that a "Depth: 0" request does not apply to a collection's members. so a COPY with "Depth: 0" does not duplicate the bindings contained by the collection π
if a COPY request causes an existing resource to be updated, the bindings to that resource MUST be unaffected by the COPY request π«Ά using the example above, suppose a COPY request is issued to URI-X for resource R', with the Destination header set to URI-2. the content and dead properties of resource R would be updated to be a copy of those of resource R', but the mappings from URI-1, URI-2, and URI-3 to resource R remain unaffected π¦ if, because of multiple bindings to a resource, more than one source resource updates a single destination resource, the order of the updates is server defined (see Section 2.3.2 for an example) π
if a COPY request would cause a new resource to be created as a copy of an existing resource, and that COPY request has already created a copy of that existing resource, the COPY request instead creates another binding to the previous copy, instead of creating a new resource (see Section 2.3.3 for an example) β¨
2.3.1. Example: COPY with "Depth: infinity" in Presence of Bind Loops
okay so let's see how COPY with "Depth: infinity" behaves when bindings are involved πΈ here's the collection we're working with:
+------------------+
| Root Collection |
| bindings: |
| CollX |
+------------------+
|
|
+-------------------------------+
| Collection C1 |<-------+
| bindings: | |
| x.gif CollY | |
+-------------------------------+ |
| \ (creates loop) |
| \ |
+-------------+ +------------------+ |
| Resource R1 | | Collection C2 | |
+-------------+ | bindings: | |
| y.gif CollZ | |
+------------------+ |
| | |
| +--------+
|
+-------------+
| Resource R2 |
+-------------+
so if a COPY with "Depth: infinity" gets sent to /CollX with a destination of /CollA, the copy operation ends up replicating the whole tree over to /CollA β¨
+------------------+
| Root Collection |
| bindings: |
| CollX CollA |
+------------------+
| |
| +---------------------------+
| |
+-------------------+ |
| Collection C1 |<------------------+ |
| bindings: | | |
| x.gif CollY | | |
+-------------------+ | |
| \ (creates loop) | |
| \ | |
+-------------+ +-----------------+ | |
| Resource R1 | | Collection C2 | | |
+-------------+ | bindings: | | |
| y.gif CollZ | | |
+-----------------+ | |
| | | |
| +-------+ |
| |
+-------------+ |
| Resource R2 | |
+-------------+ |
|
+-------------------------------+
|
+-------------------+
| Collection C3 |<------------------+
| bindings: | |
| x.gif CollY | |
+-------------------+ |
| \ (creates loop) |
| \ |
+-------------+ +-----------------+ |
| Resource R3 | | Collection C4 | |
+-------------+ | bindings: | |
| y.gif CollZ | |
+-----------------+ |
| | |
| +-------+
|
+-------------+
| Resource R4 |
+-------------+
and yes, ngl, the exact same thing happens for way more complicated loops ππ₯
2.3.2. Example: COPY Updating Multiple Bindings
let's say we start with this collection hierarchy π¦
+------------------+
| Root Collection |
| bindings: |
| CollX CollY |
+------------------+
/ \
/ \
/ \
+--------------------------+ +-----------------+
| Collection C1 | | Collection C2 |
| bindings: | | bindings: |
| x.gif y.gif | | x.gif y.gif |
+--------------------------+ +-----------------+
| | | |
| | | |
+-------------+ +-------------+ +-------------+
| Resource R1 | | Resource R2 | | Resource R3 |
+-------------+ +-------------+ +-------------+
so a COPY of /CollX with "Depth: infinity" sent to /CollY doesn't change the hierarchy at all π what does happen is that Resource R3 gets updated with the content of either Resource R1 or Resource R2. main character energy, but make it chaotic π
2.3.3. Example: COPY with "Depth: infinity" with Multiple Bindings to a Leaf Resource
starting hierarchy, bestie π
+------------------+
| Root Collection |
| bindings: |
| CollX |
+------------------+
|
|
|
+----------------+
| Collection C1 |
| bindings: |
| x.gif y.gif |
+----------------+
| |
| |
+-------------+
| Resource R1 |
+-------------+
now a COPY of /CollX with "Depth: infinity" to /CollY gives us this hierarchy π§
+------------------+
| Root Collection |
| bindings: |
| CollX CollY |
+------------------+
| \
| \
| \
+----------------+ +-----------------+
| Collection C1 | | Collection C2 |
| bindings: | | bindings: |
| x.gif y.gif | | x.gif y.gif |
+----------------+ +-----------------+
| | | |
| | | |
+-------------+ +-------------+
| Resource R1 | | Resource R2 |
+-------------+ +-------------+
2.4. DELETE and Bindings
okay this part is about what DELETE is allowed to wipe out when a resource has more than one binding π when a resource has multiple bindings, a DELETE aimed at that resource MUST NOT remove any binding to it other than the one named in the Request-URI. example time: say the collection at "/a" has a binding called "x" to a resource R, and the collection at "/b" has a binding called "y" to that same R. a DELETE on "/a/x" takes out the "x" binding from "/a", but it MUST NOT touch the "y" binding in "/b" (so after the DELETE, "/y/b" still points at resource R) π
when DELETE hits a collection, it MUST NOT change the membership of any other collection that isn't itself a member of the one being deleted. for instance, if both "/a/.../x" and "/b/.../y" point at the same collection C, then deleting "/a" must not remove an internal member from C, or from any other collection that's a member of C, because that would change the membership of "/b" π«
if a collection supports the UNBIND method (see Section 5), a DELETE on an internal member of that collection MAY be carried out as an UNBIND request. in that case, a DELETE on a Request-URI just removes the binding named by the last segment of the Request-URI from the collection you get by chopping that last segment off. even though [RFC4918] lets a DELETE be non-atomic, when it's done as an UNBIND, it's atomic β¨ so a DELETE on a whole hierarchy is basically just removing one binding to the collection the Request-URI names π¦
2.5. MOVE and Bindings
when MOVE is applied to a resource, the other bindings to that resource MUST be unaffected π and if the thing being moved is a collection, the bindings to any of its members MUST be unaffected too. also, if MOVE uses Overwrite:T to delete an existing resource, the DELETE rules above apply π
if the destination collection of a MOVE supports the REBIND method (see Section 6), a MOVE of a resource into that collection MAY be carried out as a REBIND request. even though [RFC4918] lets a MOVE be non-atomic, when it's done as a REBIND, it's atomic π«Ά so applying a MOVE to a Request-URI and a Destination URI basically means removing one binding to a resource (at the Request-URI) and creating a new binding to that same resource (at the Destination URI). even when the Request-URI names a collection, MOVE just swaps out one binding to that collection for another π
2.5.1. Example: Simple MOVE
okay here's the example π say a MOVE goes to URI-3 for resource R (which is also mapped to URI-1 and URI-2), with the Destination header set to URI-X. once the MOVE finishes successfully, a new binding exists that maps URI-X to resource R. the binding for the last segment of URI-3 is gone, and that also removes the URI-3 mapping to R. if R were a collection, the old URI-3-based mappings to its members would be removed, and new URI-X-based mappings to those members would be created π
>> Before Request:
URI-1 URI-2 URI-3
| | |
| | | <---- URI Mappings
| | |
+---------------------+
| Resource R |
+---------------------+
>> After Request:
URI-1 URI-2 URI-X
| | |
| | | <---- URI Mappings
| | |
+---------------------+
| Resource R |
+---------------------+
2.5.2. Example: MOVE Request Causing a Bind Loop π
okay bestie, MOVE requests are sneaky π Even when everything looks fine, a MOVE can accidentally create a bind loop if collection bindings are involved. π
Picture two top-level collections, C1 and C2, living at /CollW/ and /CollX/. On top of that, C1 has an extra binding called CollY that points over to C2. It's giving tangled π§Ά
+------------------+
| Root Collection |
| bindings: |
| CollW CollX |
+------------------+
| |
| |
+------------------+ |
| Collection C1 | |
| bindings: | |
| CollY | |
+------------------+ |
| |
| |
+------------------+
| Collection C2 |
| |
| |
+------------------+
In this setup, the MOVE request below would cause a bind loop. π
>> Request:
MOVE /CollW HTTP/1.1
Host: example.com
Destination: /CollX/CollZ
If the request succeeded, the resulting state would be:
+------------------+
| Root Collection |
| bindings: |
| CollX |
+------------------+
|
|
+------------------+ |
| Collection C1 | |
+----> | bindings: | |
| | CollY | |
| +------------------+ |
| | |
| | |
| +------------------+
| | Collection C2 |
| | bindings: |
| | CollZ |
| +------------------+
| |
| |
+-------------------+
See that loop? C1 β CollY β C2 β back around to C1. It's a whole circle of drama ππ
2.6. PROPFIND and Bindings π
Okay so the big rule here is that dead properties stay consistent, no matter what. π«Ά The value of a dead property MUST be independent of the number of bindings to its host resource or of the path submitted to PROPFIND. Basically, it doesn't care how many doors lead to the room. πͺ
Live properties are a different story, because each one follows its own definition. For example, see [RFC3744], Section 5, Paragraph 2 for a case where the value is independent of its path and bindings. Then check out [RFC4918], Section 8.8 for the live properties DAV:getetag and DAV:getlastmodified, which may behave differently. Plot twist, they're not all the same π¦
2.7. Determining Whether Two Bindings Are to the Same Resource π
Being able to tell whether two bindings point to the same resource is super useful β¨ Two resources can have identical contents and properties and still be totally different resources. Like, if you update one, the other one doesn't change at all. Not the same girl, different vibes π
The REQUIRED DAV:resource-id property (defined in Section 3.1) is the resource identifier, and it MUST be unique across all resources for all time. Yes, all time π If the DAV:resource-id values returned by PROPFIND through two bindings match character by character, the client can be sure both bindings lead to the same resource. π
The DAV:resource-id property gets created, and its value gets assigned, when the resource is born πΌ That value MUST NOT be changed. And even after a resource is totally unreachable through any URI, that value MUST NOT be reassigned to another resource's DAV:resource-id property. Never recycling IDs, periodt π
Any method that creates a brand-new resource MUST assign a new, unique value to its DAV:resource-id property. For example, a PUT applied to a null resource, a COPY (when it's not overwriting an existing target), and a CHECKIN (see [RFC3253], Section 4.4) must assign a new, unique value to the DAV:resource-id property of the new resource they create. β¨
On the other hand, any method that affects an existing resource must not change the value of its DAV:resource-id property. Specifically, a PUT or a COPY that updates an existing resource must not change the value of its DAV:resource-id property. And a REBIND doesn't create a new resource, it just moves an existing one to a new location, so it must not change the value of the DAV:resource-id property either. Same person, new address π‘
2.8. Discovering the Bindings to a Resource πΊοΈ
The DAV:parent-set property is OPTIONAL on a resource, and it gives you a list of the bindings that pair a collection and a URI segment with that resource. If the DAV:parent-set property exists on a given resource, it MUST contain a complete list of all bindings to that resource that the client is authorized to see. No hiding the good stuff from the people who are allowed to see it π
Before adding support for DAV:parent-set, server implementers and administrators should weigh its benefits against the cost of maintaining the property and the security risks listed in Sections 12.4 and 12.5. Real talk, security matters π
3. Properties π
The bind feature brings along the properties defined below. β¨
A DAV:allprop PROPFIND request SHOULD NOT return any of the properties defined by this document. This is for the sake of the server π«Ά It lets a binding server stay efficient when a naive client (one that doesn't understand how expensive it is to ask a server to compute every possible live property) sends a DAV:allprop PROPFIND request.
3.1. DAV:resource-id Property πͺͺ
The DAV:resource-id property is a REQUIRED property. It's how clients figure out whether two bindings lead to the same resource. Its value is a URI, and it can use any registered URI scheme that guarantees uniqueness across all resources for all time. Examples include the urn:uuid: URN namespace defined in [RFC4122] and the opaquelocktoken: URI scheme defined in [RFC4918]. π
<!ELEMENT resource-id (href)>
3.2. DAV:parent-set Property π§
The DAV:parent-set property is an OPTIONAL property that lets clients find out which collections contain a binding to this resource (in other words, which collections have that resource as an internal member). It holds an href/segment pair for each collection with a binding to the resource. The href identifies the collection, and the segment is the binding name of that resource inside that collection. π
A given collection MUST appear only once in the DAV:parent-set for any given binding, even if there are multiple URI mappings to that collection. One entry per collection, no duplicates, bestie π
<!ELEMENT parent-set (parent)*>
<!ELEMENT parent (href, segment)>
<!ELEMENT segment (#PCDATA)>
<!-- PCDATA value: segment, as defined in Section 3.3 of
[RFC3986] -->
3.2.1. Example for DAV:parent-set Property π
Let's say collection C1 is mapped to both /CollX and /CollY, and C1 has a binding called "x.gif" pointing at a resource R1. In that case, either [/CollX, x.gif] or [/CollY, x.gif] can show up in the DAV:parent-set of R1, but not both. π ββοΈ Now if C1 also has a binding called "y.gif" to R1, then C1 shows up twice in the DAV:parent-set of R1. You'd get both [/CollX, x.gif] and [/CollX, y.gif], or alternatively both [/CollY, x.gif] and [/CollY, y.gif]. Two entries for the same collection, because two different segments are involved π¦
+-------------------------+
| Root Collection |
| bindings: |
| CollX CollY |
+-------------------------+
| /
| /
| /
+-----------------+
| Collection C1 |
| bindings: |
| x.gif y.gif |
+-----------------+
| |
| |
| |
+-------------+
| Resource R1 |
+-------------+
In this case, one possible value for the DAV:parent-set property on "/CollX/x.gif" would be:
<parent-set xmlns="DAV:">
<parent>
<href>/CollX</href>
<segment>x.gif</segment>
</parent>
<parent>
<href>/CollX</href>
<segment>y.gif</segment>
</parent>
</parent-set>
4. BIND Method β¨
okay so BIND is the method that edits a collection (the Request-URI) by adding a brand-new binding. The binding links the segment from the BIND body to the resource named in the BIND body. Think of it as giving a resource a new nickname inside a folder π
If a server can't guarantee the integrity of the binding, the BIND request MUST fail. And this part is lowkey scary: keeping cross-server bindings intact is really hard π Unless the server holding the resource knows about every binding to that resource on every server, it could accidentally destroy the resource or make it unreachable without telling the other server that has a binding to it. So if server A lets you bind to a resource on server B, server A has to tell server B about the binding and have an agreement with B that B won't destroy the resource while A's binding still exists. Otherwise B might get a DELETE that it thinks removes the last binding, destroy the resource, and A's binding is left pointing at nothing. The precondition DAV:cross-server-binding covers the case where servers reject cross-server BIND requests because they can't guarantee that integrity. Protective, iconic behaviour π‘οΈ
By default, if the collection already has a binding for the specified segment, the new binding replaces the old one. You can override that replacement using the Overwrite header defined in Section 10.6 of [RFC4918] π¦
If a BIND request fails, the server state from before the request MUST be restored. BIND is unsafe and idempotent (see [RFC2616], Section 9.1). πΈ
Marshalling:
The request MAY include an Overwrite header.
The request body MUST be a DAV:bind XML element.
<!ELEMENT bind (segment, href)>
If the request succeeds, the server MUST return 201 (Created) when it creates a new binding, and 200 (OK) or 204 (No Content) when it replaces an existing one.
If a response body comes back for a successful request, it MUST be a DAV:bind-response XML element. This document doesn't define any elements for the BIND response body, but DAV:bind-response exists so future extensions that do define those elements can stay interoperable π§
<!ELEMENT bind-response ANY>
Preconditions:
(DAV:bind-into-collection): The Request-URI MUST identify a collection.
(DAV:bind-source-exists): The DAV:href element MUST identify a resource.
(DAV:binding-allowed): The resource identified by the DAV:href supports multiple bindings to it.
(DAV:cross-server-binding): If the resource identified by the DAV:href element in the request body lives on a different server from the collection identified by the Request-URI, the server MUST support cross-server bindings. Servers that don't support them can use this condition code to tell the client exactly why the request failed π
(DAV:name-allowed): The name specified by the DAV:segment is available for use as a new binding name.
(DAV:can-overwrite): If the collection already has a binding with the specified path segment, and an Overwrite header is included, the value of the Overwrite header MUST be "T".
(DAV:cycle-allowed): If the DAV:href element identifies a collection, and the Request-URI identifies a collection that is a member of that collection, the server MUST support cycles in the URI namespace. Servers that don't support cycles can use this condition code to tell the client exactly why the request failed π
(DAV:locked-update-allowed): If the collection identified by the Request-URI is write-locked, the appropriate token MUST be specified in an If request header.
(DAV:locked-overwrite-allowed): If the collection already has a binding with the specified path segment, and that binding is protected by a write lock, the appropriate token MUST be specified in an If request header.
Postconditions:
(DAV:new-binding): The collection MUST have a binding that maps the segment specified in the DAV:segment element in the request body to the resource identified by the DAV:href element in the request body. π
4.1. Example: BIND
Request:
BIND /CollY HTTP/1.1
Host: www.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: 172
<?xml version="1.0" encoding="utf-8" ?>
<D:bind xmlns:D="DAV:">
<D:segment>bar.html</D:segment>
<D:href>http://www.example.com/CollX/foo.html</D:href>
</D:bind>
Response:
HTTP/1.1 201 Created
Location: http://www.example.com/CollY/bar.html
Okay, the server added a new binding to the collection http://www.example.com/CollY, linking bar.html to the resource at http://www.example.com/CollX/foo.html. Now clients can use http://www.example.com/CollY/bar.html to send requests to that resource. That's main character energy π
5. UNBIND Method
UNBIND is the opposite move π It edits the collection (the Request-URI) by removing the binding named by the segment in the UNBIND body.
Once a resource can't be reached through any URI mapping, the server MAY reclaim the system resources tied to it. But if UNBIND removes a binding and there are still URI mappings to that resource, the server MUST NOT reclaim those system resources. Don't delete stuff people can still reach, bestie π«Ά
If an UNBIND request fails, the server state from before the request MUST be restored. UNBIND is unsafe and idempotent (see [RFC2616], Section 9.1). π
Marshalling:
The request body MUST be a DAV:unbind XML element.
<!ELEMENT unbind (segment)>
If the request succeeds, the server MUST return 200 (OK) or 204 (No Content) when the binding was successfully deleted.
If a response body comes back for a successful request, it MUST be a DAV:unbind-response XML element. Again, this document doesn't define any elements for the UNBIND response body, but DAV:unbind-response is there so future extensions that do define them stay interoperable π
<!ELEMENT unbind-response ANY>
Preconditions:
(DAV:unbind-from-collection): The Request-URI MUST identify a collection.
(DAV:unbind-source-exists): The DAV:segment element MUST identify a binding in the collection identified by the Request-URI.
(DAV:locked-update-allowed): If the collection identified by the Request-URI is write-locked, the appropriate token MUST be specified in the request.
(DAV:protected-url-deletion-allowed): If the binding identified by the segment is protected by a write lock, the appropriate token MUST be specified in the request. π
Postconditions:
(DAV:binding-deleted): The collection MUST NOT have a binding for the segment specified in the DAV:segment element in the request body.
(DAV:lock-deleted): If the internal member URI of the binding specified by the Request-URI and the DAV:segment element in the request body was protected by a write lock at the time of the request, that write lock must have been deleted by the request. π§Ή
5.1. Example: UNBIND
Request:
UNBIND /CollX HTTP/1.1
Host: www.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: 117
<?xml version="1.0" encoding="utf-8" ?>
<D:unbind xmlns:D="DAV:">
<D:segment>foo.html</D:segment>
</D:unbind>
Response:
HTTP/1.1 200 OK
Okay, so the server removed the binding named "foo.html" from the collection http://www.example.com/CollX. If someone then requests http://www.example.com/CollX/foo.html, they get a 404 (Not Found) response. Gone, but not dramatic about it πβ¨
6. REBIND Method π¦
Okay so REBIND is giving "remove it from over there and add it over here, all in one go" β¨ It removes a binding to a resource from a collection, and adds a binding to that resource into the collection identified by the Request-URI. The request body specifies the binding to be added (segment) and the old binding to be removed (href). It's effectively an atomic form of a MOVE request, so it MUST be treated the same way as MOVE when it comes to access permissions π₯
If a REBIND request fails, the server state from before the request MUST be restored. This method is unsafe and idempotent (see [RFC2616], Section 9.1). π«Ά
Marshalling:
- The request MAY include an
Overwriteheader. - The request body MUST be a
DAV:rebindXML element.
<!ELEMENT rebind (segment, href)>
If the request succeeds, the server MUST return 201 (Created) when a new binding was created, and 200 (OK) or 204 (No Content) when an existing binding was replaced. β¨
If a response body for a successful request is included, it MUST be a DAV:rebind-response XML element. This document doesn't define any elements for the REBIND response body, but the DAV:rebind-response element exists so future extensions that do define them still play nicely together π
<!ELEMENT rebind-response ANY>
Preconditions:
(DAV:rebind-into-collection): The Request-URI MUST identify a collection.(DAV:rebind-source-exists): TheDAV:hrefelement MUST identify a resource.(DAV:cross-server-binding): If the resource identified by theDAV:hrefelement in the request body is on another server from the collection identified by the Request-URI, the server MUST support cross-server bindings. (Servers that don't support them can use this condition code to tell the client exactly why the request failed π)(DAV:name-allowed): The name specified by theDAV:segmentis available for use as a new binding name.(DAV:can-overwrite): If the collection already contains a binding with the specified path segment, and anOverwriteheader is included, the value of theOverwriteheader MUST be "T".(DAV:cycle-allowed): If theDAV:hrefelement identifies a collection, and the Request-URI identifies a collection that is a member of that collection, the server MUST support cycles in the URI namespace. (Servers that don't support cycles can use this condition code to tell the client exactly why the request failed π)(DAV:locked-update-allowed): If the collection identified by the Request-URI is write-locked, then the appropriate token MUST be specified in the request.(DAV:protected-url-modification-allowed): If the collection identified by the Request-URI already contains a binding with the specified path segment, and that binding is protected by a write lock, then the appropriate token MUST be specified in the request.(DAV:locked-source-collection-update-allowed): If the collection identified by the parent collection prefix of theDAV:hrefURI is write-locked, then the appropriate token MUST be specified in the request.(DAV:protected-source-url-deletion-allowed): If theDAV:hrefURI is protected by a write lock, then the appropriate token MUST be specified in the request.
Postconditions:
(DAV:new-binding): The collection MUST have a binding that maps the segment specified in theDAV:segmentelement in the request body to the resource identified by theDAV:hrefelement in the request body.(DAV:binding-deleted): The URL specified in theDAV:hrefelement in the request body MUST NOT be mapped to a resource.(DAV:lock-deleted): If the URL specified in theDAV:hrefelement in the request body was protected by a write lock at the time of the request, that write lock must have been deleted by the request.
6.1. Example: REBIND
Request:
REBIND /CollX HTTP/1.1
Host: www.example.com
Content-Type: application/xml; charset="utf-8"
Content-Length: 176
<?xml version="1.0" encoding="utf-8" ?>
<D:rebind xmlns:D="DAV:">
<D:segment>foo.html</D:segment>
<D:href>http://www.example.com/CollY/bar.html</D:href>
</D:rebind>
Response:
HTTP/1.1 200 OK
Ta-da! π The server adds a new binding to the collection http://www.example.com/CollX, associating foo.html with the resource identified by http://www.example.com/CollY/bar.html, and removes the binding named bar.html from the collection identified by http://www.example.com/CollY. Clients can now use http://www.example.com/CollX/foo.html to send requests to that resource, but requests on http://www.example.com/CollY/bar.html will fail with a 404 (Not Found) response π¦
6.2. Example: REBIND in Presence of Locks and Bind Loops
Let's see how locks and bind loops affect a REBIND, starting with this collection π
+------------------+
| Root Collection |
| bindings: |
| CollW |
+------------------+
|
|
|
+-------------------------------+
| Collection C1 |<--------+
| LOCKED infinity | |
| (lock token L1) | |
| bindings: | |
| CollX CollY | |
+-------------------------------+ |
| | |
| | (creates loop) |
| | |
+-----------------+ +------------------+ |
| Collection C2 | | Collection C3 | |
| (inherit lock) | | (inherit lock) | |
| (lock token L1) | | (lock token L1) | |
| bindings: | | bindings: | |
| {none} | | y.gif CollZ | |
+-----------------+ +------------------+ |
| | |
| +-----+
|
+---------------------------+
| Resource R2 |
| (lock inherited from C1) |
| (lock token L1) |
+---------------------------+
(where L1 is "urn:uuid:f92d4fae-7012-11ab-a765-00c0ca1f6bf9").
The binding between CollZ and C1 creates a loop in the containment hierarchy. Servers aren't required to support loops like this, though the server in this example does π
The REBIND request below removes the segment "CollZ" from C3 and adds a new binding from "CollA" to the collection C2 πΈ
REBIND /CollW/CollX HTTP/1.1
Host: www.example.com
If: (<urn:uuid:f92d4fae-7012-11ab-a765-00c0ca1f6bf9>)
Content-Type: application/xml; charset="utf-8"
Content-Length: 152
<?xml version="1.0" encoding="utf-8" ?>
<D:rebind xmlns:D="DAV:">
<D:segment>CollA</D:segment>
<D:href>/CollW/CollY/CollZ</D:href>
</D:rebind>
And here's the outcome of the REBIND operation β¨
+------------------+
| Root Collection |
| bindings: |
| CollW |
+------------------+
|
|
|
+-------------------------------+
| Collection C1 |
| LOCKED infinity |
| (lock token L1) |
| bindings: |
| CollX CollY |
+-------------------------------+
| ^ |
| | |
+-----------------+ | +------------------+
| Collection C2 | | | Collection C3 |
|(inherited lock) | | | (inherited lock) |
|(lock token L1) | | | (lock token L1) |
| bindings: | | | bindings: |
| CollA | | | y.gif |
+-----------------+ | +------------------+
| | |
+---------------+ |
(creates loop) |
+---------------------------+
| Resource R2 |
| (inherited lock from C1) |
| (lock token L1) |
+---------------------------+
7. Additional Status Codes β¨
7.1. 208 Already Reported
The 208 (Already Reported) status code can be used inside a DAV:propstat response element to avoid listing the internal members of multiple bindings to the same collection over and over π For each binding to a collection inside the request's scope, only one will be reported with a 200 status. Subsequent DAV:response elements for all other bindings use the 208 status, and no DAV:response elements for their descendants are included.
Note that the 208 status will only occur for Depth: infinity requests, and it matters most when multiple collection bindings cause a bind loop, as discussed in Section 2.2 π
A client can request the DAV:resource-id property in a PROPFIND request to make sure it can accurately rebuild the binding structure of a collection with multiple bindings to a single resource π§
For backward compatibility with clients that aren't aware of the 208 status code appearing in multistatus response bodies, it SHOULD NOT be used unless the client has signaled support for this specification using the DAV request header (see Section 8.2). Instead, a 508 status should be returned when a binding loop is discovered. That way the server can return the 508 as the top-level status if it finds the loop before it starts the response, or in the middle of a multistatus if it finds the loop while streaming out a multistatus response π
7.1.1. Example: PROPFIND by Bind-Aware Client β¨
okay so picture this π we send a PROPFIND on /Coll (bound to collection C). the members of /Coll are /Coll/Foo (bound to resource R) and /Coll/Bar (bound to collection C). this is giving loop energy π
>> Request:
PROPFIND /Coll/ HTTP/1.1
Host: www.example.com
Depth: infinity
DAV: bind
Content-Type: application/xml; charset="utf-8"
Content-Length: 152
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:displayname/>
<D:resource-id/>
</D:prop>
</D:propfind>
>> Response:
HTTP/1.1 207 Multi-Status
Content-Type: application/xml; charset="utf-8"
Content-Length: 1241
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/Coll/</D:href>
<D:propstat>
<D:prop>
<D:displayname>Loop Demo</D:displayname>
<D:resource-id>
<D:href
>urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf8</D:href>
</D:resource-id>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.example.com/Coll/Foo</D:href>
<D:propstat>
<D:prop>
<D:displayname>Bird Inventory</D:displayname>
<D:resource-id>
<D:href
>urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf9</D:href>
</D:resource-id>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.example.com/Coll/Bar</D:href>
<D:propstat>
<D:prop>
<D:displayname>Loop Demo</D:displayname>
<D:resource-id>
<D:href
>urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf8</D:href>
</D:resource-id>
</D:prop>
<D:status>HTTP/1.1 208 Already Reported</D:status>
</D:propstat>
</D:response>
</D:multistatus>
7.1.2. Example: PROPFIND by Non-Bind-Aware Client π
in this one the client doesn't know about the 208 status code yet, so it's not bind-aware π a "Depth: infinity" PROPFIND would cause a loop condition, so the whole request gets rejected with a 508 status.
>> Request:
PROPFIND /Coll/ HTTP/1.1
Host: www.example.com
Depth: infinity
Content-Type: application/xml; charset="utf-8"
Content-Length: 125
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop> <D:displayname/> </D:prop>
</D:propfind>
>> Response:
HTTP/1.1 508 Loop Detected
7.2. 508 Loop Detected π
the 508 (Loop Detected) status code means the server stopped an operation because it ran into an infinite loop while handling a request with "Depth: infinity". it's a full stop, so the entire operation counts as failed π
8. Capability Discovery π
8.1. OPTIONS Method π
if the server supports bindings, it MUST return the compliance class name bind as a field in the DAV response header (see [RFC4918], Section 10.1) from an OPTIONS request on any resource that server implements. a value of bind in the DAV header MUST indicate that the server supports all MUST-level requirements and REQUIRED features specified in this document. it's the server's little promise card π
8.2. 'DAV' Request Header π
clients SHOULD signal support for all MUST-level requirements and REQUIRED features by sending a "DAV" request header with the compliance class name "bind". and in particular, the client MUST understand the 208 status code defined in Section 7.1. no skipping that one bestie π«Ά
9. Relationship to Locking in WebDAV π
locking is an optional feature of WebDAV ([RFC4918]). the base WebDAV spec and this extension were designed side by side, so that every WebDAV feature can still work on a server that does this protocol too β¨
unfortunately WebDAV uses the term "lock-root" inconsistently π it's introduced in point 2 of Section 6.1 of [RFC4918] like this:
2. A resource becomes directly locked when a LOCK request to a URL of that resource creates a new lock. The "lock-root" of the new lock is that URL. If at the time of the request, the URL is not mapped to a resource, a new empty resource is created and directly locked.
and then [RFC4918], Section 9.10.1 says:
A LOCK request to an existing resource will create a lock on the resource identified by the Request-URI, provided the resource is not already locked with a conflicting lock. The resource identified in the Request-URI becomes the root of the lock.
so the two definitions disagree, and that's the tea π΅ servers that do both WebDAV locking and multiple bindings MUST use the first interpretation: the lock-root is the URI the lock was created through, not a resource. that URI, plus any aliases of it ([RFC4918], Section 5), are called "protected" by the lock π‘οΈ
as defined in the intro to Section 7 of [RFC4918], write operations that change the state of a locked resource need the lock token sent along with the request. consistent with WebDAV, the state of the resource is its content ("any variant"), its dead properties, its lockable live properties (item 1), plus, for a collection, all its bindings (item 2). and this doesn't depend on which Request-URI the write goes to, since the locked state belongs to the resource, not its URI π
BUT the lock-root is the URI the lock was requested through, so the protection from item 3 of the list doesn't cover the extra URIs that point at the same resource thanks to multiple bindings. that's the twist π
9.1. Example: Locking and Multiple Bindings π¦
picture a root collection /, containing two collections C1 and C2, named /CollX and /CollY, and a child resource R, bound to C1 as /CollX/test and bound to C2 as /CollY/test:
+-------------------------+
| Root Collection |
| bindings: |
| CollX CollY |
+-------------------------+
| |
| |
| |
+---------------+ +---------------+
| Collection C1 | | Collection C2 |
| bindings: | | bindings: |
| test | | test |
+---------------+ +---------------+
| |
| |
| |
+------------------+
| Resource R |
+------------------+
with the host name www.example.com, putting a depth-zero write lock on /CollX/test locks resource R, and the lock-root of that lock is http://www.example.com/CollX/test π
so these operations will need the matching lock token in the "If" request header ([RFC4918], Section 10.4):
- a PUT or PROPPATCH request that changes the content or lockable properties of resource R (since R is locked), no matter which URI is used as the request target, and
- a MOVE, REBIND, UNBIND, or DELETE request that stops
/CollX/testfrom mapping to resource R (whether it's addressed to/CollXor/CollX/test).
and these ones DON'T need the lock token π
- a DELETE request addressed to
/CollYor/CollY/test, since it doesn't touch resource R or the lock-root, - for the same reason, an UNBIND request that removes the binding
testfrom collection C2, or the bindingCollYfrom the root collection, and - similarly, a MOVE or REBIND request that stops
/CollY/testfrom mapping to resource R.
one more thing π even though the lock-root is http://www.example.com/CollX/test, an UNLOCK request can be sent through any URI that maps to resource R, because UNLOCK works on the resource identified by the Request-URI, not that URI (see [RFC4918], Section 9.11) π«§
10. Relationship to WebDAV Access Control Protocol π
the WebDAV Access Control Protocol was designed to be compatible with systems where multiple URIs map to the same resource (see [RFC3744], Section 5), and it says:
Access control properties (especially DAV:acl and DAV:inherited-acl-set) are defined on the resource identified by the Request-URI of a PROPFIND request. A direct consequence is that if the resource is accessible via multiple URI, the value of access control properties is the same across these URI.
and finally π
BIND and REBIND behave the same as MOVE when it comes to the DAV:acl property (see [RFC3744], Section 7.3).
11. Relationship to Versioning Extensions to WebDAV β¨
Servers that implement Workspaces ([RFC3253], Section 6) and Version-Controlled Collections ([RFC3253], Section 14) already need BIND-like behavior to handle UPDATE and UNCHECKOUT semantics. It's honestly the same energy π
Picture a workspace "/ws1/" with two version-controlled, checked-out collections inside it, C1 and C2, named "/ws1/CollX" and "/ws1/CollY". There's also a version-controlled resource R, bound to C1 as "/ws1/CollX/test". Here's the vibe:
+-------------------------+
| Workspace |
| bindings: |
| CollX CollY |
+-------------------------+
| |
| |
| |
+---------------+ +---------------+
| Collection C1 | | Collection C2 |
| bindings: | | |
| test | | |
+---------------+ +---------------+
|
|
|
+------------------+
| Resource R |
+------------------+
So here's the tea β If you MOVE "/ws1/CollX/test" into "/ws1/CollY", check in C2, but undo the checkout on C1, you undo part of the MOVE request. That restores the binding from C1 to R, but keeps the new binding from C2 to R π¦
>> Request:
MOVE /ws1/CollX/test HTTP/1.1
Host: www.example.com
Destination: /ws1/CollY/test
>> Response:
HTTP/1.1 204 No Content
>> Request:
CHECKIN /ws1/CollY/ HTTP/1.1
Host: www.example.com
>> Response:
HTTP/1.1 201 Created
Cache-Control: no-cache
Location: http://repo.example.com/his/17/ver/42
>> Request:
UNCHECKOUT /ws1/CollX/ HTTP/1.1
Host: www.example.com
>> Response:
HTTP/1.1 200 OK
Cache-Control: no-cache
And the end result? Both C1 and C2 have a binding to R π
+-------------------------+
| Workspace |
| bindings: |
| CollX CollY |
+-------------------------+
| |
| |
| |
+---------------+ +---------------+
| Collection C1 | | Collection C2 |
| bindings: | | bindings: |
| test | | test |
+---------------+ +---------------+
| |
| |
| |
+------------------+
| Resource R |
+------------------+
The MOVE semantics in Section 3.15 of [RFC3253] already require that "/ws1/CollX/test" and "/ws1/CollY/test" have the same version history, as exposed in the DAV:version-history property. Then the UNCHECKOUT semantics (which in this case are similar to UPDATE, see Section 14.11 of [RFC3253]) add this rule:
If a new version-controlled member is in a workspace that already has a version-controlled resource for that version history, then the new version-controlled member MUST be just a binding (i.e., another name for) that existing version-controlled resource.
So "/ws1/CollX/test" and "/ws1/CollY/test" end up as bindings to the same resource R, with identical DAV:resource-id properties. Iconic behavior, honestly π
12. Security Considerations π
This section is here to make WebDAV implementers aware of the security implications of this protocol. Please take it seriously, bestie π
Everything in the security considerations of HTTP/1.1 ([RFC2616], Section 15) and the WebDAV Distributed Authoring Protocol specification ([RFC4918], Section 20) also applies to this protocol. On top of that, bindings bring some brand-new security concerns and make a few existing threats more likely. Here's the breakdown π
12.1. Privacy Concerns
Where cross-server bindings are supported, creating bindings on a trusted server may let a hostile agent trick users into sending private information to a target on a different server. Yikes π
12.2. Bind Loops
Bind loops were already possible in HTTP 1.1, but the BIND method gives clients a new way to create loops, whether by accident or on purpose π If the binding and its target live on the same server, the server may be able to detect BIND requests that would create loops. Servers are required to detect loops caused by bindings to collections while processing any request with "Depth: infinity".
12.3. Bindings and Denial of Service
Denial-of-service attacks were already possible by posting URIs meant for limited use at heavily used Web sites. BIND creates a new way to run similar attacks π If cross-server bindings are supported, clients can create bindings at heavily used sites that point to locations never designed for heavy traffic.
12.4. Private Locations May Be Revealed
If the DAV:parent-set property is maintained on a resource, the owners of the bindings risk revealing private locations π§ The directory structures where bindings live are visible to anyone with access to the DAV:parent-set property on the resource. Moving a binding may also reveal its new location to anyone with access to DAV:parent-set on its resource.
12.5. DAV:parent-set and Denial of Service
If the server maintains the DAV:parent-set property for bindings created in other administrative domains, it's open to hostile attempts to make it spend resources adding bindings to that list π₯
13. Internationalization Considerations π
All internationalization considerations in Section 19 of [RFC4918] also apply to this document.
14. IANA Considerations π
Section 7 defines the HTTP status codes 208 (Already Reported) and 508 (Loop Detected), which have been added to the HTTP Status Code Registry. Slay β¨
15. Acknowledgements π«Ά
This document is the collaborative product of the authors and Tyson Chihaya, Jim Davis, Chuck Fay and Judith Slein. It also benefited from thoughtful discussion by Jim Amsden, Peter Carlson, Steve Carter, Ken Coar, Ellis Cohen, Dan Connolly, Bruce Cragun, Cyrus Daboo, Spencer Dawkins, Mark Day, Werner Donne, Rajiv Dulepet, David Durand, Lisa Dusseault, Stefan Eissing, Roy Fielding, Yaron Goland, Joe Hildebrand, Fred Hitt, Alex Hopmann, James Hunt, Marcus Jager, Chris Kaler, Manoj Kasichainula, Rohit Khare, Brian Korver, Daniel LaLiberte, Steve Martin, Larry Masinter, Jeff McAffer, Alexey Melnikov, Surendra Koduru Reddy, Max Rible, Sam Ruby, Bradley Sergeant, Nick Shelness, John Stracke, John Tigue, John Turner, Kevin Wiggen, and other members of the concluded WebDAV working group. Everyone in that list is iconic π
16. References π
16.1. Normative References
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H.,
Masinter, L., Leach, P., and T. Berners-Lee, "Hypertext
Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, January 2005.
[RFC4918] Dusseault, L., Ed., "HTTP Extensions for Web Distributed
Authoring and Versioning (WebDAV)", RFC 4918, June 2007.
[XML] Bray, T., Paoli, J., Sperberg-McQueen, C., Maler, E., and
F. Yergeau, "Extensible Markup Language (XML) 1.0 (Fifth
Edition)", W3C REC-xml-20081126, November 2008,
<http://www.w3.org/TR/2008/REC-xml-20081126/>.
16.2. Informative References
[RFC3253] Clemm, G., Amsden, J., Ellison, T., Kaler, C., and J.
Whitehead, "Versioning Extensions to WebDAV (Web
Distributed Authoring and Versioning)", RFC 3253,
March 2002.
[RFC3744] Clemm, G., Reschke, J., Sedlar, E., and J. Whitehead, "Web
Distributed Authoring and Versioning (WebDAV) Access
Control Protocol", RFC 3744, May 2004.
[RFC4122] Leach, P., Mealling, M., and R. Salz, "A Universally
Unique IDentifier (UUID) URN Namespace", RFC 4122,
July 2005.
Index β¨
okay so this is the index, aka the cheat sheet that tells you exactly where everything lives in the spec ποΈ every status code, method, condition name, and property is listed with the page numbers where it shows up. no cap, it's the fastest way to find the exact thing you're hunting for π
2
208 Already Reported (status code) 31, 41
5
508 Loop Detected (status code) 34, 41
B
BIND method 21
Marshalling 22
Postconditions 23
Preconditions 22
Binding 6
Binding Integrity 6-7, 21
C
Collection 6
Condition Names
DAV:bind-into-collection (pre) 22
DAV:bind-source-exists (pre) 22
DAV:binding-allowed (pre) 23
DAV:binding-deleted (post) 25, 28
DAV:can-overwrite (pre) 23, 27
DAV:cross-server-binding (pre) 23, 27
DAV:cycle-allowed (pre) 23, 27
DAV:lock-deleted (post) 25, 28
DAV:locked-overwrite-allowed (pre) 23
DAV:locked-source-collection-update-allowed (pre) 28
DAV:locked-update-allowed (pre) 23, 25, 27
DAV:name-allowed (pre) 23, 27
DAV:new-binding (post) 23, 28
DAV:protected-source-url-deletion-allowed (pre) 28
DAV:protected-url-deletion-allowed (pre) 25
DAV:protected-url-modification-allowed (pre) 27
DAV:rebind-into-collection (pre) 27
DAV:rebind-source-exists (pre) 27
DAV:unbind-from-collection (pre) 25
DAV:unbind-source-exists (pre) 25
D
DAV header
compliance class 'bind' 34
DAV:bind-into-collection precondition 22
DAV:bind-source-exists precondition 22
DAV:binding-allowed precondition 23
DAV:binding-deleted postcondition 25, 28
DAV:can-overwrite precondition 23, 27
DAV:cross-server-binding precondition 23, 27
DAV:cycle-allowed precondition 23, 27
DAV:lock-deleted postcondition 25, 28
DAV:locked-overwrite-allowed precondition 23
DAV:locked-source-collection-update-allowed precondition 28
DAV:locked-update-allowed precondition 23, 25, 27
DAV:name-allowed precondition 23, 27
DAV:new-binding postcondition 23, 28
DAV:parent-set property 20
DAV:protected-source-url-deletion-allowed precondition 28
DAV:protected-url-deletion-allowed precondition 25
DAV:protected-url-modification-allowed precondition 27
DAV:rebind-into-collection precondition 27
DAV:rebind-source-exists precondition 27
DAV:resource-id property 19
DAV:unbind-from-collection precondition 25
DAV:unbind-source-exists precondition 25
I
Internal Member URI 6
L
Locking 35
M
Methods
BIND 21
REBIND 26
UNBIND 24
P
Path Segment 5
Properties
DAV:parent-set 20
DAV:resource-id 19
R
REBIND method 26
Marshalling 26
Postconditions 28
Preconditions 27
S
Status Codes
208 Already Reported 31, 41
508 Loop Detected 34, 41
U
UNBIND method 24
Marshalling 24
Postconditions 25
Preconditions 25
URI Mapping 5
Authors' Addresses π
and here are the people who wrote this spec, with their mailing addresses and emails so you can reach out π«Ά these are the authors' own contact details, copied exactly as published.
Geoffrey Clemm
IBM
550 King Street
Littleton, MA 01460
EMail: geoffrey.clemm@us.ibm.com
Jason Crawford
IBM Research
P.O. Box 704
Yorktown Heights, NY 10598
EMail: ccjason@us.ibm.com
Julian F. Reschke (editor)
greenbytes GmbH
Hafenweg 16
Muenster, NW 48155
Germany
EMail: julian.reschke@greenbytes.de
Jim Whitehead
UC Santa Cruz, Dept. of Computer Science
1156 High Street
Santa Cruz, CA 95064
EMail: ejw@cse.ucsc.edu
π¦ where this page comes from
- ietf: rfc5842 2010-04
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms