Author: ts Date: Fri Feb 29 21:04:18 2008 New Revision: 7473 Log: - Changed structure of design document. - Rephrased some parts.
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 21:04:18 2008 @@ -1,4 +1,4 @@ -eZ component: Webdav, Design, 1.2 +eZ component: Webdav, Design, 1.1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Tobias Schlitt @@ -17,8 +17,8 @@ The general goal for this version is to support locking as described in RFC 2518. To achieve this, the if-header must be parsed and respected by the Webdav component. This currently is not the case. The if-header must also be used to -respect entity tags, which is not an integral part of the locking feature. However, -the support of entity tags is part of this design, too. +respect entity tags, which is not an integral part of the locking feature. +However, the support of entity tags is part of this design, too. The following issues are covered in this design: @@ -26,16 +26,295 @@ (#12583). - Lock support (#12286). +For locking, a plugin based approach has been favored while desiging and +creating the Webdav component version 1.0. However, it turned out that the +realization of lock support through a plugin is not as easy as it seemed to be. +Therefore this document describes 2 different design approaches for lock +related functionality: A plugin based one and an integrated one. + +The document is devided into 3 parts. The first part deals with the realization +of functionality that is execlusively meant to support entity tags. The second +part describes features that are exclusively used to support locking features. +Since WebDAV mixes entity tags (originally HTTP/1.1) and locking in some +places, the third section describes the design for these common concerns. + +Entity tag support +^^^^^^^^^^^^^^^^^^ + +This section describes the support of entity tags in the Webdav component, including +the usage of the if-header with entity tags and the generation and sending of the +ETag header. + +The following design only refers to the support of entity tags as defined in +the HTTP/1.1 RFC. This includes the headers mentioned in the above RFC overview +and the generation and comparison of entity tags. + +Entity tag generation +===================== + +The generation of an entity tag requires uniqueness for the state of a resource +(the so-called entity), To achieve this, multiple data of the resource and be +involved and combined. + +The last modification time in combination with the file size should be a +sufficient combination of data to generate an entity tag from. The Lighttpd +web server uses this information on a configurable basis, too. In addition it +can use the inode of the file for entity tag generation. Since inodes are +operating system dependent and only available for file system based back ends, +they will not be used in our entity tag generation scheme. + +Since entity tags in WebDAV are also available through the getetag +live-property, a common way is needed to generate the entity tags for the +headers and the property. The ezcWebdavSimpleBackend will therefore request the +getetag property from the extending back end and use it's value for the headers +and validation. + +The current generation of entity tags in ezcWebdavFileBackend will be replaced +by a mechanism that uses the last modification time and the size of the file. +It currently uses the path, which is not reliable and does not belong into the +entity tag. Entity tags are only valid for a single resource and only in +combination with its URI. + +Header handling +=============== + +The handling of entity tag related headers must take place in several different +architecture levels of the Webdav component. + +Transport layer +--------------- + +The transport layer needs to be able to parse the request headers and to +serialize the response headers back. Therefore the ezcWebdavHeaderHandler class +will be adjusted. + +The class must parse the following new request headers: + +- If-Match +- If-None-Match + +ezcWebdavHeaderHandler will check if both of these headers are set. If this is +the case, both headers will be silently discarded, since such a combination is +undefined. + +Both headers can contain a list of weak/non-weak entity tags or the "*" value, +to indicate that the resource must just exists, no matter in which state. To +represent this in PHP, the parsed headers will be represented either as an +array of string values or as the boolean value true. The headers will be parsed +into every request object automatically, if they are set. + +The back end layer must take responsibility for interpreting the headers and +their values. + +In addition, ezcWebdavHeaderHandler must take care of serializing an ETag +header, if this one is present in a response object. Since the ETag header may +only contain the string value of an entity tag, this mechanism is already +implemented in the response processing. + +Back end layer +-------------- + +The interpretation of incoming If-Match and If-None-Match headers must be done +in the back end. The implementation will take place in the +ezcWebdavSimpleBackend class. With every incoming request, no matter which +request method is used, the If-Match and If-None-Match headers will be honored +in the following way: + +If the back end determines that an If-Match header is set, it will: + +- Check if all preconditions (except the If-Match) are fulfilled. + + - If not, return a corresponding error response. + +- Check if the If-Match value is a boolean true. + + - Check if the requested path exists. + + - If it *does not*, cancel the method and return 412 (Precondition Failed). + +- Check if the If-Match value is an array of strings. + + - Retrieve the affected resources getetag property and compare it with all + strings in the array. + + - If *none* matches, cancel the method and return 412 (Precondition Failed). + +- Process the method as if the If-Match header was not set. + +If the back end determines that an If-None-Match header is set, it will: + +- Check if all preconditions (except the If-Match) are fulfilled. + + - If not, return a corresponding error response. + +- Check if the If-Match value is a boolean true. + + - Check if the requested path exists. + + - If it *does*, cancel the method and return 412 (Precondition Failed). + +- Check if the If-Match value is an array of strings. + + - Retrieve the affected resources getetag property and compare it with all + strings in the array. + + - If *any* matches, cancel the method and return 412 (Precondition Failed). + +- Process the method as if the If-None-Match header was not set. + +Since this behavior will be implemented within the ezcWebdavSimpleBackend +class, it automatically works with all extending back end classes. Back ends +that do not extend ezcWebdavSimpleBackend will have to take care for these +headers on their own. + +Lock support +^^^^^^^^^^^^ + +Locking allows a WebDAV client to gain exclusive access to a resource +(collection or non-collection) to avoid the "lost update problem". This means +that a client can define to have exclusive access to a resource for a certain +time, where no other client may gain access to this resource. + +The WebDAV RFC distinguishes locks by 2 essential properties: The scope of the +lock (shared vs. exclusive) and the type of the lock (write vs. read), while +for the type only a write lock is specified. Using an exclusive lock the client +ensures that he has absolutely exclusive access to the locked resource. With a +shared lock it is possible the multiple clients take part in one and the same +lock. More information on lock scopes are provided later. + +============ +Plugin based +============ + +This section describes a potential realization of locking through a plugin for +the Webdav component. This plugin will make use of the, not yet officially +released, plugin API. + +Design goals +============ + +This design drafts goal is to build a lock plugin that is almost completely +independent from the used back end. In this sense, the requirements to be +fulfilled by a back end must be cut down as far as possible. Beside that, the +plugin should provide the largest possible compatibility to clients. However a +plugin that hooks into the parsing process cannot provide the same client +compatibility mechanisms as the base Webdav transport layer. + +Hooks +===== + +The plugin needs to assign to several hooks offered by the plugin API, which +will be described roughly in this section. + +parseUnknownRequest (ezcWebdavTransport) +---------------------------------------- + +The requests LOCK and UNLOCK are dedicated to the locking mechanism. Therefore +the plugin needs to hook into parseUnknownRequest and parse the incoming +requests into (new) corresponding request objects. + + + +=========== +Open issues +=========== + +Authentication +============== + +The problem +----------- + +The WebDAV RFC specifies that lock tokens are not secure for authentication +since the can be obtained by every client with access to the repository through +the lockdiscovery property. Therefore, a server must provide its own +authentication scheme. We currently do not support any authentication mechanism +in the Webdav component. To realize locking, we need to support at least 1 +authentication model in the component. + +Solution attempt +---------------- + +The only possible authentication scheme provided through the HTTP protocol is +HTTP-Auth. Therefore the HTTP-Auth information should be integrated into every +request object, if provided. To check this information, an interface should be +provided that provides the following capabilities: + +- Information of the assignment of a new lock token to a specific HTTP-Auth + user. +- Removal of a lock token. +- Answer to the question if a certain user may perform an action with a given + lock token. + +In addition we should provide a basic implementation of this class, which does +actually not do anything but discard the given information and return true on +authentication question. This will not provide any security, but allow users to +plug their own authentication mechanisms into the lock facilities. + +Further thoughts +---------------- + +In future it might be possibly that a WebdavAuthenticationTiein is implemented, +which might then be plugged into the described mechanism, too. This could in +addition be used for a "plugin" that performs authentication (and possibly +authorization?) in general on the transport/server level. + +Lock null resources +=================== + +The problem +------------ + +For our special case this means, that we need to "physically" create +lock-null resources in the utilized back end, to make it persist during +requests, whenever a null-lock is acquired. This lock-null resource must +not appear as a real resource to the client (e.g. must not have a +correct content type and must not respond to GET requests). If the +resource is unlocked again, it must be removed from the back end again. + +In our internal handling, that means, that we need to intervene any of +the operations not supported by a lock-null resource (e.g. COPY, MOVE, +PROPPATCH) requests to check is a lock-null resource is affected and +remove it potentially or forbid the operation. Furthermore, we need to +intervene any operation that is supported by a lock-null resource to +remove potential information from responses that must not be available +for lock-null resources. This will mean a lot of internally generated +requests to the back end and a lot of processing of the back end generated +responses. + +For example, if a MOVE request is issued by a client, we need to check +the whole affected directory tree for lock-null resources and remove +those from the destination and send a special error code for them in the +response. + +Atomicity of operations also comes into play here, since our internal +requests to the back end might interfere with other external requests. For +example, a null-lock might be acquired by the client while we are +internally checking the correctness of a MOVE request (race-condition). + +Solution attempts +----------------- + +I currently do not see a full solution for this problem, still there are +some ideas in my mind, that might be helpful. For lock-null resources we +can invent a special dead-property name space to indicate such resources. +If a special (for lock-null resources forbidden) operation occurs, we +can easily check for them using a PROPFIND request. Creating and +maintaining lock-null resources should then be not problem. + +For the race-condition issue, we'll definitely need support in the +back end, because I see no other solution attempt here to ensure the +consistency. + Common concerns ^^^^^^^^^^^^^^^ -This section introduces common concerns of the issues covered in this design -document and the features resulting from them. Especially the if-header and its -support in the Webdav component are described. - -========================= -Plugin based design draft -========================= +This section describes the design to realize support for the If header, which +is used in WebDAV with combinations of entity tags and lock tokens. + +============ +Plugin based +============ This section tries to design the honoring of the If header in the Webdav component using a plugin based approach for lock handling. This works @@ -159,8 +438,8 @@ will be contained, since the If header does not use tagging to specify which resources are affected by the conditions. -Plugin -====== +Plugin layer +============ 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 @@ -267,276 +546,6 @@ request object passes ezcWebdavServer, the headers are validated anyways there. -Entity tag support -^^^^^^^^^^^^^^^^^^ - -This section describes the support of entity tags in the Webdav component, including -the usage of the if-header with entity tags and the generation and sending of the -ETag header. - -The following design only refers to the support of entity tags as defined in -the HTTP/1.1 RFC. This includes the headers mentioned in the above RFC overview -and the generation and comparison of entity tags. - -Entity tag generation -===================== - -The generation of an entity tag requires uniqueness for the state of a resource -(the so-called entity), To achieve this, multiple data of the resource and be -involved and combined. - -The last modification time in combination with the file size should be a -sufficient combination of data to generate an entity tag from. The Lighttpd -web server uses this information on a configurable basis, too. In addition it -can use the inode of the file for entity tag generation. Since inodes are -operating system dependent and only available for file system based back ends, -they will not be used in our entity tag generation scheme. - -Since entity tags in WebDAV are also available through the getetag -live-property, a common way is needed to generate the entity tags for the -headers and the property. The ezcWebdavSimpleBackend will therefore request the -getetag property from the extending back end and use it's value for the headers -and validation. - -The current generation of entity tags in ezcWebdavFileBackend will be replaced -by a mechanism that uses the last modification time and the size of the file. -It currently uses the path, which is not reliable and does not belong into the -entity tag. Entity tags are only valid for a single resource and only in -combination with its URI. - -Header handling -=============== - -The handling of entity tag related headers must take place in several different -architecture levels of the Webdav component. - -Transport layer ---------------- - -The transport layer needs to be able to parse the request headers and to -serialize the response headers back. Therefore the ezcWebdavHeaderHandler class -will be adjusted. - -The class must parse the following new request headers: - -- If-Match -- If-None-Match - -ezcWebdavHeaderHandler will check if both of these headers are set. If this is -the case, both headers will be silently discarded, since such a combination is -undefined. - -Both headers can contain a list of weak/non-weak entity tags or the "*" value, -to indicate that the resource must just exists, no matter in which state. To -represent this in PHP, the parsed headers will be represented either as an -array of string values or as the boolean value true. The headers will be parsed -into every request object automatically, if they are set. - -The back end layer must take responsibility for interpreting the headers and -their values. - -In addition, ezcWebdavHeaderHandler must take care of serializing an ETag -header, if this one is present in a response object. Since the ETag header may -only contain the string value of an entity tag, this mechanism is already -implemented in the response processing. - -Back end layer --------------- - -The interpretation of incoming If-Match and If-None-Match headers must be done -in the back end. The implementation will take place in the -ezcWebdavSimpleBackend class. With every incoming request, no matter which -request method is used, the If-Match and If-None-Match headers will be honored -in the following way: - -If the back end determines that an If-Match header is set, it will: - -- Check if all preconditions (except the If-Match) are fulfilled. - - - If not, return a corresponding error response. - -- Check if the If-Match value is a boolean true. - - - Check if the requested path exists. - - - If it *does not*, cancel the method and return 412 (Precondition Failed). - -- Check if the If-Match value is an array of strings. - - - Retrieve the affected resources getetag property and compare it with all - strings in the array. - - - If *none* matches, cancel the method and return 412 (Precondition Failed). - -- Process the method as if the If-Match header was not set. - -If the back end determines that an If-None-Match header is set, it will: - -- Check if all preconditions (except the If-Match) are fulfilled. - - - If not, return a corresponding error response. - -- Check if the If-Match value is a boolean true. - - - Check if the requested path exists. - - - If it *does*, cancel the method and return 412 (Precondition Failed). - -- Check if the If-Match value is an array of strings. - - - Retrieve the affected resources getetag property and compare it with all - strings in the array. - - - If *any* matches, cancel the method and return 412 (Precondition Failed). - -- Process the method as if the If-None-Match header was not set. - -Since this behavior will be implemented within the ezcWebdavSimpleBackend -class, it automatically works with all extending back end classes. Back ends -that do not extend ezcWebdavSimpleBackend will have to take care for these -headers on their own. - -Lock support -^^^^^^^^^^^^ - -Locking allows a WebDAV client to gain exclusive access to a resource -(collection or non-collection) to avoid the "lost update problem". This means -that a client can define to have exclusive access to a resource for a certain -time, where no other client may gain access to this resource. - -The WebDAV RFC distinguishes locks by 2 essential properties: The scope of the -lock (shared vs. exclusive) and the type of the lock (write vs. read), while -for the type only a write lock is specified. Using an exclusive lock the client -ensures that he has absolutely exclusive access to the locked resource. With a -shared lock it is possible the multiple clients take part in one and the same -lock. More information on lock scopes are provided later. - -Locking -^^^^^^^ - -=================== -Plugin design draft -=================== - -This section describes a potential realization of locking through a plugin for -the Webdav component. This plugin will make use of the, not yet officially -released, plugin API. - -Design goals -============ - -This design drafts goal is to build a lock plugin that is almost completely -independent from the used back end. In this sense, the requirements to be -fulfilled by a back end must be cut down as far as possible. Beside that, the -plugin should provide the largest possible compatibility to clients. However a -plugin that hooks into the parsing process cannot provide the same client -compatibility mechanisms as the base Webdav transport layer. - -Hooks -===== - -The plugin needs to assign to several hooks offered by the plugin API, which -will be described roughly in this section. - -parseUnknownRequest (ezcWebdavTransport) ----------------------------------------- - -The requests LOCK and UNLOCK are dedicated to the locking mechanism. Therefore -the plugin needs to hook into parseUnknownRequest and parse the incoming -requests into (new) corresponding request objects. - - - -=========== -Open issues -=========== - -Authentication -============== - -The problem ------------ - -The WebDAV RFC specifies that lock tokens are not secure for authentication -since the can be obtained by every client with access to the repository through -the lockdiscovery property. Therefore, a server must provide its own -authentication scheme. We currently do not support any authentication mechanism -in the Webdav component. To realize locking, we need to support at least 1 -authentication model in the component. - -Solution attempt ----------------- - -The only possible authentication scheme provided through the HTTP protocol is -HTTP-Auth. Therefore the HTTP-Auth information should be integrated into every -request object, if provided. To check this information, an interface should be -provided that provides the following capabilities: - -- Information of the assignment of a new lock token to a specific HTTP-Auth - user. -- Removal of a lock token. -- Answer to the question if a certain user may perform an action with a given - lock token. - -In addition we should provide a basic implementation of this class, which does -actually not do anything but discard the given information and return true on -authentication question. This will not provide any security, but allow users to -plug their own authentication mechanisms into the lock facilities. - -Further thoughts ----------------- - -In future it might be possibly that a WebdavAuthenticationTiein is implemented, -which might then be plugged into the described mechanism, too. This could in -addition be used for a "plugin" that performs authentication (and possibly -authorization?) in general on the transport/server level. - -Lock null resources -=================== - -The problem ------------- - -For our special case this means, that we need to "physically" create -lock-null resources in the utilized back end, to make it persist during -requests, whenever a null-lock is acquired. This lock-null resource must -not appear as a real resource to the client (e.g. must not have a -correct content type and must not respond to GET requests). If the -resource is unlocked again, it must be removed from the back end again. - -In our internal handling, that means, that we need to intervene any of -the operations not supported by a lock-null resource (e.g. COPY, MOVE, -PROPPATCH) requests to check is a lock-null resource is affected and -remove it potentially or forbid the operation. Furthermore, we need to -intervene any operation that is supported by a lock-null resource to -remove potential information from responses that must not be available -for lock-null resources. This will mean a lot of internally generated -requests to the back end and a lot of processing of the back end generated -responses. - -For example, if a MOVE request is issued by a client, we need to check -the whole affected directory tree for lock-null resources and remove -those from the destination and send a special error code for them in the -response. - -Atomicity of operations also comes into play here, since our internal -requests to the back end might interfere with other external requests. For -example, a null-lock might be acquired by the client while we are -internally checking the correctness of a MOVE request (race-condition). - -Solution attempts ------------------ - -I currently do not see a full solution for this problem, still there are -some ideas in my mind, that might be helpful. For lock-null resources we -can invent a special dead-property name space to indicate such resources. -If a special (for lock-null resources forbidden) operation occurs, we -can easily check for them using a PROPFIND request. Creating and -maintaining lock-null resources should then be not problem. - -For the race-condition issue, we'll definitely need support in the -back end, because I see no other solution attempt here to ensure the -consistency. .. -- svn-components mailing list svn-components@lists.ez.no http://lists.ez.no/mailman/listinfo/svn-components