blob: 91181891882659e94926abc2aafcdb41c36d4f84 [file] [log] [blame]
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 ###