Hi list, Toby and I finished a first revision of the webdav design document which you may find in SVN [1] and attached to this mail.
There are two major points of discussion left for us, which are described at the end of the document. 1) Indication of supported mechanism in backend handlers. 2) Selection of best transport handler for requesting client. If there are no general comments or other suggestions how to solve these two design issues we will start a SUMZERO on this, soon. [1] http://svn.ez.no/svn/ezcomponents/experimental/Webdav/design/design.txt -- Mit freundlichen Grüßen / Med vennlig hilsen Kore Nordmann (GPG: 0xDDC70BBB) eZ Components Developer eZ systems Headquaters tel +49 (0) 231-9742-7750 | fax +49 (0) 231-9742-7751 [EMAIL PROTECTED] | eZ systems | ez.no
eZ component: Webdav, Design, 1.0 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Kore Nordmann, Tobias Schlitt :Revision: $Rev$ :Date: $Date$ :Status: Draft .. contents:: Scope ===== The scope of this document is to describe the initial design of a component that provides a WebDAV server, which works with all major other implementations of the WebDAV_ protocol. .. _WebDAV_: http://en.wikipedia.org/wiki/WebDAV It is currently not planned to also offer a WebDAV client component. Design overview =============== Because of the variaty of buggy and incomplete implementations of WebDAV, this component will provide an abstraction to suite the different needs. Beside that, an abstract interface to the backend will be provided. The main class of this component will provide a fully `RFC 2518`_ compliant implementation of a WebDAV_ server. An instance of this class retrieves an instance of a handler class, which takes care for performing the requested operations on a backend (for example the filesystem). .. _`RFC 2518`: http://tools.ietf.org/html/rfc2518 Additionally, a collection of classes, which inherit the main class will be provided. Each of this classes will provide a compatibility layer on top of the RFC implementation, which works correctly with one or more "buggy" WebDAV clients. A factory pattern implementation will be provided, which takes automatically care of creating the correct server instance for a client. Tiers ===== The component is basically devided into 3 tiers: The top tier, being represented by the main server class. An instance of this class is responsible to dispatch a received request to a correct transport handler, which is capable of parsing the request. The transport handler level is the second tier. Classes in this tier are responsible to parse an incoming request and extract all relevant information to generate a response for it into a struct object. These struct object is then passed back to the server object. Based on the request struct object, the server checks the capabilities of its third tier, the used backend handler. If the handler object provides all necessary capabilities to generate a response, it is called to do so. If the server class can perform emulation of not available capabilities and rely on different features of the backend. In case there is no way, the backend can handle the request, the server class will indicate that with an error response. The way back flows through the 3 tiers back again: The backend handler generates a response object, which is passed back to the main server object, which makes the active transport handler encode the response and sends it back to the client. Classes ======= ezcWebdavServer --------------- The ezcWebdavServer class is the main class of the package. It has to be instantiated to create a server instance and provides a method to get the server up and running. An object of this class takes the main controll over serving the webdav service. Among the configuration of the server instance there must be: A backend handler object, which will be used to serve the received WebDAV requests. A fitting configuration for the backend handler. A collection of transport handlers which can be used to parse incoming requests. General configuration on the bevahiour of the server instance (like locking and stuff). The backend handler object must extend the base class ezcWebdavBackendHandler and must indicate to the main server, which capabilities it provides. The server class can potentially emulate certain capabilities, if the handler does not provide it. An example here is locking, which can be either performed by the handler itself or the main server class. Such emulation functionality could possibly be extracted to a third category of classes, which is only loaded by the main server object on-demand. All configured transport handlers must implement the interface ezcWebdavTransportHandler, which defines the necessary methods. ezcWebdavBackendHandler ----------------------- All backend handlers for the Webdav component must extends this abstract base class and implement its abstract methods for very basic WebDAV serving. The operations defined for every backend handler to be mandatory are: - head() - get() - propFind() - propFetch() All other WebDAV operations are optional to be implemented by a backend handler and are defined by the handler itself. It is an open issue, if the handlers should implement different interfaces, to indicate different capabilities or if a bitmask is more efficient here. The logical groups of capabilities are: Put The put capability indicates, that a handler is capable of handling file uploads via HTTP-PUT method. Change This sub class of WebDAV operations defines delete, copy and move operations to be supported by the handler class. Make collection The creation of new collections also makes up a capability unit and can optionally be implemented. Lock If the hander provides locking facilities on its own, the main server object must not take care about that. GZIP-Compress Handlers implementing this facility can deal with GZIP and bzip2 based compression. If a handler does not support a certain facility and the main server object is not capable of emulating it, the server will respond using a "501 Not Implemented" server error. ezcWebdavTransportHandler ------------------------- A class implementing this interface is capable of parsing a raw HTTP request into a struct extending ezcWebdavRequest and generating the HTTP response out of the ezcWebdavResponse struct. One transport handler is usually built to handle the communication with a certain set of specific client implementations. A transport handler class will be able to parse the incoming HTTP request data into a struct identifying a certain type of request and containg all necessary and unified data, so that a backend handler can repsond to it. The backend handler will then create a corresponding response object, which will be encoded back into HTTP data by the transport handler and send to the client by the server. Each request type will come with its own struct classes to represent request and response data for the request. Beside the structured HTTP data, the structs can contain any additional information that must be transferred between server, transport handler and backend handler. All struct classes representing either a request of response of the server will extend the abstract base classes ezcWebdavRequest and ezcWebdavResponse. An example of this structure is: ezcWebdavGetRequest and ezcWebdavGetResponse These 2 classes will be used to serve GET requests. Beside the usual request information - like URI, date and headers - the request object will contain information about partial GET mechanisms to use and what else is important. The backend handler will return an instance of ezcWebdavGetResponse if the request was handled correctly, or a corresponding ezcWebdavErrorResponse object, if the request failed. An open issue is, how the server instance can figure out best, which transport to use - see below for this. Example code ============ The following snippet shows the API calls necessary to get a WebDAV server up and running. :: <?php $server = new ezcWebdavServer(); // Server data using file backend with data in "path/" $server->backend = new ezcWebdavBackendFile( '/path' ); // Register transport handlers $server->registerTransportHandler( // Regular expression to match client name '(Microsoft.*Webdav\s+XP)i', // Class name of transport handler, extending ezcWebdavTransportHandler 'ezcWebdavMicrosoftTransport' ); $server->registerTransportHandler( // Regular expression to match client name '(.*Firefox.*)i', // Class name of transport handler, extending ezcWebdavTransportHandler 'ezcWebdavMozillaTransport' ); // Serve requests $server->handle(); Open issues =========== There are several open issues which need to be discussed before starting to implement this design: Capabilities ------------ Backend handlers can offer several different capabilities as noted in the specific section. It is not set, if the indication of supported capabilities should be done by implementing interfaces or going another way. Implementing interfaces would be a nice, OO-style solution, but can possibly end up in a huge lot of interfaces and possibly with interfaces that don't indicate any methods. For example, every handler needs to support GET and can optioanlly support partial GET. There are several ways, how a handler can indicate that he supports this: The implementation of an interface is the most plausible one: :: <?php interface ezcWebdavPartialGetHandler { public function partialGet(); } ?> Going this way, we end up with 1 method for every special case for a handler, which will result in messy code in the main server class, which needs to check for several methods and interfaces, which could satisfy a request and then choose the right method of the right interface to perform the work. Combination of partial *and* - for exampel - encoded request support would require to define a custom interface here which would end up in 2^$features interfaces and methods. The second option is, to let the handler implement empty interfaces and just let those be used for declarative purposes. That way, the above shown example would implement :: <?php interface ezcWebdavPartialGetHandler { } ?> The server class could then use the interface to determine the capability of partial GET and utilize the usual get() method to initialize the operation and possibly add a parameter for partiality to the request struct. The third alternative is to not use interfaces but a bitmask for handlers to indicate their capabilities. This will possibly the fastest way, because one can define fine graned stages of capability support and can easily check on different capabilities. Suitable transport ------------------ Another open issue is the mechanism to identify a suitable transport handler for a certain request. Currently, the main server instance will know about available clients and will have a regular expression for each of them, to identify the clients it communicates to. The regex must be defined by the user, when registering the handler. It is not clear, if 1 regex into 1 header field is enough to identify the handler correctly every time. Therefore, it must be discussed, if handlers shouldn't better have a static method like canParse() to perform the parsing checks on their own. That way, the mechanism to identify the correct handler is much more flexible, but all classes need to be loaded on every request. .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79
signature.asc
Description: This is a digitally signed message part
-- Components mailing list [email protected] http://lists.ez.no/mailman/listinfo/components
