Ben's Quick Summary of WebDAV and DeltaV ========================================= * WebDAV: RFC 2518. Extends the standard HTTP methods to make web servers behave as traditional fileservers, complete with a locking model and meta-data properties. * DeltaV: RFC 3253. Adds more HTTP methods to WebDAV, introducing versioning concepts. Provides a number of flexible versioning models that servers can support, and some backwards-compatibility modes for older WebDAV or HTTP/1.1 clients. ---------------------------------------- WebDAV ====== Key concepts introduced: properties, collections, locking. New HTTP client request headers: {Depth, Destination, If, ...} New HTTP server response headers: {DAV, ...} * Property: a meta-data name/value. every property exists in some unique "namespace", defined using xml namespaces. - a "live" property is one that is controlled by the server, like a file's content-length, for example, or a file's checked-in/checked-out state. often the property is read-only; if not, the server enforces the propval's syntax/semantics. - a "dead" property is one that is invented and controlled by a user, just like file contents. - new HTTP methods: PROPFIND, PROPPATCH to change propval. * collection: a directory. contains a bunch of URIs and has props. - each child is called a 'member' URI. each internal member URI must be relative to parent collection. - collection URIs are supposed to end with trailing slashes. servers should auto-append them if not present. - new HTTP method: MKCOL to create collection. * locking: a way of serializing access to a resource. - locking is totally optional -- the only 'flexible' part of the WebDAV spec. a WebDAV server may support locking to any degree: either not at all, or some combination of exclusive or shared locks. An OPTIONS response can return a header of DAV: 1 or DAV: 2. Level-2 support means locking is available. - new HTTP method: LOCK. creates a lock and attaches it to the resource. the server returns a 'lock token' to the client, which is defined to be any universally unique URI. the 'lock' attached to the resource has these properties: * owner: some authenticated username * token: the specific lock identifier * scope: either "exclusive" or "shared" * type: "write". [other types may exist someday] * depth: for a collection, either 0 or infinity. * timeout: some value in seconds - exclusive locks behave how you think -- only one per resource allowed. shared locks, on the other hand, are just for communication -- any number of them can be attached. - lock tokens are *not* secret: anyone can query the "DAV:lockdiscovery" property to see all the locks attached to a resource, which includes detailed descriptions of every field above. - to remove a lock with UNLOCK, or to modify something with an exclusive lock, the client must provide *two* things: 1. authentication/authorization. prove you own and/or are allowed to mess with the lock. this happens via existing HTTP methods. 2. the lock token, i.e. the "name" of the lock. (this requirement also prevents some non-DAV aware program from using your auth credentials and accidentally doing an ignorant PUT. think of it as credentials for your client software!) - 'DAV:supportedlock' live property: indicates what kinds of locking is allowed on a resource. - the rfc defines an 'opaquelocktoken' scheme that all dav servers must know how to understand: clients may generate and post them in an If: header. - a collection can have a lock of either Depth 0 or Infinity. a lock on a collection prevents adding/removing member URIs. if a lock-holder adds something to a deeply locked collection, then the newly added member becomes part of the same write lock. - a 'null resource' (which normally returns 404) can be locked, in order to reserve a name. see section 7.4. * other methods added by WebDAV: - COPY: - copies resource to Destination: header. - optional "Overwrite: [T | F]" header defaults to T. - for collections, either Depth: [0 | infinity] allowed. - client can specify how to behave when copying props. - MOVE - defined to be COPY + DELETE, but an atomic operation. ------------------------------------------------------------------------- DeltaV ====== Models ====== A DeltaV server can support two different ways of working: server-side working copies, and client-side working copies. These systems aren't mutually exclusive at all. An OPTIONS request reveals which systems the server supports. The General Concepts ==================== If you understand this, everything will become really clear. These are the fundamentals. DeltaV allows you version any kind of resource -- a file, a collection, whatever. * If you take a resource on a server and put it under version control (using the VERSION-CONTROL method), a "Version Controlled Resource", or VCR, is created. A VCR is a special thing: it's a unique, permanent URL used to talk about an entity under version control, no matter how many times it changes. * Every time you change a VCR (discussed below), a new "Version Resource" is created, or VR. The VR is also a unique, permanent URL, representing some immutable object on the server; it represents the contents and (dead) properties of the VCR at one particular moment in time. * At any given time, a VCR has a "pointer" to some particular VR of itself. The pointer is just a property, called "DAV:checked-in". By definition, the contents of the VCR are always equal to the contents of the VR it points to. If you change the pointer to a different VR, the VCR's contents magically change to match. * All of a VCR's VR objects need to be organized somehow. And in fact, they *are* organized into a little tree of predecessors and successors. It turns out that every VCR has a "history" resource sitting in the background. (The history resource may or may not be directly accessible, depending on whether the server supports the 'Version History' feature.) Regardless, a VCR's history resource is a container that contains all of the VRs, organized into a tree. You might think of a history resource like an RCS file... except that the history is allowed to contain 'forks', i.e. a VR in the history might have multiple predecessors or successors. Also, each VR in a history can have a human-readable "label" attached to it, so it's easier to talk about which VR you want. Changing a VCR ============== So, how do you make a change to VCR, then? It all depends on what deltaV features the server supports. * If the user is using the server-side working-copy model: - The client creates something called a 'workspace', using MKWORKSPACE. - CHECKOUT a VCR into the workspace. The VCR's 'DAV:checked-in' property suddenly becomes a 'DAV:checked-out' property... but it still points to the same VR. - Use PUT and PROPATCH to change the contents or dead props of the VCR. If you want to revert everything, just UNCHECKOUT. - CHECKIN the VCR. A new VR is created in the VCR's history, and the 'DAV:checked-out' property becomes a 'DAV:checked-in' property, pointing to the new VR. * If the user is using the client-side working-copy model: - The client creates something called an 'activity', using MKACTIVITY. - CHECKOUT a VR into the activity. This creates a temporary 'working resource' (WR) in the activity. The VCR's 'DAV:checked-in' property suddenly becomes a 'DAV:checked-out' property... but it still points to the same VR. The WR has a 'DAV:checked-out' property that points to VR as well. - Use PUT and PROPATCH to change the contents or dead props of the WR. If you want to revert everything, just UNCHECKOUT. - CHECKIN the WR. A new VR is created in the VCR's history, and the VCR's 'DAV:checked-in' property points to it. And normally, the temporary WR is deleted. See? Not such a big deal. Ahem. Auto-Versioning =============== What if some regular WebDAV client tries to use a deltaV server? Or an even dumber HTTP 1.1 client? If the server supports the 'auto-versioning' feature, then all resources gain a new live property called 'DAV:auto-version'. The value of this property indicates how the server should behave when a non-deltaV client does an ignorant PUT or PROPPATCH on a resource. I won't go into detail, but there are many possible behaviors: * do an implicit (auto-) CHECKOUT and CHECKIN. * auto-CHECKOUT, and wait for a lock to vanish before auto-CHECKIN. * same as above, but if not locked, wait for an explicit CHECKIN. * require a lock. LOCK causes auto-CHECKOUT, UNLOCK causes auto-CHECKIN. Basic Features ============== DeltaV has a bunch of "basic features", and a bunch of "advanced features". Here are the basic features, in a nutshell. * Version Control feature * new VERSION-CONTROL method to create a VCR. * resources gain a whole bunch of new live props (not all listed here), such some of which include DAV:checked-[in|out], DAV:auto-version, DAV:comment, the author. VRs have properties that describe lists of successor and predecessor VRs. * new REPORT method. two 'standard' reports are defined, but custom reports can be created. * Checkout-in-place feature * new CHECKOUT, CHECKIN, UNCHECKOUT methods, which are able to modify VCRs in-place. * Version History feature * version histories become tangible URLs. introduce new dav resourcetype called 'DAV:version-history'. * all VCRs and VR's gain a 'DAV:version-history' prop that points to their history resource. * a version-history has a 'DAV:version-set' property that lists all VRs it contains, and a 'DAV:root-version' that points to the very first VR in the history. * a special REPORT allows one to convert a version-history URL into the VCR it represents. (i.e. reverse-lookup.) * Workspace feature * MKWORKSPACE creates a server-side working area. an OPTIONS request can tell you where the client is allowed to do this. * the workspace resource has a property that lists all the resources it contains. regular resources have a property indicating what workspace they're in. * The workspace can hold unversioned items put there by PUT & MKCOL. It can hold VCRs via CHECKOUT. * Special: the VERSION-CONTROL method can create a *new* VCR from a history. If two people both CHECKIN VCRs created from the same history resource, then poof... the history develops forks! * Update feature * UPDATE method is able to tweak a VCR to "point" to a new VR. Very simple! * Label feature * LABEL method allows you to attach a human-readable name to a particular VR. * Each VR can have many names. They're listed in a 'DAV:label-name-set' property. * New http request header, "Label:", can be used to target a specific VR of a VCR. This works when doing a GET of a VCR. It also works as you think on COPY, CHECKOUT, UDPATE, etc. * Working Resource feature * This feature essentially allows client-side working copies to synchronize their data with the server. * all VRs gain two properties that control whether or not histories can (or should) contain forks. * a CHECKOUT of a VR creates a temporary 'working resource' (WR), which can then be modified. When the WR is checked in, a new VR is created as usual, the WR vanishes, and the VCR is updated to point to the VR as usual. * note that this technique is an alternative to the Checkout-in-place feature, whereby VCRs are directly checked out and modified. Advanced Features ================= The advanced features of deltaV introduce a bunch of new concepts. Here are the fundamentals. [Whenever I say, "points to", I'm talking about some object leading to another object via a specific property.] * A "configuration" is a set of VCRs. In particular, it contains a "root collection" which organizes the VCRs in some way. Note that this is _different_ than a versioned collection. The main difference is that a collection is a *single* resource which contains dead-props and some directory-entries; its VRs just capture various states of the props and dirents. But it's just ONE resource. A configuration, however, is a SET of VCRs. The VCRs may not necessarily be related to each other, either. A configuration is a flexible thing -- its VCRs can be tweaked to point to different VRs, however you want, with no versioning happening in the background. A collection, on the other hand, has a static set of dirents; to change them, you have to do a CHECKOUT, CHECKIN, which results in a new, static collection VR. * A "baseline" is a special kind of resource which remembers this state of a configuration... it knows exactly which VR each VCR in the configuration should point to. Just like a VR is a 'snapshot' of a VCR, a baseline is a 'snapshot' of the configuration. And just like a VR, a baseline can have a human label too. * Another kind of resource is a "version controlled configuration", or VCC. This resource floats out in space; its sole purpose is to magically connect a configuration to a baseline. Specifically, each VCR in the configuration points to the VCC, and the VCC points to a baseline. And here's the usual magic: if you make the VCC point to a different baseline, then poof, the whole configuration suddenly switches to the baseline. (That is, all of the configuration's VCRs suddenly point to the specific VRs of the baseline.) * Finally, it's worth mentioning that a baseline resource points to a "baseline collection" resource. This collection is a tree made up of the VRs in the baseline, easily browseable. You can think of it as a "what-if" sort of preview -- i.e. "what would the configuration look like if I made its VCC point to this baseline?" It also means people can view a baseline in action, *without* having to tweak a VCC, which might require write access of some kind. Got all that? Good. Make some pictures. :-) How to create new baselines =========================== The "in-place" method: Get this. A VCC is really just a special kind of VCR! But it's a VCR which represents the *whole state* of a configuration. Just like a normal VCR, the VCC's "DAV:checked-in" property points to a baseline, which just a special kind of VR. That means you can do a CHECKOUT of the VCC in-place... then tweak the configuration to point to a new set of VR's... then CHECKIN the VCC. Poof, a new baseline is created which captures your new configuration state. And the VCC now points to that new baseline. The "working resource" method: Okay, so a baseline is a special kind of VR. Fine, so we do a CHECKOUT of it, and get a "working baseline", which a special kind of WR. Now, assuming you're using this method all around, you checkout the configuration's various VRs as WRs, modify the WRs, and check them back in to create new VRs. Finally, you CHECKIN the working baseline, which creates a new baseline that captures the state of the configuration. (The working baseline isn't something you tweak directly; it's more like a token used at CHECKIN time.) How Merging Works... at least for SVN. ================= The deltaV MERGE command is very fancy. It tracks merge ancestors in properties, and sets flags for clients to manually resolve conflicts on the server. Subversion uses MERGE in a simpler way: 1. We checkout a bunch of VRs into an activity, and patch them as a bunch of WRs. 2. We checkout a "working baseline" into the activity, from whatever baseline represents the HEAD svn revision. 3. We issue a MERGE request with the activity as the source. By definition, this causes the whole activity to be auto-checked-in. First each WR in the activity is checked-in, causing the configuration to morph. Then the working-baseline in the activity is checked-in, which creates a new baseline that captures the configuration state. Of course, mod_dav_svn doesn't actually do all the checkin stuff; but what's important is that the *result* of the MERGE is exactly as IF all this stuff had happened. And that's all that matters.