<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE xep SYSTEM 'xep.dtd' [ <!ENTITY % ents SYSTEM 'xep.ent'> %ents; ]> <?xml-stylesheet type='text/xsl' href='xep.xsl'?> <xep> <header> <title>Atomically Compare-And-Publish PubSub Items</title> <abstract>This specification provides a mechanism to atomically Compare-And-Publish items to a PubSub node.</abstract> &LEGALNOTICE; <number>0395</number> <status>Experimental</status> <type>Standards Track</type> <sig>Standards</sig> <approver>Council</approver> <dependencies> <spec>XEP-0030</spec> <spec>XEP-0060</spec> </dependencies> <supersedes/> <supersededby/> <shortname>cap</shortname> &flow; <revision> <version>0.1</version> <date>2017-11-29</date> <initials>XEP Editor (jwi)</initials> <remark><p>Accepted by Council as Expremental XEP</p></remark> </revision> <revision> <version>0.0.3</version> <date>2017-10-06</date> <initials>fs</initials> <remark><p>Use a custom item value (CAP-V).</p></remark> </revision> <revision> <version>0.0.2</version> <date>2017-08-25</date> <initials>fs</initials> <remark><p>Use PubSub publish-options preconditions.</p></remark> </revision> <revision> <version>0.0.1</version> <date>2017-04-20</date> <initials>fs</initials> <remark><p>First draft.</p></remark> </revision> </header> <section1 topic='Introduction' anchor='intro'> <p>This specification provides a mechanism to atomically publish items to a PubSub node depending on the item ID of the node's latest item. This allows to prevent race conditions and avoids data loss in certain situations.</p> </section1> <section1 topic='Discoverying Support' anchor='disco'> <p>If an entity supports the Compared-And-Publish feature it MUST advertise the fact by returning a <feature/> with the 'var' attribute set to 'urn:xmpp:pubsub:cap:0' in response to a &xep0030; query for information.</p> </section1> <section1 topic='Compare-And-Publish PubSub Items' anchor='cap'> <section2 topic='PubSub Item Compare-And-Publish Value (CAP-V)' anchor='cap-v'> <p>PubSub services supporting the Compare-And-Publish PubSub extension MUST include a Comapre-and-Publish value (CAP-V) for every item in every response. The CAP-V value MUST change if the content of the item changed and different item content under the same node MUST NOT yield the same CAP-V. A simple computation of the CAP-ID would be to hash the String representation of the item's content.</p> <p>CAP-Vs are assoicated with PubSub node's items via the item ID. The maping information is placed by the PubSub service in a <cap-v-map/> extension element, qualified by the 'urn:xmpp:pubsub:cap:0' namespace, as child element of the <items/> element. The <cap-v-map/> element contains one or more <cap-v-map-entry/> elements, of which each MUST have a 'item-id' and a 'cap-value' attribute. The former contains the PubSub item ID value and the later contains the according CAP-V of the item.</p> <example caption='Service returns some items and their according CAP-Vs'><![CDATA[ <iq type='result' from='pubsub.shakespeare.lit' to='francisco@denmark.lit/barracks' id='items1'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <items node='princely_musings'> <item id='368866411b877c30064a5f62b917cffe'> <entry xmlns='http://www.w3.org/2005/Atom'> <title>The Uses of This World</title> <summary> O, that this too too solid flesh would melt Thaw and resolve itself into a dew! </summary> </entry> </item> <item id='3300659945416e274474e469a1f0154c'> <entry xmlns='http://www.w3.org/2005/Atom'> <title>Ghostly Encounters</title> <summary> O all you host of heaven! O earth! what else? And shall I couple hell? O, fie! Hold, hold, my heart; And you, my sinews, grow not instant old, But bear me stiffly up. Remember thee! </summary> </entry> </item> <item id='4e30f35051b7b8b42abe083742187228'> <entry xmlns='http://www.w3.org/2005/Atom'> <title>Alone</title> <summary> Now I am alone. O, what a rogue and peasant slave am I! </summary> </entry> </item> <cap-v-map xmlns='urn:xmpp:pubsub:cap:0'> <cap-value-map-entry item-id='368866411b877c30064a5f62b917cffe' cap-value='35a204c2-5d6c-43a2-8e0d-a235a627b04a'/> <cap-value-map-entry item-id='3300659945416e274474e469a1f0154c' cap-value='166b7c04-ed4d-4872-aa56-a58268da84e2'/> <cap-value-map-entry item-id='4e30f35051b7b8b42abe083742187228' cap-value='67f7f792-f2ee-4918-8894-36a3c4a6dd5f'/> </cap-v-map> </items> </pubsub> </iq> ]]></example> </section2> <section2 topic='PubSub publishing using Compare-And-Publish'> <p>In order to atomically compare-and-publish an item, a client sends a <cite>XEP-0060</cite> <publish/> IQ with a 'pubsub#prev_item_cap_value' precondition publishing option, set to the value of the currently assumed CAP-V of the latest item of the node.</p> <p>The PubSub service MUST only publish the item if the node's latest item CAP-V is equal to the CAP-V found in the 'pubsub#prev_item_cap_value' field.</p> <example caption='Atomically publishing with Compare-And-Publish'><![CDATA[ <iq type='set' from='hamlet@denmark.lit/blogbot' to='pubsub.shakespeare.lit' id='pub1'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <publish node='princely_musings'> <item id='2'> <entry xmlns='https://example.org'> <title>Soliloquy</title> <summary> To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? </summary> </entry> </item> </publish> <publish-options> <x xmlns='jabber:x:data' type='submit'> <field var='FORM_TYPE' type='hidden'> <value>http://jabber.org/protocol/pubsub#publish-options</value> </field> <field var='pubsub#prev_item_cap_value'> <value>1</value> </field> </x> </publish-options> </pubsub> </iq> ]]></example> </section2> <section2 topic='Could not publish because newest item ID did not match'> <p>In case the Compare-And-Publish operation failed because the latest node id is not the same as given in the 'previd' attribute in the request, the server returns an <conflict/> error of type 'modify' which a pubsub-specific condition of <precondition-not-met/> and a <compare-and-publish-failed/> element qualifed by the 'urn:xmpp:pubsub:cap:0' namespace. The element MUST have a 'cap-id' attribute with the CAP-V of the lastest item.</p> <example caption='Service returns IQ response notifying of failed Compare-And-Publish operation'><![CDATA[ <iq type='error' from='pubsub.shakespeare.lit' to='hamlet@denmark.lit/elsinore' id='retract1'> <error type='modify'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <precondition-not-met xmlns='http://jabber.org/protocol/pubsub#errors'/> <compare-and-publish-failed xmlns='urn:xmpp:pubsub:cap:0' cap-id='2'/> </error> </iq> ]]></example> </section2> </section1> <section1 topic='Rationale' anchor='rationale'> <p>Unfortunately it was not possible to re-use the PubSub item ID for the "Atomically Compare-And-Publish" purpose. This is mostly due <cite>XEP-0060 § 12.8</cite> stating that:</p> <p class='box'> "If a publisher publishes an item and the ItemID matches that of an existing item, the pubsub service MUST overwrite the existing item and generate a new event notification." </p> <p> Which means that the content of an item could change without its ID, rendering the item ID unusable for CAP. </p> <p>Injecting a "cap"-namespaced attribute carrying the item's CAP-V into PubSub's <item/> would be a very elegant approach to assign CAP-Vs to PubSub items (and the favored one of the XEP's author). But the usage of namespaces attributes within XMPP is controversial. Therefore this XEP resorts to using the <cap-v-map/> approach for now.</p> </section1> <section1 topic='Security Considerations' anchor='security'> <p>This extension protocol does not add any further security considerations to the ones mentioned in <cite>XEP-0060 § 14.</cite>.</p> </section1> <section1 topic='IANA Considerations' anchor='iana'> <p>This document requires no interaction with the Internet Assigned Numbers Authority (IANA).</p> </section1> <section1 topic='XMPP Registrar Considerations' anchor='registrar'> <p>This specification defines the following XML namespaces:</p> <ul> <li>urn:xmpp:pubsub:cap:0</li> </ul> <code caption='Registry Submission'><![CDATA[ <var> <name>urn:xmpp:pubsub:cap:0</name> <desc>Indicates support for Compare-And-Publish</desc> <doc>XEP-XXXX</doc> </var>]]></code> <p>This specification defines the following <publish-options/> fields:</p> <ul> <li>pubsub#prev_item_cap_value</li> </ul> <code caption='Registry Submission'><![CDATA[ <field var='pubsub#prev_item_cap_value' type='text-single' label='Precondition: The assumed value of the latest item' CAP-V of the node'/>]]></code> </section1> <section1 topic='XML Schema' anchor='schema'> <p>TODO: Add after the XEP leaves the 'experimental' state.</p> </section1> <section1 topic='Acknowledgements' anchor='acknowledgements'> <p>Thanks to Kim Alvefur and Dave Cridland for their feedback.</p> </section1> </xep> <!-- Local Variables: --> <!-- fill-column: 100 --> <!-- indent-tabs-mode: nil --> <!-- End: -->