This file documents Subversion's use of the WebDAV/DeltaV protocol. IMPORTANT RFCs and LINKS ======================== * RFC 2518 (WebDAV) * RFC 3253 (DeltaV) * Subversion's limited uses of DeltaV, as well as interoperability issues, are explained in the "WebDAV" appendix of the free Subversion book (at https://svnbook.red-bean.com) HTTP METHODS USED, indexed by svn commands that access network ============================================================== Read Commands : (OPTIONS, PROPFIND, GET, REPORT) ------------- Most commands have to resolve peg-revisions before starting: * -r X foo@Y REPORT ('get-locations') ...if an old server doesn't support 'get-locations' report, the client traces history using the 'log-report' instead. And any command which has to convert a date to a revision: * -r {DATE} REPORT ('dated-rev-report') The following group of commands all use the custom 'update-report' request, which is just a fancy way of driving svn_repos_dir_delta(): * svn checkout / svn export / svn update: (do_update RA interface) ra_neon: PROPFIND, REPORT ('update-report' w/send-all) ra_serf: PROPFIND, REPORT ('update-report') ... then many PROPFIND/GETs on many parallel connections svn update only ('merge-info-report') * svn switch: OPTIONS, PROPFIND, REPORT ('update-report', 'merge-info-report') * svn diff: OPTIONS, PROPFIND, REPORT ('update-report') ... then many GETs * svn merge: OPTIONS, PROPFIND, REPORT ('update-report', 'merge-info-report') ... then many GETs * svn status -u: OPTIONS, PROPFIND, REPORT ('update-report' and 'get-locks-report') * svn cp URL wc: OPTIONS, PROPFIND, REPORT ('update-report') (this is just like checkout) And these guys are left over: * svn log: OPTIONS, PROPFIND, REPORT ('log-report') * svn blame: OPTIONS, PROPFIND, REPORT ('file-revs-report') [older clients use GET and different REPORT] ('log-report') * svn ls: PROPFIND * svn ls -v: PROPFIND, REPORT ('get-locks-report') * svn cat: PROPFIND, GET * svn info URL: PROPFIND * svn plist URL: PROPFIND * svn pget URL: PROPFIND Write Commands : (MKACTIVITY, PROPPATCH, PUT, CHECKOUT, MKCOL, MOVE, -------------- COPY, DELETE, LOCK, UNLOCK, MERGE) With the exception of LOCK/UNLOCK, every write command performs some sort of DeltaV commit operation. In DeltaV, a commit always starts by creating a transaction (MKACTIVITY), applies a log message (PROPPATCH), does some other write methods, and then ends by committing the transaction (MERGE). If the MERGE fails, the client may try to remove the transaction with a DELETE. * svn commit: ra_neon: OPTIONS, PROPFIND, MKACTIVITY, {CHECKOUT, COPY, MOVE, DELETE, PROPPATCH, PUT, MKCOL}, MERGE (DELETE) ra_serf: OPTIONS to acquire activity collection set (no major MKACTIVITY to a unique UUID relative to activity set differences) PROPFIND to get what we think our baseline is CHECKOUT of baseline revision into activity Setting log: PROPPATCH on root directory Delete a file: CHECKOUT file / DELETE Add a dir: MKCOL Add a file: CHECKOUT parent dirs / PUT raw-file Edit a file: CHECKOUT file / PUT svndiff stream End commit: MERGE activity, DELETE activity * svn import: OPTIONS, PROPFIND, MKACTIVITY, {PROPPATCH, PUT, MKCOL}, MERGE (DELETE) * svn lock: PROPFIND, LOCK * svn unlock: PROPFIND, UNLOCK * svn cp URL URL: OPTIONS, PROPFIND, MKACTIVITY, PROPPATCH, COPY, MERGE. (DELETE) * svn mv URL URL: OPTIONS, PROPFIND, MKACTIVITY, PROPPATCH, COPY, DELETE, MERGE. (DELETE) * svn rm URL: OPTIONS, PROPFIND, MKACTIVITY, PROPPATCH, DELETE, MERGE. * svn mkdir URL: OPTIONS, PROPFIND, MKACTIVITY, PROPPATCH, MKCOL, MERGE. * svn pset --revprop: PROPPATCH Remembering Our Location ======================== For a file in our WC, both ra_serf and ra_neon will store the checked-in href (where the original text-base and properties can be found) in the svn:wc:ra_dav:version-url wcprop. Example property: svn:wc:ra_dav:version-url -> /repos/test/!svn/ver/2/httpd/configure GET === ra_serf ------- For a file that a WC already has when it wants to do an update, ra_serf will send two extra headers: X-SVN-VR-Base: Accept-Encoding: svndiff1;q=0.9,svndiff;q=0.8 The server may choose not to return svndiff content but return full-text. (ra_neon has this same functionality, but is largely just dead code.) Example ------- Request: GET /repos/test/!svn/ver/3/httpd/configure HTTP/1.1 X-SVN-VR-Base: /repos/test/!svn/ver/2/httpd/configure Accept-Encoding: svndiff1;q=0.9,svndiff;q=0.8 Response: HTTP/1.1 200 OK ETag: "3//httpd/configure" Vary: Accept-Encoding Content-Type: application/vnd.svn-svndiff ...svn-svndiff stream that can be passed to svn_txdelta_parse_svndiff... PROPPATCH ========= We extend PROPPATCH as follows. To pass OLD_VALUE_P (as in svn_ra_change_rev_prop2()), any propchange which is accompanied by a non-NULL OLD_VALUE_P goes within the tag (and never within the tag --- even if it is a propdel). Consequently, in mod_dav_svn it would land in db_store() and not db_remove(). The property tag (in the C: or S: namespace) always contains the propval in its cdata (potentially base64-encoded). The extension is as follows: * The property tag grows a V:absent attribute, to represent that the property is being removed (i.e., a propdel routed to ). * A tag may be nested within the property tag. The nested tag supports the same V:absent and V:encoding attributed as the parent (property) tag. * To preserve SVN_ERR_FS_PROP_BASEVALUE_MISMATCH (which is part of the API promise), the HTTP/1.1 500 (status) part of the "207 Multi-Status" response is used. We transmit in it a "412 Precondition Failed" response, which ra_neon and ra_serf then special-case to interpret SVN_ERR_FS_PROP_BASEVALUE_MISMATCH. Someday we will marshal complete svn_error_t chains over the wire in ra_dav, just like ra_svn does (see svn_ra_svn__handle_failure_status()), or at least will preserve the outer apr_err code in more cases. In the meantime, using 412 allows us to preserve the SVN_ERR_FS_PROP_BASEVALUE_MISMATCH error code, which is required for implementing svn_ra_change_rev_prop2(). Historical note: we route propdels via /db_store() because the mod_dav API for db_remove() was insufficient. See this thread: http://mid.gmane.org/4C531CFB.2010202@collab.net Custom REPORTs ============== We use a bunch of custom reports, here's a little info on what they look like. update-report ------------- Purpose: Present what we have in our WC to the server and let it tell us what has changed. Has an optional 'send-all' attribute that will include the text-deltas in base64-encoding inline to the XML REPORT response. Target URL: Base VCC URL Example: REPORT /repos/test/!svn/vcc/default Note: ra_serf may not set the send-all attribute to the update-report. It will instead take the returned D:checked-in href and do a pipelined PROPFIND / GET on that resource. Note: If a client had a previous revision, it would not send the 'start-empty' attribute to entry. Request: http://localhost:8080/repos/test/httpd/support 2 Response: /repos/test/!svn/ver/2/httpd/support 2 ... more set props ... /repos/test/!svn/ver/2/httpd/support/ab.c 2 ... more set props for the file ... ...base64-encoded file content... /repos/test/!svn/ver/2/httpd/os ...directory contents... dated-rev-report ---------------- Purpose: Get the revision associated with a particular date. Target URL: VCC URL for repos. Request: 2005-12-07T13:06:26.034802Z Response: 4747 get-locks-report ---------------- Purpose: Get the locks associated with a particular resource. Target URL: URL of item we're getting the locks for Request: Response: /foo/bar/baz opaquelocktoken:706689a6-8cef-0310-9809-fb7545cbd44e fred ET39IGCB93LL4M 2005-02-07T14:17:08Z 2005-02-08T14:17:08Z get-locations ------------- Purpose: Get the location of a path appearing in a particular revision. Target URL: Current baseline collection for a directory plus relative paths. Example: REPORT /repos/test/!svn/bc/5/httpd Request: 5 1 Response: log-report ---------- Purpose: Retrieve the log for a portion of the repository. Target URL: Current baseline collection for a directory plus relative paths. Example: REPORT /repos/test/!svn/bc/5/httpd/support Request: 2 2 1 (optional) (optional) (optional) (optional) (optional) REVPROP... | | ('revprop', 'all-revprops', and 'no-revprops' are all optional) ... (optional) Response: 2 bob 2006-02-27T18:44:26.149336Z Add doo-hickey value... (optional) encoded value... (optional) (optional) PATH... (optional) PATH... (optional) PATH... (optional) PATH... (optional) ...multiple log-items for each returned revision... mergeinfo-report ---------------- Purpose: Retrieve the merge history for a portion of the repository (e.g. a set of paths) at a particular revision. Target URL: URL of item we're getting merge info for. Note: is a representation of the svn_mergeinfo_inheritance_t struct and can have the values 'explicit', 'inherited', or 'nearest-ancestor'. The default value is 'explicit' if is not present or has any other value than those three. represents the 'include_descendants' boolean argument to svn_ra_get_mergeinfo(). It can be 'yes' or 'no'; the default value is 'no' (mapping to FALSE). Request: 1 inherited yes /A/B/E/alpha Response: /A_COPY/B/E /A/B/E:1,3-4 replay-report ------------- Purpose: Retrieve a record of the changes made in a given revision, possibly limited to only those changes which affect a specific subtree of the repository. Target URL: Prior to Subversion 1.8, the target URL was the public resource URL of the aforementioned subtree. Per issue #4287 (https://issues.apache.org/jira/browse/SVN-4287), it was discovered that this was an incorrect approach, so in Subversion 1.8, mod_dav_svn allowed clients to submit this report (with a slightly different Request syntax) against baselined version resources. Request: Original syntax, used against a regular resource URL: REVISION LOW_WATER_MARK_REV 0 (... or non-zero if sending deltas) New (in Subversion 1.8) syntax, used against a baselined version resource URL: /trunk/subversion/tests LOW_WATER_MARK_REV 0 (... or non-zero if sending deltas) Response: ### TODO ###