| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
| <html xmlns="http://www.w3.org/1999/xhtml"> | |
| <head> | |
| <style type="text/css"> /* <![CDATA[ */ | |
| @import "branding/css/tigris.css"; | |
| @import "branding/css/inst.css"; | |
| /* ]]> */</style> | |
| <link rel="stylesheet" type="text/css" media="print" | |
| href="branding/css/print.css"/> | |
| <script type="text/javascript" src="branding/scripts/tigris.js"></script> | |
| <title>Use of WebDAV in Subversion</title> | |
| </head> | |
| <body> | |
| <div class="app"> | |
| <h2>Use of WebDAV in Subversion</h2> | |
| <p> | |
| This document details how WebDAV is used within the | |
| <a href="http://subversion.apache.org/">Subversion | |
| product</a>. Specifically, how the client side interfaces with | |
| <a href="http://www.webdav.org/neon/">Neon</a> to generate | |
| WebDAV requests over the wire, and what the | |
| server must do to map incoming WebDAV requests into operations | |
| against the Subversion repository. Note that the server side is | |
| implemented as an | |
| <a href="http://httpd.apache.org/">Apache 2.0</a> module, | |
| operating as a back-end for its mod_dav functionality. | |
| </p> | |
| <p> | |
| This document heavily refers to the | |
| <a href="http://svn.apache.org/repos/asf/subversion/trunk/notes/subversion-design.html">Subversion | |
| design document</a> and the | |
| <a href="http://www.webdav.org/deltav/">latest Delta-V protocol | |
| draft</a>. Details of those documents will <em>not</em> be | |
| replicated here. | |
| </p> | |
| <table width="70%" border="0" cellspacing="0" cellpadding="10" | |
| style="background-color: #ff0000; color: white; | |
| margin-left: auto; margin-right: auto"> | |
| <tr> | |
| <td> | |
| <strong>NOTE:</strong> Subversion uses DeltaV for its | |
| communication, but the Subversion client is | |
| <strong>not</strong> a general-purpose DeltaV client. In | |
| fact, it expects some custom features from the | |
| server. Further, the Subversion server is | |
| <strong>not</strong> a general-purpose DeltaV server. It | |
| implements a strict <strong>subset</strong> of the | |
| DeltaV specification. A WebDAV or DeltaV client may very | |
| well be able to interoperate with it, but only if that | |
| client operates within the narrow confines of those | |
| features the server has implemented. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td> | |
| Version 2.0 of Subversion will address WebDAV | |
| interoperability (Class 1, Class 2, and DeltaV | |
| features). Each of the custom features expected by the | |
| client actually has an alternate mechanism available in | |
| DeltaV, but in a much less efficient form. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td> | |
| It is expected that Version 1.0 will support read-only, | |
| Class 1 WebDAV clients. Any "low-hanging fruit" to | |
| increase DeltaV interoperability will be considered. | |
| </td> | |
| </tr> | |
| </table> | |
| <p></p> | |
| <h3>Basic Concepts</h3> | |
| <p> | |
| Subversion uses a tree-based format to describe a change set | |
| against the repository. This tree is constructed on the client | |
| side (by "walking" over the working copy) to describe the | |
| change. The tree is marshalled to the server as a linear | |
| sequence of changes to be applied to the repository. The | |
| repository can accept changes in a random-access manner, so the | |
| mapping from a tree to a set of changes works very well for the | |
| repository. | |
| </p> | |
| <p> | |
| Subversion provides properties on files, directories, and even | |
| the abstract concept of a revision. Each of the operations | |
| involving properties are mapped directly to WebDAV properties, | |
| which are manipulated with the <span | |
| class="method">PROPFIND</span> and <span | |
| class="method">PROPPATCH</span> HTTP methods. Revisions are | |
| modeled as DeltaV <span class="term">baselines</span>, so | |
| revision properties are available through a <span | |
| class="method">PROPFIND</span> on the baseline. | |
| </p> | |
| <p> | |
| The Subversion server can efficiently compute deltas between two | |
| revisions (these deltas are complete <span class="term">tree | |
| deltas</span>, not simple text deltas). DeltaV does not have a | |
| direct analogue for the tree delta concept. A client could | |
| discover changes by issuing a sequence of <span | |
| class="method">PROPFIND</span> requests on the various WebDAV | |
| resources, but this would be a time-consuming operation, | |
| involving many requests. Instead, Subversion marshals this | |
| concept as a custom WebDAV <span | |
| class="term">report</span>. Using this report, the client learns | |
| which items in the working copy are out of date and can issue | |
| <span class="method">GET</span> and <span | |
| class="method">PROPFIND</span> methods to fetch the new data. | |
| </p> | |
| <p> | |
| Tags and branches are simple copies in Subversion, which are | |
| handled with the WebDAV <span class="method">COPY</span>. | |
| </p> | |
| <blockquote class="comment"> | |
| <p>need to talk about copies somewhere. need to discuss how copy | |
| history is retained (svn does it automatically, but interop with | |
| other servers may require us to set a custom property on those | |
| servers.</p> | |
| </blockquote> | |
| <h3>DeltaV Concepts Used by Subversion</h3> | |
| <p> | |
| Subversion uses many of the DeltaV concepts, as listed | |
| below. Note that many of these concepts are not fully | |
| implemented by Subversion; we have implemented enough to meet | |
| our needs, but little more. | |
| </p> | |
| <dl> | |
| <dt>Baseline</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Activity</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Version Resource</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Version-Controlled Configuration</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Baseline Collection</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Version-Controlled Resource</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Working Resource (Feature)</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Merge Feature</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Label Feature</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| <dt>Version-Controlled-Collection Feature</dt> | |
| <dd> | |
| <span class="comment">further info to come...</span><p></p> | |
| </dd> | |
| </dl> | |
| <h3>Subversion Projects as URLs</h3> | |
| <p> | |
| The very first concept to define is how a project is exposed to | |
| the client. Subversion will expose all projects as URLs on a | |
| server. The files and subdirectories under this project will be | |
| exposed through the URL namespace. | |
| </p> | |
| <p> | |
| For example, let us assume that we have a project named | |
| "example". And let us say that this project will be exposed at | |
| the URL: | |
| <span class="url">http://subversion.tigris.org/repos/example/</span>. | |
| </p> | |
| <p> | |
| This mapping is set up through a set of configuration | |
| parameters for the Apache HTTP Server (which is hosting the | |
| Subversion code and the particular project in question). The | |
| configuration could look like: | |
| </p> | |
| <blockquote> | |
| <pre><Location /repos/example> | |
| DAV svn | |
| SVNPath /home/svn-projects/example | |
| </Location></pre> | |
| </blockquote> | |
| <p> | |
| Files and directories within the project will be directly mapped | |
| into the URL namespace. For example, if the project contains a | |
| file "file.c" in a subdirectory "sub", then the URL for that | |
| file will be | |
| <span class="url">http://subversion.tigris.org/repos/example/sub/file.c</span>. | |
| </p> | |
| <h3>Initial Checkout</h3> | |
| <p> | |
| When the user performs the initial checkout of a Subversion | |
| project, the client will issue a series of <span | |
| class="method">PROPFIND</span> and <span | |
| class="method">GET</span> requests. These requests will traverse | |
| the repository, pick up some necessary metadata, and then fetch | |
| the latest revision. | |
| </p> | |
| <p class="comment"> | |
| describe the OPTIONS request for fetching the activity | |
| collection set. describe the sequence of PROPFINDs to reach the | |
| baseline collection. | |
| </p> | |
| <p class="comment"> | |
| <i>(moved here from below; need to rewrite)</i><br/> | |
| When the initial checkout was performed, Subversion fetched | |
| the <span class="prop">DAV:activity-collection-set</span> value | |
| and stored it as a property on each directory in the working copy. | |
| property for each | |
| collection. This property lists all of the locations on the | |
| server where an activity may be created. The first of these | |
| locations will be stored on the client for use during the commit | |
| process. | |
| </p> | |
| <p class="comment"> | |
| Should probably describe the metadata we fetch, and how a | |
| checkout of "not the latest" (e.g. by date or revision) will | |
| work. | |
| </p> | |
| <h3>Committing a Change</h3> | |
| <p> | |
| Subversion commits are modeled using the "activity" concept from | |
| DeltaV. An activity can be viewed as a transaction for a set of | |
| resources. | |
| </p> | |
| <h3>Creating the activity</h3> | |
| <p> | |
| At commit time, the Subversion client will retrieve the stored | |
| <span class="prop">DAV:activity-collection-set</span> value to | |
| know where it should create the activity. Next, | |
| the client will generate a UUID (a unique value) to use for the | |
| activity's location. Finally, the client will issue a | |
| <span class="method">MKACTIVITY</span> method request, where the Request-URL is | |
| composed from the activity location and the UUID. This request | |
| will construct an activity to hold all of the changes for the | |
| commit. | |
| </p> | |
| <p>Abbreviated summary:</p> | |
| <dl> | |
| <dt>At checkout time:</dt> | |
| <dd> | |
| <div>Request: <span class="method">OPTIONS</span> for | |
| <span class="prop">DAV:activity-collection-set</span></div> | |
| <div>Response: <span | |
| class="url">http://www.example.com/repos/foo/$svn/act/</span></div> | |
| </dd> | |
| <dt>At commit time:</dt> | |
| <dd> | |
| <div>Request: <span class="method">MKACTIVITY</span> | |
| <span class="url">http://www.example.com/repos/foo/$svn/act/01234567-89ab-cdef-0123-456789abcdef</span></div> | |
| <div>Response: 201 (Created)</div> | |
| </dd> | |
| </dl> | |
| <p> | |
| The <span class="method">CHECKOUT</span> method can specify an | |
| activity to use upon checkout. This feature is used to associate | |
| all items with the newly-created activity. | |
| </p> | |
| <h3>Storing the commit message</h3> | |
| <p class="comment"> | |
| talk about checking out the baseline and applying a PROPPATCH to | |
| the working baseline. | |
| </p> | |
| <h3>Mapping changes to WebDAV</h3> | |
| <p> | |
| A change set in Subversion is specified with a "tree delta" (see | |
| the SVN design for more details on the changes that can be | |
| placed into a tree delta). The tree delta will be unravelled | |
| into a set of requests. These requests will be one of the | |
| following forms: | |
| </p> | |
| <dl> | |
| <dt>Delete file or directory</dt> | |
| <dd> | |
| These changes are mapped onto a <span | |
| class="method">DELETE</span> operation. The version resource | |
| of the target's parent collection is checked out using the | |
| <span class="method">CHECKOUT</span> method (into the current | |
| activity). The target (name) is then deleted from the | |
| resulting working collection using the <span | |
| class="method">DELETE</span> method. | |
| <p></p> | |
| </dd> | |
| <dt>Add file</dt> | |
| <dd> | |
| This is modeled by performing a <span | |
| class="method">CHECKOUT</span> of the version resource of the | |
| target's parent collection. The new file is created within the | |
| resulting working collection using a <span | |
| class="method">PUT</span> request. Properties are applied | |
| using <span class="method">PROPPATCH</span>. | |
| <p></p> | |
| </dd> | |
| <dt>Add directory</dt> | |
| <dd> | |
| This is modeled by performing a <span | |
| class="method">CHECKOUT</span> on the version resource of the | |
| target's parent collection. The new directory is created | |
| within the resulting working collection with a <span | |
| class="method">MKCOL</span> request. Properties are applied | |
| using <span class="method">PROPPATCH</span>. | |
| <p></p> | |
| </dd> | |
| <dt>Add file or directory, with previous ancestory (a copy)</dt> | |
| <dd> | |
| <span class="comment">need to fix this section</span> | |
| <p> | |
| A tree delta can specify that a file/directory originates as | |
| a copy of another file/dir. This copy may be further | |
| modified by additional elements the tree delta. | |
| </p> | |
| <p> | |
| This change will be modeled by performing a | |
| <code>CHECKOUT</code> on the version resource of the parent | |
| collection which will contain the new resource. The | |
| <code>VERSION-CONTROL</code> method will create a new | |
| version-controlled resource (VCR) within the working | |
| collection, with the VCR's <code>DAV:checked-in</code> | |
| property referring to the ancestor's version resource. | |
| </p> | |
| <blockquote> | |
| <p><strong>Note:</strong> it appears that we will use | |
| <code>COPY</code> to copy the appropriate resource into the | |
| working collection. This will create a new version history | |
| which is then placed into the working collection. The | |
| version history will use the <code>DAV:precursor-set</code> | |
| property to specify the version resource of the ancestor.</p> | |
| <p> | |
| Because a version resource does not specify the revision, | |
| it will not be possible to <code>COPY</code> a version | |
| resource into the working collection -- it will not tell | |
| us what revision was copied. Instead, we will most likely | |
| copy a version resource out of the appropriate | |
| baseline. This implies the client must be able to map from | |
| a URL/revision pair to a baselined version resource URL. | |
| </p> | |
| <p> | |
| The second issue is whether/how we set the | |
| <code>DAV:precursor-set</code> property of the version | |
| history. Or, more precisely, how we synthesize the value | |
| from information stored in the repository. This is still | |
| under investigation. | |
| </p> | |
| </blockquote> | |
| </dd> | |
| <dt>Replace file/dir by another file/dir</dt> | |
| <dd> | |
| This change does not have a WebDAV modeling because tree | |
| deltas model it as two, sequential operations: a | |
| <em>delete</em>, followed by an <em>add</em>. | |
| <p></p> | |
| </dd> | |
| <dt>Moving a file or directory</dt> | |
| <dd> | |
| This change does not have a WebDAV modeling because tree | |
| deltas model it as two, distinct operations: a | |
| <em>delete</em>, and an <em>add</em> with previous ancestry. | |
| <p></p> | |
| </dd> | |
| <dt>Replace file</dt> | |
| <dd> | |
| This is modeled with a <span class="method">CHECKOUT</span> on | |
| the target's version resource, followed by a <span | |
| class="method">PUT</span> to the resulting working resource. | |
| <p></p> | |
| </dd> | |
| <dt>Replace directory</dt> | |
| <dd> | |
| In Subversion terms, "replace directory" means that additions, | |
| deletions, and other changes will occur <em>within</em> the | |
| directory. Each of these changes are modeled individually, and | |
| the change to the directory is performed | |
| implicitly. Therefore, this "change" has no particular mapping | |
| into WebDAV. | |
| <p></p> | |
| </dd> | |
| <dt>Property delta</dt> | |
| <dd> | |
| A property delta (against a file or directory) maps directly | |
| to a <span class="method">PROPPATCH</span> in WebDAV | |
| terms. The target's version resource will be checked out using | |
| <span class="method">CHECKOUT</span> and the <span | |
| class="method">PROPPATCH</span> will be applied to the | |
| resulting working resource. | |
| </dd> | |
| </dl> | |
| <h3>Final Commit</h3> | |
| <p> | |
| The final action of the commit process is to issue a <span | |
| class="method">MERGE</span> request to the Subversion server, | |
| specifying that the activity (created earlier) be checked in and | |
| the corresponding version-controlled resources be updated to | |
| refer to the new version resources. | |
| </p> | |
| <p class="comment"> | |
| the comment below is not quite right. talk about the working | |
| baseline, and how that is used to create a new baseline (with | |
| the commit message on it) | |
| </p> | |
| <p> | |
| The version-controlled resources are also baseline-controlled, | |
| which means that updates to them will automatically create a new | |
| baseline. In essence, the commit will create a new baseline | |
| corresponding to the new Subversion revision. | |
| </p> | |
| <h3>Example</h3> | |
| <p class="comment"> | |
| <strong>Warning:</strong> this section has not been updated to | |
| reflect some recent changes to the SVN-to-DAV mapping. Consider | |
| it out of date until this warning is removed. | |
| </p> | |
| <p> | |
| Consider the following set of operations and its corresponding | |
| tree delta (taken from the SVN design document): | |
| </p> | |
| <ol> | |
| <li>rename <code>/dir1/dir2</code> to <code>/dir1/dir4</code>,</li> | |
| <li>rename <code>/dir1/dir3</code> to <code>/dir1/dir2</code>, and</li> | |
| <li>move <code>file3</code> from <var>/dir1/dir4</var> to <var>/dir1/dir2</var>.</li> | |
| </ol> | |
| <pre><tree-delta> | |
| <replace name='dir1'> | |
| <directory> | |
| <tree-delta> | |
| <replace name='dir2'> | |
| <directory ancestor='/dir1/dir3'> (1) | |
| <tree-delta> | |
| <new name='file3'> (2) | |
| <file ancestor='/dir1/dir2/file3'/> | |
| </new> | |
| </tree-delta> | |
| </directory> | |
| </replace> | |
| <delete name='dir3'/> (3) | |
| <new name='dir4'> (4) | |
| <directory ancestor='/dir1/dir2'> | |
| <tree-delta> | |
| <delete name='file3'/> (5) | |
| </tree-delta> | |
| </directory> | |
| </new> | |
| </tree-delta> | |
| </directory> | |
| </replace> | |
| </tree-delta> | |
| </pre> | |
| <p> | |
| Walking through this delta, we map out the WebDAV requests | |
| listed below. The numbers in the above delta roughly correspond | |
| to the numbered entries below. The correspondence is not exact | |
| because a specific, resulting behavior is typically based on a | |
| combination of a few elements in the delta. | |
| </p> | |
| <ol> | |
| <li> | |
| The <code><directory ancestor="/dir1/dir3"></code> | |
| specifies that we are overwriting <code>/dir1/dir2</code> with | |
| <code>/dir1/dir3</code>. | |
| <p> | |
| <code>CHECKOUT /dir1/dir2/</code><br/> | |
| <i>(returns a working resource URL for the directory)</i> | |
| </p> | |
| <p> | |
| <code>COPY /dir1/dir3/</code><br/> | |
| <code>Destination: http://www.example.com/$svn/wrk/.../</code><br/> | |
| <code>Overwrite: T</code> | |
| </p> | |
| </li> | |
| <li> | |
| <code>/dir1/dir2/file3</code> is new (since we just overwrote | |
| the original <code>dir2</code> directory), and originates from | |
| <code>/dir1/dir2/file3</code>. Thus, we simply | |
| <code>COPY</code> the file into the target directory's working | |
| resource: | |
| <p> | |
| <code>COPY /dir1/dir2/file3</code><br/> | |
| <code>Destination: http://www.example.com/$svn/wrk/.../file3</code> | |
| </p> | |
| </li> | |
| <li> | |
| <p> | |
| <code>CHECKOUT /dir1/dir3/</code><br/> | |
| <i>(returns a working resource URL for the directory)</i> | |
| </p> | |
| <p> | |
| <code>DELETE /$svn/wrk/.../</code> | |
| </p> | |
| </li> | |
| <li> | |
| We are going to creating a new subdirectory (<code>dir4</code>) in the | |
| <code>/dir1</code> directory. Since we don't have | |
| <code>/dir1</code> checked out yet, we do so: | |
| <p> | |
| <code>CHECKOUT /dir1/</code><br/> | |
| <i>(returns a working resource URL for the directory)</i> | |
| </p> | |
| <p> | |
| And now we copy the right directory into the new working | |
| resource: | |
| </p> | |
| <p> | |
| <code>COPY /dir1/dir2/</code><br/> | |
| <code>Destination: http://www.example.com/$svn/wrk/.../dir4/</code> | |
| </p> | |
| </li> | |
| <li> | |
| The <code>COPY</code> created a complete set of working | |
| resources on the server, so we simply delete the part that we | |
| don't want: | |
| <p> | |
| <code>DELETE: /$svn/wrk/.../dir4/file3</code> | |
| </p> | |
| </li> | |
| </ol> | |
| <h3>URL Layout</h3> | |
| <p> | |
| The Subversion server exposes repositories at user-defined | |
| URLs. For example, the "foo" repository might be located at | |
| <span | |
| class="url">http://www.example.com/repos/foo/</span>. However, | |
| the server also requires a number of other resources to be | |
| exposed for proper operation. These additional resources will be | |
| associated with each repository in a location under the main | |
| repository URL. By default, this location is "<span | |
| class="url">$svn</span>". It may be changed by using the | |
| <code>SVNSpecialURI</code> directive: | |
| </p> | |
| <blockquote> | |
| <pre><Location /repos/foo> | |
| DAV svn | |
| SVNPath /home/svn-projects/foo | |
| SVNSpecialURI .special | |
| </Location></pre> | |
| </blockquote> | |
| <p> | |
| Underneath the location specified by <code>SVNSpecialURI</code>, | |
| we will expose several collections. Assuming we use the default | |
| of "<span class="url">$svn</span>", the collections are: | |
| </p> | |
| <dl> | |
| <dt><span class="url">$svn/act/</span></dt> | |
| <dd> | |
| This area is where activity resources are created. The client | |
| will pick a unique name within this collection and issue a | |
| <span class="method">MKACTIVITY</span> for that URL. The client will then use | |
| the activity in further interactions. | |
| <p> | |
| No methods are allowed on the <span class="url">$svn/act/</span> | |
| resource. | |
| </p> | |
| <blockquote> | |
| <p>Note: actually, we may want to allow a <code>PROPFIND</code> | |
| with a <code>Depth: 1</code> header to allow clients to | |
| enumerate the current activities.</p> | |
| </blockquote> | |
| <p> | |
| Only a subset of methods are allowed on the activities | |
| within the collection. They are: <span class="method">PROPFIND</span>, | |
| <span class="method">MERGE</span> (commit the activity), and | |
| <span class="method">DELETE</span> (abort the activity). | |
| </p> | |
| <p> | |
| Per the Delta-V specification, all activity resources will | |
| have a <span class="prop">DAV:resourcetype</span> of | |
| <span class="prop">DAV:activity</span>. | |
| </p> | |
| </dd> | |
| <dt><span class="url">$svn/his/</span></dt> | |
| <dd> | |
| <span class="comment">do something with this section; we | |
| actually don't use version history resources. in the future, | |
| they might be modeled like this</span> | |
| <p> | |
| This collection contains the version history resources for | |
| files and directories in a project. Its internal layout is | |
| completely server-defined. Clients will receive URLs into | |
| this collection (or a subcollection) from various responses. | |
| </p> | |
| <p> | |
| No methods are allowed on the <span class="url">$svn/his/</span> | |
| resource. | |
| </p> | |
| <p> | |
| Internally, the URL namespace is laid out with URLs of the | |
| following form: | |
| </p> | |
| <blockquote class="url"> | |
| <p>$svn/his/<var>node-id</var></p> | |
| </blockquote> | |
| <p> | |
| The <var>node-id</var> is an internal value | |
| that Subversion uses to reference individual files and | |
| directories. This <var>node-id</var> is a single integer | |
| defined by the Subversion repository. Note that this is an | |
| undotted node id, which is the base for the entire history | |
| of a given node in the repository. | |
| </p> | |
| <p> | |
| The <span class="prop">DAV:resourcetype</span> of the <var>node-id</var> | |
| collection is <span class="prop">DAV:version-history</span>. | |
| </p> | |
| <blockquote class="comment"> | |
| <p><strong>Note:</strong> the above information is probably not | |
| quite correct. The issue of linking one version history to | |
| another is still open. Further, I think that node 73 and | |
| node 73.4.1 are each version histories (where the latter is | |
| linked to the former). 73.x and 73.4.1.x are the versions | |
| within the version history.</p> | |
| </blockquote> | |
| </dd> | |
| <dt><span class="url">$svn/ver/</span></dt> | |
| <dd> | |
| This collection contains the version resources for the | |
| project. | |
| <p> | |
| No methods are allowed on the <span class="url">$svn/ver/</span> | |
| resource. | |
| </p> | |
| <p> | |
| The layout of this collection is internal to the server. For | |
| reference purposes here (and to describe the | |
| implementation), it is laid out as: | |
| </p> | |
| <blockquote class="url"> | |
| <p>$svn/ver/<var>node-id</var>/<var>path</var></p> | |
| </blockquote> | |
| <p> | |
| Only read-only methods are allowed against these resources | |
| (e.g. <span class="method">GET</span>, <span class="method">PROPFIND</span>, | |
| <span class="method">REPORT</span>); all other methods are illegal. | |
| </p> | |
| <p> | |
| The <span class="prop">DAV:resourcetype</span> of a version resource is | |
| simply the value of the resource at checkin time | |
| (e.g. <code><D:resourcetype/></code> or | |
| <code><D:resourcetype><D:collection/></D:resourcetype></code>). | |
| </p> | |
| </dd> | |
| <dt><span class="url">$svn/wrk/</span></dt> | |
| <dd> | |
| This collection contains working resources for the resources | |
| that have been checked out with the <span class="method">CHECKOUT</span> | |
| method. The form and construction of this collection is | |
| server-defined, but is also well-defined so that clients may | |
| interact properly with collection versions that have been | |
| checked out. | |
| <p> | |
| No methods are allowed on the <span class="method">$svn/wrk/</span> | |
| resource. | |
| </p> | |
| <p> | |
| For reference purposes, the working resource URLs are | |
| constructed as: | |
| </p> | |
| <blockquote class="url"> | |
| <p>$svn/wrk/<var>activity</var>/<var>path</var></p> | |
| </blockquote> | |
| <p> | |
| Any method is allowed on the working resources, but no | |
| methods are allowed on any of its parents. | |
| </p> | |
| <p> | |
| The <span class="prop">DAV:resourcetype</span> of the working resources | |
| follows normal resource typing: | |
| <code><D:resourcetype/></code> for regular working | |
| resources, and | |
| <code><D:resourcetype><D:collection/></D:resourcetype></code> | |
| for working collections. | |
| </p> | |
| </dd> | |
| <dt><span class="url">$svn/vcc/</span></dt> | |
| <dd> | |
| <span class="comment">This section is not yet complete.</span> | |
| <p> | |
| version-controlled configuration... | |
| </p> | |
| <p> | |
| <code>$svn/vcc/root</code> as a singleton. | |
| </p> | |
| </dd> | |
| <dt><code>$svn/bln/</code></dt> | |
| <dd> | |
| <span class="comment">This section is not yet complete.</span> | |
| <p> | |
| baselines... | |
| </p> | |
| <p> | |
| <code>$svn/bln/<var>rev</var>/</code> | |
| </p> | |
| </dd> | |
| <dt><code>$svn/wbl/</code></dt> | |
| <dd> | |
| <span class="comment">This section is not yet complete.</span> | |
| <p> | |
| working baseline... | |
| </p> | |
| </dd> | |
| <dt><code>$svn/bc/</code></dt> | |
| <dd> | |
| <span class="comment">This section is not yet complete.</span> | |
| <p> | |
| baseline collection... | |
| </p> | |
| </dd> | |
| </dl> | |
| <h3>Property Management (and History/Log Reporting)</h3> | |
| <p class="comment"> | |
| this section needs to be reworked. the properties occur on the | |
| FS revisions (and exposed via baselines). | |
| </p> | |
| <p> | |
| As mentioned before, Subversion properties map onto WebDAV | |
| properties. For history/log reporting, the following WebDAV | |
| properties will be applied to each baseline (a Subversion | |
| revision) and to each version resource created by the | |
| revision. Since these resources are all version resources, the | |
| properties below are read-only. | |
| </p> | |
| <dl> | |
| <dt><code>DAV:comment</code></dt> | |
| <dd> | |
| This is the standard (dead) property for specifying a checkin | |
| comment. | |
| <p></p> | |
| </dd> | |
| <dt><code>DAV:creator-displayname</code></dt> | |
| <dd> | |
| This is a (dead) property that is generated from Subversion's | |
| concept of the "user" who made a particular change. | |
| <p></p> | |
| </dd> | |
| <dt><code>DAV:creationdate</code></dt> | |
| <dd> | |
| This is a read-only live property created by the server at | |
| commit time. | |
| </dd> | |
| </dl> | |
| <p> | |
| The history for a specified file will be generated using the | |
| <code>REPORT</code> method and a | |
| <code>DAV:property-report</code> report. A typical history will | |
| fetch the three properties mentioned above for each version of | |
| the file/directory. | |
| </p> | |
| <p> | |
| Based on the client design, it may be important to specify other | |
| read-only live properties for information about versions. For | |
| example, how many lines were added/removed in a particular | |
| checkin for a file? Creating these live properties will be quite | |
| straight-forward, and driven by the client design over time. | |
| </p> | |
| <blockquote> | |
| <p>Note: if we do this, however, then we'd end up tying the client | |
| to the server. Of course, if the client were run against another | |
| DeltaV server which didn't report these properties, then we'd | |
| simply not display them in the UI. (e.g. graceful degradation of | |
| functionality)</p> | |
| </blockquote> | |
| <h3>Fetching Status and Updates</h3> | |
| <p> | |
| After the initial checkout, the client can request a status | |
| report (what has been changed on the client, pending a commit; | |
| what has been changed on the server, pending an update). The | |
| update process is similar, except that we also fetch the changes | |
| from the server. | |
| </p> | |
| <p> | |
| The local changes can be handled entirely on the client | |
| side. The Working Copy library can easily handle the detection | |
| and reporting of these changes. We're concerned with efficiently | |
| detecting what has changed on the server. | |
| </p> | |
| <p> | |
| While it would be possible to traverse the repository, fetching | |
| the current state, and comparing that to the client state, it | |
| would not be efficient. The Subversion design enables the server | |
| to easily compute what has changed (relative to the client), if | |
| it is given a description of the client state. | |
| </p> | |
| <p> | |
| The core of the <em>status</em> and <em>update</em> commands is | |
| based on a custom Subversion-specific WebDAV report. This custom | |
| report will transmit the state of the working copy to the | |
| server, and the server response will specify which resources | |
| will need to be updated (fetched). | |
| </p> | |
| <p> | |
| The request is a standard <code>REPORT</code> request, with a | |
| custom XML body. The body will use the standard Subversion | |
| technique of reporting a top-level revision number, and then | |
| only reporting children that have different revisions. The | |
| result of the report will use the same technique of reporting | |
| only the resources where a change is found. If a change is | |
| found, the server will provide a URL to the version resource to | |
| fetch for the changed resource. The server will also report the | |
| current revision number. | |
| </p> | |
| <blockquote class="comment"> | |
| <p>The XML DTDs for the request and response are TBD.</p> | |
| </blockquote> | |
| <blockquote> | |
| <p><small> | |
| The custom report will tie the client to only those servers | |
| which support the report, but a future version of the software | |
| will contain a fallback codepath, a graceful degradation, to | |
| support other DeltaV servers. | |
| </small></p> | |
| </blockquote> | |
| <p> | |
| When an updated is performed, the client will fetch each of the | |
| URLs (using <code>GET</code> requests) provided in the server | |
| response. | |
| </p> | |
| <p> | |
| <code>GET</code> (and <code>PUT</code>) operations will transfer | |
| content in a "diff" format when possible. The mechanics of this | |
| will follow the Internet Draft, titled | |
| <a href="http://www.ietf.org/internet-drafts/draft-mogul-http-delta-10.txt">Delta Encoding in HTTP</a>. | |
| </p> | |
| <h3>Entity Tags (etags)</h3> | |
| <p> | |
| Etags are required to be unique across all versions of a | |
| resource. Luckily, this | |
| is very easy for a version control system. Each etag will be | |
| simply be the repository's <em>node-id</em> for the resource. | |
| </p> | |
| <p> | |
| Etags are used to generate diffs, following the guidelines in | |
| the aforementioned draft: | |
| <a href="http://www.ietf.org/internet-drafts/draft-mogul-http-delta-10.txt">Delta Encoding in HTTP</a>. | |
| The problem then becomes how to get the etag for each file | |
| stored on the client (we don't need etags for directories since | |
| we never fetch them). During a <em>checkout</em> or | |
| <em>update</em> process, this is easy: the etag is provided in | |
| the HTTP response headers for each file retrieved. | |
| </p> | |
| <p> | |
| The other part of the problem is getting the etag after a | |
| <em>commit</em> has occurred. The <code>MERGE</code> response | |
| provides a way to request properties from the version resources | |
| which are created as part of the checkin of the activity. The | |
| etag (and other properties) can be fetched using that mechanism. | |
| </p> | |
| <h3>Tags and Branches</h3> | |
| <p> | |
| Tags and branches within Subversion are performed by copying | |
| from one area to another. For example: | |
| </p> | |
| <blockquote> | |
| <pre> | |
| [.../src/my-project]$ svn cp trunk tags/1.0.3-rc4 | |
| [.../src/my-project]$ svn commit | |
| </pre> | |
| </blockquote> | |
| <p> | |
| In the above example, <code>tags/1.0.3-rc4</code> should now be | |
| considered readonly and will always reflect the status of | |
| <code>trunk</code>. | |
| </p> | |
| <p> | |
| These copies are handled just like a regular commit. An activity | |
| is created with <span class="method">MKACTIVITY</span>, a | |
| working resource is created via <span | |
| class="method">CHECKOUT</span> (for the target directory; | |
| <code>tags/</code> in our example above), and then a <span | |
| class="method">COPY</span> is performed. The activity is then | |
| merged back into the repository with a <span | |
| class="method">MERGE</span> request. | |
| </p> | |
| <h3>Server Requirements</h3> | |
| <p class="comment"> | |
| <strong>Warning:</strong> this section is out of date. The | |
| DeltaV draft has gone through a number of revisions, and our use | |
| of DeltaV has changed some. | |
| </p> | |
| <h3>DAV Methods</h3> | |
| <p> | |
| The server will need to implement the following WebDAV methods | |
| for proper operation: | |
| </p> | |
| <ul> | |
| <li><span class="method">OPTIONS</span></li> | |
| <li><span class="method">GET</span></li> | |
| <li><span class="method">DELETE</span></li> | |
| <li><span class="method">COPY</span></li> | |
| <li><span class="method">PROPPATCH</span></li> | |
| <li><span class="method">PROPFIND</span></li> | |
| <li><span class="method">MKACTIVITY</span></li> | |
| <li><span class="method">CHECKOUT</span></li> | |
| <li><span class="method">MERGE</span></li> | |
| <li><span class="method">REPORT</span></li> | |
| </ul> | |
| <p> | |
| The following methods are not required by Subversion at this | |
| time: | |
| </p> | |
| <ul> | |
| <li><span class="method">CHECKIN</span></li> | |
| <li><span class="method">UNCHECKOUT</span></li> | |
| <li><span class="method">UPDATE</span></li> | |
| <li><span class="method">LABEL</span></li> | |
| <li><span class="method">VERSION-CONTROL</span></li> | |
| <li><span class="method">BASELINE-CONTROL</span></li> | |
| <li><span class="method">MKWORKSPACE</span></li> | |
| </ul> | |
| <h3>DAV Properties</h3> | |
| <p> | |
| The following DeltaV properties will be implemented: | |
| </p> | |
| <ul> | |
| <!-- resource properties --> | |
| <li><span class="prop">DAV:comment</span></li> | |
| <li><span class="prop">DAV:creator-displayname</span></li> | |
| <li><span class="prop">DAV:supported-method-set</span></li> | |
| <li><span class="prop">DAV:supported-live-property-set</span></li> | |
| <li><span class="prop">DAV:supported-report-set</span></li> | |
| <li><span class="prop">DAV:version-controlled-configuration</span></li> | |
| <!-- version-controlled resource properties --> | |
| <li><span class="prop">DAV:checked-in</span></li> | |
| <li> | |
| <span class="prop">DAV:auto-version</span> is a readonly, | |
| empty element (auto versioning not supported). | |
| </li> | |
| <!-- checked-out resource properties --> | |
| <li><span class="prop">DAV:checked-out</span></li> | |
| <li> | |
| <span class="prop">DAV:predecessor-set</span> | |
| <div><i> | |
| Note: the Subversion design document is not clear on the | |
| mechanics of how multiple predecessors are merged to create | |
| a single, new revision. When this clarifies, then | |
| <code>DAV:predecessor-set</code> may end up containing more | |
| than zero or one predecessor URLs | |
| </i></div> | |
| </li> | |
| <!-- version resource properties --> | |
| <!-- predecessor-set --> | |
| <li> | |
| <span class="prop">DAV:version-name</span> is simply the | |
| (global) revision number. | |
| </li> | |
| <li><span class="prop">DAV:checkout-fork</span></li> | |
| <li><span class="prop">DAV:checkin-fork</span></li> | |
| <!-- checked-out (working resource) properties --> | |
| <!-- checkout-fork, checkin-fork --> | |
| <li><span class="prop">DAV:auto-update</span></li> | |
| <li> | |
| <span class="prop">DAV:subbaseline-set</span> is a readonly, | |
| empty property (sub-baselines not supported). | |
| </li> | |
| <li> | |
| <span class="prop">DAV:unreserved</span> is set to | |
| <code>F</code>. | |
| </li> | |
| <!-- vcc properties --> | |
| <li><span class="prop">DAV:baseline-controlled-collection</span></li> | |
| <!-- baseline properties --> | |
| <!-- subbaseline-set --> | |
| <li><span class="prop">DAV:baseline-collection</span></li> | |
| <!-- activity properties --> | |
| <li> | |
| <span class="prop">DAV:subactivity-set</span> is a readonly, | |
| empty property (sub-activities not supported). | |
| </li> | |
| <!-- version-controlled collection properties --> | |
| <li> | |
| <span class="prop">DAV:eclipsed-set</span> is always empty | |
| (internal members can never be eclipsed). | |
| </li> | |
| </ul> | |
| <p> | |
| Contrary to the DeltaV specification, the following required | |
| properties will not be implemented: | |
| </p> | |
| <ul> | |
| <li> | |
| <span class="prop">DAV:successor-set</span> - this may be an | |
| expensive operation to synthesize this value. | |
| </li> | |
| <li> | |
| <span class="prop">DAV:checkout-set</span> - we do not record | |
| what has actually been checked out, but use the working | |
| resource URL to provide the necessary information; thus we | |
| have no record of the data to populate this property. | |
| </li> | |
| <li> | |
| <span class="prop">DAV:merge-set</span> - our <span | |
| class="method">MERGE</span> method is solely to support a | |
| commit. It doesn't really support the arbitrary merging | |
| defined within the spec. | |
| </li> | |
| <li> | |
| <span class="prop">DAV:auto-merge-set</span> - same as for | |
| <span class="prop">DAV:merge-set</span>. | |
| </li> | |
| <li> | |
| <span class="prop">DAV:activity-version-set</span> - | |
| activities are only used for working resources, so versions | |
| cannot be part of an activity. | |
| <div><i>maybe this should be defined as the empty set?</i></div> | |
| </li> | |
| <li> | |
| <span class="prop">DAV:activity-checkout-set</span> | |
| activities are only used for working resources, and we do not | |
| record what working resources "exist". | |
| </li> | |
| <li> | |
| <span class="prop">DAV:activity-set</span> - | |
| activities are only used for working resources, so versions | |
| cannot be part of an activity. | |
| <div><i>maybe this should be defined as the empty set?</i></div> | |
| </li> | |
| <li> | |
| <span class="prop">DAV:version-controlled-binding-set</span> - | |
| we do not have version history resources to include in the | |
| property. | |
| </li> | |
| </ul> | |
| <h3>OPTIONS</h3> | |
| <p> | |
| The <span class="method">OPTIONS</span> request will signal that | |
| it supports the following DAV features: | |
| </p> | |
| <ul> | |
| <li><code>1</code></li> | |
| <li><code>2</code></li> | |
| <li><code>version-control</code></li> | |
| <li><code>checkout</code></li> | |
| <li><code>working-resource</code></li> | |
| <li><code>merge</code></li> | |
| <li><code>baseline</code></li> | |
| <li><code>activity</code></li> | |
| <li><code>version-controlled-collection</code></li> | |
| </ul> | |
| <h3>Reports</h3> | |
| <p> | |
| The <span class="prop">DAV:supported-report-set</span> property | |
| will signal support for the following reports: | |
| </p> | |
| <ul> | |
| <li>svn:update-report</li> | |
| <li>svn:log-report</li> | |
| </ul> | |
| <p> | |
| These reports are available only on the "public" resources (the | |
| VCRs). They are not available on the resources within the | |
| <span class="url">$svn/</span> area. | |
| </p> | |
| <h3>Notes, reminders</h3> | |
| <p> | |
| Discuss timeouts and auto-purge of activities (and the related | |
| working resources). | |
| <br/> | |
| Discuss the activity database maintained by mod_dav_svn. | |
| <br/> | |
| Discuss other implementation details of ra_dav and mod_dav_svn. | |
| </p> | |
| <h3><a name="rationale">Appendix A: Rationale</a></h3> | |
| <p> | |
| Several times, people have asked, "Why choose | |
| HTTP/WebDAV/DeltaV? That seems awfully bloated and | |
| ill-suited. Why didn't you design a custom, well-tuned protocol? | |
| Or maybe use the CVS protocol?" Listed below are a number of | |
| reasons for our choice of WebDAV as our network protocol. | |
| </p> | |
| <blockquote> | |
| <p><small> | |
| While this list could certainly be expanded with more reasons | |
| (and to be fair, with a list of reasons why WebDAV was a poor | |
| choice), it certainly demonstrates the basic reasons for our | |
| choice. | |
| </small></p> | |
| </blockquote> | |
| <blockquote> | |
| <p><small> | |
| Note: this list came from an email note, so the tone and point | |
| of view might be a bit off. Further word-smithing is | |
| welcome... | |
| </small></p> | |
| </blockquote> | |
| <h3>Builtin web browsing of the repository</h3> | |
| <blockquote> | |
| <p>For example, take a | |
| look at: | |
| <a href="http://svn.apache.org/repos/asf/subversion/trunk/README">http://svn.apache.org/repos/asf/subversion/trunk/README</a> | |
| (that's the HEAD right there; we also have URLs for every | |
| previous revision of every file)</p> | |
| </blockquote> | |
| <h3>DAV-based browsing</h3> | |
| <blockquote> | |
| <p>Use Web Folders or WebDrive or somesuch on | |
| your Windows box (or Windows XP's native DAV mounts) to browse | |
| the SVN repository with Windows Explorer. Mac OS X has builtin | |
| DAV server mounting. Nautilus has DAV capabilities. Then you | |
| have your Open Source tools such as cadaver, Goliath, etc.</p> | |
| </blockquote> | |
| <h3>People can use existing libraries</h3> | |
| <blockquote> | |
| <p>I couldn't even begin to count the number of HTTP tools and | |
| libraries available. If we had designed our own protocol, then | |
| we would have /none/ of those benefits. Heck, two HTTP library | |
| implementors (Joe Orton of Neon, and Daniel Stenberg of CURL) | |
| are regulars here. we wouldn't get that benefit. I've used | |
| Python's httplib (and a davlib of my own) to do a lot of testing | |
| of our server. No need to go and roll new protocol libraries.</p> | |
| </blockquote> | |
| <h3>Existing tools</h3> | |
| <blockquote> | |
| <p>One word: Ethereal :-) When we capture network traces, Ethereal | |
| already knows about HTTP. It's quite nice, but I know there are | |
| even better ones out there. But we also have other tools like | |
| squid and other (caching) proxies (see the next item).</p> | |
| </blockquote> | |
| <h3>Caching proxies</h3> | |
| <blockquote> | |
| <p>Subversion will work great with caching proxies. There is no | |
| longer a need for specialized tools like "cvsup". Just drop in a | |
| caching proxy, and you've already got your distributed read-only | |
| repository. That European dev team can just drop in the cache | |
| between them and the US server and their checkouts/updates will | |
| get cached for the benefit of the other team members. Commits | |
| will flow through, back to the US-based server.</p> | |
| </blockquote> | |
| <h3>Sophisticated and broad-choice authentication</h3> | |
| <blockquote> | |
| <p>We don't have to reimplement an authentication scheme for a new | |
| protocol. We can use all of the various schemes that have been | |
| defined for HTTP. Ever look at the CVS protocol? Ever see the "I | |
| Love You" or "I Hate You" lines? :-) That is all part of | |
| creating a new authentication scheme. But we get to use SSL and | |
| certificate-based auth if we want. Kerberos. NTLM. or even just | |
| simple Basic or Digest. And our users can come from text files, | |
| database, LDAP, or PAM. We don't have to reinvent the wheel cuz | |
| it is all available for Apache already.</p> | |
| </blockquote> | |
| <h3>Awesome network server</h3> | |
| <blockquote> | |
| <p>We don't have to worry about how to portably set TCP_CORK for | |
| optimal network packets. We don't have to worry about when | |
| sendfile() makes sense, or if it is available. We don't have to | |
| worry about dropped client connections, how to best use threads | |
| and processes to scale, request management, monitoring, logging, | |
| etc. Apache gives us all of that and a ton more. I *really* | |
| would not want to do that through xinetd. I mean... setting | |
| TCP_CORK on stdout? freaky :-)</p> | |
| </blockquote> | |
| <h3>Well-defined on-wire compression</h3> | |
| <blockquote> | |
| <p>We already have on-wire compression, similar to CVS's "-z#" | |
| switch. And we didn't do anything. The client library and server | |
| that we use just support it automatically for us, according to | |
| RFC 2616.</p> | |
| </blockquote> | |
| <h3>Future interoperability</h3> | |
| <blockquote> | |
| <p>In the future, we'll be able to interoperate with a multitude of | |
| IDEs and other WebDAV/DeltaV clients. As DeltaV becomes more | |
| prevalent, IDEs could very well use it for source code | |
| management, and we'll be right there without needing to write | |
| some MS/SCC library to interface to the tool.</p> | |
| </blockquote> | |
| <hr/> | |
| <address><a href="mailto:gstein@lyra.org">Greg Stein</a></address> | |
| <!-- Created: Thu Aug 10 19:14:20 PDT 2000 --> | |
| <!-- hhmts start --> | |
| Last modified: Fri Jan 25 12:54:20 PST 2002 | |
| <!-- hhmts end --> | |
| </div> | |
| </body> | |
| </html> |