This section covers retrieval of properties or property names through the PROPFIND method defined in WebDAV. 7.2.1 PROPFIND RequestWhen querying metadata, clients need to be able to specify which resources to query and which properties to return. The first is achieved with the target URI and the Depth header. The second is achieved by listing the properties desired in an XML request body. The body is in a simple format (see Listing 7-3). Listing 7-3 PROPFIND request for getlastmodified property.PROPFIND /hr/ergonomics/ HTTP/1.1 Host: www.example.com 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:prop> <D:getlastmodified/> </D:prop> </D:propfind> A PROPFIND request body always has a propfind element as the top-level document element. Within the propfind element, a number of elements can appear, depending on the purpose of the request. If the client is asking for a specific list of properties, then the prop element appears inside the propfind element. Finally, the prop element contains any number of empty property name elements in any order. 7.2.2 PROPFIND ResponseThe PROPFIND response is another Multi-Status response, just like those used in response to depth infinity MOVE, COPY, or DELETE requests (Section 5.5.1). The multistatus element is the root of the response body, followed by one response element for each resource listed. These response elements can be in any order because PROPFIND has no way of specifying order. The client must sort the results in order to be able to list the contents of the collection in a reliable order. The PROPFIND response extends the Multi-Status response. Recall that for MOVE, COPY, and DELETE of collections, the Multi-Status response can include one status element inside up to N response elements, where N is the number of resources affected. PROPFIND must contain N response elements, and each of those contains M property status elements, where M is the number of properties requested. Therefore, a PROPFIND Multi-Status response can contain much more information, even though it shares the same response framework. Inside the response element for each resource, the server must include the resource's URL, any requested property values that it can return, or error codes for the property values it can't return. When the property value is included, it's formatted as shown in Figure 7-1, with the property value inside an XML element that has the same name and namespace as the property. Listing 7-4 is a complete PROPFIND response. Figure 7-1. Diagram for PROPFIND response in Listing 7-4: Response elements are unsorted.Each response element in Listing 7-4 has at least one propstat element to hold the property identification, status code, and possibly value. Each propstat element has one status element, plus a number of property names that belong with that status element. In Listing 7-4, only the HTTP/1.1 200 OK status code is used, because there were no errors. Listing 7-4 PROPFIND response with getlastmodified property.HTTP/1.1 207 Multi-Status Date: Sun, 29 Jul 2001 15:24:17 GMT 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.example.com/hr/ergonomics/posture.doc </D:href> <D:propstat> <D:prop> <D:getlastmodified>Thu, 16 Aug 2001 23:24:33 GMT</D:getlastmodified> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response> <D:href>http://www.example.com/hr/ergonomics/chairs.doc </D:href> <D:propstat> <D:prop> <D:getlastmodified>Sun, 26 Aug 2001 00:08:21 GMT</D:getlastmodified> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response> <D:href>http://www.example.com/hr/ergonomics/</D:href> <D:propstat> <D:prop> <D:getlastmodified>Sun, 26 Aug 2001 00:06:01 GMT</D:getlastmodified> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response> </D:multistatus> 7.2.3 Reporting Errors in PROPFIND ResponsesListing 7-5 shows a possible PROPFIND error. In the example, a client asks for a property on a resource that doesn't normally support that property. The getetag property does not exist on collections, because collections do not have ETags. The client also requests getlastmodified, which does exist on a collection. This shows how the failure and the success are reported in the same response. Listing 7-5 PROPFIND request and response showing errors and successes.Request: PROPFIND /hr/ergonomics/ HTTP/1.1 Host: www.example.com Depth: 0 Content-type: text/xml; charset="utf-8" Content-Length: xxxx <?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:prop> <D:getetag/> <D:getlastmodified/> </D:prop> </D:propfind> Response: HTTP/1.1 207 Multi-Status Date: Sun, 29 Jul 2001 15:24:17 GMT Content-Type: text/xml; charset="utf-8" Content-Length: xxxx <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> <href>http://www.example.com/hr/ergonomics/</href> <propstat> <prop> <getlastmodified>Sun, 26 Aug 2001 00:06:01 GMT</getlastmodified> </prop> <status>HTTP/1.1 200 OK</status> </propstat> <propstat> <prop><getetag/></prop> <status>HTTP/1.1 404 Not Found</status> </propstat> </response> </multistatus> The getlastmodified property is returned successfully, but getetag is not. The name of the errored property is returned associated with a status of 404 Not Found. Other status codes are also possible in other situations: 403 Forbidden, 401 Not Authorized, and so forth. The response element must contain a separate propstat element for every different status code. In this case, only two status codes are used, so only two propstat elements appear. 7.2.4 Finding the Names of PropertiesWebDAV also defines a way for the client to find the names of all properties that exist on a resource. This is great for the server because it may be significantly faster to send property names than to calculate some values (as for lockdiscovery). It can also help the client because not only is the response shorter (thus faster), it also is the only way that is guaranteed to include all the properties that exist on the resource. To find out what properties exist on a resource, the client should ask for the property names only, using the propname element inside a PROPFIND request body (see Listing 7-6). This request means "tell me the names of properties that exist on the resource." The propname element is always empty. Listing 7-6 PROPFIND to discover what properties exist.PROPFIND /hr/ergonomics/ HTTP/1.1 Host: www.example.com Depth: 0 Content-Type: text/xml; charset="utf-8" Content-Length: xxxx <?xml version="1.0" encoding="utf-8" ?> <propfind xmlns="DAV:"> <propname/> </propfind> The response is a slight variation on the regular PROPFIND response format. The property elements do not contain the values of the properties (see Listing 7-7). Listing 7-7 PROPFIND response showing what properties exist.HTTP/1.1 207 Multi-Status Date: Sun, 29 Jul 2001 15:24:17 GMT Content-Type: text/xml; charset="utf-8" Content-Length: xxxx <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> <href>http://www.example.com/hr/ergonomics/</href> <propstat> <prop xmlns:ns1="http://www.xythos.com/namespaces/StorageServer"> <creationdate/><displayname/><getlastmodified/> <lockdiscovery/><resourcetype/><supportedlock/> <ns1:quota><ns1:size> </prop> <status>HTTP/1.1 200 OK</status> </propstat> </response> </multistatus> This response shows that all the WebDAV properties that might be expected on a collection do exist on this collection, along with two custom properties (quota and size). The definitions and meanings of the multistatus, response, propstat, prop, and status elements are unchanged. 7.2.5 AllProp Is Not What It Seems
These servers are all theoretically noncompliant, but when noncompliance is this widespread and intentional, the real problem is with the standard. The versioning standard extending WebDAV already specifically requires that live versioning properties must not be returned in response to allprop requests. The WebDAV standard may be revised so that reasonable server implementations will be compliant.
However, a depth 0 or depth 1 allprop request may still be appropriate and useful. The client may want to retrieve the values of the dead properties (dead properties were defined in Section 4.4.3), along with the properties defined in RFC2518. As long as this request targets a reasonably small number of resources, it can be used responsibly (see Listing 7-8). Listing 7-8 PROPFIND request for all RFC2518 properties and dead properties.PROPFIND /hr/ergonomics/posture.doc HTTP/1.1 Host: www.example.com Depth: 0 <?xml version="1.0" encoding="utf-8" ?> <D:propfind xmlns:D="DAV:"> <D:allprop/> </D:propfind> As usual, the propfind is the top-level element in a PROPFIND request body. Instead of propname or prop with a list of property names, it now contains the allprop element, which is empty. There's also a short form of this request. If a PROPFIND request does not contain a body, the server interprets it as an allprop request (see Listing 7-9). Listing 7-9 PROPFIND request with no body.PROPFIND /hr/ergonomics/posture.doc HTTP/1.1 Host: www.example.com Depth: 0 In general, however, the client should only ask for the properties it actually plans to use. If the client needs to discover the names of unknown properties, use propname instead of allprop. 7.2.6 Large Response BodiesSome PROPFIND responses, even when the depth of the request is only 1, can be quite large. Collections are not limited in the number of resources they can contain, and some newer WebDAV features may lead to very large collections. The WebDAV ACLs proposal uses a collection of "principal" resources to allow client software to list the users that may be granted access to a file. The ACL proposal also defines a couple of very large properties.
Large responses pose a scaling problem to servers. Normally, the response headers show the length of the entire response. Since the headers must be sent before the body, the natural way to achieve this is to buffer the response in memory as it's created. The server finds the length of the buffered body before sending the Content-Length header and then sends the body. This can use large amounts of system resources when multiple large responses are being handled simultaneously. The brute-force approach to this problem is to omit the Content-Length header and send the body as it is being generated. This requires the connection to be closed when the body is finished, so that the client will know what the end of the response is. This approach is not recommended in HTTP/1.1 communication. However, this brute approach is the only approach available for HTTP/1.0 compliant clients [Krishnamurthy99]. At least with a PROPFIND response, it is always possible to detect a truncated message (if the connection closes accidentally) the XML body must end with </multistatus>. A more sophisticated approach is to use chunked transfer-encoding (Chapter 3, Section 3.2.8). This encoding is defined for HTTP/1.1 specifically in order to deal with long bodies of unknown length. Clients must be able to handle both chunked transfer encoding and responses with unknown content length where the end of the body is signaled by closing the connection. |