Date: 5/3/2007 9:45:00 PM
© 2007 Microsoft Corporation. This specification licensed under the Creative Commons Attribution 3.0 United States copyright license, available at: http://creativecommons.org/licenses/by/3.0/us/legalcode. All other rights reserved.
PDF version of this specification
The key issues that Live Contacts faces in terms of designing a protocol to let third parties access it are:
Simplicity – The target audience for Web3S are web developers and their code runs in a dizzying array of operating systems, application execution environments, programming languages, tool kits, etc. Many of these environments are completely custom so we can’t just hand out sample code for all of them. This means that many people wanting to interact with us will have to build their own libraries to do so from scratch. As such it is critical that our protocol be as simple as possible. We have therefore chosen to take a straight forward HTTP approach where our resources are all URI addressable and use the standard RFC 2616 methods (DELETE/GET/PUT/POST). We have introduced, however, a new method – UPDATE. This method was introduced to deal with a specific issue that comes up with some of the more complex schemas. We have also defined a very simple data infoset that can be easily serialized into/out of XML and JSON. We feel that there are important communities that want to interact with us via both XML and JSON so we wanted a system simple enough to properly support both.
Cost of Read/Writes – Although Live Contacts presents a view of a single coherent data structure that contains all the information in a particular address book in reality the data is spread across numerous tables. Therefore when someone asks for an entire address book their request will kick off numerous read requests. Similarly when someone asks to update an entire contact or even an entire address book their update will cause numerous writes to many tables.
To address this problem every value in an address book is individually addressable with a URL using a path language (e.g. https://example.com/.../com.example.contacts/com.example.contact(123)/com.example.firstname). Therefore every single part of the address book is an addressable resource that can be interacted with using DELETE/GET/POST/PUT/UPDATE HTTP methods. This enables read and writes to occur at the level that makes most sense. It also has the happy side effect of enabling scenarios we never thought of by giving names to everything. Naming is power and in Web3S everything has a publicly addressable name.
In addition all writes are merge, not replacement based. In a replacement system if someone wanted to update a contact’s value they would have to upload the entire contact, even if they are just changing one value. This is prohibitively expensive for Live Contacts as it requires touching many tables without actually doing any useful work. So instead we specify the use of merge semantics. Only explicitly named fields with no values will be changed, all other fields will be ignored. This enables write requests to only specify values that need to be changed.
Versioning – Live Contacts is constantly adding new fields to its address book schema. This creates a challenge because we cannot rely on clients being updated when new fields are added. So it’s critical that both older clients and newer clients can coexist with Live Contacts data without stepping on each other.
To address this issue in the case of querying content (e.g. GET) we require that all clients implement an ignore rule – that is, clients must ignore data they don’t recognize. This means that when new values are added older clients won’t ‘see’ them and thus not break.
In the case of writes (e.g. PUT/POST/UPDATE) we use merge semantics. This means that only fields that are explicitly specified by the client are changed, other fields are left alone. So if a V1 client updates a contact with V2 fields none of the V1 client’s update requests will affect the V2 fields since none of those fields will be mentioned in the V1 client’s request.
Web Structured, Schema’d & Searchable (Web3S)
6 Syntax for representing a Web3S Infoset Instance
7 Addressing Web3S Information Items in HTTP
8.1 Common Requirements for all MIME types
8.2 Application/Web3S+xml Mime Type
8.3 Application/Web3S+xml with Merge Semantics
8.4 Application/Web3SDelta+xml Mime Type
8.5 Application/Web3SDefPage+xml Mime Type
9 Web3S Resources & HTTP Methods
9.1 Common Requirements For All Web3S Methods
9.1.1 Well Formed Request-URI Requirement
9.1.3 511 – Response Too Large
9.4 PUT/POST/DELETE/UPDATE Common Requirements
9.7 PUT/UPDATE Common Requirements
10.2 Web3S Location Information
10.3 Sort Query Segment Extension
10.4 XPATH Query Segment Extension
10.6 Serializing the Web3S Infoset into/out of JSON
Information Set (Infoset) – A model that represents the information Web3S can describe.
Schema – A theoretical entity that captures the syntax and semantics of a Web3S resource, the actual representation of the schema (if any) is not constrained by this spec. (Read: No, this has nothing to do with XML Schema.)
Single Valued – An element information item (EII) whose schema forbids it have any sibling EIIs with the same name.
Multi-valued – An EII whose schema explicitly allows or even requires that the EII have siblings with the same name.
Root EII – The EII that roots an instance of the Web3S Infoset.
Non-Web3S Prefix Path – The part of a HTTP URL path that points to a Web3S root EII. For example, if the root EII com.example.lists is addressable as http://example.com/web3sparser/joesstuff/com.example.lists and com.example.lists is a Web3S resource then web3sparser/joestuff is the non-Web3S prefix path.
Full Name – In the case of single valued EIIs this is the value of the name property of the EII. In the case of multi-valued EIIs this is the combination of the value of the name and ID properties.
Annotation Command – In the context of Application/Web3SDefPage+xml and Application/Web3SDelta+xml this is an XML element included in the XML serialization that is intended to be interpreted as a command to the parser of the message rather than a description of a member of the Web3S infoset.
A Web3S client wishes to get its first copy of a user’s address book. The address book is represented as an XML document. Each element in the address book is individually addressable via XPATH style syntax in the request URI. But to kick things off the client asks for the entire address book.
GET /someuser@example.com/LiveContacts/com.live.livecontacts.livecontacts HTTP/1.1
Host: cumulus.services.live.com
Accept: application/Web3S+xml
…
HTTP/1.1 200 OK
Content-Type: application/Web3S+xml
…
<LiveContacts xmlns=”Web3SBase:com.live.livecontacts”
xmlns:Web3S = “Web3S:”>
…
<Contacts>
<Contact>
<Web3S:ID>123ABC</Web3S:ID>
<Profiles>
<Personal>
<FirstName>Karina</FirstName>
<MiddleName>Normann</MiddleName>
<LastName>jacobsen</LastName>
</Personal>
</Profiles>
<Phones>
<Phone>
<Web3S:ID>9993</Web3S:ID>
<Number>+15555555555</Number>
</Phone>
<Phone>
<Web3S:ID>123A</Web3S:ID>
<Number>+15555551234</Number>
</Phone>
</Phones>
</Contact>
</Contacts>
</addressbook>
Example 1 - GET request/response for the contents of an address book
All elements in the Web3S infoset are named using reverse domain names. So the ‘proper’ name of the root element is com.live.livecontacts.addressbook. To make it easy to serialize into XML we split the name such that the last segment becomes the XML localname and the rest of the DNS name, prefixed with the protocol identifier Web3SBase becomes the namespace.
The Web3S infoset also recognizes the difference between single valued and multi-valued elements. A multi-valued element is one that can appear multiple times in the schema. In the GET both com.live.livecontacts.contact and com.live.livecontacts.phone are examples of multi-valued elements. Multi-valued elements always have an ID that enables multiple values of the elements to be distinguished from each other.
PUT /someuser@example.com/LiveContacts/com.live.livecontacts.livecontacts/com.live.livecontacts.contacts/com.live.livecontacts.contact(123ABC) HTTP/1.1
Host: cumulus.services.live.com
Content-Type: application/Web3S+xml
…
<Contact xmlns=”Web3SBase:com.live.livecontacts”
xmlns:Web3S = “Web3S:”>
<Profiles>
<Personal>
<lastname>Jakobsen</lastname>
</Personal>
</Profiles>
<Phones>
<Phone>
<Web3S:ID>123A</Web3S:ID>
<Number>+15555555678</Number>
</Phone>
</Phones>
</Contact>
HTTP/1.1 200 OK
…
Example 2 - A PUT request/response to update a last name and number in an address book
The PUT is addressed to the contact element with the ID 123ABC and yes, the ID element is intentionally omitted in the body of the request. The PUT instructs that com.live.livecontacts.lastname and com.live.livecontacts.number be changed. All other values are left unaltered as PUT with the application/Web3S+xml MIME type uses merge semantics.
POST /someuser@example.com/LiveContacts/com.live.livecontacts.livecontacts/com.live.livecontacts.contacts HTTP/1.1
Host: cumulus.services.live.com
Content-Type: application/Web3S+xml
…
<Contact xmlns=”Web3SBase:com.live.livecontacts”
xmlns:Web3s = “Web3S:”>
<Web3s:ID/>
<Profiles>
<Personal>
<FirstName>Manish</FirstName>
</Personal>
</Profiles>
</Contact>
HTTP/1.1 201 Created
Location: http://cumulus.services.live.com/someuser@example.com/com.live.livecontacts.livecontacts/com.live.livecontacts.constacts/com.example.contact(43432)
Content-Type: application/Web3s+xml
…
<Contact xmlns=”Web3SBase:com.example”
xmlns:Web3s = “Web3S:”>
<Web3s:ID>43432</Web3s:ID>
<Profiles>
<Personal>
<FirstName>Manish</FirstName>
</Personal>
</Profiles>
</Contact>
Example 3 - A POST request/response to add an entry to an address book
In this example the client appends a new contact using POST to the address book. The IDs are left empty because the server has to decide on their value.
DELETE /someuser@example.com/LiveContacts/com.example.addressbook/com.example.contact(123ABC)/com.example.phones/com.example.phone(9993) HTTP/1.1
Host: cumulus.services.live.com
…
HTTP/1.1 200 OK
…
Example 4 - DELETE request/response to remove a phone number from an address book
Using the same URI syntax it’s possible to delete at any level, in this case an individual number is deleted.
UPDATE /someuser@example.com/LiveContacts/com.live.livecontacts.livecontacts HTTP/1.1
Host: cumulus.services.live.com
Content-Type: application/Web3SDelta+xml
…
<LiveContacts xmlns=”Web3SBase:com.example”
xmlns:Web3S = “Web3S:”>
<Contacts>
<Contact>
<Web3S:ID>123ABC</Web3S:ID>
<Profiles>
<Personal>
<LastName>Jakobsen</LastName>
</Personal>
</Profiles>
<Phones>
<Web3S:delete>
<Phone>
<Web3S:ID>9993</Web3S:ID>
</Phone>
</Web3S:delete>
<Phone>
<Web3S:ID>123A</Web3S:ID>
<Number>+15555555678</Number>
</Phone>
</Phones>
</Contact>
<Contact>
<Web3S:ID/>
<FirstName>Manish</FirstName>
</Contact>
</LiveContacts>
HTTP/1.1 200 OK
…
Example 5 - Use UPDATE to perform the same actions as the previous three methods
UPDATE is used by Web3S to enable multiple simultaneous changes to a data structure. The method was necessitated by more complex schemas where fields had dependent values and therefore certain changes could only be made to the schema if all parts of the change were made at once. In the previous example the four changes made by the previous three methods (change the com.live.livecontacts.lastname and com.live.live.contacts.phone elements, delete a phone number and add a new contact) are all made in a single method request.
The Web3S infoset consists of two information items, the element information item (EII) and the string information item (SII).
For modeling purposes each of the externally viewable representation of these information items is described by the properties specified below. The manifestation of the information items on the wire is determined by the serialization in use.
Element Information Item (EII) Properties
|
Property Name |
Property Description |
|
Name |
A globally unique name consisting of a reverse DNS name (e.g. com.live.livecontacts.firstname).
Note however that RFC 3490 encoding is not necessary, unicode characters can be used directly at the infoset level. How this translates to serializations (from URLs to XML to JSON) depends on the serialization’s own character encoding rules. |
|
Parent |
If the EII is the root then this value is empty. Otherwise this value must point to a single EII that contains this EII.
EIIs must always form acyclic single rooted trees. |
|
Children |
This value can be: · empty, · point to a single string information item or · point to a collection of element information items. |
|
ID |
Used to disambiguate multiple sibling instances of EIIs that have the same name.
This value does not exist for single valued EIIs. This value is a string for multi-valued EIIs.
ID values are only guaranteed to be unique amongst sibling EIIs of the same name. Re-use of IDs (e.g. after an EII with a particular ID is deleted) is discouraged but is not prevented. |
com.example.root
com.example.child(12)
com.example.grandchild(12)
com.example.grandchild(abc)
com.example.adoptedgrandchild(12)
com.example.child(abc)
com.example.grandchild(12)
com.example.starchild
Example 6 - Demonstrating of Web3S ID rules
In the previous example the ID values 12 and abc get used over and over again. That is legal. The ID requirements only specify that EIIs with the same name that are siblings have to have different ID values.
com.example.child(12) and com.example.grandchild(12) can both have the same ID because they are not siblings.
com.example.child(12) and com.example.child(abc) can both contain EIIs with the name com.example.grandchild(12) even though both EIIs have the same name, com.example.grandchild, because they do not share the same parent.
com.example.grandchild(12) and com.example.adoptedgrandchild(12) can both have the ID because even though both EIIs are siblings they do not have the same name.
Finally, com.example.adoptedgrandchild(12) and com.example.grandchild(12) have IDs while com.example.starchild doesn’t even though all of these elements appear only once under their respective parents. What a reader can immediately determine from the infoset example even though no schema has been provided is that com.example.adoptedgrandchild must have a schema that defines it as multi-valued and com.example.starchild must have a schema that defines it as single valued. Multi-valued EIIs must always have IDs, even if there is only a single instance of them in a particular Web3S infoset instance while single valued EIIs must never have IDs.
By default Web3S resources do not allow an ordering of the values in the children property. However when a Web3S message is in transit (e.g. being sent over the wire) the serialization can have an ordering and that ordering can be semantically meaningful. Put another way, children are unordered on disk but can optionally be ordered inside of a message on the wire.
String Information Item (SII) Properties
|
Property Name |
Property Description |
|
Value |
This value must contain an ordered series of one or more unicode characters.
Note that there is no explicit ‘empty string’ value in the Web3S infoset. |
|
Parent |
This value points to a single EII that contains this SII. |
When we refer to Unicode it is to the abstract Unicode character planes rather than to any specific encoding (e.g. utf-8, 16, 32, etc.)
The following provides a short hand notation for presenting an instance of a Web3S infoset. The short hand is only used for illustrative purposes and has no normative standing beyond its use for illustrations in this spec.
org.example.contacts
org.example.contact(2344)
org.example.contactType
org.example.work
org.example.firstname
“Inbar”
org.example.lastname
“Gazit”
org.example.contact(1)
org.example.contactType
org.example.home
org.example.firstname
“Marina”
org.example.lastname
“”
Example 7 - An instance of a Web3S Infoset
In this example the EII org.example.contacts contains two org.example.contact EIIs with the IDs 2344 and 1 respectively. In this example each of the contact EIIs contain the same three children, contactType, firstname and lastname. The children of firstname and lastname are strings. In the org.example.contacts/org.example.contact(1) example the lastname value is the empty string (e.g. the explicit value “”, this is distinct from having no children). The contactType EIIs contain a single EII who has no children.
As this short hand notation is only intended for illustrative purposes and is not intended as an actual serialization no formal definition is provided.
In order to enable maximum flexibility EIIs are directly exposed as HTTP resources. That is, each EII can be addressed as a HTTP resource and manipulated with the usual methods. To keep things simple we have chosen not to make SIIs URL addressable although that is functionality that could be added later.
net.example.articles
net.example.article(8383)
net.example.title
“Manual of Surgery Volume First: General Surgery. Sixth Edition.”
net.example.authors
net.example.author(23455)
org.example.firstname
“Alexander”
org.example.lastname
“Miles”
net.example.author(88828)
org.example.firstname
“Alexis”
org.example.lastname
“Thomson”
Example 8 - Articles recorded in a Web3S Infoset
If the non-Web3S prefix path is http://example.net/stuff/morestuff then we could address the lastname EII in Alexander Miles’s entry as http://example.net/stuff/morestuff/net.examples.articles/net.example.article(8383)/net.example.authors/net.example.author(23455)/org.example.lastname.
Although SIIs are modeled as resources they currently do not have their own URLs and therefore are addressed only in the context of EIIs. E.g. the value of an SII would be set by setting the value of its parent EII.
All Web3S EIIs serialized into XML will have a XML namespace with the same URI protocol – Web3SBase. If a Web3S XML MIME type contains a XML element whose namespace URI protocol isn’t Web3SBase then by definition the XML element cannot be representing Web3S infoset content.
Instead such elements are referred to as annotation commands. These are “decorations” of the Web3S infoset that provide instructions to the serialization processor.
<foo xmlns = “Web3SBase:com.example”
xmlns:ack=”http://foo.example.com”
xmlns:foo=”zippy:deDoDa”>
<ack:processPriority>
33
</ack:processPriority>
<foo:somethingOdd>
<ack:aNewThing>23</ack:aNewThing>
<foo:go/>
</foo:somethingOdd>
123
</foo>
Example 9 - Application/Web3S+xml with Annotation Commands
If the previous were submitted in a Web3S XML serialization the first thing the processor would do is recognize that because processPriority and somethingOdd do not come from a Web3SBase URI protocol the XML elements must be an annotation commands.
Assuming the processor doesn’t recognize processPriority then the processor would act as if processPriority and its children were not present (per 3SAFI). But if the processor does recognize somethingOdd but doesn’t recognize aNewThing then the processor would treat the somethingOdd annotation command as being present but ignore the aNewThing XML element (per 3SAFK).
In other words the processor, when processing the previous, would ‘see’:
<foo xmlns = “Web3SBase:com.example”>
<foo:somethingOdd>
<foo:go/>
</foo:somethingOdd>
123
</foo>
Example 10 - Application/Web3S+xml after unrecognized Annotation Commands are ignored
Once the processor has applied whatever semantics are required by somethingOdd the processor would effectively remove somethingOdd and its children from the serialization and treat the remaining XML as serializing a Web3S infoset.
The Web3S infoset does not have a native serialization. When it has to be directly expressed on the wire it can only do so by using some existing serialization mechanism. In this section we define the Application/Web3S+xml MIME type. This enables a Web3S infoset to be represented using XML. This section also defines certain processing rules for dealing with unrecognized content in Application/Web3S+xml messages.
Document Information Items:
|
Property |
Web3S Handling |
|
Children |
|
|
Document Element |
|
|
Notations |
|
|
Unparsed Entities |
3SAAM – The unparsed entities property of the XML DII MUST be null. |
|
Base URI |
3SAAN – The base URI property of the XML DII MUST be ignored for Web3S processing. |
|
Character Encoding Scheme |
|
|
Standalone |
3SAAP – The standalone property of the XML DII MUST be set to “yes” |
|
Version |
|
|
All Declarations Processed |
3SAAR – The all declarations processed property of the XML DII MUST be set to “yes” or ignored. |
Element Information Items:
|
Property |
Web3S Handling |
|
Namespace Name |
For example, if the Web3S EII name of an element was com.example.stuff.thing then the namespace name in XML would be “Web3SBase:com.example.stuff”. |
|
Local name |
For example, if the Web3S EII name of an element was com.example.stuff.thing then the local name would be “thing”.
|
|
Prefix, namespace attributes, in-scope namespaces, base URI |
|
|
Children |
3SAAW – The children property of an XML EII MUST contain either: · nothing, · only EIIs, · CharIIs that all MUST be presented in order, one after another and MAY contain a single Web3S ID element either before or after the CharIIs. |
|
Attributes |
3SAAX – The attributes property of an XML EII MUST be ignored for purposes of the Web3S infoset. |
|
Parent |
Maps to the Web3S EII resource’s parent. |
Character Information Item:
|
Property |
Web3S Handling |
|
Character Code |
|
|
Element content whitespace |
|
|
Parent |
Parent of the CharII. |
com.example.namespace.DiskManagement
com.example.namespace.DiskQuota
com.example.namespace.MeasurementType
com.example.namespace.Gigabytes
com.example.namespace.Amount
“400”
com.example.namespace.Owners
com.example.namespace.Owner(234234)
com.example.namespace.OwnerID
“tiborL”
com.example.namespace.Owner(13234)
com.example.namespace.OwnerID
“Ralf”
Example 11 - A Web3S Infoset Instance to be translated to/from Application/Web3S+xml
Would translate to/from:
<cen:DiskManagement
xmlns:cen = “com.example.namespace”
xmlns:web3s = “Web3S:“>
<cen:DiskQuota>
<cen:MeasurementType>
<cen:Gigabytes>
</cen:MeasurementType>
<cen:Amount>400</cen:Amount>
</cen:DiskQuota>
<cen:Owners>
<cen:Owner>
<web3s:ID>234234</web3s:ID>
<cen:OwnerID>tiborL</cen:OwnerID>
</cen:Owner>
<cen:Owner>
<web3s:ID>13234</web3s:ID>
<cen:OwnerID>Ralf</cen:OwnerID>
</cen:Owner>
</cen:Owners>
</cen:DiskManagement>
Example 12 - An Application/Web3S+xml serialization to be translated to/from the Web3S Infoset
The previous Application/Web3S+xml example assumes that the Web3S processor has a schema that will allow it to determine significant from insignificant whitespace.
To ignore an XML element means to act as if the XML element and all of its contents do not appear in the Application/Web3S+xml serialization for the purposes of parsing the XML file. This does not mean that the element has to be physically removed from the file.
<cen:Owner xmlns:e = “Web3SBase:org.example”>
<web3s:ID>234234</web3s:ID>
<cen:OwnerID>tiborL</cen:OwnerID>
<e:firstname>Tibor</e:firstname>
<e:lastname>Lukacs</e:lastname>
</cen:Owner>
Example 13 - An Application/Web3S+xml example with extended elements
In the previous example someone has submitted a com.example.namespace.Owner EII with some extension EIIs, org.example.firstname and org.example.lastname. Assuming that these elements are not defined nor banned by the schema for com.example.namespace.Owner being used by the processor of this request the proper behavior would be to just ignore the e:firstname and e:lastname elements. E.g. pretend they are not there.
On its own the Application/Web3S+xml content type is used to represent a Web3S infoset. But the semantics of that infoset can change depending on what method it is used with.
In the case of PUT the semantics of the Application/Web3S+xml request body are “merge the infoset information in the Application/Web3S+xml request with the infoset of the EII identified in the request-URI.” This section defines how Application/Web3S+xml is to be handled specifically in the case of PUT or any other context in which the Web3S infoset in the Application/Web3S+xml serialization is to be merged with some existing Web3S infoset.
Definition of Source & Destination - To increase readability this section will refer to the Application/Web3S+xml serialization with merge semantics as the ‘source’ and the Web3S infoset that the ‘source’ is to be merged into as the ‘destination’.
Implementer’s Note: The practical consequence of 3SAFE is that the requester has no idea what order the resource will use in processing a merge request. E.g. the resource is free to ignore the serialization order, can process multiple parts of the tree in parallel, etc. This approach has explicitly been chosen in order to give implementers of the destination maximum flexibility in how they apply merge semantics.
Typical examples of why a merge might fail are that the required change violates the destination’s schema or the merge involved a multi-valued EII whose ID the destination did not wish to create.
For example, imagine that the source contains:
org.example.whatever(234)
com.randomthirdparty.yo(efghi)
org.example.avalue
com.randomthirdparty.somethingElse
“YO!!”
Example 14 - Source Web3S infoset for a merge
Now imagine that the destination, before the merge, contains:
org.example.whatever(234)
com.randomthirdparty.nobodyhome
Example 15 - Destination Web3S infoset for a merge
In this example the only successful outcome of the merge would have to be:
org.example.whatever(234)
com.randomthirdparty.yo(efghi)
org.example.avalue
com.randomthirdparty.somethingElse
“YO!!”
com.randomthirdparty.nobodyhome
Example 16 - Web3S infoset created after a merge
In other words, not only would all of the source’s contents have to be copied over but the full names (E.g. EII names and IDs) must also be copied over exactly. Note that the ordering of com.randomthirdparty.yo(efghi) and com.randomthirdparty.nobodyhome is irrelevant since the resulting merged Web3S infoset is unordered.
|
Source/Destination |
Empty EII |
EII w/EII children |
EII w/SII child |
|
Empty EII |
No Action |
No Action |
The SII child MUST be deleted |
|
EII w/EII children |
No Action |
No Action |
The SII child MUST be deleted |
|
EII w/SII child |
The SII child from the source MUST be copied into the destination |
The EII children of the destination MUST be deleted and replaced with the SII child from the source |
The SII child in the destination MUST be replaced with the SII child from the source |
If the source’s state is:
com.example.a
com.example.b
com.example.f(1)
com.example.g
com.example.h(1)
“Ork”
Example 17 - Source Web3S infoset for a merge
and the destination’s state is:
com.example.a
com.example.b
com.randomthirdparty.morestuff(3h23rfh23)
com.example.f(1)
“Eep”
com.example.h(1)
“Op”
Example 18 - Destination Web3S infoset for a merge
Then the processing rules would be:
|
Step |
Source |
Destination |
Action |
|
1 |
com.example.a |
com.example.a |
3SAFG: Match roots, e.g. source(com.example.a) == destination(com.example.a) |
|
2 |
com.example.a/com.example.b, an Empty EII |
com.example.a/com.example.b, EII w/EII children. |
3SAFF: No Action |
|
3 |
com.example.a/com.example.h(1), EII w/SII child [Note: As allowed by 3SAFE, we are processing the source out of serialization order] |
com.example.a/com.example.h(1), EII w/SII child |
3SAFF: The SII child in the destination MUST be replaced with the SII child from the source |
|
4 |
com.example.a/com.example.f(1), EII w/EII child |
com.example.a/com.example.f(1), EII w/SII child |
3SAFF: The SII child MUST be deleted |
|
5 |
com.example.a/com.example.f(1)/com.example.g, an Empty EII |
No matching EII w/same full name and location |
3SAFD: create com.example.a/com.example.f(1)/com.example.g in destination |
So the infoset of the destination after the merge would be:
com.example.a
com.example.b
com.randomthirdparty.morestuff(3h23rfh23)
com.example.f(1)
com.example.g
com.example.h(1)
“Ork”
Example 19 - Outcome Web3S infoset for a merge
Application/Web3SDelta+xml is used to transmit a set of instructions that are to be used to update a Web3S infoset. The instructions tell the receiver what EIIs/SIIs to delete, alter or add.
The base format for Application/Web3SDelta+xml is the syntax and serialization used for Application/Web3S+xml with merge semantics. But Application/Web3SDelta+xml adds the delete annotation command that allows the Application/Web3SDelta+xml serialization to identify EIIs that are to be deleted. Application/Web3SDelta+xml also explicitly allows for empty IDs to be submitted for elements and for the semantics of this to mean ‘append the following new EII’.
See the example for UPDATE.
The infosets represented by a Web3S resource can potentially be enormous. For bandwidth or CPU reasons a resource may refuse to return the full serialization of a complete infoset. By default the best the resource can do in that case is return a 511 Response Too Large. This tells the requester that the resource has refused the request because the response body is larger than the resource is willing to serialize.
To prevent having to return 511s a compression format of sort is needed. Application/Web3SDefPage+xml is intended to provide just such a format. This is an optional MIME type that resources may choose to support to enable them to return partial content. The Application/Web3SDefPage+xml mime type supports two annotation commands – DeferredContent and PagingContent.
DeferredContent tells the processor of the serialization “None of the children of the EII that contains the DeferredContent annotation command have been returned in this serialization. To retrieve them you must do a GET directly on the EII that contains the annotation command.”
PagingContent tells the processor of the serialization “Some of the children of the EII that contains the PagingContent annotation command have been returned in this serialization. To retrieve the rest of the children you must perform a GET on the URL provided in the body of the PagingContent annotation command.”
Per section 14.1 of RFC 2616 servers should not return Application/Web3SDefPage+xml MIME types unless the client explicitly indicates support for that MIME type in the accept request header.
Generally the proper response code for a HTTP response that contains Application/Web3SDefPage+xml is 200. 206 Partial Content is explicitly in appropriate as RFC 2616 mandates that 206 can only be returned if the request contained a HTTP Range request header.
Note that it is theoretically possible to use a HTTP Range request header on a request that will generate an Application/Web3SDefPage+xml response. The syntax and semantics are as defined in RFC 2616. In other words the request acts normally, the response is theoretically generated normally and then only the requested byte subset is returned. There is however no requirement that a Web3S resource support the Range HTTP request header.
The semantics of the DeferredContent annotation command is that the contents of the EII that the DeferredContent element is annotating have not been returned in the serialization. However the requester can always retrieve the contents directly by performing a GET on the parent EII directly.
Without 3SAFL we could enter loop conditions where the root EII of the response body contains a DeferredContent that tells the requester to retrieve the same EII.
The semantics of placing a PagingContent annotation command as a child of an EII in an Application/Web3SDefPage+xml response is that some, possibly none, of the EII’s children have been returned but there are still more to be retrieved. In order to retrieve the next ‘page’ of results the requester will have to execute a GET request on the URI in the PagingContent annotation command.
The resource identified by the URI in a PagingContent annotation command is almost certainly not a Web3S resource and most likely supports no method other than GET and has no state beyond blindly returning the next ‘page’ of results. There is no need or use in submitting Web3S HTTP request headers to the resource identified in the URI as its function is very specialized.
The client will know it has reached the last ‘page’ when there are no further page annotation commands as the child of the root of the response.
Resources referred to in PagingContent annotation command URLs may be very short lived so clients should be expeditious in their retrieval of their contents unless explicitly told otherwise via out of band communications with the resource.
There is no guarantee that the infoset returned in a GET request on a PagingContent URI will be unique. That is, the same EIIs or even slightly different versions of the same EIIs could potentially be returned in multiple pages. It is the responsibility of the requester to detect such situations.
The ‘pages’ returned by this protocol are generally intended to be unique to a particular request/response pair. So sharing paging URLs is not recommended.
Imagine that a Web3S requester makes a request that returns the following Application/Web3SDefPage+xml response body:
GET /com.foo.bar HTTP/1.1
Host: example.com
Accept: Application/Web3S+xml, Application/Web3SDefPage+xml
…
HTTP/1.1 200 OK
<foo xmlns=”Web3SBase:com.example” xmlns:web3s=”Web3S:”>
<bar>
<web3s:ID>123</web3s:ID>
<web3s:DeferredContent/>
</bar>
<bar>
<web3s:ID>456</web3s:ID>
<web3s:DeferredContent/>
</bar>
<bar>
<web3s:ID>789</web3s:ID>
<blah>
<web3s:DeferredContent/>
</blah>
<icky>456</icky>
</bar>
</foo>
Example 20 - Application/Web3SDefPage+xml example
Seeing that the caller supports Application/Web3SDefPage+xml the server choose not to return any of the infoset contents for com.example.bar(123) and com.example.bar(456). The resource did decide to return the children of com.example.bar(789) but then decided to not return the contents of com.example.blah. Any of the EIIs marked with DeferredContent can have their contents retrieved by making a GET request. E.g. http://www.example.net/com.example.foo/com.example.bar(789)/com.example.blah.
GET /com.foo.bar?com.live.web3s.sort=com.foo.foosort, com.foo.icksort, com.foo.racksort HTTP/1.1
Host: example.com
Accept: Application/Web3S+xml, Application/Web3SDefPage+xml
…
HTTP/1.1 200 OK
…
Web3sSorted = com.foo.foosort, com.foo.icksort, com.foo.racksort
<bar xmlns=”Web3SBase:com.foo” xmlns:web3s=”Web3S:”>
<foo>
<ick>
<web3s:DeferredContent/>
</ick>
<bick>
…
<web3s:PagingContent>
http://example.com/abcdefg
</web3s:PagingContent>
</bick>
</foo>
</bar>
Example 21 - Example of Application/Web3SDefPage+xml with both DeferredContent and PagingContent
The response includes both DeferredContent and PagingContent annotation commands. The requester can get the DeferredContent (e.g. all the children of com.foo.ick) by issuing a GET request on http://example.com/com.foo.bar/com.foo.foo/com.foo.ick. To get the PagingContent the requester will have to issue the following GET request:
GET /abcdefg HTTP/1.1
Host: example.com
…
HTTP/1.1 200 OK
…
<bick xmlns=”Web3SBase:com.foo” xmlns:web3s=”Web3S:”>
<fizbang>
<web3s:DeferredContent/>
</fizbang>
<foo/>
<blah>
…
<web3s:PagingContent>
http://example.com/qrstuvwxyz
</web3s:PagingContent>
</blah>
<web3s:PagingContent>
http://example.com/1234567
</web3s:PagingContent>
</bick>
Example 22 - Example of content returned by a paging URL
This response also contains DeferredContent but now the situation is trickier. The resource that was requested, http://example.com/abcdefg is not a Web3S resource. So the requester has to know the ‘context’ of this request, that is, that the requester was asking for the children of http://example.com/com.foo.bar/com.foo.foo/com.foo.bick. Only by knowing that context information can the requester get the deferred content by making a request to http://example.com/com.foo.bar/com.foo.foo/com.foo.bick/com.foo.fizbang.
But, just to make things more interesting, the first page of the paging content contains two different pages. The PagingContent annotation command under com.foo.bick indicates that the enclosed URL will provide the next page of com.foo.bick’s children. But the PagingContent under com.foo.blah is new. It indicates that the returned serialization contains some of com.foo.blah’s children, but not all. In order for the requester to get a full picture of all of com.foo.bick’s children the requester is now going to have to follow two different paging ‘trails’.
GET /1234567 HTTP/1.1
Host: example.com
…
HTTP/1.1 200 OK
…
<bick xmlns=“Web3SBase:com.foo” xmlns:web3s=”Web3S:”>
<ack/>
</bick>
Example 23 - Another example of paging content
This GET request returns the last page of com.foo.bick’s children. The requester knows this because the com.foo.bick XML element does not contain a PagingContent annotation. The requester will still have to make a GET request to http://example.com/qrstuvwxyz to get com.foo.blah’s children from the previous page.
HTTP introduced two ways to implement optimistic concurrency, date based and etag based. Originally only date based optimistic concurrency was available but this was recognized as a flawed technique due to problems with the granularity of the date values. E.g. the values only had a granularity of 1 second and many servers were able to produce numerous changes within 1 second, all of which would have the same change date.
To rectify this situation HTTP/1.1 introduced etags. These are opaque values that identify the state of a resource. In RFC 2616 an etag returned from a specific resource is only applicable to that resource. This specification, when dealing exclusively with Web3S resources, extends the range of resources that an etag can be applied to from just the resource that issued the etag to that resource and all of its Web3S children. This change is necessary in order to enable clients to use optimistic concurrency in regards to the state of the overall Web3S infoset. E.g. a client will want to say “Only change this leaf of the tree if the tree itself has not changed state.”
Implementer’s Note: RFC 2616 assumes that support for If-* headers in HTTP is mandatory on all resources for all methods.
|
Method |
Etag Semantics |
|
GET/PUT/UPDATE |
The etag identifies the state of the resource identified by the request-URI and all of its children as described in the response body. |
|
HEAD |
Same semantics as GET except there is no actual response body. |
|
POST |
The etag identifies the state of the newly created resource and all of its children as described in the response body. |
Note that DELETE doesn’t return an etag header since etags are used to indicate ‘something’ not ‘nothing’. To make a request with the semantic “Only execute this request if the underlying resource doesn’t exist” use “if-none-match: *”.
For example, requester A makes a GET request for com.example.bar and receives the etag XYZ. Later on requester A executes a PUT request on com.example.bar/com.blah.foo with an if-match header containing the etag XYZ. The Web3S resource has to be smart enough to:
· recognize that XYZ is an etag describing the state of com.example.bar and all of its children,
· know what state com.example.bar and its children were in when the XYZ etag was issued
· make sure that the current state of com.example.bar and all of its children are the same as they were when XYZ was issued otherwise the request must fail with a 412 precondition failed.
Note however that it is completely up to the Web3S resource to decide at what granularity it will support etags.
For example, imagine that requester A executes a GET request for org.different.whatever/net.someserver.someplace and gets back the etag ABC.
It may be that the software behind org.different.whatever is only able to generate a single etag value for the entire resource. So if any part of org.different.whatever is changed then the etag for the whole resource will change. Although this can introduce inefficiencies it cannot introduce errors.
Continuing the previous example, imagine that requester B comes along and issues a PUT on org.different.whatever/co.jp.cool.
Requester A then issues a PUT on org.different.whatever/net.someserver.someplace using the etag ABC. Requester A’s request will fail because requester B’s change, even though to a completely different part of the resource, will cause the “global” etag to change. The result is that the ABC etag is ‘out of date’ even though the part of the resource requester A wanted to change had in fact not altered since requester A executed the GET. So requester A will be forced to do a second (wasted) GET to confirm that the org.different.whatever/net.someserver.someplace’s state hasn’t changed, get the new etag and repeat the request.
Having such low granularity etags may be inefficient but, again, it doesn’t cause ‘errors’.
Web3S provides no way for a requester to discover where an etag is ‘rooted’. All the requester can be sure of is that the etag is ‘good’ for at least the resource that returned it and that resource’s children.
In RFC 2616 etags are only meaningful in the context of a single resource. So etags only needed to be unique in the context of t