| 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 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: |
| |
| <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:encode-binary-props> (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:revprop name="REVPROP" encoding="base64">encoded 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> |
| |
| 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: |
| |
| <S:replay-report xmlns:S=\"svn:\"> |
| <S:revision>REVISION</S:revision> |
| <S:low-water-mark>LOW_WATER_MARK_REV</S:low-water-mark> |
| <S:send-deltas>0</S:send-deltas> (... or non-zero if sending deltas) |
| </S:replay-report> |
| |
| New (in Subversion 1.8) syntax, used against a baselined version |
| resource URL: |
| |
| <S:replay-report xmlns:S=\"svn:\"> |
| <S:include-path>/trunk/subversion/tests</S:include-path> |
| <S:low-water-mark>LOW_WATER_MARK_REV</S:low-water-mark> |
| <S:send-deltas>0</S:send-deltas> (... or non-zero if sending deltas) |
| </S:replay-report> |
| |
| Response: |
| |
| ### TODO ### |