The LOCK request is used in WebDAV both to get new locks and to refresh existing locks. 8.2.1 Creating a LockThe server needs a number of pieces of information to create a lock. Listing 8-1 is an example of a LOCK request that locks a single file for exclusive use, followed by a run-through of each piece of information that appears in the request. Listing 8-1 LOCK request.LOCK /hr/ergonomics/posture.doc HTTP/1.1 Host: www.example.com Timeout: Infinite If-Match: * Content-Type: text/xml; charset="utf-8" Content-Length: xxxx <?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 xmlns:x="http://www.customapp.com/ns/"> <x:lock-user>alice@example.com</x:lock-user> <x:created-by>Text Editor v1.2.5</x:created-by> </D:owner> </D:lockinfo> Table 8-1 takes each relevant piece of information in the request the request URI, the new header, and the request body to show what each piece means.
Assuming the LOCK request is successful, most of the same information (plus the lock token) is returned in the response, as shown in Listing 8-2. The lock information is also preserved in the lockdiscovery property as long as the lock exists. The format of the response body is the same as the format of the lockdiscovery property, which we cover in more detail in Section 8.5.1. The client should pay particular attention to the lock token and the timeout, in case the server chooses a different timeout value. Since there are no restrictions on how the server chooses a timeout value, the value could be shorter or longer than the timeout requested by the client. Listing 8-2 Response to LOCK successfully locked the resource.HTTP/1.1 200 OK Date: Sun, 29 Jul 2001 15:24:17 GMT Lock-Token:opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6 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>0</D:depth> <D:owner xmlns:a="http://www.customapp.com/ns/"> <a:lock-user>alice@example.com</a:lock-user> <a:created-by>Text Editor v1.2.5</a:created-by> </D:owner> <D:timeout>Second-604800</D:timeout> <D:locktoken> <D:href>opaquelocktoken:e71d4fae-5dec -22d6-fea5-00a0c91e6</D:href> </D:locktoken> </D:activelock> </D:lockdiscovery> </D:prop>
Note that the lock token is shown both in the body and in the Lock-Token header. This is required by RFC2518 in response to the creation of a new lock. Clients should pay attention to the LOCK response return code. The return code is 201 Created, not 200 OK, if a new resource was created. The client may have expected there to be an existing resource to lock, but there's a chance the existing resource was just deleted by another user. Clients should use the If-Match or If-None-Match header on a LOCK request to make sure that the correct resource is being locked. The request in Listing 8-1 shows how to use the If-Match header to assert that the resource must exist; otherwise, the server should fail the request rather than create a new resource. 8.2.2 Locking a CollectionWhen the Request-URI identifies a collection, the LOCK request may include a Depth header. If the Depth header is omitted, the server must choose a default depth of infinity. The values 0 and infinity are supported when locking collections, but a depth of 1 is never supported with a LOCK request (thus, servers should respond with 400 Bad Request to a LOCK request with a depth of 1). Depth InfinityA lock depth infinity on a collection is easy to interpret: Lock the collection and every descendant of the collection, as illustrated in Figure 8-1. No write operation, whether PUT, PROPPATCH, COPY, MOVE, or DELETE, can be applied to the collection or any descendant of the collection without providing the correct lock token. It also means that if this is an exclusive lock, then none of the descendants of the collection can be locked with a different lock until the infinite-depth lock is removed. Figure 8-1. Depth infinity lock.Despite the apparent simplicity, there are some difficult issues to deal with when infinite-depth collection locks are used. These issues are more related to the If header syntax than to the application of the lock itself, so we'll discuss that in a bit (Section 8.4.3). In the meantime, it's enough to point out that some servers (including IIS 5.0) don't support this type of lock, and most clients don't use it. Authoring applications may never need infinite-depth locks, because typically the user opens files one at a time to edit them, and the application locks each file as it is opened. Multiple resources may be opened for simultaneous editing, but there's no need to lock the parent collection (which would prevent other users from creating new resources). File management clients may sometimes need to lock collections, but even for these clients, operations on many files at once are rare. When the user does want to operate on entire collections, it's often possible to use a single infinite-depth COPY or MOVE request, in which case a lock may not be required. Clients do not use collection locks much. Perhaps it's because IIS 5.0 doesn't support collection locks, and it's easier for clients to rely on features that are supported by all popular WebDAV servers. Perhaps clients do not use infinite-depth locks much because the If header is quite complicated to use with multiple resources (see Section 8.4.13). When a collection descendent is included in the scope of a depth infinity collection lock, even though the descendent is not directly locked, the value of its lockdiscovery property must include all the lock information. Depth 0A depth 0 lock on a collection means that the collection's contents and metadata, but not the contents or metadata of its children or other descendents, are protected from changes. The contents of a collection are usually interpreted as the list of children, so if the list changes, that's governed by the lock. Changes that take place that don't affect the list of children are allowed, however. Figure 8-2 shows how the lock encompasses changes to the collection itself, its membership list, and its properties but not the content of its descendents. Figure 8-2. Depth 0 collection lock.Here are a few examples to illustrate this concept. If the collection /hr is locked with a depth 0 lock, some write operations are always affected, and some are affected only under certain circumstances. These requests are affected by a depth 0 lock on /hr:
These requests are not affected by the same depth 0 lock:
There are a couple of interesting use cases for the depth 0 collection lock. The most useful case is simply to change properties. If the repository supports access control, depth 0 collection locks would be quite useful so that the client can get the access control information, modify it, and resubmit the changed access control information to the server. Another use case is to be able to create a resource without risk of overwriting an existing one (a problem first discussed in Section 5.4.3). When a resource is locked depth 0, only the holder of the lock can create new resources in the collection, but the lock doesn't prevent other users from modifying the body or properties of existing child resources. To ensure that a file creation is not overwriting an existing resource, the client can issue a LOCK (depth 0) on the collection, a PROPFIND on the collection to see if the resource exists, and then the PUT or MKCOL request to create the new resource. Of course, an infinite-depth lock would serve the same purpose, but that would be overkill, unnecessarily preventing other users' actions. 8.2.3 Creating Lock-Null ResourcesIf a LOCK request is sent to an unmapped URL, rather than return 404 Not Found, the server must create a lock-null resource (and return a status of 201 Created).
Lock-null resources were invented to help prevent two clients sending a PUT request for a new resource at nearly the same time. The client with the second PUT will unintentionally overwrite the content first put there. It's not sufficient to just check to see if the resource already exists, because with the latency of requests over the Internet, there's no guarantee that the resource will be in the same state when the actual PUT request is made. A lock-null resource behaves in the following manner:
After the lock-null resource is created, the next step is usually for the client to convert the lock-null resource into a regular resource or collection, using the lock token, of course. Now the resource is no longer a lock-null resource, so it behaves as a regular resource or collection, and property changes can be made. When all the write operations are complete, the client will probably unlock the resource.
8.2.4 Refreshing a LockAnother use of the LOCK method is to refresh an existing lock on a resource (see Listing 8-3). An existing lock can be renewed or refreshed any time before it expires. Listing 8-3 LOCK request to refresh a lock.LOCK /hr/ergonomics/posture.doc HTTP/1.1 Host: www.example.com Timeout: Second-300 If: (<opaquelocktoken:e71d4fae-5dec-22d6-fea5-00a0c91e6>) The Timeout header is optional on a lock refresh request, but the If header is required. The syntax and meaning of the Timeout header are unchanged. The If header is required in order to supply the correct lock token, because there may be more than one shared lock on a given resource. Although the If header syntax has not been described yet, there will be a lot to say about it shortly (see Section 8.4.2). 8.2.5 Lock TimeoutThe server controls lock timeout. It has a great deal of flexibility:
Servers grant shorter lock timeouts than requested to keep unused locks to a minimum in a system where there are many authors collaborating or to reduce the system resources required to track and maintain locks. Many servers refuse to grant infinite length locks, but there's no reason that the client can't request those anyway. Typically, the server responds with the maximum lifetime it allows. It's a little less obvious why servers grant a longer lock timeout than the client requests, but this practice arises from real implementation experience. The MS Web Folders implementation Office 2000 uses requests lock timeouts as short as two minutes. That requires the client software to refresh the lock at least that often, as long as the user still has the document open for editing. A server receiving lock refresh requests every two minutes from thousands of clients may see a noticeable performance degradation from this practice. Thus, the server grants the client a longer lock timeout. Happily, Web Folders does not refresh every two minutes if the lock lifetime granted by the server is longer. Grace periods are also found in existing lock timeout implementations because Web Folders doesn't give itself much leeway when refreshing locks. See Section 8.6.2 for client lock refresh guidelines and an explanation of why the Web Folders practice causes many user errors. Although the server has final power to choose a timeout, the client should try to give an opinion if the client has useful extra information about what the user intends. When a user opens a document in Word and makes changes, Word automatically locks the file for a short time. That's reasonable, because Word will be editing the document only as long as the software is still active and connected to the network. In contrast, a client application that allows the user to "check out" or synchronize files for editing offline may choose to lock certain files for a longer period, say from 12 to 72 hours. In this case, the client application has some indication that the author wants to reserve the file and prevent changes from other users. The lock will then last even while the author's editing software is inactive or not connected to the network. 8.2.6 Use of the Lock Owner ElementWhen a user wants to modify a resource but a lock already exists, often the only recourse is to wait until the lock expires or is removed. However, if information about the lock owner is provided, it's possible the user may be able to ask the lock owner to remove the lock. Thus, the owner tag is included in the lockdiscovery property so that one human user can contact another. The value of the lock owner tag may be XML or a string. The client defines the value when the lock is created. The client should provide useful identification information about the user who created the lock. This could be an email address and a client software identification string, as shown in the examples here. It could also include a full name, a URL to a Web page, a Principal URL as defined by the Access control extensions to WebDAV, or some other construct related to user or client identity. Although it's not specified, the owner tag can contain an href tag if the information identifying the lock creator is formatted as a URI (this is shown by the examples in RFC2518, although it's not required). Clients and servers must be prepared to handle a regular string, one or more href tags, or any other XML construct.
Servers should not enforce any particular syntax in the owner value, or some clients will fail to interoperate. Some clients send nothing in this element. A server could use authentication information to replace a blank or missing owner value with some information identifying the user, but the server should not alter a nonblank owner value, or some clients will fail to interoperate. 8.2.7 Special Status Codes for LOCKIf the resource is already locked with an exclusive lock, the server returns 423 Locked. Moreover, if the resource is already locked with a shared lock and the client requests an exclusive lock, the server responds with a 423 Locked. Both 200 OK and 201 Created indicate that locks were created. The latter shows that a lock-null resource (or in the case of IIS 5.0, a locked empty resource) was created. Many server implementations can return a 401 Unauthorized or 403 Forbidden response if the user asking for the lock does not have permission to perform write methods on a resource. Although it might be useful for a client to be able to lock a resource while reading it, to make sure that the resource doesn't change during the read, most clients don't do this. |