Author: ts Date: Fri Feb 29 12:42:03 2008 New Revision: 7465 Log: - Finished design draft for If header implementation with a lock plugin. # Note the warning and note hints in there.
Modified: trunk/Webdav/design/design-1.1.txt Modified: trunk/Webdav/design/design-1.1.txt ============================================================================== --- trunk/Webdav/design/design-1.1.txt [iso-8859-1] (original) +++ trunk/Webdav/design/design-1.1.txt [iso-8859-1] Fri Feb 29 12:42:03 2008 @@ -195,8 +195,8 @@ { public function __construct( array $lockTokens = array(), - array $eTags = array(), - bool $negated = false + array $eTags = array(), + bool $negated = false ); property-read array $lockTokens; @@ -209,8 +209,160 @@ defined to be negated ($negated === true). The combination represented by such an object is a logical AND combination. -Usage examples --------------- +Code examples +------------- + +Some small code examples to illustrate the above class design will be showen +here. + +:: + + 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"]) + +This example shows a tagged list in the If header, which will be parsed into an +instance of ezcWebdavIfHeaderTaggedList will be created from it in the +`Transport layer`_. The access to this object in the backend or the lock plugin +will look as follows: :: + + $res1items = $ifHeader['/resource1']; + + $res2items = $ifHeader['/resource2']; + + $randomItems = $ifHeader['/random']; + +The $res1items variable will contain an array reflecting the conditions +specified for http://www.foo.bar/resource1. The $res2items variable will +contain an empty array since no conditions were defined for this resource. +While the $randomItems variable should normally not be requested (since the +resource is not affected) it would contain the corresponding list items for the +http://www.bar.bar/random resource. + +In contrast, the following reqeuest would return an instance of +ezcWebdavIfHeaderNoTagList for the contained If header: :: + + COPY /resource1 HTTP/1.1 + Host: www.foo.bar + Destination: http://www.foo.bar/resource2 + If: (<locktoken:a-write-lock-token> [W/"A weak ETag"]) (["strong ETag"]) + (["another strong ETag"]) + +Taking the same accesses to the corresponding $ifHeader variable as shown above +will result in all 3 variables containing the same values: All 3 list items +will be contained, since the If header does not use tagging to specify which +resources are affected by the conditions. + +Plugin +====== + +If the lock plugin is active, it needs to hook into every affected request (see +`Affected base methods`_) and check the If header conditions. The check does +not only affect the checking of locktoken conditions, but also the check of +etag validation, because both condition types are combineable. + +The procedure (in pseudo code) is as follows: :: + + lock backend; + foreach ( <range of affected resources> as <basse resource> ) + { + create propfind request for <base resource>; + set request properties to <getetag> and <lockdiscovery>; + set depth according to incoming request; + send request to backend; + foreach ( <resources in response> as <resource> ) + { + if ( <resource> does not conform to If header ) + { + return <precondition failed response>; + } + } + } + discard If header; + unlock backend; + +The If header needs to be discarded after correct validation of all entity +tag/lock token conditions. This avoids that the backend checks for the entity +tag conditions a second time. + +.. Note:: + The checking of both (lock token and entity tag) conditions is necessary in + this case, although it results in a small part of code-duplication. + +.. Warning:: + The behaviour showen here does not conform to 100% with the WebDAV RFC, + which states that the "If header is intended to have similar functionality + to the If- Match header defined in section 14.25 of [RFC2068]". If this is + taken literally, the lock plugin would need to check if a request would fail + without the If header before checking the If header itself. This would + result in unmanageable overhead and code duplication. + +.. Warning:: + Actually the backend would have need to be locked completly, in case an If + header occured and was succesfully checked by the lock plugin. This complete + lock must be held until the corresponding response was created by the + backend. Else there is a race condition in the time frame after the lock + checking until the backend starts processing. This can lead to extremly + strange results in high-load environments. + +Backend layer +============= + +The backend receives the parsed If header as described in the `Transport +layer`_ section through the $headers property of the request object. We cannot +enforce the honoring of the If header, so back ends do not neccessarily honor +them. However, it should be properly documented that this header exists and is +must be honored if shipped with a request. + +If a backend takes care for the header, it may only use the $eTag and $negated +properties and must ignore the $lockTokens property. The latter one is used +exclusively in the lock plugin. In case the lock plugin is active, the back end +should never receive any If header. The If header will then be processed +exclusively by the lock plugin. + +If the backend pays attention to the If header, it must honor it for every +request and every resource path that is accessed during execution of the +request. To include the checking of the If header into request processing the +following algorith must be used (pseudo-code): :: + + lock backend; + if ( preconditions for request without If header are not fulfilled ) + { + return <corresponding error response>; + } + foreach ( <affected resources> as <resource> ) + { + if ( If header not fulfilled for <resource> ) + { + return <precondition failed error response>; + } + } + process request; + unlock backend; + return <corresponding response>; + + +The backend does not need to take care of If headers, if the lock plugin is +installed. In this case, the lock plugin will take over the complete check for +the If headers conditions and remove the header from the request object +afterwards. + +Infrastructure +============== + +The ezcWebdavRequest class does currently not support the removal of headers as +required by the lock plugin. A method :: + + public removeHeader( $headerName ) + +needs therefore to be added. This method also needs to invalidate the headers +internally in the class, so that a manual revalidation using validateHeaders() +needs to occur. Since the lock plugin will remove the If header before the +request object passes ezcWebdavServer, the headers are validated anyways there. + Entity tag support ^^^^^^^^^^^^^^^^^^ -- svn-components mailing list svn-components@lists.ez.no http://lists.ez.no/mailman/listinfo/svn-components