No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xep-0024.xml 39KB

  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <!DOCTYPE xep SYSTEM 'xep.dtd' [
  3. <!ENTITY % ents SYSTEM "xep.ent">
  4. %ents;
  5. ]>
  6. <?xml-stylesheet type='text/xsl' href='xep.xsl'?>
  7. <xep>
  8. <header>
  9. <title>Publish/Subscribe</title>
  10. <abstract>A publish-subscribe protocol for Jabber.</abstract>
  12. <number>0024</number>
  13. <status>Retracted</status>
  14. <type>Standards Track</type>
  15. <sig>Standards</sig>
  16. <dependencies/>
  17. <supersedes/>
  18. <supersededby><spec>XEP-0060</spec></supersededby>
  19. <shortname>None</shortname>
  20. <author>
  21. <firstname>DJ</firstname>
  22. <surname>Adams</surname>
  23. <email></email>
  24. <jid></jid>
  25. </author>
  26. <author>
  27. <firstname>Piers</firstname>
  28. <surname>Harding</surname>
  29. <email></email>
  30. <jid></jid>
  31. </author>
  32. <revision>
  33. <version>0.2</version>
  34. <date>2003-04-22</date>
  35. <initials>psa</initials>
  36. <remark>At the request of the authors, the status of this document has been changed to Retracted since it has been superseded by XEP-0060.</remark>
  37. </revision>
  38. <revision>
  39. <version>0.1</version>
  40. <date>2002-03-05</date>
  41. <initials>dja</initials>
  42. <remark>Initial draft.</remark>
  43. </revision>
  44. </header>
  45. <section1 topic='Abstract'>
  46. <p>
  47. Pubsub ("publish/subscribe") is a technique for coordinating the efficient
  48. delivery of information from publisher to consumer. This specification
  49. describes the use of pubsub within a Jabber context and is a result of
  50. two separate but related goals:
  51. </p>
  52. <ul>
  53. <li>to be able to exchange information _within_ a Jabber environment
  54. (for example continuously changing personal information between users)</li>
  55. <li>to be able to exchange information _using_ Jabber as a mechanism for
  56. <ul>
  57. <li>organising that exchange</li>
  58. <li>providing transport for the information</li>
  59. </ul>
  60. </li>
  61. </ul>
  62. <p>
  63. The specification details the use of the Jabber protocol elements and
  64. introduces a new namespace, jabber:iq:pubsub.
  65. It also includes notes on actual implementation of such a
  66. mechanism in Jabber.
  67. </p>
  68. </section1>
  69. <section1 topic='Introduction'>
  70. <p>
  71. It's clear that as Jabber is deployed over a wider spectrum of platforms
  72. and circumstances, more and more information will be exchanged. Whether
  73. that information is specific to Jabber (JSM) users, or components, we need
  74. an mechanism to be able to manage the exchange of this information in an
  75. efficient way.
  76. </p>
  77. <p>
  78. For example, it is currently the trend to embed information about a
  79. particular client's circumstance inside presence packets, either in the
  80. &lt;status/&gt; tag or in an &lt;x/&gt; extension. One example that comes
  81. to mind is "song currently playing on my MP3 player" (to which I have to
  82. admit some responsibility for the meme in the first place). While embedding
  83. information inside presence packets and having that information diffused to
  84. the users who are subscribed to that user's presence has the desired effect,
  85. it has a couple of non-trivial drawbacks:
  86. </p>
  87. <ul>
  88. <li>the diffusion is inefficient, sending potentially huge amounts of data
  89. to recipients who aren't interested</li>
  90. <li>the distribution is tied to closely to presence subscription; any entity
  91. that wants to receive information must be subscribed to the source's presence,
  92. and there is no mechanism for specifying _what_ information they wish to
  93. receive. It is also arguably too closely tied to the JSM to be useful for
  94. _component_-based information exchange.</li>
  95. </ul>
  96. <p>
  97. This is above and beyond the simple fact that this overloading of presence
  98. packets and the presence subscription and diffusion mechanism can only end
  99. in tears.
  100. </p>
  101. <p>
  102. It would be far better to have a separate (sub-)protocol that enabled
  103. entities to take part in publish/subscribe relationships, and have a service
  104. that facilitated the efficient exchange of information. Not only would it
  105. relax the undue pressure on the presence mechanism, but it would also allow
  106. people to use Jabber, which is, after all, about exchanging structured content
  107. between endpoints, as a publish/subscribe _mechanism_ in its own right.
  108. </p>
  109. <p>
  110. This specification describes a publish/subscribe protocol in terms
  111. of IQ packets with payload data in a new namespace, jabber:iq:pubsub. The
  112. choice for this namespace is slightly arbitrary - it was the same namespace
  113. used in temas's original document, seems to fit well, and we need a namespace
  114. to focus on.<note>It may well be that we will move to a URI-based namespace
  115. in the form of a URL pointing to this specification.</note>
  116. </p>
  117. <p>
  118. The aim of the specification is to provide for a facility where Jabber
  119. entities can subscribe to (consume) and publish (emit) information in an
  120. efficient and organised way. These entities could be JSM users or components.
  121. </p>
  122. <p>
  123. Push technology is back with a vengeance. Jabber can play a fundamental
  124. part.
  125. </p>
  126. </section1>
  127. <section1 topic='The Specification'>
  128. <p>
  129. The pubsub services will be typically provided by a component. In what
  130. follows, there are generally three parties involved:
  131. </p>
  132. <ul>
  133. <li>the subscriber</li>
  134. <li>the pubsub service</li>
  135. <li>the publisher</li>
  136. </ul>
  137. <p>
  138. Bear in mind that it is perfectly possible for a subscriber to be a
  139. publisher, and a publisher to be a subscriber, too.
  140. </p>
  141. <p>
  142. The pubsub traffic will be carried in info/query (IQ) packets. All of the
  143. data in these packets will be qualified by the jabber:iq:pubsub namespace.
  144. </p>
  145. <p>
  146. Pubsub scenarios can be seen in a subscribe (or unsubscribe) context or a
  147. publish context. In light of this, we will examine the IQ packets
  148. used in these contexts.
  149. </p>
  150. <section2 topic='Subscribe/Unsubscribe Context'>
  151. <p>
  152. A potential consumer, or recipient, of published information, needs to
  153. request that he be sent that published information. Requesting to receive,
  154. or be pushed, information is known as subscribing.
  155. </p>
  156. <p>
  157. A subscription request generally takes this form:
  158. </p>
  159. <example caption='General form of a subscription'>
  160. SEND: &lt;iq type='set' from='subscriber' to='pubsub' id='s1'&gt;
  161. &lt;query xmlns='jabber:iq:pubsub'&gt;
  162. &lt;subscribe to='publisher'&gt;
  163. &lt;ns&gt;namespace:1&lt;/ns&gt;
  164. &lt;ns&gt;namespace:2&lt;/ns&gt;
  165. ...
  166. &lt;ns&gt;namespace:N&lt;/ns&gt;
  167. &lt;/subscribe&gt;
  168. &lt;/query&gt;
  169. &lt;/iq&gt;
  170. RECV: &lt;iq type='result' to='subscriber' from='pubsub' id='s1'&gt;
  171. &lt;query xmlns='jabber:iq:pubsub'&gt;
  172. &lt;subscribe to='publisher'&gt;
  173. &lt;ns&gt;namespace:1&lt;/ns&gt;
  174. &lt;ns&gt;namespace:2&lt;/ns&gt;
  175. ...
  176. &lt;ns&gt;namespace:N&lt;/ns&gt;
  177. &lt;/subscribe&gt;
  178. &lt;/query&gt;
  179. &lt;/iq&gt;
  180. </example>
  181. <section3 topic='Publisher-Specific Subscriptions and Unsubscriptions'>
  182. <p>
  183. Subscriptions can be specific to a publisher, in which case a to attribute
  184. is specified in the &lt;subscribe/&gt; tag:
  185. </p>
  186. <example caption='Publisher-specific subscription'>
  187. SEND: &lt;iq type='set' to='pubsub.localhost'
  188. from='subscriber@localhost/resource' id='s1'&gt;
  189. &lt;query xmlns='jabber:iq:pubsub'&gt;
  190. &lt;subscribe to='publisher'&gt;
  191. &lt;ns&gt;namespace:1&lt;/ns&gt;
  192. &lt;ns&gt;namespace:2&lt;/ns&gt;
  193. &lt;/subscribe&gt;
  194. &lt;/query&gt;
  195. &lt;/iq&gt;
  196. RECV: &lt;iq type='result' from='pubsub.localhost'
  197. to='subscriber@localhost/resource' id='s1'&gt;
  198. &lt;query xmlns='jabber:iq:pubsub'&gt;
  199. &lt;subscribe to='publisher'&gt;
  200. &lt;ns&gt;namespace:1&lt;/ns&gt;
  201. &lt;ns&gt;namespace:2&lt;/ns&gt;
  202. &lt;/subscribe&gt;
  203. &lt;/query&gt;
  204. &lt;/iq&gt;
  205. </example>
  206. <p>
  207. In this case, the namespaces specified will be added to any existing list
  208. of namespaces already recorded for that subscriber:publisher relationship.
  209. In other words, it's a relative, not an absolute, subscription request.
  210. </p>
  211. <p>
  212. It is also possible in a publisher-specific subscription to omit specific
  213. namespaces, if you want to be sent everything that particular publisher
  214. might publish:
  215. </p>
  216. <example caption='Publisher-specific subscription without namespace specification'>
  217. SEND: &lt;iq type='set' to='pubsub.localhost'
  218. from='subscriber.localhost' id='s1'&gt;
  219. &lt;query xmlns='jabber:iq:pubsub'&gt;
  220. &lt;subscribe to='publisher'/&gt;
  221. &lt;/query&gt;
  222. &lt;/iq&gt;
  223. RECV: &lt;iq type='result' from='pubsub.localhost'
  224. to='subscriber.localhost' id='s1'&gt;
  225. &lt;query xmlns='jabber:iq:pubsub'&gt;
  226. &lt;subscribe to='publisher'/&gt;
  227. &lt;/query&gt;
  228. &lt;/iq&gt;
  229. </example>
  230. <p>
  231. This type of subscription should have the effect of absolutely replacing any
  232. previous namespace-specific subscription to the publisher specified.
  233. </p>
  234. <p>
  235. If a subscriber wishes to cancel a subscription from a particular publisher,
  236. he can send an unsubscribe like this:
  237. </p>
  238. <example caption='Publisher-specific unsubscription'>
  239. SEND: &lt;iq type='set' to='pubsub.localhost'
  240. from='subscriber@localhost/resource' id='s1'&gt;
  241. &lt;query xmlns='jabber:iq:pubsub'&gt;
  242. &lt;unsubscribe to='publisher'&gt;
  243. &lt;ns&gt;namespace:1&lt;/ns&gt;
  244. &lt;/unsubscribe&gt;
  245. &lt;/query&gt;
  246. &lt;/iq&gt;
  247. RECV: &lt;iq type='result' from='pubsub.localhost'
  248. to='subscriber@localhost/resource' id='s1'&gt;
  249. &lt;query xmlns='jabber:iq:pubsub'&gt;
  250. &lt;unsubscribe to='publisher'&gt;
  251. &lt;ns&gt;namespace:1&lt;/ns&gt;
  252. &lt;/unsubscribe&gt;
  253. &lt;/query&gt;
  254. &lt;/iq&gt;
  255. </example>
  256. <p>
  257. This should have the effect of removing the subscription from that publisher
  258. for the namespaces specified.
  259. </p>
  260. <p>
  261. You can also send an unsubscribe without specifying any namespaces:
  262. </p>
  263. <example caption='Publisher-specific general unsubscription'>
  264. SEND: &lt;iq type='set' to='pubsub.localhost'
  265. from='subscriber.localhost' id='s1'&gt;
  266. &lt;query xmlns='jabber:iq:pubsub'&gt;
  267. &lt;unsubscribe to='publisher'/&gt;
  268. &lt;/query&gt;
  269. &lt;/iq&gt;
  270. RECV: &lt;iq type='result' from='pubsub.localhost'
  271. to='subscriber.localhost' id='s1'&gt;
  272. &lt;query xmlns='jabber:iq:pubsub'&gt;
  273. &lt;unsubscribe to='publisher'/&gt;
  274. &lt;/query&gt;
  275. &lt;/iq&gt;
  276. </example>
  277. <p>
  278. This should have the effect of removing any subscription relationship with
  279. the publisher specified. Note, however, that this won't stop the subscriber
  280. being pushed information from that publisher if he's specified a
  281. "publisher-generic" subscription (see next section).
  282. </p>
  283. </section3>
  284. <section3 topic='Non-Publisher-Specific Subscriptions and Unsubscriptions'>
  285. <p>
  286. As well as being able to subscribe to specific publishers, it is also
  287. possible to subscribe to receive data, according to namespace, regardless
  288. of publisher:
  289. </p>
  290. <example caption='General namespace specific subscription'>
  291. SEND: &lt;iq type='set' to='pubsub.localhost'
  292. from='subscriber@localhost/resource' id='s1'&gt;
  293. &lt;query xmlns='jabber:iq:pubsub'&gt;
  294. &lt;subscribe&gt;
  295. &lt;ns&gt;namespace:1&lt;/ns&gt;
  296. &lt;ns&gt;namespace:2&lt;/ns&gt;
  297. &lt;/subscribe&gt;
  298. &lt;/query&gt;
  299. &lt;/iq&gt;
  300. RECV: &lt;iq type='result' from='pubsub.localhost'
  301. to='subscriber@localhost/resource' id='s1'&gt;
  302. &lt;query xmlns='jabber:iq:pubsub'&gt;
  303. &lt;subscribe&gt;
  304. &lt;ns&gt;namespace:1&lt;/ns&gt;
  305. &lt;ns&gt;namespace:2&lt;/ns&gt;
  306. &lt;/subscribe&gt;
  307. &lt;/query&gt;
  308. &lt;/iq&gt;
  309. </example>
  310. <p>
  311. This means that the subscriber wishes to be pushed information in the
  312. namespaces specified, regardless of who publishes it. Like the
  313. publisher-specific subscribe that specifies namespaces, this request is
  314. relative, in the namespaces are added to any existing namespaces already
  315. recorded for this generic subscription.
  316. </p>
  317. <p>
  318. Subscribing to everything from everyone is probably not a good idea and
  319. we should not allow this. (The format of the request is actually used in
  320. an IQ-get context - see later).
  321. </p>
  322. <example caption='This is not allowed'>
  323. SEND: &lt;iq type='set' to='pubsub.localhost'
  324. from='subscriber@localhost/resource' id='s1'&gt;
  325. &lt;query xmlns='jabber:iq:pubsub'&gt;
  326. &lt;subscribe/&gt;
  327. &lt;/query&gt;
  328. &lt;/iq&gt;
  329. RECV: &lt;iq type='error' from='pubsub.localhost'
  330. to='subscriber@localhost/resource' id='s1'&gt;
  331. &lt;query xmlns='jabber:iq:pubsub'&gt;
  332. &lt;subscribe/&gt;
  333. &lt;/query&gt;
  334. &lt;error code='405'&gt;Not Allowed&lt;/error&gt;
  335. &lt;/iq&gt;
  336. </example>
  337. <p>
  338. Likewise, you can unsubscribe from certain namespaces in this non-publisher-specific context like this:
  339. </p>
  340. <example caption='General unsubscription to specific namespaces'>
  341. SEND: &lt;iq type='set' to='pubsub.localhost'
  342. from='subscriber.localhost' id='s1'&gt;
  343. &lt;query xmlns='jabber:iq:pubsub'&gt;
  344. &lt;unsubscribe&gt;
  345. &lt;ns&gt;namespace:1&lt;/ns&gt;
  346. &lt;ns&gt;namespace:2&lt;/ns&gt;
  347. &lt;/unsubscribe&gt;
  348. &lt;/query&gt;
  349. &lt;/iq&gt;
  350. RECV: &lt;iq type='result' from='pubsub.localhost'
  351. to='subscriber.localhost' id='s1'&gt;
  352. &lt;query xmlns='jabber:iq:pubsub'&gt;
  353. &lt;unsubscribe&gt;
  354. &lt;ns&gt;namespace:1&lt;/ns&gt;
  355. &lt;ns&gt;namespace:2&lt;/ns&gt;
  356. &lt;/unsubscribe&gt;
  357. &lt;/query&gt;
  358. &lt;/iq&gt;
  359. </example>
  360. <p>
  361. If there are any subscriptions to specific publishers for the namespaces
  362. specified here, they should be removed (for those namespaces) in addition
  363. to the removal from the 'all publishers' list.
  364. </p>
  365. <p>
  366. Finally, a subscriber can wipe the slate clean like this:
  367. </p>
  368. <example caption='Wiping the slate'>
  369. SEND: &lt;iq type='set' to='pubsub.localhost'
  370. from='subscriber.localhost' id='s1'&gt;
  371. &lt;query xmlns='jabber:iq:pubsub'&gt;
  372. &lt;unsubscribe/&gt;
  373. &lt;/query&gt;
  374. &lt;/iq&gt;
  375. RECV: &lt;iq type='result' from='pubsub.localhost'
  376. to='subscriber.localhost' id='s1'&gt;
  377. &lt;query xmlns='jabber:iq:pubsub'&gt;
  378. &lt;unsubscribe/&gt;
  379. &lt;/query&gt;
  380. &lt;/iq&gt;
  381. </example>
  382. <p>
  383. which should have the effect of removing all namespace subscriptions
  384. from everywhere.
  385. </p>
  386. </section3>
  387. <section3 topic='Further Notes'>
  388. <p>
  389. All the examples so far have shown actions on the subscriber's part, and
  390. have consisted of IQ-sets. In an IQ-set, within the jabber:iq:pubsub
  391. namespace, multiple children can exist in the query payload, but those
  392. children must be of the same type. In other words, you can send multiple
  393. &lt;subscribe/&gt;s, or multiple &lt;unsubscribe/&gt;s, but not a combination
  394. of the two.
  395. </p>
  396. <p>
  397. This is allowed:
  398. </p>
  399. <example caption='Subscribing to more than one publisher at once'>
  400. SEND: &lt;iq type='set' to='pubsub.localhost'
  401. from='subscriber@localhost/resource' id='s1'&gt;
  402. &lt;query xmlns='jabber:iq:pubsub'&gt;
  403. &lt;subscribe to='publisherA'&gt;
  404. &lt;ns&gt;namespace:1&lt;/ns&gt;
  405. &lt;ns&gt;namespace:2&lt;/ns&gt;
  406. &lt;/subscribe&gt;
  407. &lt;subscribe to='publisherB'&gt;
  408. &lt;ns&gt;namespace:3&lt;/ns&gt;
  409. &lt;/subscribe&gt;
  410. &lt;/query&gt;
  411. &lt;/iq&gt;
  412. RECV: &lt;iq type='result' from='pubsub.localhost'
  413. to='subscriber@localhost/resource' id='s1'&gt;
  414. &lt;query xmlns='jabber:iq:pubsub'&gt;
  415. &lt;subscribe to='publisherA'&gt;
  416. &lt;ns&gt;namespace:1&lt;/ns&gt;
  417. &lt;ns&gt;namespace:2&lt;/ns&gt;
  418. &lt;/subscribe&gt;
  419. &lt;subscribe to='publisherB'&gt;
  420. &lt;ns&gt;namespace:3&lt;/ns&gt;
  421. &lt;/subscribe&gt;
  422. &lt;/query&gt;
  423. &lt;/iq&gt;
  424. </example>
  425. <p>
  426. But this is not allowed:
  427. </p>
  428. <example caption='Subscribes and unsubscribes in same IQ-set is not allowed'>
  429. SEND: &lt;iq type='set' to='pubsub.localhost'
  430. from='subscriber.localhost' id='s1'&gt;
  431. &lt;query xmlns='jabber:iq:pubsub'&gt;
  432. &lt;subscribe to='publisherA'&gt;
  433. &lt;ns&gt;namespace:1&lt;/ns&gt;
  434. &lt;ns&gt;namespace:2&lt;/ns&gt;
  435. &lt;/subscribe&gt;
  436. &lt;unsubscribe to='publisherB'&gt;
  437. &lt;ns&gt;namespace:3&lt;/ns&gt;
  438. &lt;/unsubscribe&gt;
  439. &lt;/query&gt;
  440. &lt;/iq&gt;
  441. RECV: &lt;iq type='result' from='pubsub.localhost'
  442. to='subscriber.localhost' id='s1'&gt;
  443. &lt;query xmlns='jabber:iq:pubsub'&gt;
  444. &lt;subscribe to='publisherA'&gt;
  445. &lt;ns&gt;namespace:1&lt;/ns&gt;
  446. &lt;ns&gt;namespace:2&lt;/ns&gt;
  447. &lt;/subscribe&gt;
  448. &lt;unsubscribe to='publisherB'&gt;
  449. &lt;ns&gt;namespace:3&lt;/ns&gt;
  450. &lt;/unsubscribe&gt;
  451. &lt;/query&gt;
  452. &lt;error code='400'&gt;
  453. Bad Request: only subscribes or unsubscribes
  454. &lt;/error&gt;
  455. &lt;/iq&gt;
  456. </example>
  457. <p>
  458. In the case where multiple &lt;subscribe/&gt;s or &lt;unsubscribe/&gt;s
  459. appear in an action, each element will be processed in turn, as they appear
  460. in the payload.
  461. </p>
  462. <p>
  463. As well as actions, the subscriber can query his subscription using an
  464. IQ-get in the jabber:iq:pubsub namespace. This should return a list of
  465. the subscribers current subscriptions, like this:
  466. </p>
  467. <example caption='Querying current subscription'>
  468. SEND: &lt;iq type='get' to='pubsub.localhost'
  469. from='subscriber@localhost/resource' id='s1'&gt;
  470. &lt;query xmlns='jabber:iq:pubsub'&gt;
  471. &lt;subscribe/&gt;
  472. &lt;/query&gt;
  473. &lt;/iq&gt;
  474. RECV: &lt;iq type='result' from='pubsub.localhost'
  475. to='subscriber@localhost/resource' id='s1'&gt;
  476. &lt;query xmlns='jabber:iq:pubsub'&gt;
  477. &lt;subscribe&gt;
  478. &lt;ns&gt;namespace:1&lt;/ns&gt;
  479. &lt;ns&gt;namespace:2&lt;/ns&gt;
  480. &lt;/subscribe&gt;
  481. &lt;subscribe to='publisherA'&gt;
  482. &lt;ns&gt;namespace:2&lt;/ns&gt;
  483. &lt;ns&gt;namespace:4&lt;/ns&gt;
  484. &lt;/subscribe&gt;
  485. &lt;subscribe to='publisherB'&gt;
  486. &lt;ns&gt;namespace:5&lt;/ns&gt;
  487. &lt;/subscribe&gt;
  488. &lt;/query&gt;
  489. &lt;/iq&gt;
  490. </example>
  491. <p>
  492. Note the two references to namespace:2 - one inside the non-publisher-specific
  493. subscription list and one inside the subscription list specific to publisherA.
  494. This example implies that the non-publisher-specific and publisher-specific
  495. subscription information should be kept separately. This is designed to make
  496. it easier on the subscriber to manage his specific subscriptions over time.
  497. </p>
  498. </section3>
  499. </section2>
  500. <section2 topic='Publish Context'>
  501. <p>
  502. In contrast to the subscribe and unsubscribe context, the publishing
  503. context is a lot simpler to explain.
  504. </p>
  505. <p>
  506. A publisher can publish information within a certain namespace, like this:
  507. </p>
  508. <example caption='Publishing information'>
  509. SEND: &lt;iq type='set' to='pubsub.localhost'
  510. from='publisher@localhost/resource' id='s1'&gt;
  511. &lt;query xmlns='jabber:iq:pubsub'&gt;
  512. &lt;publish ns='foo'&gt;
  513. &lt;foo xmlns='foo'&gt;bar&lt;/foo&gt;
  514. &lt;/publish&gt;
  515. &lt;/query&gt;
  516. &lt;/iq&gt;
  517. RECV: &lt;iq type='result' from='pubsub.localhost'
  518. to='publisher@localhost/resource' id='s1'&gt;
  519. &lt;query xmlns='jabber:iq:pubsub'&gt;
  520. &lt;publish ns='foo'&gt;
  521. &lt;foo xmlns='foo'&gt;bar&lt;/foo&gt;
  522. &lt;/publish&gt;
  523. &lt;/query&gt;
  524. &lt;/iq&gt;
  525. </example>
  526. <p>
  527. It's also possible for a publisher to publish more than one item at once,
  528. like this:
  529. </p>
  530. <example caption='Publishing information in different namespaces'>
  531. SEND: &lt;iq type='set' to='pubsub.localhost'
  532. from='publisher.localhost' id='s1'&gt;
  533. &lt;query xmlns='jabber:iq:pubsub'&gt;
  534. &lt;publish ns='foo'&gt;
  535. &lt;foo xmlns='foo'&gt;bar&lt;/foo&gt;
  536. &lt;/publish&gt;
  537. &lt;publish ns='jabber:x:oob'&gt;
  538. &lt;x xmlns='jabber:x:oob'&gt;
  539. &lt;url&gt;;/url&gt;
  540. &lt;desc&gt;Some stuff about Jabber&lt;/desc&gt;
  541. &lt;/x&gt;
  542. &lt;/publish&gt;
  543. &lt;/query&gt;
  544. &lt;/iq&gt;
  545. RECV: &lt;iq type='result' from='pubsub.localhost'
  546. to='publisher.localhost' id='s1'&gt;
  547. &lt;query xmlns='jabber:iq:pubsub'&gt;
  548. &lt;publish ns='foo'&gt;
  549. &lt;foo xmlns='foo'&gt;bar&lt;/foo&gt;
  550. &lt;/publish&gt;
  551. &lt;publish ns='jabber:x:oob'&gt;
  552. &lt;x xmlns='jabber:x:oob'&gt;
  553. &lt;url&gt;;/url&gt;
  554. &lt;desc&gt;Some stuff about Jabber&lt;/desc&gt;
  555. &lt;/x&gt;
  556. &lt;/publish&gt;
  557. &lt;/query&gt;
  558. &lt;/iq&gt;
  559. </example>
  560. <!--
  561. <p>
  562. Optionally, a pubsub component may respond with an empty IQ-result, to
  563. reduce traffic:
  564. </p>
  565. <example>
  566. RECV: &lt;iq type='result' from='pubsub.localhost'
  567. to='publisher.localhost' id='s1'&gt;
  568. &lt;/iq&gt;
  569. </example>
  570. -->
  571. <p>
  572. Each published item is wrapped in a &lt;publish/&gt; tag. This tag
  573. must contain the namespace of the item being publishes, in an ns
  574. attribute, as shown. This is distinct from the xmlns attribute of
  575. the fragment of XML actually being published. It is theoretically
  576. none of the pubsub component's business to go poking around in the
  577. real published data, nor should it have to. It needs to know what
  578. namespace is qualifying the published information that has been
  579. received, so that the list of appropriate recipients can be
  580. determined.
  581. </p>
  582. </section2>
  583. <section2 topic='Distributing Published Information'>
  584. <p>
  585. While it's the responsibility of the publishing entities to publish
  586. information, it's the responsibility of the pubsub
  587. component to push out that published data to the subscribers. The
  588. list of recipient subscribers must be determined by the information
  589. stored by the pubsub component as a result of receiving subscription
  590. requests (which are described earlier).
  591. </p>
  592. <p>
  593. On receipt of an IQ-set containing published information, the pubsub
  594. entity must determine the list of subscribers to which that information
  595. should be pushed. If the IQ-set contains multiple &lt;publish/&gt;
  596. fragments, this process must be carried out for each one in turn.
  597. <note>Whether a pubsub component implementation should be allowed to
  598. batch up individual published information fragments for one recipient
  599. as a result of a large, multi-part incoming publishing IQ-set, is not
  600. specified here, the choice is down to the implementer. Receiving entities
  601. should be able to cope with being pushed an IQ-set with multiple
  602. fragments of published data.</note>
  603. </p>
  604. <p>
  605. Taking the earlier example of the publishing of data in the 'foo'
  606. namespace, the following example shows what the pubsub component
  607. must send to push this foo data out to a subscriber.
  608. </p>
  609. <example caption='Pushing out published information to a subscriber'>
  610. SEND: &lt;iq type='set' to='subscriber@localhost/foosink'
  611. from='pubsub.localhost' id='push1'&gt;
  612. &lt;query xmlns='jabber:iq:pubsub'&gt;
  613. &lt;publish ns='foo' from='publisher@localhost'&gt;
  614. &lt;foo xmlns='foo'&gt;bar&lt;/foo&gt;
  615. &lt;/publish&gt;
  616. &lt;/query&gt;
  617. &lt;/iq&gt;
  618. </example>
  619. <p>
  620. The recipient is _not_ required to send an 'acknowledgement' in the
  621. form of an IQ-result; the idea that this _push_ of information is
  622. akin to how information is pushed in a live browsing context (see
  623. jabber:iq:browse documentation for more details).
  624. </p>
  625. </section2>
  626. <section2 topic='Delivery Sensitivity'>
  627. <p>
  628. When a pubsub service receives a publish packet like the ones above, it
  629. needs to deliver (push) the information out according to the subscriptions
  630. that have been made.
  631. </p>
  632. <p>
  633. However, we can introduce a modicum of sensitivity by using a presence
  634. subscription between the pubsub service and the subscriber(s). If the
  635. subscriber wishes only to receive information when he's online (this is
  636. a JSM-specific issue), then he needs to set up a presence subscription
  637. relationship with the pubsub service. The pubsub service should respond
  638. to presence subscriptions and unsubscriptions by
  639. </p>
  640. <ul>
  641. <li>accepting the (un)subscription request</li>
  642. <li>reciprocating the (un)subscription request</li>
  643. </ul>
  644. <p>
  645. If the pubsub service deems that a published piece of information should
  646. be pushed to a subscriber, and there is a presence subscription relationship
  647. with that subscriber, the service should only push that information to the
  648. subscriber if he is available. If he is not available, the information is not
  649. to be sent.
  650. </p>
  651. <p>
  652. Thus the subscriber can control the sensitivity by initiating (or not) a
  653. presence relationship with the service. If the subscriber wishes to receive
  654. information regardless of availability, he should not initiate a (or cancel
  655. any previous) presence relationship with the service.
  656. </p>
  657. <p>
  658. This loose coupling of presence relationships for sensitivity allows this
  659. specification to be used in the wider context of component-to-component
  660. publish/subscribe where presence is not a given.
  661. </p>
  662. </section2>
  663. <section2 topic='Use of Resources'>
  664. <p>
  665. When in receipt of a pubsub subscription request from an entity
  666. where a resource is specified in the JID, the pubsub component must
  667. honour the resource specified in the from attribute of the request.
  668. For example, here's a typical subscription request from a JSM user:
  669. </p>
  670. <example caption='Incoming subscription request from a JSM user'>
  671. RECV: &lt;iq type='set' to='pubsub.localhost'
  672. from='subscriber@localhost/resource' id='s1'&gt;
  673. &lt;query xmlns='jabber:iq:pubsub'&gt;
  674. &lt;subscribe to='publisher'&gt;
  675. &lt;ns&gt;namespace:1&lt;/ns&gt;
  676. &lt;ns&gt;namespace:2&lt;/ns&gt;
  677. &lt;/subscribe&gt;
  678. &lt;/query&gt;
  679. &lt;/iq&gt;
  680. </example>
  681. <p>
  682. When storing the subscriber/publisher/namespace relationship matrix for
  683. eventual querying when a publisher publishes some information, the
  684. pubsub component must use the full JID, not just the username@host part.
  685. </p>
  686. <p>
  687. Similarly, in this example:
  688. </p>
  689. <example caption='Incoming subscription request from a component'>
  690. RECV: &lt;iq type='set' to='pubsub.localhost'
  691. from='news.server/politics-listener' id='s1'&gt;
  692. &lt;query xmlns='jabber:iq:pubsub'&gt;
  693. &lt;subscribe to='publisher'&gt;
  694. &lt;ns&gt;news:politics:home&lt;/ns&gt;
  695. &lt;ns&gt;news:politics:foreign:usa&lt;/ns&gt;
  696. &lt;/subscribe&gt;
  697. &lt;/query&gt;
  698. &lt;/iq&gt;
  699. </example>
  700. <p>
  701. the full JID of the component subscriber - news.server/politics-listener,
  702. should be used to qualify the matrix.
  703. </p>
  704. <p>
  705. This is because it allows the subscribing entities to arrange the
  706. receipt of pushed items by resource. In the case of a JSM user, it
  707. allows him to organise his clients, which may have different capabilities
  708. (some being able to handle the jabber:iq:pubsub data, others not) to
  709. receive the 'right' data. In the case of a component, it allows the
  710. component to associate component-specific data with incoming published
  711. namespace-qualified information.
  712. </p>
  713. </section2>
  714. </section1>
  715. <section1 topic='Implementation Notes'>
  716. <p>
  717. While the specification describes the fundamental building blocks of the
  718. pubsub protocol, there are ideas that are not discussed above but nonetheless
  719. may be incorporated into an implementation. There are other considerations
  720. that have to be made in the wider context of publish and subscribe. Some of
  721. the main ones are discussed briefly here too.
  722. </p>
  723. <section2 topic='Publisher Discovery'>
  724. <p>
  725. There is no part of this pubsub specification that determines how a
  726. potential subscriber might discover publishers. After all, there are
  727. no rules governing which pubsub component a publisher could or should
  728. publish to. And since pubsub subscriptions are specific to a pubsub
  729. component, there is an information gap - "how do I find out what
  730. publishers there are, and through which pubsub components they're publishing
  731. information?"
  732. </p>
  733. <p>
  734. This problem domain should be solved using other methods, not with the
  735. actual jabber:iq:pubsub specific namespace. A combination of jabber:iq:browse
  736. usage (the magic ointment that heals all things) and perhaps a DNS style
  737. (or at least root-node-based) knowledge hierarchy might be the right
  738. direction.
  739. </p>
  740. <p>
  741. In the case where a server administrator wishes to facilitate pubsub
  742. flow between JSM users on a server, a pubsub component can be plugged
  743. into the jabberd backbone, and there is potentially no real issue with
  744. knowing which pubsub component to use, and where it is.
  745. But what about if the JSM users on one server wish to build pubsub
  746. relationships with JSM users on another server? (Note that this general
  747. question is not specific to JSM users, although that example will be used
  748. here). The next two sections look at how these things might pan out.
  749. </p>
  750. </section2>
  751. <section2 topic='Cross-Server Relationships'>
  752. <p>
  753. When JSM users on server1 wish to subscribe to information published
  754. by JSM users on server2 (let's say it's the mp3 player info, or avatars)
  755. then there are some issues that come immediately to mind:
  756. </p>
  757. <ul>
  758. <li>Does a JSM user on server1 (userA@server1) send his IQ-set subscription
  759. to the pubsub component on server2 (pubsub.server2), or server1
  760. (pubsub.server1)?</li>
  761. <li>If he sends it to pubsub.server2, can we expect
  762. pubsub.server2 to always accept that subscription request, i.e. to
  763. be willing to serve userA@server1 (if pubsub.server2 knows that
  764. pubsub.server1 exists)?</li>
  765. <li>Will there be performance (or at least server-to-server traffic)
  766. implications if many subscription relationships exist between subscribers on
  767. server1 and publishers on server2?</li>
  768. </ul>
  769. <section3 topic='Proxy Subscriptions'>
  770. <p>
  771. To reduce the amount of server-to-server traffic, we can employ the
  772. concept of "proxy subscriptions". This is simply getting a pubsub component
  773. to act on behalf of a (server-local) subscriber. Benefit comes when a pubsub
  774. component acts on behalf of multiple (server-local) subscribers.
  775. </p>
  776. <p>
  777. Here's how such proxy subscriptions can work, to reduce the amount of
  778. server-to-server traffic:
  779. </p>
  780. <p>
  781. Step 1: Subscriber sends original subscription
  782. </p>
  783. <p>
  784. JSM users on server1 wish to subscribe to information published by an
  785. entity on server2. Each of them sends a subscription request to the
  786. _local_ pubsub component:
  787. </p>
  788. <example>
  789. SEND: &lt;iq type='set' to='pubsub.server1'
  790. from='subscriber@server1/resource' id='s1'&gt;
  791. &lt;query xmlns='jabber:iq:pubsub'&gt;
  792. &lt;subscribe to='publisher.server2'&gt;
  793. &lt;ns&gt;namespace:1&lt;/ns&gt;
  794. &lt;/subscribe&gt;
  795. &lt;/query&gt;
  796. &lt;/iq&gt;
  797. </example>
  798. <p>
  799. Step2: Pubsub component subscribes on subscriber's behalf
  800. </p>
  801. <p>
  802. The pubsub component knows about the publisher, and where (to which
  803. pubsub component) that publisher publishes information. It formulates
  804. a subscription request and sends it to the remote pubsub component:
  805. </p>
  806. <example>
  807. SEND: &lt;iq type='set' to='pubsub.server2'
  808. from='pubsub.server1' id='s1'&gt;
  809. &lt;query xmlns='jabber:iq:pubsub'&gt;
  810. &lt;subscribe to='publisher.server2'&gt;
  811. &lt;ns&gt;namespace:1&lt;/ns&gt;
  812. &lt;/subscribe&gt;
  813. &lt;/query&gt;
  814. &lt;/iq&gt;
  815. </example>
  816. <p>
  817. The remote pubsub component receives and acknowledges the subscription
  818. request, and the local pubsub component relays the response back to
  819. the original requester:
  820. </p>
  821. <example>
  822. SEND: &lt;iq type='result' from='pubsub.server1'
  823. to='subscriber@server1/resource' id='s1'&gt;
  824. &lt;query xmlns='jabber:iq:pubsub'&gt;
  825. &lt;subscribe to='publisher.server2'&gt;
  826. &lt;ns&gt;namespace:1&lt;/ns&gt;
  827. &lt;/subscribe&gt;
  828. &lt;/query&gt;
  829. &lt;/iq&gt;
  830. </example>
  831. <p>
  832. If the remote pubsub server was unable or unwilling to accept the
  833. subscription request, this should be reflected in the response:
  834. </p>
  835. <example>
  836. SEND: &lt;iq type='error' from='pubsub.server1'
  837. to='subscriber@server1/resource' id='s1'&gt;
  838. &lt;query xmlns='jabber:iq:pubsub'&gt;
  839. &lt;subscribe to='publisher.server2'&gt;
  840. &lt;ns&gt;namespace:1&lt;/ns&gt;
  841. &lt;/subscribe&gt;
  842. &lt;/query&gt;
  843. &lt;error code='406'&gt;Not Acceptable&lt;/error&gt;
  844. &lt;/iq&gt;
  845. </example>
  846. <p>
  847. Step3: Publisher publishes information
  848. </p>
  849. <p>
  850. The publisher, publisher.server2, publishes information in the
  851. namespace:1 namespace, to the remote pubsub component pubsub.server2:
  852. </p>
  853. <example>
  854. SEND: &lt;iq type='set' from='publisher.server2'
  855. to='pubsub.server2' id='p1'&gt;
  856. &lt;query xmlns='jabber:iq:pubsub'&gt;
  857. &lt;publish ns='namespace;1'&gt;
  858. &lt;stuff xmlns='namespace:1'&gt;nonsense&lt;/stuff&gt;
  859. &lt;/publish&gt;
  860. &lt;/query&gt;
  861. &lt;/iq&gt;
  862. </example>
  863. <p>
  864. Step4: Pubsub component receives published information
  865. </p>
  866. <p>
  867. The pubsub component pushes the published information to pubsub.server1,
  868. who has been determined to be a valid recipient:
  869. </p>
  870. <example>
  871. RECV: &lt;iq type='set' from='pubsub.server2'
  872. to='pubsub.server1' id='p1'&gt;
  873. &lt;query xmlns='jabber:iq:pubsub'&gt;
  874. &lt;publish ns='namespace;1' from='publisher.server2'&gt;
  875. &lt;stuff xmlns='namespace:1'&gt;nonsense&lt;/stuff&gt;
  876. &lt;/publish&gt;
  877. &lt;/query&gt;
  878. &lt;/iq&gt;
  879. </example>
  880. <p>
  881. Step5: Pubsub component forwards published information to original subscriber
  882. </p>
  883. <p>
  884. The local pubsub component then diffuses the information received to the
  885. original subscriber:
  886. </p>
  887. <example>
  888. SEND: &lt;iq type='set' from='pubsub.server1'
  889. to='subscriber@server1/resource' id='p1'&gt;
  890. &lt;query xmlns='jabber:iq:pubsub'&gt;
  891. &lt;publish ns='namespace;1' from='publisher.server2'&gt;
  892. &lt;stuff xmlns='namespace:1'&gt;nonsense&lt;/stuff&gt;
  893. &lt;/publish&gt;
  894. &lt;/query&gt;
  895. &lt;/iq&gt;
  896. </example>
  897. <p>
  898. This way, only a single published element must travel between servers
  899. to satisfy a multiplex of subscribed entities at the delivery end.
  900. </p>
  901. <p>
  902. Of course, this mechanism will rely upon knowledge about pubsub components
  903. and where they're available; furthermore, it will require knowledge about
  904. where publisher entities publish their information.
  905. This knowledge, and the mechanisms to discover this sort of information,
  906. is not to be covered in this spec, which purely deals with the subscription
  907. and publishing of information. As SOAP is to UDDI (to use a slightly
  908. controversial pair of technologies), so is jabber:iq:pubsub to this
  909. discovery mechanism as yet undefined. To include the definition of such
  910. a discovery mechanism in this specification is wrong on two counts:
  911. </p>
  912. <ul>
  913. <li>Discovery mechanisms by nature should not be tied to specific areas</li>
  914. <li>Trying to load too much onto jabber:iq:pubsub will only produce a
  915. complex and hard-to-implement specification</li>
  916. </ul>
  917. <p>
  918. After all, the jabber:iq:pubsub spec as defined here is usable out of the
  919. box for the simple scenarios, and scenarios where discovery is not
  920. necessary or the information can be exchanged in other ways.
  921. </p>
  922. </section3>
  923. <section3 topic='Willingness to Serve'>
  924. <p>
  925. There are some situations where it might be appropriate for a pubsub
  926. component to refuse particular subscription requests. Here are two
  927. examples:
  928. </p>
  929. <ul>
  930. <li>Where a pubsub component that's been designed, implemented, or
  931. configured to handle local-only pubsub traffic, and a subscription request
  932. is received, specifying a publisher that the local pubsub component knows
  933. to be one that publishes to a remote pubsub component <note>under other
  934. circumstances, this would trigger a 'Proxy Subscription', as described earlier, if supported</note>. In this case, the local pubsub component would be
  935. unwilling to provoke a server-to-server connection and therefore unwilling to
  936. honour the request.</li>
  937. <li>Where a pubsub component receives a subscription request from a
  938. remote subscriber, and that pubsub component knows that there's a
  939. pubsub component local to the subscriber. In this case, the (administrator
  940. of the) remote pubsub component might want to encourage proxy subscriptions.
  941. </li>
  942. </ul>
  943. <p>
  944. A refusal could take one of a number of guises:
  945. </p>
  946. <example caption='A flat refusal'>
  947. SEND: &lt;iq type='error' from='pubsub.server2'
  948. to='subscriber@server1/resource' id='s1'&gt;
  949. &lt;query xmlns='jabber:iq:pubsub'&gt;
  950. &lt;subscribe to='publisher.server2'&gt;
  951. &lt;ns&gt;namespace:1&lt;/ns&gt;
  952. &lt;/subscribe&gt;
  953. &lt;/query&gt;
  954. &lt;error code='406'&gt;Local pubsub only&lt;/error&gt;
  955. &lt;/iq&gt;
  956. </example>
  957. <example caption='A refusal with redirection'>
  958. SEND: &lt;iq type='error' from='pubsub.server2'
  959. to='subscriber@server1/resource' id='s1'&gt;
  960. &lt;query xmlns='jabber:iq:pubsub'&gt;
  961. &lt;subscribe to='publisher.server2'&gt;
  962. &lt;ns&gt;namespace:1&lt;/ns&gt;
  963. &lt;/subscribe&gt;
  964. &lt;/query&gt;
  965. &lt;error code='302' jid='pubsub.server1'/&gt;
  966. &lt;/iq&gt;
  967. </example>
  968. <p>Note: This 302 redirect is not covered in the general protocol specification,
  969. but it's an interesting concept :-)</p>
  970. </section3>
  971. </section2>
  972. <section2 topic='Subscriber Anonymity and Acceptance?'>
  973. <p>
  974. The jabber:iq:pubsub specification makes no provision for
  975. publishers to query a pubsub component to ask for a list of those entities
  976. that are subscribed to (namespaces) it (publishes). This is deliberate.
  977. Do we wish to add to the specification to allow the publisher to discover
  978. this information? If so, it must be as an optional 'opt-in' (or 'opt-out')
  979. tag for the subscriber, to determine whether his JID will show up on the
  980. list.
  981. <note>Even if there is no provision for querying the subscribers, perhaps
  982. we should make a provision for the publisher to ask the pubsub component
  983. for a list of namespaces that have been subscribed to (for that publisher).
  984. </note>
  985. </p>
  986. <p>
  987. Associated with this is the semi-reciprocal issue of acceptance? The
  988. specification deliberately makes no provision for a subscription acceptance
  989. mechanism (where the publisher must first accept a subscriber's request,
  990. via the pubsub component). If we're to prevent the publishers knowing
  991. who is subscribing, ought we to give them the power of veto, to 'balance
  992. things out'?
  993. </p>
  994. <p>
  995. Note that if we do, the acceptance issue is not necessarily one for the
  996. pubsub specification to resolve; there are other ways of introducing
  997. access control, at least in a component environment; use of a mechanism
  998. that the Jabber::Component::Proxy Perl module represents is one example:
  999. wedge a proxy component in front of a real (pubsub) component and have
  1000. the ability to use ACLs (access control lists) to control who gets to
  1001. connect to the real component.
  1002. </p>
  1003. </section2>
  1004. </section1>
  1005. </xep>