(* $Id: webdav_client_methods.mli 1 2011-08-26 21:00:39Z gerd $ *) (** Extension of the Http_client module for submitting WebDAV requests. See RFC 4918 (http://www.ietf.org/rfc/rfc4918.txt) This definition is incomplete. Strings are encoded in UTF-8, except where something else is specified. URLs are ASCII. This module allows it to create method objects that can be passed to HTTP pipelines, e.g. {[ let http = new Http_client.pipeline let propfind_cl = new propfind "http://server/" http # add (propfind_cl :> Http_client.http_call); http # run(); (* now look at propfind_cl for response *) ]} Note that the method objects need to be coerced to [http_call] before being passed to the pipeline. There is no way of coercing them back, so users should keep the object [propfind] with the original type. *) (* Missing methods: LOCK, UNLOCK *) (* Missing headers: If *) open Webdav_http (** {2 Success codes} *) (** WebDAV error reporting is complicated: File system conditions are mapped to the HTTP response status codes, which is looks rather weird. Also, many operations can return multistatus responses, with detailed status codes for each affected URL or even each property. *) type call_status = [ Http_client.status | `Multi_status ] (** Condensed status information of a WebDAV call: * - [`Unserved]: The call has not yet been finished * - [`HTTP_protocol_error e]: An error on HTTP level occurred. Corresponds * to the exception {!Http_client.Http_protocol}. * - [`Successful]: The call is successful, and the response code is between * 200 and 299 (except 207 which is special, see below). * - [`Redirection]: The call is successful, and the response code is * between 300 and 399. * - [`Client_error]: The call failed with a response code between 400 and * 499. * - [`Server_error]: The call failed for any other reason. * - [`Multi_status]: The server responded with a 207 code. For * [PROPFIND] and [PROPPATCH] the multistatus response includes * detailed data about properties. For other methods the multistatus * response means that for some URL the operation ran into an error * but for other URLs it was successful. The classes defined below * have methods to further analyze the situation (especially [good_urls] * and [bad_urls]). *) val string_of_call_status : call_status -> string (** {2 General types and values} *) type property = Webdav_xml.property (** A property is an XML tree. See {!Webdav_xml.property} for more information *) type prepost_code = Webdav_xml.prepost_code (** A precondition/postcondition element. Works in the same way as [property]. *) (** Information about individual properties *) class type propstat_t = object method properties : property list (** The properties this object is about *) method status : webdav_status method status_code : int method status_text : string method status_protocol : string (** These four methods reflect the status indicated for the property. *) method error : prepost_code list (** Additional error token *) method responsedescription : string (** User information. Empty if not found in the response *) end (** Information about the response status per path *) class type response_t = object method href : string list (** The URLs this response refers to. The list is non-empty. For propfind responses the length is always 1. URLs should be ASCII only. *) method paths : string list (** The paths corresponding to the URLs in [href] *) method status : webdav_status method status_code : int method status_text : string method status_protocol : string (** These four methods reflect the status indicated for the URL. If no status is found (as in responses for PROPFIND), the status is reported as "200 OK". *) method propstat : propstat_t list (** The properties requested via PROPFIND *) method prop_creationdate : float option method prop_displayname : string option method prop_getcontentlanguage : string option method prop_getcontentlength : int64 option method prop_getcontenttype : string option method prop_getcontenttype_decoded : (string * (string * string) list) option method prop_getetag : string option method prop_getetag_decoded : Nethttp.etag option method prop_getlastmodified : float option method prop_resourcetype_is_collection : bool option (** Returns the value of the standard property if set. For some properties there are versions returning raw and decoded values. *) method find_prop : string -> property * propstat_t (** Return the named property and the propstat data, or raise [Not_found]. The name is the qualified XML name after prefix normalization (e.g. "DAV:creationdate"). *) method error : prepost_code list (** Additional error tokens *) method responsedescription : string (** User information. Empty if not found in the response *) method location : string option (** The destination URL for redirects (status = 3xx). Should be ASCII *) end (** A WebDAV call is a request with response *) class type webdav_call_t = object inherit Http_client.http_call method response_webdav_status : webdav_status (** Extended status information for WebDAV purposes *) method call_status : call_status (** Condensed status information about the call *) method multistatus : response_t list (** If the [call_status] is [`Multi_status], this list contains for every URL the requested data *) method query_path : string (** Returns the target path of this call *) method effective_query_path : string (** Returns the target path of this call, after following redirections *) method paths : string list (** Return the paths for which we got multistatus responses. This list is empty if the [call_status] is not [`Multi_status]. *) method good_paths : string list (** The subset of [paths] for which the response is considered as successful. The exeact criterion depends on the type of call. For multistatus responses [good_paths <> []] means that there was success for at least one path. *) method bad_paths : string list (** The subset of [paths] for which the response is considered as erroneous. The exeact criterion depends on the type of call. For multistatus responses [bad_paths = []] means that all paths could be processed successfully. *) method fully_successful : bool (** Same as [call_status = `Successful || (call_status = `Multi_status && bad_paths = [])] *) method response_of_path : string -> response_t (** Return the response object for this path. Raises [Not_found] if nothing is known about the path (or no multistatus response was available). In a PROPFIND response the status is per property, not per path. So [(response_of_path p) # status] is always [`Ok]. The only property that can always be retrieved is [resourcetype], so to find out whether a path is generally accessible one should ask for that property, and check whether [prop_resourcetype_is_collection] is [Some true] (for collections) or [Some false] (for non-collections). A value of [None] means that there is an error with the path. For other query types the status is per path. When the client had to follow redirections, only information about the redirected path is available. Use [effective_query_path] to determine this path. *) method responsedescription : string (** The overall description *) method status_report : string (** Returns a client-generated message describing the success of the operation URL by URL *) end (** {2 URL construction} *) val url_append : string -> string -> string (** [url_append base path]: Appends the [path] to the URL [base], and returns the new URL. Here, [base] must be a properly encoded URL, with [http://server] prefix. [path] is a normal slash-separated path without special escaping. The return value is again an absolute URL. The [path] must be absolute (begins with "/"). Examples: - [url_append "http://server" "/dir/file" = "http://server/dir/file"] - [url_append "http://server/dir" "/file" = "http://server/dir/file"] - [url_append "http://server" "/a file" = "http://server/a%20file"] *) (** {2 PROPFIND} *) type propfind_request = [ `Prop of property list | `Propname | `Allprop of property list ] (** What is requested: - [`Prop l]: Request the properties listed in [l] (which must be non-empty). The nodes in [l] are XML elements without children. - [`Propname]: Request a list of property names - [`Allprop l]: Request all properties, and include especially the extension properties [l] (which may be empty). In [l] one can request additional properties of the WebDAV namespace that are not defined in RFC 4918. *) val propname_creationdate : property val propname_displayname : property val propname_getcontentlanguage : property val propname_getcontentlength : property val propname_getcontenttype : property val propname_getetag : property val propname_getlastmodified : property val propname_resourcetype : property (** Standard WebDAV properties. These objects can be included in [`Prop] requests. These properties should be returned anyway for [`Allprop []]. *) class type propfind_call_t = webdav_call_t class propfind_call : propfind_call_t (** Creates a request object for PROPFIND. Header and body are uninitialized *) class propfind : ?depth:depth -> ?propfind_request:propfind_request -> ?strip_prefix:string -> string -> propfind_call_t (** [new propfind url]: Creates a PROPFIND request. If successful, this request is usually responded by a [`Multistatus] document listing the status for every matching URL. - [depth]: The [Depth] header value: [`Zero] means to only report about the object [url], [`One] means to also include data about the direct children, and [`Infinity] means to include data of the whole subtree. If missing, servers usually assume [`Infinity]. - [propfind_request]: The detailed request. If missing, servers usually assume [`Allprop []]. - [strip_prefix]: If set this path prefix is stripped from the reported paths. Must be an absolute path. *) (** {b Simplified interface for getting file listings} *) type list_request = [ `Existence | `Standard ] (** [`Existence] means a list request where only the [resourcetype] property is queried - useful for finding out which files exist. [`Standard] includes all standard properties. *) class type filelist_t = propfind_call_t (** In order to get property values, look up the per-URL response with [response_of_url], and then call one of the [prop_*] methods, e.g. {[ let url = List.hd l#list_good_url let r = l#response_of_url url let t = r#prop_creationdate ]} *) class filelist : ?depth:depth -> ?strip_prefix:string -> list_request -> string -> filelist_t (** [let l = new filelist req url]: Creates a new request object for retrieving file listings. *) (** {2 PROPPATCH} *) type proppatch_instruction = [ `Remove of property list | `Set of property list ] (** Which properties to modify: - [`Remove props]: Removes the properties [props]. The list [props] should only contain the property names with empty contents - [`Set props]: Sets the properties [props]. The list [props] must include properties that include contents. One can create such properties with the [encode_*] functions in {!Webdav_xml}. *) type proppatch_request = proppatch_instruction list (** The property updates are executed in order. The updates are either all executed, or none is executed *) class type proppatch_call_t = webdav_call_t class proppatch_call : propfind_call_t (** Creates a request object for PROPPATCH. Header and body are uninitialized *) class proppatch : ?strip_prefix:string -> proppatch_request:proppatch_request -> string -> propfind_call_t (** [new proppatch ~proppatch_request url]: Creates a PROPPATCH request. If successful, this request is usually responded by a [`Multistatus] document listing the status for every matching URL. *) (** {2 MKCOL} *) (** MKCOL creates collections (directories) *) class type mkcol_call_t = webdav_call_t class mkcol_call : mkcol_call_t (** Creates a request object for MKCOL. Header and body are uninitialized *) class mkcol : ?strip_prefix:string -> string -> mkcol_call_t (** [new mkcol uri]: Creates a new collection at [uri]. On success, the expected status value is [`Created]. See RFC 4918 for error codes - it is quite interesting. *) (** {2 GET} *) (** GET requests a document *) class type get_call_t = webdav_call_t class get_call : get_call_t (** Creates a request object for GET. Header and body are uninitialized *) class get : ?strip_prefix:string -> string -> get_call_t (** [new get uri]: Gets the document at [uri]. On success, the expected status value is [`Ok]. Access [response_body] to get the downloaded document. The status value [`No_content] is also possible. *) (** {2 DELETE} *) (** DELETE collections and documents *) class type delete_call_t = webdav_call_t class delete_call : delete_call_t (** Creates a request object for DELETE. Header and body are uninitialized *) class delete : ?strip_prefix:string -> string -> delete_call_t (** [new delete uri]: Deletes the document or collection at [uri]. Deletions are always recursive (the whole tree is deleted). On success, the expected status value is [`No_content]. When some URLs of the tree to delete result in errors, the status value will be [`Multi_status] reporting the errors. In that case the delete was only incompletely performed. *) (** {2 PUT} *) (** Add/replace documents *) class type put_call_t = webdav_call_t class put_call : put_call_t (** Creates a request object for PUT. Header and body are uninitialized *) class put : ?content_type:string -> ?content_length:int64 -> ?expect_handshake:bool -> ?strip_prefix:string -> string -> Netmime.mime_body -> put_call_t (** [new put url body]: Uploads the contents of [body] to the server so it will be visible at [url]. - [content_type]: The media type of the body. The server is free to ignore this. - [content_length]: The length of the body, if already known. There are servers that accept PUT only if the content length is set in the header. - [expect_handshake]: Set this to [true] to enable a special handshake before the body is uploaded. This is reasonable when the PUT request may cause errors - the error can be received before the upload starts. There might be compatibility problems, though, as this feature was incorrectly specified in some versions of HTTP. Note that some servers do not permit that existing files are replaced. The RFC says nothing about this case, though. *) (** {2 COPY} *) (** Copy documents, collections, or subtrees *) class type copy_call_t = webdav_call_t class copy_call : copy_call_t (** Creates a request object for COPY. Header and body are uninitialized *) class copy : ?depth:depth -> ?overwrite:bool -> ?strip_prefix:string -> string -> string -> copy_call_t (** [new copy src_url dest_url]: Copies the object(s) at [src_url] so that they become visible at [dest_url]. This works for documents, collections, or whole subtrees. The [dest_url] needs to be the full URL, including the [http://server] prefix. - [depth]: If set to [`Zero], only the single object at [src_url] is copied without member objects (in case of collections). If set to [`Infinity], the whole subtree is copied. The depth value of [`One] is illegal. If missing servers usually assume [`Infinity]. - [overwrite]: Whether it is allowed to overwrite destination objects. If missing servers usually assume [true]. *) (** {2 MOVE} *) (** Move documents, collections, or subtrees *) class type move_call_t = webdav_call_t class move_call : copy_call_t (** Creates a request object for MOVE. Header and body are uninitialized *) class move : ?overwrite:bool -> ?strip_prefix:string -> string -> string -> move_call_t (** [new move src_url dest_url]: Moves the object(s) at [src_url] so that they become visible at [dest_url]. This works for documents, and whole subtrees (moves of collections are always recursive). The [dest_url] needs to be the full URL, including the [http://server] prefix. - [overwrite]: Whether it is allowed to overwrite destination objects. If missing servers usually assume [true]. *) (**/**) (* Backward compat: *) class type list_t = filelist_t class list : ?depth:depth -> ?strip_prefix:string -> list_request -> string -> list_t (* other name for list_t. [list] is a bad name because the type ['a list] exists already *)