| 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 http://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: <checked-in href of locally-present file> | |
| 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 <D:set><D:prop> tag (and never within the | |
| <D:remove><D:prop> 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 <D:set><D:prop>). | |
| * A <V:old-value> 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 <D:status>HTTP/1.1 500 (status)</D: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 <D:set>/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 will 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: | |
| <S:update-report send-all="true" xmlns:S="svn:"> | |
| <S:src-path>http://localhost:8080/repos/test/httpd/support</S:src-path> | |
| <S:target-revision>2</S:target-revision> | |
| <S:entry rev="2" start-empty="true"></S:entry> | |
| </S:update-report> | |
| Response: | |
| <S:update-report xmlns:S="svn:" xmlns:V="..." xmlns:D="DAV:" send-all="true"> | |
| <S:target-revision rev="2"/> | |
| <S:open-directory rev="2"> | |
| <D:checked-in> | |
| <D:href>/repos/test/!svn/ver/2/httpd/support</D:href> | |
| </D:checked-in> | |
| <S:set-prop name="svn:entry:committed-rev">2</S:set-prop> | |
| ... more set props ... | |
| <S:add-file name="ab.c"> | |
| <D:checked-in> | |
| <D:href>/repos/test/!svn/ver/2/httpd/support/ab.c</D:href> | |
| </D:checked-in> | |
| <S:set-prop name="svn:entry:committed-rev">2</S:set-prop> | |
| ... more set props for the file ... | |
| <S:txdelta>...base64-encoded file content...</S:txdelta> | |
| </S:add-file> | |
| <S:add-directory name="os" bc-url="/repos/test/!svn/bc/2/httpd/os"> | |
| <D:checked-in> | |
| <D:href>/repos/test/!svn/ver/2/httpd/os</D:href> | |
| </D:checked-in> | |
| ...directory contents... | |
| </S:add-directory> | |
| </S:open-directory> | |
| </S:update-report> | |
| dated-rev-report | |
| ---------------- | |
| Purpose: Get the revision associated with a particular date. | |
| Target URL: VCC URL for repos. | |
| Request: | |
| <S:dated-rev-report xmlns:S="svn:" xmlns:D="DAV:"> | |
| <D:creationdate>2005-12-07T13:06:26.034802Z</D:creationdate> | |
| </S:dated-rev-report> | |
| Response: | |
| <S:dated-rev-report xmlns:S="svn:" xmlns:D="DAV:"> | |
| <D:version-name>4747</D:version-name> | |
| </S:dated-rev-report> | |
| get-locks-report | |
| ---------------- | |
| Purpose: Get the locks associated with a particular resource. | |
| Target URL: URL of item we're getting the locks for | |
| Request: | |
| <S:get-locks-report xmlns:S="svn"> | |
| </S:get-locks-report> | |
| Response: | |
| <S:get-locks-report xmlns:S="svn"> | |
| <S:lock> | |
| <S:path>/foo/bar/baz</S:path> | |
| <S:token>opaquelocktoken:706689a6-8cef-0310-9809-fb7545cbd44e</S:token> | |
| <S:owner>fred</S:owner> | |
| <S:comment encoding="base64">ET39IGCB93LL4M</S:comment> | |
| <S:creationdate>2005-02-07T14:17:08Z</S:creationdate> | |
| <S:expirationdate>2005-02-08T14:17:08Z</S:expirationdate> | |
| </S:lock> | |
| </S:get-locks-report> | |
| 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: | |
| <S:get-locations xmlns:S="svn:"> | |
| <S:path></S:path> | |
| <S:peg-revision>5</S:peg-revision> | |
| <S:location-revision>1</S:location-revision> | |
| </S:get-locations> | |
| Response: | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <S:get-locations-report xmlns:S="svn:" xmlns:D="DAV:"> | |
| <S:location rev="1" path="/httpd"/> | |
| </S:get-locations-report> | |
| 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: | |
| <S:log-report xmlns:S="svn:"> | |
| <S:start-revision>2</S:start-revision> | |
| <S:end-revision>2</S:end-revision> | |
| <S:limit>1</S:limit> (optional) | |
| <S:discover-changed-paths/> (optional) | |
| <S:strict-node-history/> (optional) | |
| <S:include-merged-revisions/> (optional) | |
| <S:revprop>REVPROP</S:revprop>... | <S:all-revprops/> | <S:no-revprops/> | |
| ('revprop', 'all-revprops', and 'no-revprops' are all optional) | |
| <S:path></S:path>... (optional) | |
| </S:log-report> | |
| Response: | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <S:log-report xmlns:S="svn:" xmlns:D="DAV:"> | |
| <S:log-item> | |
| <D:version-name>2</D:version-name> | |
| <S:creator-displayname>bob</S:creator-displayname> | |
| <S:date>2006-02-27T18:44:26.149336Z</S:date> | |
| <D:comment>Add doo-hickey</D:comment> | |
| <S:revprop name="REVPROP">value</S:revprop>... (optional) | |
| <S:has-children/> (optional) | |
| <S:added-path( copyfrom-path="PATH" copyfrom-rev="REVNUM">PATH</S:added-path>... (optional) | |
| <S:replaced-path( copyfrom-path="PATH" copyfrom-rev="REVNUM">PATH</S:replaced-path>... (optional) | |
| <S:deleted-path>PATH</S:deleted-path>... (optional) | |
| <S:modified-path>PATH</S:modified-path>... (optional) | |
| </S:log-item> | |
| ...multiple log-items for each returned revision... | |
| </S:log-report> | |
| 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: <S:inherit> 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 <S:inherit> | |
| is not present or has any other value than those three. | |
| <S:include-descendants> 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: | |
| <S:mergeinfo-report xmlns:S="svn:"> | |
| <S:revision>1</S:revision> | |
| <S:inherit>inherited</S:inherit> | |
| <S:include-descendants>yes</S:include-descendants> | |
| <S:path>/A/B/E/alpha</S:path> | |
| </S:mergeinfo-report> | |
| Response: | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <S:mergeinfo-report xmlns:S="svn:" xmlns:D="DAV:"> | |
| <S:mergeinfo-item> | |
| <S:mergeinfo-path>/A_COPY/B/E</S:mergeinfo-path> | |
| <S:mergeinfo-info>/A/B/E:1,3-4</S:mergeinfo-info> | |
| </S:mergeinfo-item> | |
| </S:mergeinfo-report> |