RFC 2518
HTTP Extensions for Distributed Authoring -- WEBDAV
RFC 2518: HTTP Extensions for Distributed Authoring, aka WEBDAV ๐
okay bestie, this is the RFC that taught the web how to be a shared folder ๐โจ it's a Standards Track doc from February 1999, and the crew behind it is giving: Y. Goland (Microsoft), E. Whitehead (UC Irvine), A. Faizi (Netscape), S. Carter (Novell), and D. Jensen (Novell). it was written in the Network Working Group, and its title block doesn't list anything it obsoletes or updates, so it's standing on its own ๐
Status of this Memo โจ
this doc is an Internet standards track protocol for the Internet community, and it's literally asking for discussion and suggestions to make it better ๐ซถ if you want to know where this protocol stands right now, check the current edition of the "Internet Official Protocol Standards" (STD 1). and the memo can be distributed with no limits ๐ฆ
Copyright Notice
Copyright (C) The Internet Society (1999). All Rights Reserved. ๐
Abstract
okay so the big idea is this ๐ธ the doc defines a bunch of methods, headers, and content-types that sit on top of HTTP/1.1. they help you manage resource properties, make and handle resource collections, play with the namespace, and lock resources so people don't crash into each other ๐ (that last part is the collision avoidance era, iykyk ๐ญ)
Table of Contents ๐ง
ABSTRACT............................................................1
1 INTRODUCTION .....................................................5
2 NOTATIONAL CONVENTIONS ...........................................7
3 TERMINOLOGY ......................................................7
4 DATA MODEL FOR RESOURCE PROPERTIES ...............................8
4.1 The Resource Property Model ...................................8
4.2 Existing Metadata Proposals ...................................8
4.3 Properties and HTTP Headers ...................................9
4.4 Property Values ...............................................9
4.5 Property Names ...............................................10
4.6 Media Independent Links ......................................10
5 COLLECTIONS OF WEB RESOURCES ....................................11
5.1 HTTP URL Namespace Model .....................................11
5.2 Collection Resources .........................................11
5.3 Creation and Retrieval of Collection Resources ...............12
5.4 Source Resources and Output Resources ........................13
6 LOCKING .........................................................14
6.1 Exclusive Vs. Shared Locks ...................................14
6.2 Required Support .............................................16
6.3 Lock Tokens ..................................................16
6.4 opaquelocktoken Lock Token URI Scheme ........................16
6.4.1 Node Field Generation Without the IEEE 802 Address ........17
6.5 Lock Capability Discovery ....................................19
6.6 Active Lock Discovery ........................................19
6.7 Usage Considerations .........................................19
7 WRITE LOCK ......................................................20
7.1 Methods Restricted by Write Locks ............................20
7.2 Write Locks and Lock Tokens ..................................20
7.3 Write Locks and Properties ...................................20
7.4 Write Locks and Null Resources ...............................21
7.5 Write Locks and Collections ..................................21
7.6 Write Locks and the If Request Header ........................22
7.6.1 Example - Write Lock ......................................22
7.7 Write Locks and COPY/MOVE ....................................23
7.8 Refreshing Write Locks .......................................23
8 HTTP METHODS FOR DISTRIBUTED AUTHORING ..........................23
8.1 PROPFIND .....................................................24
8.1.1 Example - Retrieving Named Properties .....................25
8.1.2 Example - Using allprop to Retrieve All Properties ........26
8.1.3 Example - Using propname to Retrieve all Property Names ...29
8.2 PROPPATCH ....................................................31
8.2.1 Status Codes for use with 207 (Multi-Status) ..............31
8.2.2 Example - PROPPATCH .......................................32
8.3 MKCOL Method .................................................33
8.3.1 Request ...................................................33
8.3.2 Status Codes ..............................................33
8.3.3 Example - MKCOL ...........................................34
8.4 GET, HEAD for Collections ....................................34
8.5 POST for Collections .........................................35
8.6 DELETE .......................................................35
8.6.1 DELETE for Non-Collection Resources .......................35
8.6.2 DELETE for Collections ....................................36
8.7 PUT ..........................................................36
8.7.1 PUT for Non-Collection Resources ..........................36
8.7.2 PUT for Collections .......................................37
8.8 COPY Method ..................................................37
8.8.1 COPY for HTTP/1.1 resources ...............................37
8.8.2 COPY for Properties .......................................38
8.8.3 COPY for Collections ......................................38
8.8.4 COPY and the Overwrite Header .............................39
8.8.5 Status Codes ..............................................39
8.8.6 Example - COPY with Overwrite .............................40
8.8.7 Example - COPY with No Overwrite ..........................40
8.8.8 Example - COPY of a Collection ............................41
8.9 MOVE Method ..................................................42
8.9.1 MOVE for Properties .......................................42
8.9.2 MOVE for Collections ......................................42
8.9.3 MOVE and the Overwrite Header .............................43
8.9.4 Status Codes ..............................................43
8.9.5 Example - MOVE of a Non-Collection ........................44
8.9.6 Example - MOVE of a Collection ............................44
8.10 LOCK Method ..................................................45
8.10.1 Operation .................................................46
8.10.2 The Effect of Locks on Properties and Collections .........46
8.10.3 Locking Replicated Resources ..............................46
8.10.4 Depth and Locking .........................................46
8.10.5 Interaction with other Methods ............................47
8.10.6 Lock Compatibility Table ..................................47
8.10.7 Status Codes ..............................................48
8.10.8 Example - Simple Lock Request .............................48
8.10.9 Example - Refreshing a Write Lock .........................49
8.10.10 Example - Multi-Resource Lock Request ....................50
8.11 UNLOCK Method ................................................51
8.11.1 Example - UNLOCK ..........................................52
9 HTTP HEADERS FOR DISTRIBUTED AUTHORING ..........................52
9.1 DAV Header ...................................................52
9.2 Depth Header .................................................52
9.3 Destination Header ...........................................54
9.4 If Header ....................................................54
9.4.1 No-tag-list Production ....................................55
9.4.2 Tagged-list Production ....................................55
9.4.3 not Production ............................................56
9.4.4 Matching Function .........................................56
9.4.5 If Header and Non-DAV Compliant Proxies ...................57
9.5 Lock-Token Header ............................................57
9.6 Overwrite Header .............................................57
9.7 Status-URI Response Header ...................................57
9.8 Timeout Request Header .......................................58
10 STATUS CODE EXTENSIONS TO HTTP/1.1 ............................59
10.1 102 Processing ...............................................59
10.2 207 Multi-Status .............................................59
10.3 422 Unprocessable Entity .....................................60
10.4 423 Locked ...................................................60
10.5 424 Failed Dependency ........................................60
10.6 507 Insufficient Storage .....................................60
11 MULTI-STATUS RESPONSE .........................................60
12 XML ELEMENT DEFINITIONS .......................................61
12.1 activelock XML Element .......................................61
1. Introduction โจ
Okay bestie, so this document describes an extension to the HTTP/1.1 protocol that lets clients do remote web content authoring operations ๐ . It gives you a coherent set of methods, headers, request entity body formats, and response entity body formats for four big jobs:
- Properties: creating, removing, and querying info about Web pages, like their authors, creation dates, etc. You can also link pages of any media type to related pages ๐.
- Collections: making sets of documents and getting back a hierarchical membership listing, like a directory listing in a file system ๐.
- Locking: keeping more than one person from working on a document at the same time ๐. This stops the "lost update problem", where changes vanish because one author writes over another author's changes without merging them. Major yikes ๐ญ.
- Namespace Operations: telling the server to copy and move Web resources ๐.
The requirements and rationale for all this live in a companion document, "Requirements for a Distributed Authoring and Versioning Protocol for the World Wide Web" [RFC2291] ๐.
The sections below give you the full tour: resource properties (section 4), collections of resources (section 5), and locking operations (section 6). They introduce the abstractions that the WebDAV-specific HTTP methods in section 8, "HTTP Methods for Distributed Authoring", manipulate ๐ง.
In HTTP/1.1, method parameter info was exclusively encoded in HTTP headers. WebDAV is different: it encodes method parameter info either in an Extensible Markup Language (XML) [REC-XML] request entity body, or in an HTTP header ๐ฆ. XML won the job for two reasons. First, you can add extra XML elements to existing structures, which means extensibility. Second, XML can encode info in ISO 10646 character sets, which means internationalization support ๐. As a rule of thumb, parameters go in XML entity bodies when they have unbounded length, or when they may be shown to a human user and therefore need encoding in an ISO 10646 character set. Everything else goes in HTTP headers. Section 9 describes the new HTTP headers used with WebDAV methods ๐.
XML isn't only for input, either. WebDAV also uses XML to encode the responses from methods, so you get the extensibility and internationalization perks on the way out too, not just on the way in ๐.
The XML elements used in this specification are defined in section 12 ๐งฉ.
The XML namespace extension (Appendix 4) is also used here, so new XML elements can be added without fear of colliding with other element names ๐ โโ๏ธ.
HTTP/1.1 status codes are enough to describe most error conditions WebDAV methods run into, but a few errors don't fit neatly into the existing categories ๐คทโโ๏ธ. The new status codes developed for WebDAV methods are defined in section 10. Some WebDAV methods can operate over many resources at once, so the Multi-Status response was introduced to return status info for multiple resources. You'll find it described in section 11 ๐ฆ.
WebDAV uses the property mechanism to store info about the current state of a resource ๐ง . For example, when a lock is taken out on a resource, a lock information property describes the current state of that lock. Section 13 defines the properties used within the WebDAV specification ๐.
To finish off, there are sections on what it means to be compliant with this specification (section 15), on internationalization support (section 16), and on security (section 17) ๐ก๏ธ. Stay tuned, it's about to get spicy ๐ถ๏ธ.
2. Notational Conventions
Since this document describes a set of extensions to the HTTP/1.1 protocol, the augmented BNF used here to describe protocol elements is exactly the same as the one described in section 2.1 of [RFC2068] ๐. That augmented BNF uses the basic production rules provided in section 2.2 of [RFC2068], so those rules apply to this document too.
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 RFC 2119 [RFC2119] ๐ซถ.
3. Terminology
Here's the vocab you need so we're all on the same page ๐:
- URI/URL - A Uniform Resource Identifier and Uniform Resource Locator, respectively. These terms (and the distinction between them) are defined in [RFC2396] ๐.
- Collection - A resource that contains a set of URIs, termed member URIs, which identify member resources and meets the requirements in section 5 of this specification ๐.
- Member URI - A URI which is a member of the set of URIs contained by a collection ๐งท.
- Internal Member URI - A Member URI that is immediately relative to the URI of the collection. (The definition of immediately relative is given in section 5.2 ๐งญ.)
- Property - A name/value pair that contains descriptive information about a resource ๐ท๏ธ.
- Live Property - A property whose semantics and syntax are enforced by the server โก. For example, the live "getcontentlength" property has its value, the length of the entity returned by a GET request, automatically calculated by the server. The server does the math so you don't have to ๐งฎ.
- Dead Property - A property whose semantics and syntax are not enforced by the server ๐. The server only records the value of a dead property, and the client is responsible for maintaining the consistency of its syntax and semantics. Main character client energy ๐.
- Null Resource - A resource which responds with a 404 (Not Found) to any HTTP/1.1 or DAV method except for PUT, MKCOL, OPTIONS and LOCK ๐ซฅ. A NULL resource MUST NOT appear as a member of its parent collection ๐ซ.
4. Data Model for Resource Properties โจ
๐จ Heads up, bestie: the sections listed in the IMPORTANT note (12.2 through 23.4) weren't in the text I was given, so I haven't invented them. Send me the original text for those and I'll slay them in the next parts ๐ .
4.1. The Resource Property Model
okay so properties are little pieces of data that describe what state a resource is in โจ basically data about data ๐ค
They're used in distributed authoring environments so you can discover and manage resources efficiently ๐ . Like, a 'subject' property could let you index every resource by its subject, and an 'author' property could help you find which authors wrote which documents ๐ iconic.
The DAV property model is made of name/value pairs ๐. The name of a property tells you its syntax and semantics, and it gives you an address to refer to them by ๐ฆ.
There are two categories: "live" and "dead" ๐. A live property has its syntax and semantics enforced by the server. That includes cases where a) the value is read-only and maintained by the server, and b) the value is maintained by the client but the server does syntax checking on submitted values. Every instance of a given live property MUST comply with the definition tied to that property name ๐ฅ. A dead property has its syntax and semantics enforced by the client, and the server just records the value verbatim ๐ซถ.
4.2. Existing Metadata Proposals
Properties have long been essential for maintaining big document repositories ๐, and lots of current proposals have some notion of a property or talk about web metadata more generally ๐ธ. These include PICS [REC-PICS], PICS-NG, XML, Web Collections, and several proposals for representing relationships within HTML. Work on PICS-NG and Web Collections got absorbed into the Resource Description Framework (RDF) metadata activity of the World Wide Web Consortium ๐ง. RDF is a network-based data model with an XML representation of that model ๐.
Some proposals come from a digital library perspective ๐. These include the Dublin Core [RFC2413] metadata set and the Warwick Framework [WF], a container architecture for different metadata schemas. The literature has tons of metadata examples too, like MARC [USMARC], a bibliographic metadata format, and a technical report bibliographic format used by the Dienst system [RFC1807] ๐. Also, the proceedings from the first IEEE Metadata conference describe loads of community-specific metadata sets ๐ .
Participants of the 1996 Metadata II Workshop in Warwick, UK [WF], noted that "new metadata sets will develop as the networked infrastructure matures" and "different communities will propose, design, and be responsible for different types of metadata." ๐ซถ These observations hold up. Lots of community-specific sets already exist, and there's real motivation for new forms of metadata, because more and more communities are making their data available in digital form and that needs a metadata format to help with data location and cataloging ๐.
4.3. Properties and HTTP Headers
Properties already exist, in a limited sense, in HTTP message headers ๐จ. But in distributed authoring environments you need a relatively large number of properties to describe a resource's state, and setting or returning them all through HTTP headers is inefficient ๐ญ. So we need a mechanism that lets a principal identify a set of properties it's interested in, then set or retrieve just those ones โจ.
4.4. Property Values
The value of a property when expressed in XML MUST be well formed. ๐
XML was picked because it's flexible, self-describing, structured, supports rich schema definitions, and supports multiple character sets ๐. Its self-describing nature means any property's value can be extended by adding new elements. Older clients won't break on extensions, because they still have the data from the original schema and ignore elements they don't understand ๐ฆ. Multiple character sets mean any human-readable property can be encoded and read in a character set the user is familiar with ๐. XML also supports multiple human languages through the "xml:lang" attribute, which handles cases where several languages share the same character set ๐ธ.
4.5. Property Names
A property name is a universally unique identifier that's associated with a schema, and that schema gives info about the property's syntax and semantics ๐.
Because a property's name is universally unique, clients can count on consistent behavior for a particular property across multiple resources, on the same server and across different servers, as long as that property is "live" on those resources and the implementation of the live property is faithful to its definition ๐.
The XML namespace mechanism, which is based on URIs [RFC2396], is used to name properties because it prevents namespace collisions and provides for varying degrees of administrative control ๐ง.
The property namespace is flat, meaning no hierarchy of properties is explicitly recognized. So if a property A and a property A/B both exist on a resource, there's no recognition of any relationship between the two ๐. A separate specification is expected to eventually come out and address hierarchical properties ๐.
Finally, it's not possible to define the same property twice on a single resource, because that would cause a collision in the resource's property namespace ๐ซ.
4.6. Media Independent Links
Although HTML resources support links to other resources, the Web needs more general support for links between resources of any media type (media types are also known as MIME types, or content types) ๐. WebDAV provides such links. A WebDAV link is a special type of property value, formally defined in section 12.4, that lets typed connections be made between resources of any media type ๐ฆ. The property value consists of source and destination Uniform Resource Identifiers (URIs), and the property name identifies the link type ๐.
5. Collections of Web Resources
This section describes a new type of Web resource, the collection, and talks about how it interacts with the HTTP URL namespace ๐. The purpose of a collection resource is to model collection-like objects (e.g., file system directories) within a server's namespace ๐๏ธ.
All DAV compliant resources MUST support the HTTP URL namespace model specified herein. ๐ซถ
5.1. HTTP URL Namespace Model
The HTTP URL namespace is hierarchical, and the hierarchy is delimited with the "/" character ๐ณ.
An HTTP URL namespace is consistent if it meets the following conditions: for every URL in the HTTP hierarchy, there exists a collection that contains that URL as an internal member. The root, or top-level collection of the namespace under consideration, is exempt from the previous rule ๐.
Neither HTTP/1.1 nor WebDAV require that the entire HTTP URL namespace be consistent. However, certain WebDAV methods are prohibited from producing results that cause namespace inconsistencies ๐ .
Although implicit in [RFC2068] and [RFC2396], any resource, including collection resources, MAY be identified by more than one URI ๐ฆ. For example, a resource could be identified by multiple HTTP URLs โจ.
5.2. Collection Resources
A collection is a resource whose state consists of at least a list of internal member URIs and a set of properties, but which may have additional state too, like entity bodies returned by GET ๐. An internal member URI MUST be immediately relative to a base URI of the collection. In other words, the internal member URI equals a containing collection's URI plus an additional segment for non-collection resources, or additional segment plus trailing slash "/" for collection resources, where segment is defined in section 3.3 of [RFC2396] ๐งฉ.
Any given internal member URI MUST only belong to the collection once, i.e., it's illegal to have multiple instances of the same URI in a collection ๐ซ. Properties defined on collections behave exactly like properties on non-collection resources ๐ .
For all WebDAV compliant resources A and B, identified by URIs U and V, for which U is immediately relative to V, B MUST be a collection that has U as an internal member URI. So if the resource with URL http://foo.com/bar/blah is WebDAV compliant and the resource with URL http://foo.com/bar/ is WebDAV compliant, then the resource with URL http://foo.com/bar/ must be a collection and must contain URL http://foo.com/bar/blah as an internal member ๐ธ.
Collection resources MAY list the URLs of non-WebDAV compliant children in the HTTP URL namespace hierarchy as internal members, but they aren't required to ๐คทโโ๏ธ. For example, if the resource with URL http://foo.com/bar/blah is not WebDAV compliant and the URL http://foo.com/bar/ identifies a collection, then http://foo.com/bar/blah may or may not be an internal member of the collection with URL http://foo.com/bar/ ๐ค.
If a WebDAV compliant resource has no WebDAV compliant children in the HTTP URL namespace hierarchy, then it isn't required to be a collection ๐.
There's a standing convention that when a collection is referred to by its name without a trailing slash, the trailing slash is automatically appended ๐. Due to this, a resource may accept a URI without a trailing "/" to point to a collection. In this case it SHOULD return a content-location header in the response pointing to the URI ending with the "/". For example, if a client invokes a method on http://foo.bar/blah (no trailing slash), the resource http://foo.bar/blah/ (trailing slash) may respond as if the operation were invoked on it, and should return a content-location header with http://foo.bar/blah/ in it. In general, clients SHOULD use the "/" form of collection names ๐.
A resource MAY be a collection but not be WebDAV compliant. That is, the resource may comply with all the rules set out in this specification about how a collection is to behave, without necessarily supporting all methods that a WebDAV compliant resource is required to support. In such a case the resource may return the DAV:resourcetype property with the value DAV:collection but MUST NOT return a DAV header containing the value "1" on an OPTIONS response ๐ฅน.
5.3 Creation and Retrieval of Collection Resources ๐
okay so this spec uses MKCOL to make new collection resources instead of the HTTP/1.1 PUT or POST methods ๐
here's why, bestie:
PUT in HTTP/1.1 is defined to store the request body at the location given by the Request-URI ๐ฆ sure, you could build a description format for a collection and PUT it, but sending that description to the server is lowkey a disaster ๐ญ if a collection description leaves out some existing resources, the server might read that as "delete those members pls" ๐ which means PUT is secretly doing DELETE's job now. that changes what PUT means, and it makes it way harder to control DELETE with an access control scheme based on methods ๐
POST is super open-ended, so yes, you could construct a "create a collection" POST command ๐คทโโ๏ธ but it's not it, because then it'd be hard to separate access control for collection creation from every other use of POST ๐ซ
The exact behavior of GET and PUT on collections gets defined later in this document โจ
5.4 Source Resources and Output Resources โญ
For lots of resources, the entity returned by a GET matches the persistent state of the resource exactly ๐ผ๏ธ think a GIF file sitting on a disk. in that simple case, the URI where you access the resource is the same URI where its source (the persistent state) lives. same goes for HTML source files the server doesn't process before sending ๐ธ
but the server can sometimes process HTML resources before they go out as a return entity body ๐ง for example, a server-side-include directive inside an HTML file might tell the server to swap the directive for another value, like the current date. so now GET gives back (HTML plus date), which is different from the persistent state of the resource (HTML plus directive). typically there's no way to access the HTML resource containing the unprocessed directive ๐
sometimes the entity GET returns is the output of a data-producing process described by one or more source resources (which might not even have a location in the URI namespace) ๐ one data-producing process can dynamically generate the state of a potentially huge number of output resources. an example is a CGI script describing a "finger" gateway process that maps part of a server's namespace into finger requests, like http://www.foo.bar.org/finger_gateway/user@host ๐
without distributed authoring capabilities, it's totally acceptable to have no mapping of source resource(s) to the URI namespace. honestly, preventing access to the source resource(s) has desirable security benefits ๐ but if remote editing of the source resource(s) is desired, they should be given a location in the URI namespace. that source location should not be one of the locations where the generated output is retrievable, since in general the server can't tell apart requests for source resources from requests for process output resources ๐ซ and there's often a many-to-many relationship between source resources and output resources ๐
on WebDAV compliant servers, the URI of the source resource(s) may be stored in a link on the output resource with type DAV:source (see section 13.10 for a description of the source link property) ๐ storing source URIs in links on output resources puts the burden of discovering the source on the authoring client ๐ต๏ธ note that the value of a source link is not guaranteed to point to the correct source. source links may break, or incorrect values may be entered ๐ also, not all servers will let the client set the source link value. for example, a server that generates source links on the fly for its CGI files will most likely not let a client set that value ๐
โโ๏ธ
6 Locking ๐
the ability to lock a resource gives you a way to serialize access to it ๐ซถ using a lock, an authoring client can provide a reasonable guarantee that another principal won't modify a resource while it's being edited. that's how a client can prevent the "lost update" problem ๐ญ
this spec lets locks vary over two client-specified parameters: the number of principals involved (exclusive vs. shared) and the type of access being granted. this document only defines locking for one access type, write ๐ but the syntax is extensible, so locking for other access types can be specified eventually ๐ฆ
6.1 Exclusive Vs. Shared Locks ๐
the most basic lock is an exclusive lock. it's a lock where the access right in question is only granted to a single principal. this arbitration is needed because of a desire to avoid having to merge results ๐ โโ๏ธ
but sometimes the goal of a lock isn't to keep others out of an access right. it's more about giving principals a way to say they intend to exercise their access rights ๐ that's what shared locks are for. a shared lock lets multiple principals receive a lock, so any principal with appropriate access can get one โจ
with shared locks there are two trust sets that affect a resource. the first is created by access permissions: principals who are trusted (for example, those who may write to the resource) ๐ among principals with access permission to write, the set of principals who've taken out a shared lock also must trust each other, creating a (typically) smaller trust set inside the access permission write set ๐ค
starting from every possible principal on the Internet, in most situations the vast majority won't have write access to a given resource ๐ of the small number who do, some may decide to guarantee their edits are free from overwrite conflicts by using exclusive write locks. others may decide they trust their collaborators not to overwrite their work (the potential collaborators being the set of principals with write permission) and use a shared lock, which tells collaborators that a principal may be working on the resource ๐ฃ
the WebDAV extensions to HTTP don't need to provide every communication path principals need to coordinate ๐ฌ with shared locks, principals may use any out-of-band channel to coordinate (face-to-face, written notes, post-it notes on the screen, telephone, Email, etc.) ๐ the intent of a shared lock is just to let collaborators know who else may be working on a resource ๐ซง
shared locks are included because experience from web distributed authoring systems showed exclusive locks are often too rigid ๐ฅฒ an exclusive lock enforces a particular editing process: take out an exclusive lock, read the resource, perform edits, write the resource, release the lock. the problem is that locks aren't always properly released, like when a program crashes or a lock owner leaves without unlocking the resource ๐ timeouts and administrative action can both remove an offending lock, but neither may be available when needed: the timeout may be long, or the administrator may not be around ๐ฉ
6.2 Required Support ๐ซถ
a WebDAV compliant server is not required to support locking in any form. if it does support locking, it may choose to support any combination of exclusive and shared locks for any access types โจ
the reason for this flexibility is that locking policy hits the very heart of the resource management and versioning systems used by various storage repositories ๐๏ธ these repositories need control over what sort of locking is made available. for example, some only support shared write locks, others only support exclusive write locks, and yet others use no locking at all ๐ since each system is different enough to merit excluding certain locking features, this spec makes locking the sole axis of negotiation within WebDAV ๐ฏ
6.3 Lock Tokens ๐๏ธ
a lock token is a type of state token, represented as a URI, that identifies a particular lock ๐ every successful LOCK operation returns a lock token in the lockdiscovery property in the response body, and you can also find it through lock discovery on a resource ๐
Lock token URIs MUST be unique across all resources for all time ๐ this uniqueness lets lock tokens be submitted across resources and servers without any fear of confusion ๐ง
this spec provides a lock token URI scheme called opaquelocktoken that meets the uniqueness requirements. but resources are free to return any URI scheme, as long as it meets the uniqueness requirements ๐
having a lock token gives you no special access rights ๐ โโ๏ธ anyone can find out anyone else's lock token by performing lock discovery. Locks MUST be enforced based upon whatever authentication mechanism the server uses, not based on the secrecy of the token values ๐
6.4 opaquelocktoken Lock Token URI Scheme ๐ฆ
the opaquelocktoken URI scheme is designed to be unique across all resources for all time ๐ฐ๏ธ because of that uniqueness, a client may submit an opaque lock token in an If header on a resource other than the one that returned it ๐ซ
All resources MUST recognize the opaquelocktoken scheme and, at minimum, recognize that the lock token does not refer to an outstanding lock on the resource ๐
to guarantee uniqueness across all resources for all time, opaquelocktoken requires the use of the Universal Unique Identifier (UUID) mechanism, as described in [ISO-11578] ๐
opaquelocktoken generators, however, have a choice of how they create these tokens ๐ they can either generate a new UUID for every lock token they create, or they can create a single UUID and then add extension characters. if the second method is selected, the program generating the extensions MUST guarantee that the same extension will never be used twice with the associated UUID ๐ซข
here's the ABNF, bestie ๐
OpaqueLockToken-URI = "opaquelocktoken:" UUID [Extension] ; The UUID
production is the string representation of a UUID, as defined in
[ISO-11578]. Note that white space (LWS) is not allowed between
elements of this production.
Extension = path ; path is defined in section 3.2.1 of RFC 2068
[RFC2068]
6.4.1. Node Field Generation Without the IEEE 802 Address
okay so UUIDs (defined in [ISO-11578]) have a "node" field that normally holds one of the IEEE 802 addresses from the server machine ๐ฌ and as noted in section 17.8, showing a machine's IEEE 802 address comes with a bunch of security risks. so this section gives you a different way to make the "node" field that doesn't use an IEEE 802 address ๐ WebDAV servers MAY use this algorithm when they generate UUIDs. the text here is originally from an Internet-Draft by Paul Leach and Rich Salz, and we're giving them credit for it ๐ซถ
the ideal move is to grab a 47 bit cryptographic quality random number and use it as the low 47 bits of the node ID, with the most significant bit of the first octet of the node ID set to 1 ๐ฆ that bit is the unicast/multicast bit, and it's never set in IEEE 802 addresses from network cards. so UUIDs from machines with network cards and UUIDs from machines without them can never collide ๐
if a system doesn't have a primitive for making cryptographic quality random numbers, don't panic, because most systems have loads of randomness sources lying around โจ they're system specific, but they often include things like:
- the percent of memory in use
- the size of main memory in bytes
- the amount of free main memory in bytes
- the size of the paging or swap file in bytes
- free bytes of paging or swap file
- the total size of user virtual address space in bytes
- the total available user address space bytes
- the size of boot disk drive in bytes
- the free disk space on boot drive in bytes
- the current time
- the amount of time since the system booted
- the individual sizes of files in various system directories
- the creation, last read, and modification times of files in various system directories
- the utilization factors of various system resources (heap, etc.)
- current mouse cursor position
- current caret position
- current number of running processes, threads
- handles or IDs of the desktop window and the active window
- the value of stack pointer of the caller
- the process and thread ID of caller
- various processor architecture specific performance counters (instructions executed, cache misses, TLB misses)
(Note that it is precisely the above kinds of sources of randomness that are used to seed cryptographic quality random number generators on systems without special hardware for their construction.) ๐ง
also, stuff like the computer's name and the name of the operating system isn't random at all, but it helps tell the results apart from what other systems come up with ๐
the exact algorithm for making a node ID from this data is system specific, since the data available and the functions to get it are super system specific too ๐ BUT, assuming you can smush all the randomness values into one buffer, and you have a cryptographic hash function like MD5, then any 6 bytes of the MD5 hash of the buffer, with the multicast bit (the high bit of the first byte) set, will be an appropriately random node ID ๐ฅ
other hash functions, like SHA-1, can be used too ๐ the only real requirement is that the result is suitably random. in other words, outputs from a set of uniformly distributed inputs have to be uniformly distributed themselves, and a single bit change in the input should be expected to flip about half of the output bits. that's the whole vibe โจ
6.5. Lock Capability Discovery
okay so server lock support is optional, which means a client trying to lock a resource has two options: it can just try the lock and hope for the best ๐ค or it can do some kind of discovery to figure out what lock capabilities the server actually supports. that second thing is called lock capability discovery ๐ it's different from discovering supported access control types, since some access control types don't have matching lock types at all. a client can check which lock types a server supports by retrieving the supportedlock property ๐
Any DAV compliant resource that supports the LOCK method MUST support the supportedlock property. no exceptions bestie ๐
6.6. Active Lock Discovery
picture this: another principal locks a resource you want to access ๐ค it's super useful for you to find out who that first principal is, and that's exactly what the lockdiscovery property is for ๐ต๏ธโโ๏ธ it lists all the outstanding locks, describes their type, and, where it's available, gives their lock token ๐
Any DAV compliant resource that supports the LOCK method MUST support the lockdiscovery property. iconic behaviour ๐
6.7. Usage Considerations
ngl the locking stuff here helps a lot with preventing lost updates, but it can't guarantee updates will never get lost ๐ญ check out this disaster scenario:
Two clients A and B are both interested in editing the resource index.html.
- Client A is an HTTP client, not a WebDAV client, so it doesn't know how to do locking. ๐
- Client A doesn't lock the document, but it does a GET and starts editing.
- Client B does a LOCK, does a GET, and starts editing.
- Client B finishes editing, does a PUT, and then an UNLOCK.
- Client A does a PUT, overwriting and losing all of B's changes. ๐
there are a few reasons why the WebDAV protocol itself can't stop this situation ๐ first, it can't force every client to use locking, because it has to stay compatible with HTTP clients that don't understand locking at all. second, it can't require servers to support locking, because repositories come in all kinds of flavours, and some of them rely on reservations and merging instead of locks ๐ธ and finally, it's stateless, so it can't enforce a sequence like LOCK / GET / PUT / UNLOCK. not me being sad about statelessness ๐ฉ
WebDAV servers that support locking can make accidental overwrites less likely by requiring clients to lock resources before they modify them โจ but that kind of server would basically stop HTTP 1.0 and HTTP 1.1 clients from modifying resources at all, so it's a trade-off ๐ซ
WebDAV clients can be good citizens by doing a lock / retrieve / write / unlock sequence (at least by default) whenever they talk to a WebDAV server that supports locking ๐ฆ
HTTP 1.1 clients can be good citizens too, and avoid overwriting other clients' changes, by putting entity tags in If-Match headers on any requests that would modify resources ๐ง
information managers can also try to prevent overwrites by building client-side procedures that require locking before anyone modifies WebDAV resources ๐
7. Write Lock โจ
okay this section is all about the semantics of the write lock type ๐ the write lock is one specific instance of a lock type, and it's the only lock type described in this specification ๐
7.1. Methods Restricted by Write Locks
a write lock MUST stop a principal without the lock from successfully running PUT, POST, PROPPATCH, LOCK, UNLOCK, MOVE, DELETE, or MKCOL on the locked resource ๐ซ all the other current methods, GET especially, work independently of the lock ๐
note, though, that as new methods get created, someone will have to specify how they interact with a write lock ๐
7.2. Write Locks and Lock Tokens
a successful request for an exclusive or shared write lock MUST result in a unique lock token being generated and associated with the requesting principal ๐ so if five principals have a shared write lock on the same resource, there will be five lock tokens, one for each principal. five girlies, five tokens ๐
7.3. Write Locks and Properties
okay so people without a write lock can't change a property on a resource, but live property values can still change while the resource is locked, because of the requirements in their schemas ๐ธ
only dead properties and live properties that are defined to respect locks are guaranteed not to change while the resource is write locked ๐
7.4. Write Locks and Null Resources
it's possible to put a write lock on a null resource, which lets you lock the name ๐ฆ
a write locked null resource, which people call a lock-null resource, MUST respond with a 404 (Not Found) or 405 (Method Not Allowed) to any HTTP/1.1 or DAV methods except for PUT, MKCOL, OPTIONS, PROPFIND, LOCK, and UNLOCK ๐
โโ๏ธ a lock-null resource MUST appear as a member of its parent collection ๐ it also MUST have all the mandatory DAV properties defined on it. most of those, like all the get* properties, won't have a value, because a lock-null resource doesn't support the GET method ๐ซ lock-null resources MUST have defined values for lockdiscovery and supportedlock ๐
until a method like PUT or MKCOL is successfully run on the lock-null resource, it MUST stay in the lock-null state ๐ง but once a PUT or MKCOL goes through successfully, the resource stops being in the lock-null state, periodt โจ
if the resource gets unlocked for any reason, without a PUT, MKCOL, or similar method having been successfully run on it, then the resource MUST go back to the null state ๐
7.5. Write Locks and Collections
a write lock on a collection, whether it came from a "Depth: 0" or a "Depth: infinity" lock request, stops non-lock owners from adding or removing member URIs of that collection ๐ง so when a principal does a PUT or POST to create a new resource at a URI that has to be an internal member of a write locked collection (to keep the HTTP namespace consistent), or does a DELETE on a resource whose URI is an existing internal member URI of a write locked collection, the request MUST fail if that principal doesn't have a write lock on the collection ๐ โโ๏ธ
BUT, if a write lock request goes to a collection that has member URIs for resources currently locked in a way that conflicts with the write lock, the request MUST fail with a 423 (Locked) status code ๐ค
if a lock owner causes the URI of a resource to be added as an internal member URI of a locked collection, then the new resource MUST be automatically added to the lock ๐ this is the only way a resource can get added to a write lock ๐
for example, if the collection /a/b/ is write locked and the resource /c is moved to /a/b/c, then the resource /a/b/c gets added to the write lock ๐
7.6 Write Locks and the If Request Header โจ
okay so, if a user agent doesn't have to know about a lock when it asks for something on a locked resource, this drama can happen ๐ญ. Program A, run by User A, grabs a write lock on a resource. Then Program B, also run by User A, has zero clue about that lock and still does a PUT to the locked resource, and the PUT goes through!! Why? Because locks belong to a principal, not a program, so Program B is using principal A's credentials and is allowed to PUT. BUT if Program B had known about the lock, it would never have overwritten the resource and would've popped up a dialog box to tell the user about the conflict ๐ . So we need a way to stop different programs with the same authorization from accidentally ignoring each other's locks ๐ซถ.
Here's the fix: a lock token MUST be submitted by an authorized principal in the If header for all locked resources that a method may interact with, or the method MUST fail. For example, if a resource is getting moved and both the source and destination are locked, then you need two lock tokens, one for the source and one for the destination ๐.
7.6.1 Example - Write Lock
Request
COPY /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
If: <http://www.ics.uci.edu/users/f/fielding/index.html>
(<opaquelocktoken:f81d4fae-7dec-11d0-a765-00a0c91e6bf6>)
Response
HTTP/1.1 204 No Content
In this example, even though both the source and destination are locked, only one lock token needs to be submitted, the one for the destination ๐ฆ. That's because a COPY doesn't modify the source resource, so the write lock on the source doesn't affect it at all. Also, user agent authentication already happened through a mechanism outside the HTTP protocol, down in the underlying transport layer ๐ธ.
7.7 Write Locks and COPY/MOVE
A COPY method invocation MUST NOT duplicate any write locks active on the source. However, like we mentioned before, if the COPY drops the resource into a collection that is locked with "Depth: infinity", then the resource gets added to that lock ๐.
A successful MOVE request on a write locked resource MUST NOT move the write lock along with the resource. Lowkey though, the resource can still get added to an existing lock at the destination, as specified in section 7.5. For example, if the MOVE makes the resource a child of a collection that is locked with "Depth: infinity", then the resource gets added to that collection's lock ๐. Also, if a resource locked with "Depth: infinity" gets moved to a destination inside the same lock's scope (like somewhere in the namespace tree that the lock covers), the moved resource gets added to the lock again โจ. In both of these examples, as specified in section 7.6, an If header must be submitted containing a lock token for both the source and the destination ๐.
7.8 Refreshing Write Locks
A client MUST NOT submit the same write lock request twice. Honestly, a client always knows when it's resubmitting the same lock request, because it has to include the lock token in the If header to make a request for a resource that's already locked ๐.
However, a client may submit a LOCK method with an If header but without a body. This form of LOCK MUST only be used to "refresh" a lock. Meaning, at minimum, that any timers associated with the lock MUST be re-set โฐ.
A server may return a Timeout header with a lock refresh that is different from the Timeout header returned when the lock was originally requested. Clients may also submit Timeout headers of arbitrary value with their lock refresh requests. And servers, as always, may ignore Timeout headers submitted by the client ๐ง.
If an error is received in response to a refresh LOCK request, the client SHOULD assume that the lock was not refreshed ๐.
8 HTTP Methods for Distributed Authoring โจ
The following new HTTP methods use XML as a request and response format. All DAV compliant clients and resources MUST use XML parsers that are compliant with [REC-XML]. All XML used in either requests or responses MUST be, at minimum, well formed. If a server receives ill-formed XML in a request, it MUST reject the entire request with a 400 (Bad Request). If a client receives ill-formed XML in a response, then it MUST NOT assume anything about the outcome of the executed method, and SHOULD treat the server as malfunctioning ๐ฑ.
8.1 PROPFIND
The PROPFIND method retrieves properties defined on the resource identified by the Request-URI, if the resource does not have any internal members. Or, if the resource is a collection that has internal member URIs, it retrieves properties defined on the resource identified by the Request-URI and potentially its member resources. All DAV compliant resources MUST support the PROPFIND method and the propfind XML element (section 12.14), along with all XML elements defined for use with that element ๐ .
A client may submit a Depth header with a value of "0", "1", or "infinity" with a PROPFIND on a collection resource with internal member URIs. DAV compliant servers MUST support the "0", "1" and "infinity" behaviors. By default, the PROPFIND method without a Depth header MUST act as if a "Depth: infinity" header was included ๐.
A client may submit a propfind XML element in the body of the request method, describing what information it wants. It's possible to request particular property values, all property values, or a list of the names of the resource's properties. A client may also choose not to submit a request body. An empty PROPFIND request body MUST be treated as a request for the names and values of all properties ๐.
All servers MUST support returning a response of content type text/xml or application/xml that contains a multistatus XML element describing the results of the attempts to retrieve the various properties ๐ฆ.
If there is an error retrieving a property, then a proper error result MUST be included in the response. Asking for the value of a property that doesn't exist is an error, and it MUST be noted (if the response uses a multistatus XML element) with a response XML element that contains a 404 (Not Found) status value ๐ โโ๏ธ.
So, the multistatus XML element for a collection resource with member URIs MUST include a response XML element for each member URI of the collection, to whatever depth was requested. Each response XML element MUST contain an href XML element that gives the URI of the resource on which the properties in the prop XML element are defined. Results for a PROPFIND on a collection resource with internal member URIs come back as a flat list, and the order of the entries doesn't matter ๐ง.
For allprop and propname, if a principal doesn't have the right to know whether a particular property exists, then the property should be silently excluded from the response ๐คซ.
The results of this method SHOULD NOT be cached ๐ซ.
8.1.1 Example - Retrieving Named Properties
Request
PROPFIND /file HTTP/1.1
Host: www.foo.bar
Content-type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox/>
<R:author/>
<R:DingALing/>
<R:Random/>
</D:prop>
</D:propfind>
Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.foo.bar/file</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox>
<R:BoxType>Box type A</R:BoxType>
</R:bigbox>
<R:author>
<R:Name>J.J. Johnson</R:Name>
</R:author>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop><R:DingALing/><R:Random/></D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
<D:responsedescription> The user does not have access to
the DingALing property.
</D:responsedescription>
</D:propstat>
</D:response>
<D:responsedescription> There has been an access violation error.
</D:responsedescription>
</D:multistatus>
In this example, PROPFIND is run on a non-collection resource, http://www.foo.bar/file. The propfind XML element names four properties whose values are being requested. But only two properties come back, because the principal making the request didn't have enough access rights to see the third and fourth properties ๐โจ.
8.1.2. Example - Using allprop to Retrieve All Properties ๐
>>Request
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Depth: 1
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
>>Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.foo.bar/container/</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox>
<R:BoxType>Box type A</R:BoxType>
</R:bigbox>
<R:author>
<R:Name>Hadrian</R:Name>
</R:author>
<D:creationdate>
1997-12-01T17:42:21-08:00
</D:creationdate>
<D:displayname>
Example collection
</D:displayname>
<D:resourcetype><D:collection/></D:resourcetype>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.foo.bar/container/front.html</D:href>
<D:propstat>
<D:prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox>
<R:BoxType>Box type B</R:BoxType>
</R:bigbox>
<D:creationdate>
1997-12-01T18:27:21-08:00
</D:creationdate>
<D:displayname>
Example HTML resource
</D:displayname>
<D:getcontentlength>
4525
</D:getcontentlength>
<D:getcontenttype>
text/html
</D:getcontenttype>
<D:getetag>
zzyzx
</D:getetag>
<D:getlastmodified>
Monday, 12-Jan-98 09:25:56 GMT
</D:getlastmodified>
<D:resourcetype/>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
okay so in this one, we PROPFIND the /container/ collection with a Depth: 1 header, which means the request covers the resource itself plus its children ๐, and the body asks for allprop, so the server hands back the name and value of every property on each resource ๐
The collection http://www.foo.bar/container/ has six properties: http://www.foo.bar/boxschema/bigbox, http://www.foo.bar/boxschema/author, DAV:creationdate, DAV:displayname, DAV:resourcetype, and DAV:supportedlock ๐ธ
The last four are the WebDAV-specific ones, defined in section 13. Since GET isn't supported on this resource, the get* properties (like getcontentlength) don't exist on it at all ๐ The DAV properties tell us the collection was created on December 1, 1997, at 5:42:21PM, in a time zone 8 hours west of GMT (creationdate), is named "Example collection" (displayname), is a collection (resourcetype), and supports exclusive and shared write locks (supportedlock) ๐ฅ
front.html has nine properties: http://www.foo.bar/boxschema/bigbox (another instance of the "bigbox" property type), DAV:creationdate, DAV:displayname, DAV:getcontentlength, DAV:getcontenttype, DAV:getetag, DAV:getlastmodified, DAV:resourcetype, and DAV:supportedlock โจ
Its DAV properties say it was created on December 1, 1997, at 6:27:21PM, in that same GMT-8 zone, is named "Example HTML resource", is 4525 bytes long, is text/html, has an entity tag of "zzyzx", was last modified on Monday, January 12, 1998, at 09:25:56 GMT, has an empty resource type (so it's not a collection, periodt ๐), and supports both exclusive and shared write locks ๐ฆ
8.1.3. Example - Using propname to Retrieve all Property Names ๐ง
>>Request
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<propfind xmlns="DAV:">
<propname/>
</propfind>
>>Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:">
<response>
<href>http://www.foo.bar/container/</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox/>
<R:author/>
<creationdate/>
<displayname/>
<resourcetype/>
<supportedlock/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
<response>
<href>http://www.foo.bar/container/front.html</href>
<propstat>
<prop xmlns:R="http://www.foo.bar/boxschema/">
<R:bigbox/>
<creationdate/>
<displayname/>
<getcontentlength/>
<getcontenttype/>
<getetag/>
<getlastmodified/>
<resourcetype/>
<supportedlock/>
</prop>
<status>HTTP/1.1 200 OK</status>
</propstat>
</response>
</multistatus>
This time we PROPFIND the collection http://www.foo.bar/container/ with a propname element in the body, which means we only want the names of the properties, not their values ๐ซถ There's no Depth header here, so it defaults to "infinity", and we get the property names for the collection and everything underneath it ๐
Same as before, the collection has six properties: http://www.foo.bar/boxschema/bigbox, http://www.foo.bar/boxschema/author, DAV:creationdate, DAV:displayname, DAV:resourcetype, and DAV:supportedlock ๐
The member http://www.foo.bar/container/index.html has nine properties: http://www.foo.bar/boxschema/bigbox, DAV:creationdate, DAV:displayname, DAV:getcontentlength, DAV:getcontenttype, DAV:getetag, DAV:getlastmodified, DAV:resourcetype, and DAV:supportedlock ๐
This example also shows off XML namespace scoping and the default namespace. Since the xmlns attribute has no prefix (no "shorthand name" letter), the namespace applies to every element inside it by default, so any element that doesn't say which namespace it belongs to is automatically in the DAV: namespace ๐
8.2. PROPPATCH ๐ธ
PROPPATCH processes the instructions in the request body that set and/or remove properties on the resource identified by the Request-URI ๐
Every DAV compliant resource MUST support PROPPATCH and MUST process instructions written with the propertyupdate, set, and remove XML elements of the DAV schema. Running these directives is, of course, subject to access control constraints ๐ DAV compliant resources SHOULD also support setting arbitrary dead properties โจ
The request body of a PROPPATCH MUST contain the propertyupdate XML element. Instructions MUST be processed in the order they're received (top to bottom) ๐ And here's the all-or-nothing part: instructions MUST either all be executed or none executed. So if any error pops up during processing, every instruction that already ran MUST be undone, and a proper error result gets returned ๐ญ The nitty-gritty of processing set and remove is in section 12.13.
8.2.1. Status Codes for use with 207 (Multi-Status) ๐
These are examples of response codes you'd expect in a 207 (Multi-Status) response for this method. Heads up though: unless it's explicitly prohibited, any 2/3/4/5xx series response code may be used in a 207 (Multi-Status) response ๐
200 (OK)- The command succeeded. Since a body can mix sets and removes, a 201 (Created) seems inappropriate ๐403 (Forbidden)- The client, for reasons the server chooses not to specify, can't alter one of the properties ๐409 (Conflict)- The client provided a value whose semantics aren't appropriate for the property. This includes trying to set read-only properties ๐423 (Locked)- The resource is locked, and the client either isn't a lock owner, or the lock type needs a lock token and the client didn't submit one ๐507 (Insufficient Storage)- The server didn't have enough space to record the property ๐งบ
8.2.2 Example - PROPPATCH โจ
Request
PROPPATCH /bar.html HTTP/1.1
Host: www.foo.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:propertyupdate xmlns:D="DAV:"
xmlns:Z="http://www.w3.com/standards/z39.50/">
<D:set>
<D:prop>
<Z:authors>
<Z:Author>Jim Whitehead</Z:Author>
<Z:Author>Roy Fielding</Z:Author>
</Z:authors>
</D:prop>
</D:set>
<D:remove>
<D:prop><Z:Copyright-Owner/></D:prop>
</D:remove>
</D:propertyupdate>
Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:Z="http://www.w3.com/standards/z39.50">
<D:response>
<D:href>http://www.foo.com/bar.html</D:href>
<D:propstat>
<D:prop><Z:Authors/></D:prop>
<D:status>HTTP/1.1 424 Failed Dependency</D:status>
</D:propstat>
<D:propstat>
<D:prop><Z:Copyright-Owner/></D:prop>
<D:status>HTTP/1.1 409 Conflict</D:status>
</D:propstat>
<D:responsedescription> Copyright Owner can not be deleted or
altered.</D:responsedescription>
</D:response>
</D:multistatus>
Okay so in this example the client asks the server to set the value of http://www.w3.com/standards/z39.50/Authors and to remove http://www.w3.com/standards/z39.50/Copyright-Owner ๐. But the Copyright-Owner can't be removed, so no property changes happen at all ๐ญ. The 424 (Failed Dependency) on Authors is the tea: it would have worked, except it's blocked by that Copyright-Owner conflict ๐
.
8.3 MKCOL Method
The MKCOL method is how you make a brand new collection ๐. All DAV compliant resources MUST support the MKCOL method. No exceptions, bestie ๐ซถ.
8.3.1 Request
MKCOL creates a new collection resource at whatever location the Request-URI points to ๐ธ. If the resource identified by the Request-URI is non-null, then the MKCOL MUST fail ๐
โโ๏ธ. During MKCOL processing, a server MUST make the Request-URI a member of its parent collection, unless the Request-URI is "/". If no such ancestor exists, the method MUST fail. When the MKCOL operation creates a new collection resource, all ancestors MUST already exist, or the method MUST fail with a 409 (Conflict) status code. For example, if someone asks for /a/b/c/d/ and neither /a/b/ nor /a/b/c/ exists, the request must fail ๐.
When MKCOL is invoked without a request body, the newly created collection SHOULD have no members โจ.
A MKCOL request message may contain a message body ๐ง. The behavior of a MKCOL request with a body is limited to creating collections, members of a collection, bodies of members, and properties on the collections or members. If the server receives a MKCOL request entity type it does not support or understand, it MUST respond with a 415 (Unsupported Media Type) status code. The exact behavior of MKCOL for various request media types is undefined in this document and will be specified in separate documents, so stay tuned ๐ฆ.
8.3.2 Status Codes
Responses from a MKCOL request MUST NOT be cached, because MKCOL has non-idempotent semantics ๐.
201 (Created)- The collection or structured resource was created in its entirety.403 (Forbidden)- This indicates at least one of two conditions: 1) the server does not allow the creation of collections at the given location in its namespace, or 2) the parent collection of the Request-URI exists but cannot accept members.405 (Method Not Allowed)- MKCOL can only be executed on a deleted/non-existent resource.409 (Conflict)- A collection cannot be made at the Request-URI until one or more intermediate collections have been created.415 (Unsupported Media Type)- The server does not support the request type of the body.507 (Insufficient Storage)- The resource does not have sufficient space to record the state of the resource after the execution of this method.
8.3.3 Example - MKCOL
This example creates a collection called /webdisc/xfiles/ on the server www.server.org ๐ธ.
Request
MKCOL /webdisc/xfiles/ HTTP/1.1
Host: www.server.org
Response
HTTP/1.1 201 Created
8.4 GET, HEAD for Collections
GET on a collection keeps its usual vibe ๐. GET is defined as, "retrieve whatever information (in the form of an entity) is identified by the Request-URI" [RFC2068]. When you GET a collection, you might get the contents of an "index.html" resource, a human-readable listing of the collection, or something else entirely. So the result of a GET on a collection might not match the membership of the collection at all ๐คทโโ๏ธ.
HEAD is just a GET without a response message body, so the semantics of HEAD stay the same for collection resources too ๐.
8.5 POST for Collections
Here's the deal: what POST actually does is decided by the server and often depends on the specific resource ๐ค. That makes POST on collections largely undefined, so it can't really be modified in a meaningful way. The semantics of POST stay unmodified when applied to a collection ๐ .
8.6 DELETE
8.6.1 DELETE for Non-Collection Resources
If the DELETE method is issued to a non-collection resource whose URIs are an internal member of one or more collections, then during DELETE processing a server MUST remove any URI for the resource identified by the Request-URI from the collections that contain it as a member ๐งน.
8.6.2 DELETE for Collections
The DELETE method on a collection MUST act as if a "Depth: infinity" header was used on it ๐ฅ. A client MUST NOT submit a Depth header with a DELETE on a collection with any value other than infinity. Not even a little bit ๐ โโ๏ธ.
DELETE says that the collection in the Request-URI and every resource identified by its internal member URIs are to be deleted ๐๏ธ.
If any resource identified by a member URI cannot be deleted, then none of the member's ancestors MUST NOT be deleted, so the namespace stays consistent ๐ซถ. Any headers included with DELETE MUST be applied while processing every resource to be deleted. When the DELETE method has completed processing, it MUST result in a consistent namespace โจ.
If an error occurs with a resource other than the one identified in the Request-URI, then the response MUST be a 207 (Multi-Status). 424 (Failed Dependency) errors SHOULD NOT be in the 207 (Multi-Status). They can be safely left out, because the client will know that the ancestors of a resource could not be deleted when it gets an error for the ancestor's progeny ๐ง . Additionally, 204 (No Content) errors SHOULD NOT be returned in the 207 (Multi-Status), because 204 (No Content) is the default success code ๐.
8.6.2.1 Example - DELETE
Request
DELETE /container/ HTTP/1.1
Host: www.foo.bar
Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<d:multistatus xmlns:d="DAV:">
<d:response>
<d:href>http://www.foo.bar/container/resource3</d:href>
<d:status>HTTP/1.1 423 Locked</d:status>
</d:response>
</d:multistatus>
In this example, the attempt to delete http://www.foo.bar/container/resource3 failed because it's locked and no lock token was submitted with the request ๐. So the attempt to delete http://www.foo.bar/container/ also failed. The client knows that the attempt to delete http://www.foo.bar/container/ must have also failed, since the parent can not be deleted unless its child has also been deleted ๐งธ. Even though no Depth header was included, a depth of infinity is assumed because the method is on a collection ๐.
8.7 PUT
8.7.1 PUT for Non-Collection Resources
A PUT performed on an existing resource replaces the GET response entity of that resource ๐. Properties defined on the resource may be recomputed during PUT processing, but they aren't otherwise affected. For example, if a server recognizes the content type of the request body, it may be able to automatically extract information that could be profitably exposed as properties ๐ฆ.
A PUT that would result in the creation of a resource without an appropriately scoped parent collection MUST fail with a 409 (Conflict) ๐ โโ๏ธ.
8.7.2 PUT for Collections
As defined in the HTTP/1.1 specification [RFC2068], the "PUT method requests that the enclosed entity be stored under the supplied Request-URI." ๐ฆ Since submitting an entity that represents a collection would implicitly encode creation and deletion of resources, this specification intentionally does not define a transmission format for creating a collection using PUT. Instead, the MKCOL method is defined to create collections ๐ซถ.
When the PUT operation creates a new non-collection resource, all ancestors MUST already exist. If all ancestors do not exist, the method MUST fail with a 409 (Conflict) status code. For example, if resource /a/b/c/d.html is to be created and /a/b/c/ does not exist, then the request must fail ๐.
8.8 COPY Method
The COPY method makes a duplicate of the source resource, which is identified by the Request-URI, in the destination resource, which is identified by the URI in the Destination header ๐ฏ. The Destination header MUST be present. How COPY behaves depends on what type of source resource you're working with ๐ท.
All WebDAV compliant resources MUST support the COPY method. However, supporting COPY doesn't guarantee you can copy every resource ๐ฌ. For example, separate programs may control resources on the same server. As a result, it may not be possible to copy a resource to a location that appears to be on the same server ๐.
8.8.1 COPY for HTTP/1.1 resources
When the source resource is not a collection, COPY creates a new resource at the destination whose state and behavior match the source as closely as possible ๐ช. After a successful COPY invocation, all properties on the source resource MUST be duplicated on the destination resource, subject to modifying headers and XML elements, following the definition for copying properties. The environment at the destination may be different from the source for reasons outside the server's control, such as missing resources needed for correct operation. So it may not be possible to completely duplicate the behavior of the resource at the destination ๐. Subsequent alterations to the destination resource will not modify the source resource, and subsequent alterations to the source resource will not modify the destination resource. Two separate lives, no drama ๐ โจ.
8.8.2. COPY for Properties
Okay so this bit is all about what happens to properties when you COPY something ๐
Live properties SHOULD be duplicated as identically behaving live properties at the destination resource. If a property can't be copied live, then its value MUST be duplicated, octet-for-octet, into an identically named, dead property on the destination resource, subject to the effects of the propertybehavior XML element ๐
The propertybehavior XML element is the boss here ๐ It can say that properties get copied on a best-effort basis, that every live property has to be copied successfully or the whole method fails, or that a specific list of live properties has to be copied successfully or the method fails. The propertybehavior XML element is defined in section 12.12 โจ
8.8.3 COPY for Collections
Main character energy time ๐ฆ A COPY on a collection without a Depth header MUST act as if a Depth header with value "infinity" was included. You're allowed to send a Depth header on a COPY on a collection with a value of "0" or "infinity" ๐ DAV compliant servers MUST support both the "0" and "infinity" Depth header behaviors ๐ซถ
A COPY with depth infinity means the collection identified by the Request-URI gets copied to the location in the Destination header, and all of its internal member resources get copied to locations relative to it, recursively through every level of the collection hierarchy ๐ณ
A COPY with "Depth: 0" only copies the collection and its properties. It does NOT copy the resources identified by its internal member URIs ๐
Any headers included with a COPY MUST be applied while processing every resource being copied, except the Destination header ๐ฅ
The Destination header only gives the destination URI for the Request-URI. When it's applied to members of the collection identified by the Request-URI, the Destination value gets modified to match where that member sits in the hierarchy. So if the Request-URI is /a/ with Host header value http://fun.com/ and the Destination is http://fun.com/b/, then when http://fun.com/a/c/d is processed it must use a Destination of http://fun.com/b/c/d ๐ง
When the COPY method has finished, it MUST have created a consistent namespace at the destination (see section 5.1 for the definition of namespace consistency) ๐
But here's the tea: if an error happens while copying an internal collection, the server MUST NOT copy any resources identified by members of that collection. The server has to skip that whole subtree, because copying it anyway would make an inconsistent namespace ๐ญ After detecting an error, the COPY operation SHOULD try to finish as much of the original copy as possible. The server should still attempt to copy other subtrees and their members that aren't descendants of the error-causing collection. For example, if an infinite depth copy runs on collection /a/, which contains collections /a/b/ and /a/c/, and an error happens copying /a/b/, an attempt should still be made to copy /a/c/ ๐ Similarly, if there's an error copying a non-collection resource during an infinite depth copy, the server SHOULD try to finish as much of the original copy operation as possible โจ
If an error happens while executing the COPY method on a resource other than the one identified in the Request-URI, the response MUST be a 207 (Multi-Status) ๐ธ
Now the drama: the 424 (Failed Dependency) status code SHOULD NOT be returned in a 207 (Multi-Status) response from a COPY method. Those responses can be safely left out, because the client will already know that a resource's progeny couldn't be copied when it gets an error for the parent ๐ Also, 201 (Created) and 204 (No Content) status codes SHOULD NOT be returned as values in 207 (Multi-Status) responses from COPY methods. They can be safely left out too, since they're the default success codes ๐
8.8.4 COPY and the Overwrite Header
Okay this one is so important ๐ญ If a resource exists at the destination and the Overwrite header is "T", then before doing the copy, the server MUST perform a DELETE with "Depth: infinity" on the destination resource. If the Overwrite header is set to "F", then the operation will fail ๐
8.8.5 Status Codes
Here's the lineup of status codes for COPY ๐
201 (Created)- The source resource was successfully copied. The copy operation created a brand-new resource โจ204 (No Content)- The source resource was successfully copied to a pre-existing destination resource ๐ซง403 (Forbidden)- The source and destination URIs are the same ๐ โโ๏ธ409 (Conflict)- A resource can't be created at the destination until one or more intermediate collections have been created ๐งฑ412 (Precondition Failed)- The server couldn't keep the liveness of the properties listed in thepropertybehaviorXML element, or the Overwrite header is "F" and the state of the destination resource is non-null ๐ฌ423 (Locked)- The destination resource was locked ๐502 (Bad Gateway)- This may happen when the destination is on another server and that destination server refuses to accept the resource ๐507 (Insufficient Storage)- The destination resource doesn't have enough space to record the state of the resource after this method runs ๐พ
8.8.6 Example - COPY with Overwrite
Let's see this in action ๐ฆ Here, the resource http://www.ics.uci.edu/~fielding/index.html is being copied to http://www.ics.uci.edu/users/f/fielding/index.html. The 204 (No Content) status code tells us the existing resource at the destination got overwritten ๐
Request
COPY /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
Response
HTTP/1.1 204 No Content
8.8.7 Example - COPY with No Overwrite
Same copy operation, but this time the Overwrite header is set to "F" ๐ You get a 412 (Precondition Failed) back because the destination resource already has a non-null state. Bestie, no overwriting allowed ๐ซ
Request
COPY /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
Overwrite: F
Response
HTTP/1.1 412 Precondition Failed
8.8.8 Example - COPY of a Collection
Okay this is the big one with a whole collection ๐งบ
Request
COPY /container/ HTTP/1.1
Host: www.foo.bar
Destination: http://www.foo.bar/othercontainer/
Depth: infinity
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<d:propertybehavior xmlns:d="DAV:">
<d:keepalive>*</d:keepalive>
</d:propertybehavior>
Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<d:multistatus xmlns:d="DAV:">
<d:response>
<d:href>http://www.foo.bar/othercontainer/R2/</d:href>
<d:status>HTTP/1.1 412 Precondition Failed</d:status>
</d:response>
</d:multistatus>
The Depth header isn't needed here, because COPY on a collection already acts like "Depth: infinity" by default ๐ธ Most resources, plus the collection itself, got copied successfully. But collection R2 failed, most likely because the liveness of its properties couldn't be maintained (that's what the propertybehavior XML element is for). Since there was an error copying R2, none of R2's members were copied. There are no errors listed for those members, thanks to the error minimization rules in section 8.8.3 ๐
8.9 MOVE Method
MOVE is giving COPY plus cleanup vibes ๐ง On a non-collection resource, MOVE is the logical equivalent of a copy (COPY), followed by consistency maintenance processing, followed by a delete of the source. All three actions happen atomically โจ The consistency maintenance step lets the server make updates caused by the move, like changing every URI other than the Request-URI that identifies the source resource so it points to the new destination resource ๐
So the Destination header MUST be present on all MOVE methods, and it MUST follow all COPY requirements for the COPY part of the MOVE method ๐ All DAV compliant resources MUST support the MOVE method. BUT support for MOVE doesn't guarantee that you can move a resource to any particular destination. Not me being picky ๐
For example, separate programs may control different sets of resources on the same server. So it might not be possible to move a resource within a namespace that seems to belong to the same server ๐ซ
If a resource exists at the destination, that destination resource will be DELETEd as a side effect of the MOVE operation, subject to the restrictions of the Overwrite header ๐
8.9.1 MOVE for Properties
The behavior of properties on a MOVE, including the effects of the propertybehavior XML element, MUST be the same as specified in section 8.8.2 ๐
8.9.2 MOVE for Collections
A MOVE with "Depth: infinity" means the collection identified by the Request-URI gets moved to the URI in the Destination header, and all resources identified by its internal member URIs get moved to locations relative to it, recursively through every level of the collection hierarchy ๐ณ
The MOVE method on a collection MUST act as if a "Depth: infinity" header was used on it. A client MUST NOT submit a Depth header on a MOVE on a collection with any value other than "infinity" ๐ โโ๏ธ
Any headers included with MOVE MUST be applied while processing every resource being moved, except the Destination header โจ
The Destination header works the same way it does for COPY on collections ๐
When the MOVE method has finished, it MUST have created a consistent namespace at both the source and the destination (see section 5.1 for the definition of namespace consistency) ๐ซถ But if an error happens while moving an internal collection, the server MUST NOT move any resources identified by members of the failed collection. The server has to skip the error-causing subtree, because that would create an inconsistent namespace ๐ญ After detecting the error, the move operation SHOULD try to finish as much of the original move as possible. The server should still attempt to move other subtrees and the resources identified by their members, as long as they aren't descendants of an error-causing collection. For example, if an infinite depth move runs on collection /a/, which contains collections /a/b/ and /a/c/, and an error happens moving /a/b/, an attempt should still be made to move /a/c/ ๐ธ Similarly, if there's an error moving a non-collection resource as part of an infinite depth move, the server SHOULD try to finish as much of the original move operation as possible ๐ง
If an error occurs with a resource other than the one identified in the Request-URI, the response MUST be a 207 (Multi-Status) ๐
Same energy as COPY: the 424 (Failed Dependency) status code SHOULD NOT be returned in the 207 (Multi-Status) response from a MOVE method. Those errors can be safely left out, because the client will already know that a resource's progeny couldn't be moved when it gets an error for the parent ๐ Also, 201 (Created) and 204 (No Content) responses SHOULD NOT be returned as values in 207 (Multi-Status) responses from a MOVE. They can be safely left out too, since they're the default success codes ๐
8.9.3 MOVE and the Overwrite Header
Okay so if something's already sitting at the destination and the Overwrite header is "T", the server MUST perform a DELETE with "Depth: infinity" on the destination resource before it does the move ๐งนโจ. If Overwrite is set to "F" instead, the whole operation fails ๐
โโ๏ธ no exceptions, bestie.
8.9.4 Status Codes
201 (Created) - The source resource got moved and a brand-new resource was made at the destination ๐
204 (No Content) - The source resource got moved onto a destination resource that already existed ๐ธ
403 (Forbidden) _ The source and destination URIs are the same. ๐ you can't move something onto itself, that's just not it.
409 (Conflict) _ A resource cannot be created at the destination until one or more intermediate collections have been created. ๐ the folders have to exist first, sis.
412 (Precondition Failed) - The server couldn't keep the properties listed in the propertybehavior XML element alive, OR the Overwrite header is "F" and the destination resource's state is non-null. Big vibes of "nope, not happening" ๐ญ
423 (Locked) - The source or the destination resource was locked ๐
502 (Bad Gateway) - This can happen when the destination lives on another server and that server refuses to accept the resource ๐
8.9.5 Example - MOVE of a Non-Collection
Okay this one is so cute ๐ฆ. We're moving http://www.ics.uci.edu/~fielding/index.html over to http://www.ics.uci.edu/users/f/fielding/index.html. If the destination had something in it, that stuff would've been overwritten. But there was nothing there, so the response is 201 (Created) โจ
>>Request
MOVE /~fielding/index.html HTTP/1.1
Host: www.ics.uci.edu
Destination: http://www.ics.uci.edu/users/f/fielding/index.html
>>Response
HTTP/1.1 201 Created
Location: http://www.ics.uci.edu/users/f/fielding/index.html
8.9.6 Example - MOVE of a Collection
>>Request
MOVE /container/ HTTP/1.1
Host: www.foo.bar
Destination: http://www.foo.bar/othercontainer/
Overwrite: F
If: (<opaquelocktoken:fe184f2e-6eec-41d0-c765-01adc56e6bb4>)
(<opaquelocktoken:e454f3f3-acdc-452a-56c7-00a5c91e4b77>)
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<d:propertybehavior xmlns:d='DAV:'>
<d:keepalive>*</d:keepalive>
</d:propertybehavior>
>>Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<d:multistatus xmlns:d='DAV:'>
<d:response>
<d:href>http://www.foo.bar/othercontainer/C2/</d:href>
<d:status>HTTP/1.1 423 Locked</d:status>
</d:response>
</d:multistatus>
So in this example the client sent a bunch of lock tokens with the request ๐. You need a lock token for every resource, source and destination both, anywhere in the scope of the method, that's locked. Here the right token wasn't sent for http://www.foo.bar/othercontainer/C2/, so /container/C2/ couldn't be moved ๐
โโ๏ธ. Because copying /container/C2/ errored, none of /container/C2/'s members got copied. But no errors are listed for those members, thanks to the error minimization rules given in section 8.8.3. And user agent authentication already happened through a mechanism outside the scope of the HTTP protocol, in an underlying transport layer ๐ง
8.10 LOCK Method
The next sections are all about the LOCK method, which takes out a lock of any access type ๐. They only cover the stuff that's specific to LOCK and don't depend on which access type is being requested, so it's giving focus.
Any resource that supports the LOCK method MUST, at minimum, support the XML request and response formats defined here ๐.
8.10.1 Operation
A LOCK invocation creates the lock described by the lockinfo XML element on the Request-URI ๐ฏ. LOCK requests SHOULD have an XML request body with an owner XML element for this lock request, unless it's a refresh request. The LOCK request may also have a Timeout header โฐ.
Clients MUST assume locks can vanish at any time, no matter what the Timeout header says ๐ณ. The Timeout header only tells you what the server does when nothing "extraordinary" happens. For example, an admin could remove a lock whenever they want, or the system could crash in a way that wipes out its record of the lock ever existing ๐. The response MUST contain the value of the lockdiscovery property in a prop XML element.
To show which lock token belongs to a brand-new lock, a Lock-Token response header MUST be included in the response for every successful LOCK request that creates a new lock ๐ชช. Heads up, the Lock-Token header won't come back on a successful refresh LOCK request, because no new lock was made ๐.
8.10.2 The Effect of Locks on Properties and Collections
A lock covers the entire state of the resource, including its body and its associated properties ๐ซถ. So a lock on a resource MUST also lock that resource's properties.
For collections, a lock also changes whether you can add or remove members ๐. How it plays out depends on the type of access control involved.
8.10.3 Locking Replicated Resources
A resource can be reachable through more than one URI ๐. But locks apply to resources, not URIs, so a LOCK request on a resource MUST NOT succeed if it can't be honored by all the URIs that resource is addressable through ๐ โโ๏ธ.
8.10.4 Depth and Locking
The Depth header may be used with the LOCK method ๐งญ. Any value other than 0 or infinity MUST NOT be used with the Depth header on a LOCK method. Every resource that supports LOCK MUST support the Depth header too.
A Depth header of 0 just locks the resource on the Request-URI ๐.
If Depth is set to infinity, the resource on the Request-URI plus all of its internal members, all the way down the hierarchy, get locked ๐ณ. A successful result MUST return a single lock token that represents all of the locked resources. If an UNLOCK succeeds on that token, every associated resource gets unlocked. If the lock can't be granted to all the resources, a 409 (Conflict) status code MUST be returned, with a response entity body containing a multistatus XML element that describes which resource(s) blocked the lock. So partial success isn't an option ๐ซ. Either the whole hierarchy gets locked or nothing does ๐ .
If a LOCK request has no Depth header, the request MUST act as if a "Depth:infinity" had been submitted ๐ซง.
8.10.5 Interaction with other Methods
How a LOCK interacts with other methods depends on the lock type ๐ญ. But no matter the lock type, a successful DELETE of a resource MUST cause all of its locks to be removed ๐๏ธ.
8.10.6 Lock Compatibility Table
This table shows what happens when a lock request is made on a resource ๐.
Current lock state/ | Shared Lock | Exclusive
Lock request | | Lock
=====================+=================+==============
None | True | True
---------------------+-----------------+--------------
Shared Lock | True | False
---------------------+-----------------+--------------
Exclusive Lock | False | False*
------------------------------------------------------
Legend: True = lock may be granted. False = lock MUST NOT be granted. *=It is illegal for a principal to request the same lock twice ๐.
The current lock state of a resource is in the leftmost column, and the lock requests are in the top row. Where a row and column meet, you get the result of that request ๐. For example, if a shared lock is held on a resource and someone asks for an exclusive lock, the entry is "false", which means the lock must not be granted (lowercase vibes, but the rule's the same: it's a no) ๐.
8.10.7 Status Codes
200 (OK) - The lock request worked, and the value of the lockdiscovery property is in the body โจ
412 (Precondition Failed) - The lock token that was included couldn't be enforced on this resource, or the server couldn't satisfy the request in the lockinfo XML element ๐ญ
423 (Locked) - The resource is locked, so the method got rejected ๐
8.10.8 Example - Simple Lock Request
>>Request
LOCK /workspace/webdav/proposal.doc HTTP/1.1
Host: webdav.sb.aol.com
Timeout: Infinite, Second-4100000000
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="ejw",
realm="ejw@webdav.sb.aol.com", nonce="...",
uri="/workspace/webdav/proposal.doc",
response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D='DAV:'>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
<D:owner>
<D:href>http://www.ics.uci.edu/~ejw/contact.html</D:href>
</D:owner>
</D:lockinfo>
>>Response
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktype><D:write/></D:locktype>
<D:lockscope><D:exclusive/></D:lockscope>
<D:depth>Infinity</D:depth>
<D:owner>
<D:href>
http://www.ics.uci.edu/~ejw/contact.html
</D:href>
</D:owner>
<D:timeout>Second-604800</D:timeout>
<D:locktoken>
<D:href>
opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4
</D:href>
</D:locktoken>
</D:activelock>
</D:lockdiscovery>
</D:prop>
This example shows a successful exclusive write lock on http://webdav.sb.aol.com/workspace/webdav/proposal.doc ๐. The resource http://www.ics.uci.edu/~ejw/contact.html has contact info for the lock owner. The server runs an activity-based timeout policy on this resource, so the lock automatically gets removed after 1 week (604800 seconds) โณ. Also, the nonce, response, and opaque fields haven't been calculated in the Authorization request header, so don't panic when you see the placeholders ๐ซถ.
8.10.9 Example - Refreshing a Write Lock โจ
Request
LOCK /workspace/webdav/proposal.doc HTTP/1.1
Host: webdav.sb.aol.com
Timeout: Infinite, Second-4100000000
If: (<opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4>)
Authorization: Digest username="ejw",
realm="ejw@webdav.sb.aol.com", nonce="...",
uri="/workspace/webdav/proposal.doc",
response="...", opaque="..."
Response
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktype><D:write/></D:locktype>
<D:lockscope><D:exclusive/></D:lockscope>
<D:depth>Infinity</D:depth>
<D:owner>
<D:href>
http://www.ics.uci.edu/~ejw/contact.html
</D:href>
</D:owner>
<D:timeout>Second-604800</D:timeout>
<D:locktoken>
<D:href>
opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6be4
</D:href>
</D:locktoken>
</D:activelock>
</D:lockdiscovery>
</D:prop>
okay so this request is a lock refresh ๐ it resets any timeouts and keeps the lock alive, bestie ๐ notice that the client asked for an infinite timeout, but the server chose to ignore that ๐ and in this example the nonce, response, and opaque fields haven't been calculated in the Authorization request header ๐
8.10.10 Example - Multi-Resource Lock Request โจ
Request
LOCK /webdav/ HTTP/1.1
Host: webdav.sb.aol.com
Timeout: Infinite, Second-4100000000
Depth: infinity
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="ejw",
realm="ejw@webdav.sb.aol.com", nonce="...",
uri="/workspace/webdav/proposal.doc",
response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D="DAV:">
<D:locktype><D:write/></D:locktype>
<D:lockscope><D:exclusive/></D:lockscope>
<D:owner>
<D:href>http://www.ics.uci.edu/~ejw/contact.html</D:href>
</D:owner>
</D:lockinfo>
Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://webdav.sb.aol.com/webdav/secret</D:href>
<D:status>HTTP/1.1 403 Forbidden</D:status>
</D:response>
<D:response>
<D:href>http://webdav.sb.aol.com/webdav/</D:href>
<D:propstat>
<D:prop><D:lockdiscovery/></D:prop>
<D:status>HTTP/1.1 424 Failed Dependency</D:status>
</D:propstat>
</D:response>
</D:multistatus>
this one is a whole vibe ๐ง the client wants an exclusive write lock on a collection AND all its children ๐ it asks for an infinite-length lock if that's available, otherwise a timeout of 4.1 billion seconds, if available. The request entity body holds the contact info for whoever is taking out the lock, here a web page URL ๐ธ
the error is a 403 (Forbidden) response on http://webdav.sb.aol.com/webdav/secret ๐ and because that resource couldn't be locked, none of the resources got locked. Also, the lockdiscovery property for the Request-URI is included, as required ๐ here it's empty, which means there are no outstanding locks on the resource.
again, the nonce, response, and opaque fields haven't been calculated in the Authorization request header ๐ซถ
8.11 UNLOCK Method
The UNLOCK method removes the lock identified by the lock token in the Lock-Token request header from the Request-URI, and from all other resources included in the lock ๐ฆ if all the resources locked under the submitted lock token can't be unlocked, then the UNLOCK request MUST fail ๐ญ
Any DAV compliant resource which supports the LOCK method MUST support the UNLOCK method ๐
8.11.1 Example - UNLOCK โจ
Request
UNLOCK /workspace/webdav/info.doc HTTP/1.1
Host: webdav.sb.aol.com
Lock-Token: <opaquelocktoken:a515cfa4-5da4-22e1-f5b5-00a0451e6bf7>
Authorization: Digest username="ejw",
realm="ejw@webdav.sb.aol.com", nonce="...",
uri="/workspace/webdav/proposal.doc",
response="...", opaque="..."
Response
HTTP/1.1 204 No Content
in this example, the lock identified by the lock token "opaquelocktoken:a515cfa4-5da4-22e1-f5b5-00a0451e6bf7" is successfully removed from the resource http://webdav.sb.aol.com/workspace/webdav/info.doc โ if that lock covered more than one resource, it gets removed from all of them ๐ the 204 (No Content) status code is used instead of 200 (OK) because there's no response entity body ๐
again, the nonce, response, and opaque fields haven't been calculated in the Authorization request header ๐
9 HTTP Headers for Distributed Authoring โจ
9.1 DAV Header
DAV = "DAV" ":" "1" ["," "2"] ["," 1#extend]
this header tells you the resource supports the DAV schema and protocol as specified ๐ All DAV compliant resources MUST return the DAV header on all OPTIONS responses ๐
The value is a list of every compliance class the resource supports. Heads up: above, a comma has already been added before the 2 ๐ that's because a resource can't be level 2 compliant unless it's also level 1 compliant. Check section 15 for more details ๐ generally though, supporting one compliance class doesn't mean you support any other one ๐ซถ
9.2 Depth Header
Depth = "Depth" ":" ("0" | "1" | "infinity")
The Depth header is used with methods run on resources that could potentially have internal members ๐ง it tells the method whether to apply only to the resource ("Depth: 0"), to the resource and its immediate children ("Depth: 1"), or to the resource and all its progeny ("Depth: infinity") ๐ณ
The Depth header is only supported if a method's definition explicitly provides for that support ๐
These rules are the default behaviour for any method that supports the Depth header ๐ A method can override them by defining different behaviour in its own definition ๐ฆ
Methods that support the Depth header may choose not to support every value of the header, and may define, case by case, what happens when there's no Depth header at all ๐ for example, the MOVE method only supports "Depth: infinity", and if there's no Depth header it acts as if a "Depth: infinity" header had been applied ๐ธ
Clients MUST NOT rely on methods executing on members of their hierarchies in any particular order, or on the execution being atomic, unless the particular method explicitly guarantees it ๐ญ
When executed, a method with a Depth header does as much of its assigned task as it can, then returns a response saying what it managed to accomplish and what it failed to do ๐
So, for example, an attempt to COPY a hierarchy might end up with some members copied and some not ๐
Any headers on a method that has a defined interaction with the Depth header MUST be applied to all resources in the scope of the method, unless alternative behaviour is explicitly defined ๐ for example, an If-Match header has its value applied against every resource in the method's scope, and it'll make the method fail if the header doesn't match ๐
If a resource (source or destination) in the scope of a method with a Depth header is locked in a way that stops the method from succeeding, then the lock token for that resource MUST be submitted with the request in the If request header ๐
The Depth header only specifies how the method behaves with regard to internal children ๐ if a resource doesn't have internal children, then the Depth header MUST be ignored ๐ซง
Please note, though, that it's always an error to submit a Depth header value the method's definition doesn't allow โ ๏ธ so submitting "Depth: 1" on a COPY gets you a 400 (Bad Request), even if the resource has no internal members ๐ the method should fail not because the resource lacks internal members, but because of the illegal value in the header ๐
โโ๏ธ
9.3 Destination Header
Destination = "Destination" ":" absoluteURI
The Destination header specifies the URI that identifies a destination resource for methods like COPY and MOVE, which take two URIs as parameters ๐ฆ Note that the absoluteURI production is defined in [RFC2396] ๐
9.4 If Header
If = "If" ":" ( 1*No-tag-list | 1*Tagged-list)
No-tag-list = List
Tagged-list = Resource 1*List
Resource = Coded-URL
List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")"
State-token = Coded-URL
Coded-URL = "<" absoluteURI ">"
The If header is meant to work a lot like the If-Match header defined in section 14.25 of [RFC2068] ๐ but the If header works with any URI that represents state information about a resource (a state token), as well as ETags โจ a classic example of a state token is a lock token, and lock tokens are the only state tokens defined in this specification ๐
All DAV compliant resources MUST honor the If header ๐ซถ
The If header describes a series of state lists ๐ if the state of the resource the header applies to doesn't match any of the specified state lists, then the request MUST fail with a 412 (Precondition Failed) ๐ญ if one of the described state lists does match the resource's state, then the request may succeed ๐
Note that the absoluteURI production is defined in [RFC2396] ๐
9.4.1 No-tag-list Production
The No-tag-list production describes a series of state tokens and ETags ๐ง if you use multiple No-tag-list productions, then only one of them needs to match the resource's state for the method to be allowed to continue ๐
If a method is applied to multiple resources because of a Depth or Destination header, then the No-tag-list production MUST be applied to each resource the method is applied to ๐
9.4.1.1 Example - No-tag-list If Header
If: (<locktoken:a-write-lock-token> ["I am an ETag"]) (["I am another
ETag"])
the If header above would require that any resources within the scope of the method must either be locked with the specified lock token and be in the state identified by the "I am an ETag" ETag, or be in the state identified by the second ETag, "I am another ETag" ๐ฆ to put it more plainly, you can think of the header above as being in the form (or (and <locktoken:a-write-lock-token> ["I am an ETag"]) (and ["I am another ETag"])) ๐ง โจ
9.4.2 Tagged-list Production ๐
okay so the tagged-list production is basically a scope thing ๐ it says the list productions after a resource spec only apply to THAT resource. the scope starts at the list right after the resource production and ends when the next resource production shows up (if there is one) โจ
when the If header gets applied to a particular resource, the tagged-list productions MUST be searched to see if any of the listed resources match the operand resource(s) for the current method. if none of the resource productions match the current resource, then the header MUST be ignored ๐ but if one of them does match the name of the resource being checked, then the list productions after that resource production MUST be applied to it, the way the previous section described ๐ซถ
and the same URI MUST NOT appear more than once in a resource production in an If header. no duplicates, bestie ๐
9.4.2.1 Example - Tagged List If header ๐ฆ
COPY /resource1 HTTP/1.1
Host: www.foo.bar
Destination: http://www.foo.bar/resource2
If: <http://www.foo.bar/resource1> (<locktoken:a-write-lock-token>
[W/"A weak ETag"]) (["strong ETag"])
<http://www.bar.bar/random>(["another strong ETag"])
okay this one is giving main character energy ๐ we're copying http://www.foo.bar/resource1 over to http://www.foo.bar/resource2. when the method first hits http://www.foo.bar/resource1, that resource has to be in the state "(<locktoken:a-write-lock-token> [W/"A weak ETag"]) (["strong ETag"])" ๐ญ which means it either has to be locked with the lock token "locktoken:a-write-lock-token" AND have the weak entity tag W/"A weak ETag", OR it has to have the strong entity tag "strong ETag". either one works ๐ธ
that's the only success condition, because http://www.bar.bar/random never gets the method applied to it (it's the only other resource in the If header), and http://www.foo.bar/resource2 isn't even listed in the If header ๐ง
9.4.3 not Production ๐
every state token or ETag is either current, which means it describes the state of a resource, or it's not current, which means it doesn't ๐ so matching a state token or ETag against the resource's current state always comes out as true or false. the not production is the thing that flips that value โจ and its scope is just the state-token or entity-tag right after it.
If: (Not <locktoken:write1> <locktoken:write2>)
when this is submitted with a request, it means all the operand resources must not be locked with locktoken:write1 and must be locked with locktoken:write2 ๐ฅ
9.4.4 Matching Function ๐
when you're doing If header processing, here's how a matching state token or entity tag is defined:
Matching entity tag: where the entity tag matches an entity tag associated with that resource.
Matching state token: where there is an exact match between the state token in the If header and any state token on the resource.
9.4.5 If Header and Non-DAV Compliant Proxies ๐
ngl this one is a little sad ๐ฅบ non-DAV compliant proxies won't honor the If header, because they won't understand it, and HTTP says headers you don't understand have to be ignored. so when you're talking to HTTP/1.1 proxies, the Cache-Control: no-cache request header MUST be used so the proxy doesn't wrongly try to answer the request from its cache ๐
โโ๏ธ and for HTTP/1.0 proxies, the Pragma: no-cache request header MUST be used for the same reason ๐
9.5 Lock-Token Header ๐
Lock-Token = "Lock-Token" ":" Coded-URL
the Lock-Token request header is used with the UNLOCK method to identify the lock to be removed. the lock token in the Lock-Token request header MUST identify a lock that contains the resource identified by Request-URI as a member โจ
the Lock-Token response header is used with the LOCK method to show the lock token that got created when a LOCK request successfully made a new lock ๐
9.6 Overwrite Header ๐ซง
Overwrite = "Overwrite" ":" ("T" | "F")
the Overwrite header says whether the server should overwrite the state of a non-null destination resource during a COPY or MOVE ๐
a value of "F" means the server must not perform the COPY or MOVE if the destination's state is non-null. if the overwrite header isn't included in a COPY or MOVE request, the resource MUST treat the request as if it had an overwrite header with the value "T" โจ now, the Overwrite header kinda seems to do the same thing as the If-Match: * header from HTTP/1.1, but If-Match only applies to the Request-URI, not to the Destination of a COPY or MOVE. so they're not the same, periodt ๐
if a COPY or MOVE doesn't happen because of the Overwrite header's value, the method MUST fail with a 412 (Precondition Failed) status code ๐
all DAV compliant resources MUST support the Overwrite header ๐ซถ
9.7 Status-URI Response Header ๐ฆ
the Status-URI response header can be used with the 102 (Processing) status code to tell the client how a method is going ๐ง
Status-URI = "Status-URI" ":" *(Status-Code Coded-URL) ; Status-Code
is defined in 6.1.1 of [RFC2068]
the URIs in the header are source resources that the outstanding method has affected. the status code shows the outcome of the method on that resource. so for example, if a MOVE on a collection is still going and a 102 (Processing) response comes back with a Status-URI header, the URIs included will show which resources had a move attempted on them and what happened ๐ธ
9.8 Timeout Request Header โฐ
TimeOut = "Timeout" ":" 1#TimeType
TimeType = ("Second-" DAVTimeOutVal | "Infinite" | Other)
DAVTimeOutVal = 1*digit
Other = "Extend" field-value ; See section 4.2 of [RFC2068]
clients can include Timeout headers in their LOCK requests ๐ but the server isn't required to honor or even consider them. clients MUST NOT submit a Timeout request header with any method other than a LOCK method ๐ โโ๏ธ
a Timeout request header MUST contain at least one TimeType, and it can contain multiple TimeType entries. listing several is how the client says which values and value types it's okay with, and the client lists them in order of preference ๐
Timeout response values MUST use a Second value, Infinite, or a TimeType the client has shown it knows about. the server may assume a client is familiar with any TimeType submitted in a Timeout header โจ
the "Second" TimeType is the number of seconds that will pass between the lock being granted at the server and the lock being automatically removed. the timeout value for TimeType "Second" MUST NOT be greater than 2^32-1 ๐ข
the timeout counter SHOULD restart any time a lock owner sends a method to any member of the lock, including unsupported methods or methods that are unsuccessful ๐ however, the lock MUST be refreshed if a refresh LOCK method is successfully received ๐
if the timeout expires, the lock may be lost. specifically, if the server wants to harvest the lock when it times out, the server SHOULD act as if it ran an UNLOCK method on the resource using the lock token of the timed-out lock, with its override authority ๐ค so logs should get updated with what happened to the lock, notifications should get sent, and so on, just like they would for an UNLOCK request ๐
servers should pay close attention to the values clients submit, because they say a lot about what kind of activity the client plans to do ๐ for example, an applet running in a browser may need to lock a resource, but since the environment it's running in is unstable, the applet might get turned off without warning. so it'll probably ask for a pretty small timeout, so that if the applet dies the lock can be harvested quickly ๐ซ a document management system, on the other hand, will probably ask for an extremely long timeout, because its user might be planning to go offline ๐
a client MUST NOT assume that just because the timeout has expired, the lock has been lost ๐
10 Status Code Extensions to HTTP/1.1 โจ
the following status codes are added to the ones defined in HTTP/1.1 [RFC2068] ๐
10.1 102 Processing โณ
the 102 (Processing) status code is an interim response that tells the client the server has accepted the complete request, but hasn't finished it yet ๐ this status code SHOULD only be sent when the server reasonably expects the request to take a significant amount of time. as a guideline, if a method is taking longer than 20 seconds (a reasonable but arbitrary value) to process, the server SHOULD return a 102 (Processing) response ๐ฐ๏ธ the server MUST send a final response once the request has been completed โจ
methods can take a really long time to process, especially methods that support the Depth header ๐ญ in those cases the client may time out the connection while it's waiting for a response. to prevent that, the server may return a 102 (Processing) status code to tell the client it's still working on the method ๐ซถ
10.2 207 Multi-Status ๐
the 207 (Multi-Status) status code gives the status for multiple independent operations (check section 11 for more info) ๐ง
10.3 422 Unprocessable Entity ๐
the 422 (Unprocessable Entity) status code means the server understands the content type of the request entity (so a 415 (Unsupported Media Type) status code would be wrong), and the syntax of the request entity is correct (so a 400 (Bad Request) status code would be wrong too), but it couldn't process the instructions inside ๐ค for example, this can happen if an XML request body is well-formed (syntactically correct) but has semantically wrong XML instructions ๐
10.4 423 Locked ๐
the 423 (Locked) status code means the source or destination resource of a method is locked ๐
10.5 424 Failed Dependency ๐
the 424 (Failed Dependency) status code means the method couldn't be performed on the resource because the requested action depended on another action, and that other action failed ๐ค for example, if a command in a PROPPATCH method fails, then at minimum the rest of the commands will also fail with 424 (Failed Dependency) ๐
10.6 507 Insufficient Storage ๐พ
the 507 (Insufficient Storage) status code means the method couldn't be performed on the resource because the server can't store the representation it needs to finish the request ๐ฉ this condition is considered temporary. if the request that got this status code was the result of a user action, the request MUST NOT be repeated until a separate user action asks for it ๐ซ
11 Multi-Status Response ๐ธ
the default 207 (Multi-Status) response body is a text/xml or application/xml HTTP entity ๐ it contains a single XML element called multistatus, which holds a set of XML elements called response. those contain the 200, 300, 400, and 500 series status codes generated during the method invocation โจ 100 series status codes SHOULD NOT be recorded in a response XML element ๐
12. XML Element Definitions โจ
okay bestie, this is the XML vocab section ๐ Each section ends with its element type declaration in the [REC-XML] format, and the Value bit (when there is one) is extra restrictions on what the element can hold, written in BNF. So it's basically the rules for each little XML tag ๐ง
12.1. activelock XML Element
- Name:
activelock - Namespace:
DAV: - Purpose: this is the lock itself, the "hands off, I'm editing this rn" sign on a resource ๐
<!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
locktoken?) >
12.1.1. depth XML Element
- Name:
depth - Namespace:
DAV: - Purpose: the value of the Depth header ๐ธ
- Value:
"0" | "1" | "infinity"
<!ELEMENT depth (#PCDATA) >
12.1.2. locktoken XML Element
- Name:
locktoken - Namespace:
DAV: - Purpose: the lock token attached to a lock ๐
- Description: the href holds one or more opaque lock token URIs, and they all point at the same lock (aka the OpaqueLockToken-URI production in section 6.4). It's giving "many keys, one door" ๐๏ธ
<!ELEMENT locktoken (href+) >
12.1.3. timeout XML Element
- Name:
timeout - Namespace:
DAV: - Purpose: the timeout attached to a lock โฐ
- Value:
TimeType ;Defined in section 9.8
<!ELEMENT timeout (#PCDATA) >
12.2. collection XML Element
- Name:
collection - Namespace:
DAV: - Purpose: marks the resource as a collection ๐ A collection resource's resourcetype property MUST have this value, no exceptions bestie ๐
<!ELEMENT collection EMPTY >
12.3. href XML Element
- Name:
href - Namespace:
DAV: - Purpose: says "the content of this element is a URI" ๐
- Value:
URI ; See section 3.2.1 of [RFC2068]
<!ELEMENT href (#PCDATA)>
12.4. link XML Element
- Name:
link - Namespace:
DAV: - Purpose: marks a property as a link and carries its source and destination ๐ฆ
- Description: the link element gives the sources and destinations of a link. The name of the property holding it tells you the type of link. Link is multi-valued, so you can stack several links together to show several links of the same type. The href values inside the src and dst elements of a link MUST NOT be rejected if they point at resources that don't exist, so don't be picky about ghosts ๐ป
<!ELEMENT link (src+, dst+) >
12.4.1. dst XML Element
- Name:
dst - Namespace:
DAV: - Purpose: the destination of a link ๐ฏ
- Value:
URI
<!ELEMENT dst (#PCDATA) >
12.4.2. src XML Element
- Name:
src - Namespace:
DAV: - Purpose: the source of a link ๐ฑ
- Value:
URI
<!ELEMENT src (#PCDATA) >
12.5. lockentry XML Element
- Name:
lockentry - Namespace:
DAV: - Purpose: lists the kinds of locks you're allowed to use on a resource ๐งพ
<!ELEMENT lockentry (lockscope, locktype) >
12.6. lockinfo XML Element
- Name:
lockinfo - Namespace:
DAV: - Purpose: goes along with the LOCK method so the client can say what kind of lock they want created ๐
<!ELEMENT lockinfo (lockscope, locktype, owner?) >
12.7. lockscope XML Element
- Name:
lockscope - Namespace:
DAV: - Purpose: says whether a lock is exclusive or shared ๐ค
<!ELEMENT lockscope (exclusive | shared) >
12.7.1. exclusive XML Element
- Name:
exclusive - Namespace:
DAV: - Purpose: specifies an exclusive lock, the "only me, periodt" kind ๐
<!ELEMENT exclusive EMPTY >
12.7.2. shared XML Element
- Name:
shared - Namespace:
DAV: - Purpose: specifies a shared lock, the "we can all be in here together" kind ๐
<!ELEMENT shared EMPTY >
12.8. locktype XML Element
- Name:
locktype - Namespace:
DAV: - Purpose: specifies the access type of a lock. For now there's only one lock type defined, the write lock โ๏ธ
<!ELEMENT locktype (write) >
12.8.1. write XML Element
- Name:
write - Namespace:
DAV: - Purpose: specifies a write lock ๐๏ธ
<!ELEMENT write EMPTY >
12.9. multistatus XML Element
- Name:
multistatus - Namespace:
DAV: - Purpose: holds multiple response messages, a whole group chat of replies ๐ฌ
- Description: the responsedescription at the top level is a general message about the overall vibe of the response. If it's there, an application can show that instead of showing each individual response description inside the responses โจ
<!ELEMENT multistatus (response+, responsedescription?) >
12.9.1. response XML Element
- Name:
response - Namespace:
DAV: - Purpose: holds one response describing what a method did to a resource and/or its properties ๐ฌ
- Description: a particular href MUST NOT appear more than once as a child of a response element under a multistatus element. This rule keeps the processing cost of a response linear, because nobody has to go hunting to group all the responses by href ๐โโ๏ธ There are no requirements about ordering based on href values, so order is free real estate ๐ธ
<!ELEMENT response (href, ((href*, status)|(propstat+)),
responsedescription?) >
12.9.1.1. propstat XML Element
- Name:
propstat - Namespace:
DAV: - Purpose: groups together a prop element and a status element that go with a particular href element ๐
- Description: the propstat element MUST contain one prop element and one status element. The contents of the prop element MUST only list the names of the properties that the result in the status element applies to. Only the names, bestie, not the whole vibe ๐ซถ
<!ELEMENT propstat (prop, status, responsedescription?) >
12.9.1.2. status XML Element
- Name:
status - Namespace:
DAV: - Purpose: holds a single HTTP status-line ๐ฆ
- Value:
status-line ;status-line defined in [RFC2068]
<!ELEMENT status (#PCDATA) >
12.9.2. responsedescription XML Element
- Name:
responsedescription - Namespace:
DAV: - Purpose: holds a message that can be shown to a user, explaining what kind of response this is ๐ญ
- Description: this element has info that's fine to show a real human ๐
<!ELEMENT responsedescription (#PCDATA) >
12.10. owner XML Element
- Name:
owner - Namespace:
DAV: - Purpose: info about the principal who took out a lock ๐งโ๐ค
- Description: the owner element gives enough info to either contact that principal directly (like a phone number or an Email URI) or find them (like the URL of a homepage). Basically, so you can slide into their DMs about the lock ๐ฑ
<!ELEMENT owner ANY>
12.11. prop XML element
- Name:
prop - Namespace:
DAV: - Purpose: holds properties related to a resource ๐๏ธ
- Description: the prop element is a generic container for properties defined on resources. Every element inside a prop element MUST define a property related to the resource. No other elements may be used inside a prop element, so keep the guest list tight ๐
<!ELEMENT prop ANY>
12.12. propertybehavior XML element
- Name:
propertybehavior - Namespace:
DAV: - Purpose: says how properties get handled during a COPY or MOVE ๐ฆข
- Description: the propertybehavior element specifies how properties are handled during a COPY or MOVE. If it's not in the request body, the server is expected to act the way the default property handling of that method says. All WebDAV compliant resources MUST support the propertybehavior element, no skipping ๐
<!ELEMENT propertybehavior (omit | keepalive) >
12.12.1. keepalive XML element
- Name:
keepalive - Namespace:
DAV: - Purpose: sets the requirements for copying or moving live properties ๐
- Description: if a list of URIs is included as the value of keepalive, the named properties MUST be "live" after they're copied (or moved) to the destination resource of a COPY (or MOVE). If the value "*" is given, that means all live properties on the source resource MUST be live on the destination. If the requirements in the keepalive element can not be honored, the method MUST fail with a 412 (Precondition Failed). That's a big no from the server, so be ready ๐ญ All DAV compliant resources MUST support the keepalive element for use with the COPY and MOVE methods.
<!ELEMENT keepalive (#PCDATA | href+) >
- Value:
"*" ; #PCDATA value can only be "*"
12.12.2. omit XML element
- Name:
omit - Namespace:
DAV: - Purpose: tells the server to do its best to copy properties, but a failure to copy a property MUST NOT cause the method to fail. It's the chill option ๐งโโ๏ธ
- Description: the default for a COPY or MOVE is to copy or move all the properties, or fail the whole method. But sometimes it's just not possible, like when a server copies a resource over another protocol such as FTP. Then any attempt to copy or move over FTP would always have to fail, because properties couldn't be moved over, not even dead properties ๐ All DAV compliant resources MUST support the omit element on COPY and MOVE methods.
<!ELEMENT omit EMPTY >
12.13. propertyupdate XML element
- Name:
propertyupdate - Namespace:
DAV: - Purpose: holds a request to change the properties on a resource โ๏ธ
- Description: this element is a container for all the info needed to modify the properties on the resource. It's multi-valued, so you can have a bunch of them ๐
<!ELEMENT propertyupdate (remove | set)+ >
12.13.1. remove XML element
- Name:
remove - Namespace:
DAV: - Purpose: lists the DAV properties that should be removed from a resource ๐๏ธ
- Description: remove says the properties listed in prop should be removed. Asking to remove a property that doesn't exist is not an error, so no drama ๐ All the XML elements in a prop element inside a remove element MUST be empty, since only the names of the properties to remove are needed.
<!ELEMENT remove (prop) >
12.13.2. set XML element
- Name:
set - Namespace:
DAV: - Purpose: lists the DAV property values to be set on a resource ๐ท
- Description: the set element MUST contain only a prop element. The elements inside that prop element MUST specify the name and value of the properties that get set on the resource identified by Request-URI. If a property already exists, its value gets replaced, new era unlocked ๐ Language tagging info in the property's value (in the "xml:lang" attribute, if it's present) MUST be persistently stored along with the property, and MUST be subsequently retrievable using PROPFIND. It's giving memory that doesn't forget ๐ง โจ
<!ELEMENT set (prop) >
12.14. propfind XML Element
- Name:
propfind - Namespace:
DAV: - Purpose: specifies which properties get returned from a PROPFIND method. There are two special elements for this, allprop and propname. If prop is used inside propfind, it MUST only contain property names, not values ๐
<!ELEMENT propfind (allprop | propname | prop) >
12.14.1. allprop XML Element
- Name:
allprop - Namespace:
DAV: - Purpose: says that all property names and values on the resource should come back, the full glow-up ๐
<!ELEMENT allprop EMPTY >
12.14.2. propname XML Element
- Name:
propname - Namespace:
DAV: - Purpose: says that only a list of property names on the resource should come back, no values, just the menu ๐
<!ELEMENT propname EMPTY >
13 DAV Properties โจ
Okay bestie, so for DAV properties the property's name is also the name of the XML element that holds its value. Super neat, right? ๐ Each section ends with an element type declaration written in the [REC-XML] format. Where there's a "Value" field, it adds BNF rules that narrow down what's allowed inside that element (basically, it restricts the PCDATA contents). ๐ฆ
13.1 creationdate Property
Name: creationdate Namespace: DAV: Purpose: Records when the resource was created, date and time both. ๐
Value: date-time ; See Appendix 2 Description: The creationdate property should be defined on all DAV compliant resources. If it's present, it holds a timestamp for the exact moment the resource was created, meaning the moment it first had non-null state. โฐ
<!ELEMENT creationdate (#PCDATA) >
13.2 displayname Property
Name: displayname Namespace: DAV: Purpose: Gives the resource a name that's nice to show a human. ๐ Description: The displayname property should be defined on all DAV compliant resources. If it's present, it holds a description of the resource that's suitable for showing to a user. โจ
<!ELEMENT displayname (#PCDATA) >
13.3 getcontentlanguage Property
Name: getcontentlanguage Namespace: DAV: Purpose: Holds the Content-Language header that comes back from a GET without accept headers. ๐ Description: The getcontentlanguage property MUST be defined on any DAV compliant resource that returns the Content-Language header on a GET. ๐ซถ Value: language-tag ;language-tag is defined in section 14.13 of [RFC2068]
<!ELEMENT getcontentlanguage (#PCDATA) >
13.4 getcontentlength Property
Name: getcontentlength Namespace: DAV: Purpose: Holds the Content-Length header that comes back from a GET without accept headers. ๐ Description: The getcontentlength property MUST be defined on any DAV compliant resource that returns the Content-Length header in response to a GET. ๐
Value: content-length ; see section 14.14 of [RFC2068]
<!ELEMENT getcontentlength (#PCDATA) >
13.5 getcontenttype Property
Name: getcontenttype Namespace: DAV: Purpose: Holds the Content-Type header that comes back from a GET without accept headers. ๐ Description: This getcontenttype property MUST be defined on any DAV compliant resource that returns the Content-Type header in response to a GET. ๐ Value: media-type ; defined in section 3.7 of [RFC2068]
<!ELEMENT getcontenttype (#PCDATA) >
13.6 getetag Property
Name: getetag Namespace: DAV: Purpose: Holds the ETag header that comes back from a GET without accept headers. ๐ท๏ธ Description: The getetag property MUST be defined on any DAV compliant resource that returns the Etag header. ๐ฆ Value: entity-tag ; defined in section 3.11 of [RFC2068]
<!ELEMENT getetag (#PCDATA) >
13.7 getlastmodified Property
Name: getlastmodified Namespace: DAV: Purpose: Holds the Last-Modified header that comes back from a GET method without accept headers. ๐ฐ๏ธ Description: Okay, this one's a plot twist ๐ญ. The last-modified date on a resource can change because of any part of the resource's state, not only a change to what the GET method sends back. For example, changing a property can make the last-modified date move. The getlastmodified property MUST be defined on any DAV compliant resource that returns the Last-Modified header in response to a GET. ๐ฅ Value: HTTP-date ; defined in section 3.3.1 of [RFC2068]
<!ELEMENT getlastmodified (#PCDATA) >
13.8 lockdiscovery Property
Name: lockdiscovery Namespace: DAV: Purpose: Describes the active locks on a resource. ๐ Description: The lockdiscovery property gives you a list of who holds a lock, what kind of lock it is, the timeout type and how much time is left on that timeout, plus the associated lock token. The server is free to hide any or all of this info if the requesting principal doesn't have enough access rights to see it. ๐
<!ELEMENT lockdiscovery (activelock)* >
13.8.1 Example - Retrieving the lockdiscovery Property
>>Request
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Content-Length: xxxx
Content-Type: text/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D='DAV:'>
<D:prop><D:lockdiscovery/></D:prop>
</D:propfind>
>>Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D='DAV:'>
<D:response>
<D:href>http://www.foo.bar/container/</D:href>
<D:propstat>
<D:prop>
<D:lockdiscovery>
<D:activelock>
<D:locktype><D:write/></D:locktype>
<D:lockscope><D:exclusive/></D:lockscope>
<D:depth>0</D:depth>
<D:owner>Jane Smith</D:owner>
<D:timeout>Infinite</D:timeout>
<D:locktoken>
<D:href>
opaquelocktoken:f81de2ad-7f3d-a1b2-4f3c-00a0c91a9d76
</D:href>
</D:locktoken>
</D:activelock>
</D:lockdiscovery>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
So this resource has one exclusive write lock on it, and that lock never times out. ๐โจ
13.9 resourcetype Property
Name: resourcetype Namespace: DAV: Purpose: Says what kind of resource this is. ๐ง Description: The resourcetype property MUST be defined on all DAV compliant resources. The default value is empty. ๐ซง
<!ELEMENT resourcetype ANY >
13.10 source Property
Name: source Namespace: DAV: Purpose: The destination of a source link points to the resource that holds the unprocessed source of the link's source. ๐ Description: The source of the link (src) is usually the URI of the output resource where the link is defined. There's usually only one destination (dst) for the link, which is the URI where the unprocessed source of the resource can be accessed. When a link has more than one destination, this specification doesn't set any policy on ordering. ๐คทโโ๏ธ
<!ELEMENT source (link)* >
13.10.1 Example - A source Property
<?xml version="1.0" encoding="utf-8" ?>
<D:prop xmlns:D="DAV:" xmlns:F="http://www.foocorp.com/Project/">
<D:source>
<D:link>
<F:projfiles>Source</F:projfiles>
<D:src>http://foo.bar/program</D:src>
<D:dst>http://foo.bar/src/main.c</D:dst>
</D:link>
<D:link>
<F:projfiles>Library</F:projfiles>
<D:src>http://foo.bar/program</D:src>
<D:dst>http://foo.bar/src/main.lib</D:dst>
</D:link>
<D:link>
<F:projfiles>Makefile</F:projfiles>
<D:src>http://foo.bar/program</D:src>
<D:dst>http://foo.bar/src/makefile</D:dst>
</D:link>
</D:source>
</D:prop>
Here the resource http://foo.bar/program has a source property with three links. ๐ฆ Each link has three elements. Two of them, src and dst, are part of the DAV schema in this document. The third one comes from the schema http://www.foocorp.com/project/ (that's Source, Library, and Makefile). A client that only implements the DAV elements won't understand the foocorp ones, so it ignores them and still sees the expected source and destination links. ๐ A smarter client might know about the foocorp elements and show the user extra info about the links. This example is a great look at the power of XML markup: you can add more info to element values without breaking older clients. ๐
13.11 supportedlock Property
Name: supportedlock Namespace: DAV: Purpose: Lists the lock capabilities this resource supports. ๐ Description: The supportedlock property of a resource returns a list of the combinations of scope and access types that can be specified in a lock request on the resource. Keep in mind the actual contents are controlled by access controls too, so a server is not required to provide info the client isn't authorized to see. ๐
<!ELEMENT supportedlock (lockentry)* >
13.11.1 Example - Retrieving the supportedlock Property
>>Request
PROPFIND /container/ HTTP/1.1
Host: www.foo.bar
Content-Length: xxxx
Content-Type: text/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop><D:supportedlock/></D:prop>
</D:propfind>
>>Response
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.foo.bar/container/</D:href>
<D:propstat>
<D:prop>
<D:supportedlock>
<D:lockentry>
<D:lockscope><D:exclusive/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope><D:shared/></D:lockscope>
<D:locktype><D:write/></D:locktype>
</D:lockentry>
</D:supportedlock>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
14 Instructions for Processing XML in DAV ๐ง
All DAV compliant resources MUST ignore any unknown XML element and all its children they run into while processing a DAV method that uses XML as its command language. ๐ โโ๏ธ Unknown stuff gets tuned out, periodt.
This rule also covers clients processing DAV property values, where unknown XML elements SHOULD be ignored unless the property's schema says otherwise. ๐
This rule does not apply to setting dead DAV properties on the server. There, the server MUST record unknown XML elements. ๐
The rule also doesn't apply to XML used as the content type of the entity body, like when XML is the body of a PUT. ๐
Since XML can be sent as text/xml or application/xml, a DAV server MUST accept DAV method requests with XML parameters sent as either text/xml or application/xml, and a DAV client MUST accept XML responses using either text/xml or application/xml. ๐ฆโจ
15 DAV Compliance Classes ๐ โจ
Okay bestie, so a DAV compliant resource can pick from two classes of compliance ๐. Clients can figure out which classes a resource is in by sending OPTIONS to it and checking the DAV header that comes back ๐.
Since this doc extends HTTP/1.1, basically every DAV compliant resource, client, and proxy MUST be compliant with [RFC2068] ๐ซถ. No cap, that's the baseline.
Compliance classes aren't necessarily sequential ๐ฆ. A class 2 resource must also be class 1 compliant. But if more classes get defined later, a resource that's class 1, 2, and 4 might not be class 3 compliant. Also, identifiers other than numbers may be used as compliance class identifiers ๐.
15.1 Class 1 ๐ธ
A class 1 compliant resource MUST meet all "MUST" requirements in all sections of this document ๐.
Class 1 compliant resources MUST return, at minimum, the value 1 in the DAV header on all responses to the OPTIONS method โจ.
15.2 Class 2 ๐
A class 2 compliant resource MUST meet all class 1 requirements and support the LOCK method, the supportedlock property, the lockdiscovery property, the Time-Out response header and the Lock-Token request header ๐. A class "2" compliant resource SHOULD also support the Time-Out request header and the owner XML element ๐ซถ.
Class 2 compliant resources MUST return, at minimum, the values 1 and 2 in the DAV header on all responses to the OPTIONS method ๐.
16 Internationalization Considerations ๐๐
In the realm of internationalization, this specification complies with the IETF Character Set Policy [RFC2277] ๐. Human-readable fields can show up either in the value of a property, or in an error message returned in a response entity body. In both cases, the human-readable content is encoded using XML, which has explicit provisions for character set tagging and encoding, and requires that XML processors read XML elements encoded, at minimum, using the UTF-8 [UTF-8] encoding of the ISO 10646 multilingual plane ๐ง . XML examples in this spec demonstrate use of the charset parameter of the Content-Type header, as defined in [RFC2376], plus the XML "encoding" attribute. Together those give charset identification info for MIME and XML processors ๐.
XML also has language tagging, so you can specify the language of a particular element's contents ๐ฃ๏ธ. XML uses either IANA registered language tags (see [RFC1766]) or ISO 639 language tags [ISO-639] in the xml:lang attribute to identify the language of an element's content and attributes ๐
.
WebDAV applications MUST support the character set tagging, character set encoding, and the language tagging functionality of the XML specification ๐ซถ. Implementors are strongly encouraged to read "XML Media Types" [RFC2376] for guidance on which MIME media type to use for XML transport, and on using the charset parameter of the Content-Type header ๐.
Names used in this spec fall into three categories: names of protocol elements like methods and headers, names of XML elements, and names of properties ๐งฉ. Protocol element names follow the precedent of HTTP, using English names encoded in USASCII for methods and headers. Since these protocol elements aren't visible to users (they're basically long token identifiers), they don't need to support encoding in multiple character sets ๐. Similarly, the XML element names in this spec are English names encoded in UTF-8, but since users never see them, they don't need multiple character set encodings either.
The name of a property defined on a resource is a URI ๐. Some apps (like a generic property viewer) will display property URIs directly to their users. But it's expected that the typical app will use a fixed set of properties and map the property name URI to a human-readable field when showing the property name to a user. Only when the set of properties isn't known ahead of time does an app need to show a property name URI to a user. We recommend that applications provide human-readable property names wherever feasible ๐.
For error reporting, we follow the HTTP/1.1 status code convention, including a short, English description of the code with each status code (e.g., 423 (Locked)) ๐ซ. A poorly crafted user agent might show that message to a user, but internationalized apps will ignore it and display an appropriate message in the user's language and character set ๐ธ.
Since interoperation of clients and servers doesn't require locale information, this spec doesn't specify any mechanism for transmitting it ๐คทโโ๏ธ.
17 Security Considerations ๐๐
This section is here to detail security issues that WebDAV apps need to be aware of ๐. All of the security considerations of HTTP/1.1 (discussed in [RFC2068]) and XML (discussed in [RFC2376]) also apply to WebDAV. On top of that, the security risks of remote authoring require stronger authentication tech, bring in several new privacy concerns, and may increase the hazards from poor server design. These issues are detailed below ๐ญ.
17.1 Authentication of Clients ๐
Because WebDAV is all about authoring, WebDAV servers need to use authentication tech to protect not just access to a network resource, but the integrity of the resource too ๐ก๏ธ. Also, adding locking functionality means you need authentication support ๐.
A password sent in the clear over an insecure channel is not enough to protect the accessibility and integrity of a resource, since the password can be intercepted ๐
โโ๏ธ. Basic authentication for HTTP/1.1 basically sends the password as clear text, so Basic authentication MUST NOT be used to authenticate a WebDAV client to a server unless the connection is secure ๐จ. Furthermore, a WebDAV server MUST NOT send Basic authentication credentials in a WWW-Authenticate header unless the connection is secure ๐
. Examples of secure connections include a Transport Layer Security (TLS) connection using a strong cipher suite with mutual authentication of client and server, or a connection over a network that's physically secure, like an isolated network in a building with restricted access ๐ข.
Basic auth over an unsecured connection is a hard no, bestie ๐ โโ๏ธ๐
WebDAV applications MUST support the Digest authentication scheme [RFC2069] ๐. Digest authentication verifies that both parties know a shared secret (a password) without having to send that secret in the clear. So it avoids the security problems of Basic authentication while still giving a level of authentication that's useful in a wide range of scenarios ๐ฆ.
17.2 Denial of Service ๐ฅ
Denial of service attacks are a special concern for WebDAV servers ๐ฌ. WebDAV plus HTTP enables denial of service attacks on every part of a system's resources, honestly so scary ๐.
The underlying storage can be attacked by PUTting extremely large files ๐ฆ. Asking for recursive operations on large collections can attack processing time โณ. Making multiple pipelined requests on multiple connections can attack network connections ๐. WebDAV servers need to be aware of the possibility of a denial of service attack at all levels ๐จ.
17.3 Security through Obscurity ๐
WebDAV provides, through the PROPFIND method, a mechanism for listing the member resources of a collection ๐. This greatly weakens security or privacy techniques that rely only on how hard it is to discover the names of network resources ๐ต. Users of WebDAV servers are encouraged to use access control techniques to prevent unwanted access to resources, rather than depending on how obscure their resource names are ๐โจ.
17.4 Privacy Issues Connected to Locks ๐๏ธ
When submitting a lock request, a user agent may also submit an owner XML field with contact info for the person taking out the lock (for cases where a person, rather than a robot, is taking out the lock) ๐งโ๐ป. That contact info gets stored in a lockdiscovery property on the resource, and other collaborators can use it to start negotiating access to the resource ๐ค. But in lots of cases this contact info can be super private, so it should not be widely disseminated ๐คซ. Servers SHOULD limit read access to the lockdiscovery property as appropriate ๐. Furthermore, user agents SHOULD provide control over whether contact information gets sent at all, and if it does get sent, control over exactly what information is included ๐.
17.5 Privacy Issues Connected to Properties ๐งพ
Property values are typically used to hold stuff like the author of a document, so privacy concerns could pop up from widespread access to a resource's property data ๐. To reduce the risk of accidentally leaking private info through properties, servers are encouraged to build access control mechanisms that separate read access to the resource body from read access to the resource's properties ๐งฑ. That way a user can control who sees their property data without overly restricting access to the resource's contents ๐.
17.6 Reduction of Security due to Source Link ๐โ ๏ธ
HTTP/1.1 warns against giving read access to script code, because it may contain sensitive info ๐ซฃ. Yet WebDAV, through its source link facility, can potentially provide a URI for script resources so they can be authored โ๏ธ. For HTTP/1.1, a server could reasonably block access to source resources, since read-only access is the usual case there ๐. WebDAV, though, puts its emphasis on authoring. It encourages read and write access to source resources, and provides the source link facility to identify the source ๐ . That cuts down the security benefit of blocking access to source resources ๐ญ. Users and administrators of WebDAV servers should be very cautious when allowing remote authoring of scripts, limiting read and write access to the source resources to authorized principals ๐จ๐ซถ.
17.7 Implications of XML External Entities ๐ง
okay so XML has this thing called "external entities" (defined in section 4.2.2 of [REC-XML]) ๐ which basically tells an XML processor to go fetch some XML sitting at a particular URI and inline-include it right into the doc. ๐ซถ An external XML entity can be used to append or modify the document type declaration (DTD) associated with an XML document. It can also pull XML into the content of the document itself โจ
for non-validating XML, like the XML used in this specification, including an external XML entity is not required by [REC-XML]. ๐ธ BUT [REC-XML] does say that an XML processor may, at its discretion, include the external XML entity. so it's optional, but it's allowed, periodt ๐
external XML entities have no inherent trustworthiness ๐จ they're subject to all the attacks that are endemic to any HTTP GET request. ๐ญ it's also possible for an external XML entity to modify the DTD, which changes the final form of the XML document. in the worst case that can significantly modify its semantics, or expose the XML processor to the security risks discussed in [RFC2376]. so implementers must be aware that external XML entities should be treated as untrustworthy. no cap, this is a big deal ๐
there's also a scalability risk when a widely deployed application uses external XML entities ๐ it's possible there would be significant numbers of requests for one external XML entity, which could potentially overload any server that fields requests for the resource containing the external XML entity. overloaded server, not it ๐
17.8 Risks Connected with Lock Tokens ๐
this one's giving "hidden tracking" energy, so pay attention ๐ this specification, in section 6.4, requires the use of Universal Unique Identifiers (UUIDs) for lock tokens, so that their uniqueness is guaranteed across space and time. ๐ฆ UUIDs, as defined in [ISO-11578], contain a "node" field which "consists of the IEEE address, usually the host address. For systems with multiple IEEE 802 nodes, any available node address can be used." Since a WebDAV server will issue many locks over its lifetime, the implication is that it will also be publicly exposing its IEEE 802 address. that's the plot twist ๐ณ
there are several risks associated with exposure of IEEE 802 addresses. Using the IEEE 802 address:
- It is possible to track the movement of hardware from subnet to subnet.
- It may be possible to identify the manufacturer of the hardware running a WebDAV server.
- It may be possible to determine the number of each type of computer running WebDAV.
section 6.4.1 of this specification details an alternate mechanism for generating the "node" field of a UUID without using an IEEE 802 address ๐ that alleviates the risks associated with exposure of IEEE 802 addresses by using an alternate source of uniqueness. โจ iconic workaround, honestly
18 IANA Considerations ๐
this document defines two namespaces: the namespace of property names, and the namespace of WebDAV-specific XML elements used within property values. ๐
URIs are used for both names, and there are a few reasons why ๐ง assignment of a URI doesn't require a request to a central naming authority, so WebDAV property names and XML elements can be quickly defined by any WebDAV user or application. URIs also provide a unique address space, which means the distributed users of WebDAV won't run into collisions among the property names and XML elements they create. main character energy for URIs, fr ๐
this specification defines a distinguished set of property names and XML elements that are understood by all WebDAV applications. The property names and XML elements in this specification are all derived from the base URI DAV: by adding a suffix to it. for example, DAV:creationdate is the "creationdate" property. โญ
this specification also defines a URI scheme for the encoding of lock tokens, the opaquelocktoken URI scheme described in section 6.4. ๐
to ensure correct interoperation based on this specification, IANA must reserve the URI namespaces starting with DAV: and with opaquelocktoken: for use by this specification, its revisions, and related WebDAV specifications. ๐ซถ reserved, sealed, done ๐
19 Intellectual Property โ๏ธ
the following notice is copied from RFC 2026 [RFC2026], section 10.4, and describes the position of the IETF concerning intellectual property claims made against this document. ๐
the IETF takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use other technology described in this document, or the extent to which any license under such rights might or might not be available. neither does it represent that it has made any effort to identify any such rights. information on the IETF's procedures with respect to rights in standards-track and standards-related documentation can be found in BCP-11. copies of claims of rights made available for publication, and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the IETF Secretariat. ๐งพ
the IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to practice this standard. please address the information to the IETF Executive Director. ๐ฎ
20 Acknowledgements ๐
a specification like this thrives on piercing critical review, and withers from apathetic neglect ๐ฅน the authors gratefully acknowledge the contributions of the following people, whose insights were so valuable at every stage of the work. the list goes like this ๐
Terry Allen, Harald Alvestrand, Jim Amsden, Becky Anderson, Alan Babich, Sanford Barr, Dylan Barrell, Bernard Chester, Tim Berners-Lee, Dan Connolly, Jim Cunningham, Ron Daniel, Jr., Jim Davis, Keith Dawson, Mark Day, Brian Deen, Martin Duerst, David Durand, Lee Farrell, Chuck Fay, Wesley Felter, Roy Fielding, Mark Fisher, Alan Freier, George Florentine, Jim Gettys, Phill Hallam-Baker, Dennis Hamilton, Steve Henning, Mead Himelstein, Alex Hopmann, Andre van der Hoek, Ben Laurie, Paul Leach, Ora Lassila, Karen MacArthur, Steven Martin, Larry Masinter, Michael Mealling, Keith Moore, Thomas Narten, Henrik Nielsen, Kenji Ota, Bob Parker, Glenn Peterson, Jon Radoff, Saveen Reddy, Henry Sanders, Christopher Seiwald, Judith Slein, Mike Spreitzer, Einar Stefferud, Greg Stein, Ralph Swick, Kenji Takahashi, Richard N. Taylor, Robert Thau, John Turner, Sankar Virdhagriswaran, Fabio Vitali, Gregory Woodhouse, and Lauren Wood.
two from this list deserve special mention ๐ the contributions by Larry Masinter have been invaluable, both in helping form the working group and in patiently coaching the authors along the way. he set standards the rest of the team has been working hard to meet ๐ซก the contributions of Judith Slein in clarifying the requirements, and in patiently reviewing draft after draft, both improved this specification and expanded everyone's minds on document management. ๐ง โจ
we would also like to thank John Turner for developing the XML DTD. ๐
21 References ๐
21.1 Normative References
[RFC1766] Alvestrand, H., "Tags for the Identification of
Languages", RFC 1766, March 1995.
[RFC2277] Alvestrand, H., "IETF Policy on Character Sets and
Languages", BCP 18, RFC 2277, January 1998.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119, March 1997.
[RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter,
"Uniform Resource Identifiers (URI): Generic Syntax",
RFC 2396, August 1998.
[REC-XML] T. Bray, J. Paoli, C. M. Sperberg-McQueen,
"Extensible Markup Language (XML)." World Wide Web
Consortium Recommendation REC-xml-19980210.
http://www.w3.org/TR/1998/REC-xml-19980210.
[REC-XML-NAMES] T. Bray, D. Hollander, A. Layman, "Namespaces in
XML". World Wide Web Consortium Recommendation REC-
xml-names-19990114. http://www.w3.org/TR/1999/REC-
xml-names-19990114/
[RFC2069] Franks, J., Hallam-Baker, P., Hostetler, J., Leach,
P, Luotonen, A., Sink, E. and L. Stewart, "An
Extension to HTTP : Digest Access Authentication",
RFC 2069, January 1997.
[RFC2068] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and
T. Berners-Lee, "Hypertext Transfer Protocol --
HTTP/1.1", RFC 2068, January 1997.
[ISO-639] ISO (International Organization for Standardization).
ISO 639:1988. "Code for the representation of names
of languages."
[ISO-8601] ISO (International Organization for Standardization).
ISO 8601:1988. "Data elements and interchange formats
- Information interchange - Representation of dates
and times."
[ISO-11578] ISO (International Organization for Standardization).
ISO/IEC 11578:1996. "Information technology - Open
Systems Interconnection - Remote Procedure Call
(RPC)"
[RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997.
[UTF-8] Yergeau, F., "UTF-8, a transformation format of
Unicode and ISO 10646", RFC 2279, January 1998.
21.2 Informational References
[RFC2026] Bradner, S., "The Internet Standards Process - Revision
3", BCP 9, RFC 2026, October 1996.
[RFC1807] Lasher, R. and D. Cohen, "A Format for Bibliographic
Records", RFC 1807, June 1995.
[WF] C. Lagoze, "The Warwick Framework: A Container
Architecture for Diverse Sets of Metadata", D-Lib
Magazine, July/August 1996.
http://www.dlib.org/dlib/july96/lagoze/07lagoze.html
[USMARC] Network Development and MARC Standards, Office, ed. 1994.
"USMARC Format for Bibliographic Data", 1994. Washington,
DC: Cataloging Distribution Service, Library of Congress.
[REC-PICS] J. Miller, T. Krauskopf, P. Resnick, W. Treese, "PICS
Label Distribution Label Syntax and Communication
Protocols" Version 1.1, World Wide Web Consortium
Recommendation REC-PICS-labels-961031.
http://www.w3.org/pub/WWW/TR/REC-PICS-labels-961031.html.
[RFC2291] Slein, J., Vitali, F., Whitehead, E. and D. Durand,
"Requirements for Distributed Authoring and Versioning
Protocol for the World Wide Web", RFC 2291, February 1998.
[RFC2413] Weibel, S., Kunze, J., Lagoze, C. and M. Wolf, "Dublin
Core Metadata for Resource Discovery", RFC 2413, September
1998.
[RFC2376] Whitehead, E. and M. Murata, "XML Media Types", RFC 2376,
July 1998.
22. Authors' Addresses ๐
Here's where you can find the authors. Their names, companies, and emails are all exactly as written ๐ซถ
Y. Y. Goland
Microsoft Corporation
One Microsoft Way
Redmond, WA 98052-6399
EMail: yarong@microsoft.com
E. J. Whitehead, Jr.
Dept. Of Information and Computer Science
University of California, Irvine
Irvine, CA 92697-3425
EMail: ejw@ics.uci.edu
A. Faizi
Netscape
685 East Middlefield Road
Mountain View, CA 94043
EMail: asad@netscape.com
S. R. Carter
Novell
1555 N. Technology Way
M/S ORM F111
Orem, UT 84097-2399
EMail: srcarter@novell.com
D. Jensen
Novell
1555 N. Technology Way
M/S ORM F111
Orem, UT 84097-2399
EMail: dcjensen@novell.com
23 Appendices ๐
Okay, the appendices are where the nitty-gritty lives, so grab a snack ๐
23.1 Appendix 1 - WebDAV Document Type Definition ๐
This part gives you a document type definition โจ It follows the rules in [REC-XML] and describes the XML elements used in the protocol stream and in the values of properties. It basically gathers up all the element definitions from sections 12 and 13 into one neat spot ๐
<!DOCTYPE webdav-1.0 [
<!--============ XML Elements from Section 12 ==================-->
<!ELEMENT activelock (lockscope, locktype, depth, owner?, timeout?,
locktoken?) >
<!ELEMENT lockentry (lockscope, locktype) >
<!ELEMENT lockinfo (lockscope, locktype, owner?) >
<!ELEMENT locktype (write) >
<!ELEMENT write EMPTY >
<!ELEMENT lockscope (exclusive | shared) >
<!ELEMENT exclusive EMPTY >
<!ELEMENT shared EMPTY >
<!ELEMENT depth (#PCDATA) >
<!ELEMENT owner ANY >
<!ELEMENT timeout (#PCDATA) >
<!ELEMENT locktoken (href+) >
<!ELEMENT href (#PCDATA) >
<!ELEMENT link (src+, dst+) >
<!ELEMENT dst (#PCDATA) >
<!ELEMENT src (#PCDATA) >
<!ELEMENT multistatus (response+, responsedescription?) >
<!ELEMENT response (href, ((href*, status)|(propstat+)),
responsedescription?) >
<!ELEMENT status (#PCDATA) >
<!ELEMENT propstat (prop, status, responsedescription?) >
<!ELEMENT responsedescription (#PCDATA) >
<!ELEMENT prop ANY >
<!ELEMENT propertybehavior (omit | keepalive) >
<!ELEMENT omit EMPTY >
<!ELEMENT keepalive (#PCDATA | href+) >
<!ELEMENT propertyupdate (remove | set)+ >
<!ELEMENT remove (prop) >
<!ELEMENT set (prop) >
<!ELEMENT propfind (allprop | propname | prop) >
<!ELEMENT allprop EMPTY >
<!ELEMENT propname EMPTY >
<!ELEMENT collection EMPTY >
<!--=========== Property Elements from Section 13 ===============-->
<!ELEMENT creationdate (#PCDATA) >
<!ELEMENT displayname (#PCDATA) >
<!ELEMENT getcontentlanguage (#PCDATA) >
<!ELEMENT getcontentlength (#PCDATA) >
<!ELEMENT getcontenttype (#PCDATA) >
<!ELEMENT getetag (#PCDATA) >
<!ELEMENT getlastmodified (#PCDATA) >
<!ELEMENT lockdiscovery (activelock)* >
<!ELEMENT resourcetype ANY >
<!ELEMENT source (link)* >
<!ELEMENT supportedlock (lockentry)* >
]>
23.2 Appendix 2 - ISO 8601 Date and Time Profile ๐๏ธ
The creationdate property uses the ISO 8601 date format [ISO-8601] โจ This section sets out a profile of that format for use with this spec. The profile is quoted from an Internet-Draft by Chris Newman, and it's mentioned here so his work gets proper credit ๐
date-time = full-date "T" full-time
full-date = date-fullyear "-" date-month "-" date-mday
full-time = partial-time time-offset
date-fullyear = 4DIGIT
date-month = 2DIGIT ; 01-12
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
month/year
time-hour = 2DIGIT ; 00-23
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-59, 00-60 based on leap second rules
time-secfrac = "." 1*DIGIT
time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset
partial-time = time-hour ":" time-minute ":" time-second
[time-secfrac]
Numeric offsets are calculated as local time minus UTC (Coordinated Universal Time) ๐ So to find the UTC equivalent, you subtract the offset from the local time. For example, 18:50:00-04:00 is the same time as 22:58:00Z ๐ฆ
If the time in UTC is known but the offset to local time isn't, you can show that with an offset of "-00:00". This is different from an offset of "Z", which implies that UTC is the preferred reference point for the specified time ๐ง
23.3 Appendix 3 - Notes on Processing XML Elements ๐งฉ
23.3.1 Notes on Empty XML Elements
XML has two ways to say an element has no content ๐ธ The first is to write it as <A></A>. The second is to write it as <A/>. Both are semantically identical, so they mean the same thing โจ
Using the <A></A> form is a violation of the XML specification if the associated DTD declares the element to be EMPTY (for example, <!ELEMENT A EMPTY>) ๐ If that declaration is there, the empty element format <A/> must be used. If the element isn't declared to be EMPTY, then either <A></A> or <A/> may be used for empty elements ๐
23.3.2 Notes on Illegal XML Processing
XML is a super flexible format, which makes it really easy to send data that looks legal but actually isn't ๐ The philosophy of "Be flexible in what you accept and strict in what you send" still applies, but it must not be applied inappropriately. XML is extremely flexible about white space, element ordering, inserting new elements, and so on. That flexibility doesn't stretch to cover extensions, especially not when it comes to the meaning of elements ๐
There is no kindness in accepting illegal combinations of XML elements. At best it causes an unwanted result, and at worst it can cause real damage ๐
Accepting illegal XML is not being nice. It's how things quietly break โ ๏ธ
23.3.2.1 Example - XML Syntax Error ๐ โโ๏ธ
The following request body for a PROPFIND method is illegal ๐ซ
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
<D:propname/>
</D:propfind>
The propfind element only allows for the allprop or the propname element, not both. So the above is an error and must be responded to with a 400 (Bad Request) ๐ค
Now imagine a server that wanted to be "kind" and decided to pick the allprop element as the true element and respond to it. A client running over a bandwidth-limited line who meant to run a propname would be in for a big surprise if the server treated the command as an allprop ๐ญ
And if a server were lenient and decided to reply to this request anyway, the results would vary randomly from server to server. Some servers would execute the allprop directive, and others would execute the propname directive. That reduces interoperability rather than increasing it ๐
23.3.2.2 Example - Unknown XML Element ๐
The previous example was illegal because it had two elements that were explicitly banned from appearing together in the propfind element. But XML is an extensible language, so you can imagine new elements being defined for use with propfind โจ Below is the request body of a PROPFIND. Like the previous example, it must be rejected with a 400 (Bad Request) by a server that doesn't understand the expired-props element ๐ซ
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:"
xmlns:E="http://www.foo.bar/standards/props/">
<E:expired-props/>
</D:propfind>
To understand why a 400 (Bad Request) comes back, let's look at the request body the way a server unfamiliar with expired-props sees it ๐ต๏ธโโ๏ธ
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:"
xmlns:E="http://www.foo.bar/standards/props/">
</D:propfind>
According to the WebDAV-specific XML processing rules in section 14, a server that doesn't understand the expired-props element must ignore it. So the server sees an empty propfind, and by the definition of the propfind element, that's illegal ๐ต
Please note that if the extension had been additive, it wouldn't necessarily have resulted in a 400 (Bad Request) ๐ For example, imagine the following request body for a PROPFIND:
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:"
xmlns:E="http://www.foo.bar/standards/props/">
<D:propname/>
<E:leave-out>*boss*</E:leave-out>
</D:propfind>
The previous example contains a made-up element called leave-out ๐ฆ Its purpose is to stop any property whose name matches the submitted pattern from being returned. If that example were sent to a server that doesn't know leave-out, the only result is that leave-out gets ignored and a propname gets executed ๐
23.4 Appendix 4 -- XML Namespaces for WebDAV ๐
23.4.1 Introduction
All DAV compliant systems MUST support the XML namespace extensions as specified in [REC-XML-NAMES] ๐
23.4.2 Meaning of Qualified Names
[Note to the reader: This section does not appear in [REC-XML-NAMES], but is necessary to avoid ambiguity for WebDAV XML processors.] ๐
WebDAV compliant XML processors MUST interpret a qualified name as a URI constructed by appending the LocalPart to the namespace name URI โจ Here's an example:
<del:glider xmlns:del="http://www.del.jensen.org/">
<del:glidername>
Johnny Updraft
</del:glidername>
<del:glideraccidents/>
</del:glider>
In this example, the qualified element name "del:glider" is interpreted as the URL "http://www.del.jensen.org/glider" ๐ช
<bar:glider xmlns:del="http://www.del.jensen.org/">
<bar:glidername>
Johnny Updraft
</bar:glidername>
<bar:glideraccidents/>
</bar:glider>
This one looks different from the previous example, but it means exactly the same thing ๐ Each instance of the namespace name "bar" is replaced with "http://www.del.jensen.org/" and then appended to the local name for each element tag. So the resulting tag names match the previous example exactly ๐ซถ
<foo:r xmlns:foo="http://www.del.jensen.org/glide">
<foo:rname>
Johnny Updraft
</foo:rname>
<foo:raccidents/>
</foo:r>
This example is semantically identical to the two before it. Each instance of the namespace name "foo" is replaced with "http://www.del.jensen.org/glide", which is then appended to the local name for each element tag. The resulting tag names are identical to the ones in the previous examples ๐ธ
24. Full Copyright Statement ๐
Copyright (C) The Internet Society (1999). All Rights Reserved. ๐
okay so this document and translations of it can be copied and furnished to others ๐ and derivative works that comment on or explain it, or help with implementing it, can be prepared, copied, published and distributed ๐, in whole or in part, without restriction of any kind. the one condition is that the above copyright notice and this paragraph are included on all of those copies and derivative works ๐ซถ
BUT (and this is a big but ๐ โโ๏ธ) this document itself may not be modified in any way. so no removing the copyright notice, and no removing references to the Internet Society or other Internet organizations. the exceptions are: when it's needed for developing Internet standards, in which case the procedures for copyrights defined in the Internet Standards process must be followed ๐, or when it's being translated into languages other than English ๐
the limited permissions above are perpetual ๐ and they will not be revoked by the Internet Society or its successors or assigns. forever and ever, bestie โจ
๐ the disclaimer, which is not something to skip:
This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. ๐ฆ
and that's the whole document!! ๐ง you made it through all 18 parts, bestie. we are SO done ๐ญ๐
๐ฆ where this page comes from
- ietf: rfc2518 1999-02
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms