BiDirectional or Server-Initiated HTTP T. Oberstein
Internet-Draft A. Goedde
Intended status: Standards Track Crossbar.io Technologies GmbH
Expires: September 20, 2017 March 19, 2017

The Web Application Messaging Protocol
draft-oberstet-hybi-crossbar-wamp-01

Abstract

This document defines the Web Application Messaging Protocol (WAMP). WAMP is a routed protocol that provides two messaging patterns: Publish & Subscribe and routed Remote Procedure Calls. It is intended to connect application components in distributed applications. WAMP uses WebSocket as its default transport, but can be transmitted via any other protocol that allows for ordered, reliable, bi-directional, and message-oriented communications.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on September 20, 2017.

Copyright Notice

Copyright (c) 2017 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.


Table of Contents

1. Introduction

1.1. Background

This section is non-normative.

The WebSocket protocol brings bi-directional real-time connections to the browser. It defines an API at the message level, requiring users who want to use WebSocket connections in their applications to define their own semantics on top of it.

The Web Application Messaging Protocol (WAMP) is intended to provide application developers with the semantics they need to handle messaging between components in distributed applications.

WAMP was initially defined as a WebSocket sub-protocol, which provided Publish & Subscribe (PubSub) functionality as well as Remote Procedure Calls (RPC) for procedures implemented in a WAMP router. Feedback from implementers and users of this was included in a second version of the protocol which this document defines. Among the changes was that WAMP can now run over any transport which is message-oriented, ordered, reliable, and bi-directional.

WAMP is a routed protocol, with all components connecting to a WAMP Router, where the WAMP Router performs message routing between the components.

WAMP provides two messaging patterns: Publish & Subscribe and routed Remote Procedure Calls.

Publish & Subscribe (PubSub) is an established messaging pattern where a component, the Subscriber, informs the router that it wants to receive information on a topic (i.e., it subscribes to a topic). Another component, a Publisher, can then publish to this topic, and the router distributes events to all Subscribers.

Routed Remote Procedure Calls (RPCs) rely on the same sort of decoupling that is used by the Publish & Subscribe pattern. A component, the Callee, announces to the router that it provides a certain procedure, identified by a procedure name. Other components, Callers, can then call the procedure, with the router invoking the procedure on the Callee, receiving the procedure's result, and then forwarding this result back to the Caller. Routed RPCs differ from traditional client-server RPCs in that the router serves as an intermediary between the Caller and the Callee.

The decoupling in routed RPCs arises from the fact that the Caller is no longer required to have knowledge of the Callee; it merely needs to know the identifier of the procedure it wants to call. There is also no longer a need for a direct connection between the caller and the callee, since all traffic is routed. This enables the calling of procedures in components which are not reachable externally (e.g. on a NATted connection) but which can establish an outgoing connection to the WAMP router.

Combining these two patterns into a single protocol allows it to be used for the entire messaging requirements of an application, thus reducing technology stack complexity, as well as networking overheads.

1.2. Protocol Overview

This section is non-normative.

The PubSub messaging pattern defines three roles: Subscribers and Publishers, which communicate via a Broker.

The routed RPC messaging pattern also defines three roles: Callers and Callees, which communicate via a Dealer.

A Router is a component which implements one or both of the Broker and Dealer roles. A Client is a component which implements any or all of the Subscriber, Publisher, Caller, or Callee roles.

WAMP Connections are established by Clients to a Router. Connections can use any transport that is message-based, ordered, reliable and bi-directional, with WebSocket as the default transport.

WAMP Sessions are established over a WAMP Connection. A WAMP Session is joined to a Realm on a Router. Routing occurs only between WAMP Sessions that have joined the same Realm.

The WAMP Basic Profile defines the parts of the protocol that are required to establish a WAMP connection, as well as for basic interactions between the four client and two router roles. WAMP implementations are required to implement the Basic Profile, at minimum.

The WAMP Advanced Profile defines additions to the Basic Profile which greatly extend the utility of WAMP in real-world applications. WAMP implementations may support any subset of the Advanced Profile features. They are required to announce those supported features during session establishment.

1.3. Design Philosophy

This section is non-normative.

WAMP was designed to be performant, safe and easy to implement. Its entire design was driven by a implement, get feedback, adjust cycle.

An initial version of the protocol was publicly released in March 2012. The intent was to gain insight through implementation and use, and integrate these into a second version of the protocol, where there would be no regard for compatibility between the two versions. Several interoperable, independent implementations were released, and feedback from the implementers and users was collected.

The second version of the protocol, which this RFC covers, integrates this feedback. Routed Remote Procedure Calls are one outcome of this, where the initial version of the protocol only allowed the calling of procedures provided by the router. Another, related outcome was the strict separation of routing and application logic.

While WAMP was originally developed to use WebSocket as a transport, with JSON for serialization, experience in the field revealed that other transports and serialization formats were better suited to some use cases. For instance, with the use of WAMP in the Internet of Things sphere, resource constraints play a much larger role than in the browser, so any reduction of resource usage in WAMP implementations counts. This lead to the decoupling of WAMP from any particular transport or serialization, with the establishment of minimum requirements for both.

1.3.1. Basic and Advanced Profiles

This document first describes a Basic Profile for WAMP in its entirety, before describing an Advanced Profile which extends the basic functionality of WAMP.

The separation into Basic and Advanced Profiles is intended to extend the reach of the protocol. It allows implementations to start out with a minimal, yet operable and useful set of features, and to expand that set from there. It also allows implementations that are tailored for resource-constrained environments, where larger feature sets would not be possible. Here implementers can weigh between resource constraints and functionality requirements, then implement an optimal feature set for the circumstances.

Advanced Profile features are announced during session establishment, so that different implementations can adjust their interactions to fit the commonly supported feature set.

1.3.2. Application Code

WAMP is designed for application code to run within Clients, i.e. Peers having the roles Callee, Caller, Publisher, and Subscriber.

Routers, i.e. Peers of the roles Brokers and Dealers are responsible for generic call and event routing and do not run application code.

This allows the transparent exchange of Broker and Dealer implementations without affecting the application and to distribute and deploy application components flexibly.

1.3.3. Language Agnostic

WAMP is language agnostic, i.e. can be implemented in any programming language. At the level of arguments that may be part of a WAMP message, WAMP takes a 'superset of all' approach. WAMP implementations may support features of the implementing language for use in arguments, e.g. keyword arguments.

1.3.4. Router Implementation Specifics

This specification only deals with the protocol level. Specific WAMP Broker and Dealer implementations may differ in aspects such as support for:

The definition and documentation of such Router features is outside the scope of this document.

1.4. Relationship to WebSocket

WAMP uses WebSocket as its default transport binding, and is a registered WebSocket subprotocol.

2. Conformance Requirements

All diagrams, examples, and notes in this specification are non-normative, as are all sections explicitly marked non-normative. Everything else in this specification is normative.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [RFC2119].

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("MUST", "SHOULD", "MAY", etc.) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps MAY be implemented in any manner, so long as the end result is equivalent.

2.1. Terminology and Other Conventions

Key terms such as named algorithms or definitions are indicated like this when they first occur, and are capitalized throughout the text.

3. Realms, Sessions and Transports

A Realm is a WAMP routing and administrative domain, optionally protected by authentication and authorization. WAMP messages are only routed within a Realm.

A Session is a transient conversation between two Peers attached to a Realm and running over a Transport.

A Transport connects two WAMP Peers and provides a channel over which WAMP messages for a WAMP Session can flow in both directions.

WAMP can run over any Transport which is message-based, bidirectional, reliable and ordered.

The default transport for WAMP is WebSocket [RFC6455], where WAMP is an officially registered subprotocol.

4. Peers and Roles

A WAMP Session connects two Peers, a Client and a Router. Each WAMP Peer MUST implement one role, and MAY implement more roles.

A Client MAY implement any combination of the Roles:

and a Router MAY implement either or both of the Roles:

4.1. Symmetric Messaging

It is important to note that though the establishment of a Transport might have a inherent asymmetry (like a TCP client establishing a WebSocket connection to a server), and Clients establish WAMP sessions by attaching to Realms on Routers, WAMP itself is designed to be fully symmetric for application components.

After the transport and a session have been established, any application component may act as Caller, Callee, Publisher and Subscriber at the same time. And Routers provide the fabric on top of which WAMP runs a symmetric application messaging service.

4.2. Remote Procedure Call Roles

The Remote Procedure Call messaging pattern involves peers of three different roles:

A Caller issues calls to remote procedures by providing the procedure URI and any arguments for the call. The Callee will execute the procedure using the supplied arguments to the call and return the result of the call to the Caller.

Callees register procedures they provide with Dealers. Callers initiate procedure calls first to Dealers. Dealers route calls incoming from Callers to Callees implementing the procedure called, and route call results back from Callees to Callers.

The Caller and Callee will usually run application code, while the Dealer works as a generic router for remote procedure calls decoupling Callers and Callees.

4.3. Publish & Subscribe Roles

The Publish & Subscribe messaging pattern involves peers of three different roles:

A Publisher publishes events to topics by providing the topic URI and any payload for the event. Subscribers of the topic will receive the event together with the event payload.

Subscribers subscribe to topics they are interested in with Brokers. Publishers initiate publication first at Brokers. Brokers route events incoming from Publishers to Subscribers that are subscribed to respective topics.

The Publisher and Subscriber will usually run application code, while the Broker works as a generic router for events decoupling Publishers from Subscribers.

4.4. Peers with multiple Roles

Note that Peers might implement more than one role: e.g. a Peer might act as Caller, Publisher and Subscriber at the same time. Another Peer might act as both a Broker and a Dealer.

5. Building Blocks

WAMP is defined with respect to the following building blocks

  1. Identifiers
  2. Serializations
  3. Transports

For each building block, WAMP only assumes a defined set of requirements, which allows to run WAMP variants with different concrete bindings.

5.1. Identifiers

5.1.1. URIs

WAMP needs to identify the following persistent resources:

  1. Topics
  2. Procedures
  3. Errors

These are identified in WAMP using Uniform Resource Identifiers (URIs) [RFC3986] that MUST be Unicode strings.

Examples

The URIs are understood to form a single, global, hierarchical namespace for WAMP.

To avoid resource naming conflicts, the package naming convention from Java is used, where URIs SHOULD begin with (reversed) domain names owned by the organization defining the URI.

5.1.1.1. Relaxed/Loose URIs

URI components (the parts between two .s, the head part up to the first ., the tail part after the last .) MUST NOT contain a ., # or whitespace characters and MUST NOT be empty (zero-length strings).

As an example, the following regular expression could be used in Python to check URIs according to the above rules:

    <CODE BEGINS>
        ## loose URI check disallowing empty URI components
        pattern = re.compile(r"^([^\s\.#]+\.)*([^\s\.#]+)$")
    <CODE ENDS>

When empty URI components are allowed (which is the case for specific messages that are part of the Advanced Profile), this following regular expression can be used (shown used in Python):

    <CODE BEGINS>
        ## loose URI check allowing empty URI components
        pattern = re.compile(r"^(([^\s\.#]+\.)|\.)*([^\s\.#]+)?$")
    <CODE ENDS>

5.1.1.2. Strict URIs

While the above rules MUST be followed, following a stricter URI rule is recommended: URI components SHOULD only contain lower-case letters, digits and _.

As an example, the following regular expression could be used in Python to check URIs according to the above rules:

    <CODE BEGINS>
        ## strict URI check disallowing empty URI components
        pattern = re.compile(r"^([0-9a-z_]+\.)*([0-9a-z_]+)$")
    <CODE ENDS>

When empty URI components are allowed (which is the case for specific messages that are part of the Advanced Profile), the following regular expression can be used (shown in Python):

    <CODE BEGINS>
        ## strict URI check allowing empty URI components
        pattern = re.compile(r"^(([0-9a-z_]+\.)|\.)*([0-9a-z_]+)?$")
    <CODE ENDS>

5.1.1.3. Reserved URIs

Further, application URIs MUST NOT use wamp as a first URI component, since this is reserved for URIs predefined with the WAMP protocol itself.

Examples

5.1.2. IDs

WAMP needs to identify the following ephemeral entities each in the scope noted:

  1. Sessions (global scope)
  2. Publications (global scope)
  3. Subscriptions (router scope)
  4. Registrations (router scope)
  5. Requests (session scope)

These are identified in WAMP using IDs that are integers between (inclusive) 0 and 2^53 (9007199254740992):

The following is a complete list of usage of IDs in the three categories for all WAMP messages. For a full definition of these see Section 6.

5.1.2.1. Global Scope IDs

5.1.2.2. Router Scope IDs

5.1.2.3. Session Scope IDs

5.2. Serializations

WAMP is a message based protocol that requires serialization of messages to octet sequences to be sent out on the wire.

A message serialization format is assumed that (at least) provides the following types:

There is no required serialization or set of serializations for WAMP implementations (but each implementation MUST, of course, implement at least one serialization format). Routers SHOULD implement more than one serialization format, enabling components using different kinds of serializations to connect to each other.

WAMP defines two bindings for message serialization:

  1. JSON
  2. MessagePack

Other bindings for serialization may be defined in future WAMP versions.

5.2.1. JSON

With JSON serialization, each WAMP message is serialized according to the JSON specification as described in RFC4627.

Further, binary data follows a convention for conversion to JSON strings. For details see the Appendix.

5.2.2. MessagePack

With MessagePack serialization, each WAMP message is serialized according to the MessagePack specification.

5.3. Transports

WAMP assumes a transport with the following characteristics:

  1. message-based
  2. reliable
  3. ordered
  4. bidirectional (full-duplex)

There is no required transport or set of transports for WAMP implementations (but each implementation MUST, of course, implement at least one transport). Routers SHOULD implement more than one transport, enabling components using different kinds of transports to connect in an application.

5.3.1. WebSocket Transport

The default transport binding for WAMP is WebSocket ([RFC6455]).

In the Basic Profile, WAMP messages are transmitted as WebSocket messages: each WAMP message is transmitted as a separate WebSocket message (not WebSocket frame). The Advanced Profile may define other modes, e.g. a batched mode where multiple WAMP messages are transmitted via single WebSocket message.

The WAMP protocol MUST BE negotiated during the WebSocket opening handshake between Peers using the WebSocket subprotocol negotiation mechanism ([RFC6455] section 4).

WAMP uses the following WebSocket subprotocol identifiers for unbatched modes:

With wamp.2.json, all WebSocket messages MUST BE of type text (UTF8 encoded payload) and use the JSON message serialization.

With wamp.2.msgpack, all WebSocket messages MUST BE of type binary and use the MessagePack message serialization.

5.3.2. Transport and Session Lifetime

WAMP implementations MAY choose to tie the lifetime of the underlying transport connection for a WAMP connection to that of a WAMP session, i.e. establish a new transport-layer connection as part of each new session establishment. They MAY equally choose to allow re-use of a transport connection, allowing subsequent WAMP sessions to be established using the same transport connection.

The diagram below illustrates the full transport connection and session lifecycle for an implementation which uses WebSocket over TCP as the transport and allows the re-use of a transport connection.

    ,------.                                    ,------.
    | Peer |                                    | Peer |
    `--+---'                                    `--+---'

                      TCP established
       |<----------------------------------------->|
       |                                           |
       |               TLS established             |
       |+<--------------------------------------->+|
       |+                                         +|
       |+           WebSocket established         +|
       |+|<------------------------------------->|+|
       |+|                                       |+|
       |+|            WAMP established           |+|
       |+|+<----------------------------------->+|+|
       |+|+                                     +|+|
       |+|+                                     +|+|
       |+|+            WAMP closed              +|+|
       |+|+<----------------------------------->+|+|
       |+|                                       |+|
       |+|                                       |+|
       |+|            WAMP established           |+|
       |+|+<----------------------------------->+|+|
       |+|+                                     +|+|
       |+|+                                     +|+|
       |+|+            WAMP closed              +|+|
       |+|+<----------------------------------->+|+|
       |+|                                       |+|
       |+|           WebSocket closed            |+|
       |+|<------------------------------------->|+|
       |+                                         +|
       |+              TLS closed                 +|
       |+<--------------------------------------->+|
       |                                           |
       |               TCP closed                  |
       |<----------------------------------------->|

    ,--+---.                                    ,--+---.
    | Peer |                                    | Peer |
    `------'                                    `------'

5.3.3. Protocol errors

WAMP implementations MUST close sessions (disposing all of their resources such as subscriptions and registrations) on protocol errors caused by offending peers.

Those implementations that MIGHT have chosen to tie the lifetime of the underlying transport connection for a WAMP connection to that of a WAMP session MUST also close the transport connection if any protocol error occurs.

Following scenarios have to be considered protocol errors:

6. Messages

All WAMP messages are a list with a first element MessageType followed by one or more message type specific elements:

    [MessageType|integer, ... one or more message type specific
        elements ...]

The notation Element|type denotes a message element named Element of type type, where type is one of

Example

A SUBSCRIBE message has the following format

    [SUBSCRIBE, Request|id, Options|dict, Topic|uri]

Here is an example message conforming to the above format

    [32, 713845233, {}, "com.myapp.mytopic1"]

6.1. Extensibility

Some WAMP messages contain Options|dict or Details|dict elements. This allows for future extensibility and implementations that only provide subsets of functionality by ignoring unimplemented attributes. Keys in Options and Details MUST be of type string and MUST match the regular expression [a-z][a-z0-9_]{2,} for WAMP predefined keys. Implementations MAY use implementation-specific keys that MUST match the regular expression _[a-z0-9_]{3,}. Attributes unknown to an implementation MUST be ignored.

6.2. No Polymorphism

For a given MessageType and number of message elements the expected types are uniquely defined. Hence there are no polymorphic messages in WAMP. This leads to a message parsing and validation control flow that is efficient, simple to implement and simple to code for rigorous message format checking.

6.3. Structure

The application payload (that is call arguments, call results, event payload etc) is always at the end of the message element list. The rationale is: Brokers and Dealers have no need to inspect (parse) the application payload. Their business is call/event routing. Having the application payload at the end of the list allows Brokers and Dealers to skip parsing it altogether. This can improve efficiency and performance.

6.4. Message Definitions

WAMP defines the following messages that are explained in detail in the following sections.

The messages concerning the WAMP session itself are mandatory for all Peers, i.e. a Client MUST implement HELLO, ABORT and GOODBYE, while a Router MUST implement WELCOME, ABORT and GOODBYE.

All other messages are mandatory per role, i.e. in an implementation that only provides a Client with the role of Publisher MUST additionally implement sending PUBLISH and receiving PUBLISHED and ERROR messages.

6.4.1. Session Lifecycle

6.4.1.1. HELLO

Sent by a Client to initiate opening of a WAMP session to a Router attaching to a Realm.

    [HELLO, Realm|uri, Details|dict]

6.4.1.2. WELCOME

Sent by a Router to accept a Client. The WAMP session is now open.

    [WELCOME, Session|id, Details|dict]

6.4.1.3. ABORT

Sent by a Peer*to abort the opening of a WAMP session. No response is expected.

    [ABORT, Details|dict, Reason|uri]

6.4.1.4. GOODBYE

Sent by a Peer to close a previously opened WAMP session. Must be echo'ed by the receiving Peer.

    [GOODBYE, Details|dict, Reason|uri]

6.4.1.5. ERROR

Error reply sent by a Peer as an error response to different kinds of requests.

    [ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict,
        Error|uri]

    [ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict,
        Error|uri, Arguments|list]

    [ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict,
        Error|uri, Arguments|list, ArgumentsKw|dict]

6.4.2. Publish & Subscribe

6.4.2.1. PUBLISH

Sent by a Publisher to a Broker to publish an event.

    [PUBLISH, Request|id, Options|dict, Topic|uri]

    [PUBLISH, Request|id, Options|dict, Topic|uri,
        Arguments|list]

    [PUBLISH, Request|id, Options|dict, Topic|uri,
        Arguments|list, ArgumentsKw|dict]

6.4.2.2. PUBLISHED

Acknowledge sent by a Broker to a Publisher for acknowledged publications.

    [PUBLISHED, PUBLISH.Request|id, Publication|id]

6.4.2.3. SUBSCRIBE

Subscribe request sent by a Subscriber to a Broker to subscribe to a topic.

    [SUBSCRIBE, Request|id, Options|dict, Topic|uri]

6.4.2.4. SUBSCRIBED

Acknowledge sent by a Broker to a Subscriber to acknowledge a subscription.

    [SUBSCRIBED, SUBSCRIBE.Request|id, Subscription|id]

6.4.2.5. UNSUBSCRIBE

Unsubscribe request sent by a Subscriber to a Broker to unsubscribe a subscription.

    [UNSUBSCRIBE, Request|id, SUBSCRIBED.Subscription|id]

6.4.2.6. UNSUBSCRIBED

Acknowledge sent by a Broker to a Subscriber to acknowledge unsubscription.

    [UNSUBSCRIBED, UNSUBSCRIBE.Request|id]

6.4.2.7. EVENT

Event dispatched by Broker to Subscribers for subscriptions the event was matching.

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
        Details|dict]

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
        Details|dict, PUBLISH.Arguments|list]

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
        Details|dict, PUBLISH.Arguments|list,
        PUBLISH.ArgumentsKw|dict]

6.4.3. Routed Remote Procedure Calls

6.4.3.1. CALL

Call as originally issued by the Caller to the Dealer.

  [CALL, Request|id, Options|dict, Procedure|uri]

  [CALL, Request|id, Options|dict, Procedure|uri, Arguments|list]

  [CALL, Request|id, Options|dict, Procedure|uri, Arguments|list,
      ArgumentsKw|dict]

6.4.3.2. RESULT

Result of a call as returned by Dealer to Caller.

    [RESULT, CALL.Request|id, Details|dict]

    [RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list]

    [RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list,
        YIELD.ArgumentsKw|dict]

6.4.3.3. REGISTER

A Callees request to register an endpoint at a Dealer.

    [REGISTER, Request|id, Options|dict, Procedure|uri]

6.4.3.4. REGISTERED

Acknowledge sent by a Dealer to a Callee for successful registration.

    [REGISTERED, REGISTER.Request|id, Registration|id]

6.4.3.5. UNREGISTER

A Callees request to unregister a previously established registration.

    [UNREGISTER, Request|id, REGISTERED.Registration|id]

6.4.3.6. UNREGISTERED

Acknowledge sent by a Dealer to a Callee for successful unregistration.

    [UNREGISTERED, UNREGISTER.Request|id]

6.4.3.7. INVOCATION

Actual invocation of an endpoint sent by Dealer to a Callee.

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict]

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict, C* Arguments|list]

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict, CALL.Arguments|list, CALL.ArgumentsKw|dict]

6.4.3.8. YIELD

Actual yield from an endpoint sent by a Callee to Dealer.

    [YIELD, INVOCATION.Request|id, Options|dict]

    [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list]

    [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list,
        ArgumentsKw|dict]

6.5. Message Codes and Direction

The following table lists the message type code for all 25 messages defined in the WAMP basic profile and their direction between peer roles.

Reserved codes may be used to identify additional message types in future standards documents.

Cod Message Pub Brk Subs Calr Dealr Callee
1 HELLO Tx Rx Tx Tx Rx Tx
2 WELCOME Rx Tx Rx Rx Tx Rx
3 ABORT Rx TxRx Rx Rx TxRx Rx
6 GOODBYE TxRx TxRx TxRx TxRx TxRx TxRx
8 ERROR Rx Tx Rx Rx TxRx TxRx
16 PUBLISH Tx Rx
17 PUBLISHED Rx Tx
32 SUBSCRIBE Rx Tx
33 SUBSCRIBED Tx Rx
34 UNSUBSCRIBE Rx Tx
35 UNSUBSCRIBED Tx Rx
36 EVENT Tx Rx
48 CALL Tx Rx
50 RESULT Rx Tx
64 REGISTER Rx Tx
65 REGISTERED Tx Rx
66 UNREGISTER Rx Tx
67 UNREGISTERED Tx Rx
68 INVOCATION Tx Rx
70 YIELD Rx Tx

6.6. Extension Messages

WAMP uses type codes from the core range [0, 255]. Implementations MAY define and use implementation specific messages with message type codes from the extension message range [256, 1023]. For example, a router MAY implement router-to-router communication by using extension messages.

6.7. Empty Arguments and Keyword Arguments

Implementations SHOULD avoid sending empty Arguments lists.

E.g. a CALL message

    [CALL, Request|id, Options|dict, Procedure|uri,
        Arguments|list]

where Arguments == [] SHOULD be avoided, and instead

    [CALL, Request|id, Options|dict, Procedure|uri]

SHOULD be sent.

Implementations SHOULD avoid sending empty ArgumentsKw dictionaries.

E.g. a CALL message

    [CALL, Request|id, Options|dict, Procedure|uri,
        Arguments|list, ArgumentsKw|dict]

where ArgumentsKw == {} SHOULD be avoided, and instead

    [CALL, Request|id, Options|dict, Procedure|uri,
        Arguments|list]

SHOULD be sent when Arguments is non-empty.

7. Sessions

The message flow between Clients and Routers for opening and closing WAMP sessions involves the following messages:

  1. HELLO
  2. WELCOME
  3. ABORT
  4. GOODBYE

7.1. Session Establishment

7.1.1. HELLO

After the underlying transport has been established, the opening of a WAMP session is initiated by the Client sending a HELLO message to the Router

    [HELLO, Realm|uri, Details|dict]

where

The HELLO message MUST be the very first message sent by the Client after the transport has been established.

In the WAMP Basic Profile without session authentication the Router will reply with a WELCOME or ABORT message.

    ,------.          ,------.
    |Client|          |Router|
    `--+---'          `--+---'
       |      HELLO      |
       | ---------------->
       |                 |
       |     WELCOME     |
       | <----------------
    ,--+---.          ,--+---.
    |Client|          |Router|
    `------'          `------'

A WAMP session starts its lifetime when the Router has sent a WELCOME message to the Client, and ends when the underlying transport closes or when the session is closed explicitly by either peer sending the GOODBYE message (see below).

It is a Section 5.3.3 to receive a second HELLO message during the lifetime of the session and the Peer MUST close the session if that happens.

7.1.1.1. Client: Role and Feature Announcement

WAMP uses Role & Feature announcement instead of protocol versioning to allow

A Client must announce the roles it supports via Hello.Details.roles|dict, with a key mapping to a Hello.Details.roles.<role>|dict where <role> can be:

A Client can support any combination of the above roles but must support at least one role.

The <role>|dict is a dictionary describing features supported by the peer for that role.

This MUST be empty for WAMP Basic Profile implementations, and MUST be used by implementations implementing parts of the Advanced Profile to list the specific set of features they support.

Example: A Client that implements the Publisher and Subscriber roles of the WAMP Basic Profile.

    [1, "somerealm", {
      "roles": {
          "publisher": {},
          "subscriber": {}
      }
    }]

7.1.2. WELCOME

A Router completes the opening of a WAMP session by sending a WELCOME reply message to the Client.

    [WELCOME, Session|id, Details|dict]

where

In the WAMP Basic Profile without session authentication, a WELCOME message MUST be the first message sent by the Router, directly in response to a HELLO message received from the Client. Extensions in the Advanced Profile MAY include intermediate steps and messages for authentication.

7.1.2.1. Router: Role and Feature Announcement

Similar to a Client announcing Roles and Features supported in the `HELLO message, a Router announces its supported Roles and Features in the WELCOME message.

A Router MUST announce the roles it supports via Welcome.Details.roles|dict, with a key mapping to a Welcome.Details.roles.<role>|dict where <role> can be:

A Router must support at least one role, and MAY support both roles.

The <role>|dict is a dictionary describing features supported by the peer for that role. With WAMP Basic Profile implementations, this MUST be empty, but MUST be used by implementations implementing parts of the Advanced Profile to list the specific set of features they support

Example: A Router implementing the Broker role of the WAMP Basic Profile.

    [2, 9129137332, {
       "roles": {
          "broker": {}
       }
    }]

7.1.3. ABORT

Both the Router and the Client may abort the opening of a WAMP session by sending an ABORT message.

    [ABORT, Details|dict, Reason|uri]

where

No response to an ABORT message is expected.

    ,------.          ,------.
    |Client|          |Router|
    `--+---'          `--+---'
       |      HELLO      |
       | ---------------->
       |                 |
       |      ABORT      |
       | <----------------
    ,--+---.          ,--+---.
    |Client|          |Router|
    `------'          `------'

Example

    [3, {"message": "The realm does not exist."},
        "wamp.error.no_such_realm"]

7.2. Session Closing

A WAMP session starts its lifetime with the Router sending a WELCOME message to the Client and ends when the underlying transport disappears or when the WAMP session is closed explicitly by a GOODBYE message sent by one Peer and a GOODBYE message sent from the other Peer in response.

    [GOODBYE, Details|dict, Reason|uri]

where

    ,------.          ,------.
    |Client|          |Router|
    `--+---'          `--+---'
       |     GOODBYE     |
       | ---------------->
       |                 |
       |     GOODBYE     |
       | <----------------
    ,--+---.          ,--+---.
    |Client|          |Router|
    `------'          `------'
    ,------.          ,------.
    |Client|          |Router|
    `--+---'          `--+---'
       |     GOODBYE     |
       | <----------------
       |                 |
       |     GOODBYE     |
       | ---------------->
    ,--+---.          ,--+---.
    |Client|          |Router|
    `------'          `------'

Example. One Peer initiates closing

    [6, {"message": "The host is shutting down now."},
        "wamp.error.system_shutdown"]

and the other peer replies

    [6, {}, "wamp.error.goodbye_and_out"]

Example. One Peer initiates closing

    [6, {}, "wamp.error.close_realm"]

and the other peer replies

    [6, {}, "wamp.error.goodbye_and_out"]

7.2.1. Difference between ABORT and GOODBYE

The differences between ABORT and GOODBYE messages are:

  1. ABORT gets sent only before a Session is established, while GOODBYE is sent only after a Session is already established.
  2. ABORT is never replied to by a Peer, whereas GOODBYE must be replied to by the receiving Peer

7.2.2. Session Statechart

The following state chart gives the states that a WAMP peer can be in during the session lifetime cycle.

                         +--------------+                           
+--------(6)------------->              |                           
|                        | CLOSED       <--------------------------+
| +------(4)------------->              <---+                      |
| |                      +--------------+   |                      |
| |                               |         |                      |
| |                              (1)       (7)                     |
| |                               |         |                      |
| |                      +--------v-----+   |                   (11)
| |                      |              +---+                      |
| |         +------------+ ESTABLISHING +----------------+         |
| |         |            |              |                |         |
| |         |            +--------------+                |         |
| |         |                     |                     (10)       |
| |         |                    (9)                     |         |
| |         |                     |                      |         |
| |        (2)           +--------v-----+       +--------v-------+ |
| |         |            |              |       |                | |
| |         |     +------> FAILED       <--(13)-+ CHALLENGING /  +-+
| |         |     |      |              |       | AUTHENTICATING |  
| |         |     |      +--------------+       +----------------+  
| |         |    (8)                                     |          
| |         |     |                                      |          
| |         |     |                                      |          
| | +-------v-------+                                    |          
| | |               <-------------------(12)-------------+          
| | | ESTABLISHED   |                                               
| | |               +--------------+                                
| | +---------------+              |                                
| |         |                      |                                
| |        (3)                    (5)                               
| |         |                      |                                
| | +-------v-------+     +--------v-----+                          
| | |               +--+  |              |                          
| +-+ SHUTTING DOWN |  |  | CLOSING      |                          
|   |               |(14) |              |                          
|   +-------^-------+  |  +--------------+                          
|           |----------+           |                                
+----------------------------------+     
# State
1 Sent HELLO
2 Received WELCOME
3 Sent GOODBYE
4 Received GOODBYE
5 Received GOODBYE
6 Sent GOODBYE
7 Received invalid HELLO / Send ABORT
8 Received HELLO or AUTHENTICATE
9 Received other
10 Received valid HELLO [needs authentication] / Send CHALLENGE
11 Received invalid AUTHENTICATE / Send ABORT
12 Received valid AUTHENTICATE / Send WELCOME
13 Received other
14 Received other / ignore

8. Agent Identification

When a software agent operates in a network protocol, it often identifies itself, its application type, operating system, software vendor, or software revision, by submitting a characteristic identification string to its operating peer.

Similar to what browsers do with the User-Agent HTTP header, both the HELLO and the WELCOME message MAY disclose the WAMP implementation in use to its peer:

    HELLO.Details.agent|string

and

    WELCOME.Details.agent|string

Example: A Client "HELLO" message.

    [1, "somerealm", {
         "agent": "AutobahnJS-0.9.14",
         "roles": {
            "subscriber": {},
            "publisher": {}
         }
    }]

Example: A Router "WELCOME" message.

    [2, 9129137332, {
        "agent": "Crossbar.io-0.10.11",
        "roles": {
          "broker": {}
        }
    }]

9. Publish and Subscribe

All of the following features for Publish & Subscribe are mandatory for WAMP Basic Profile implementations supporting the respective roles, i.e. Publisher, Subscriber and Dealer.

9.1. Subscribing and Unsubscribing

The message flow between Clients implementing the role of Subscriber and Routers implementing the role of Broker for subscribing and unsubscribing involves the following messages:

  1. SUBSCRIBE
  2. SUBSCRIBED
  3. UNSUBSCRIBE
  4. UNSUBSCRIBED
  5. ERROR

    ,---------.          ,------.             ,----------.
    |Publisher|          |Broker|             |Subscriber|
    `----+----'          `--+---'             `----+-----'
         |                  |                      |
         |                  |                      |
         |                  |       SUBSCRIBE      |
         |                  | <---------------------
         |                  |                      |
         |                  |  SUBSCRIBED or ERROR |
         |                  | --------------------->
         |                  |                      |
         |                  |                      |
         |                  |                      |
         |                  |                      |
         |                  |      UNSUBSCRIBE     |
         |                  | <---------------------
         |                  |                      |
         |                  | UNSUBSCRIBED or ERROR|
         |                  | --------------------->
    ,----+----.          ,--+---.             ,----+-----.
    |Publisher|          |Broker|             |Subscriber|
    `---------'          `------'             `----------'

A Subscriber may subscribe to zero, one or more topics, and a Publisher publishes to topics without knowledge of subscribers.

Upon subscribing to a topic via the SUBSCRIBE message, a Subscriber will receive any future events published to the respective topic by Publishers, and will receive those events asynchronously.

A subscription lasts for the duration of a session, unless a Subscriber opts out from a previously established subscription via the UNSUBSCRIBE message.

9.1.1. SUBSCRIBE

A Subscriber communicates its interest in a topic to a Broker by sending a SUBSCRIBE message:

    [SUBSCRIBE, Request|id, Options|dict, Topic|uri]

where

Example

    [32, 713845233, {}, "com.myapp.mytopic1"]

A Broker, receiving a SUBSCRIBE message, can fullfill or reject the subscription, so it answers with SUBSCRIBED or ERROR messages.

9.1.2. SUBSCRIBED

If the Broker is able to fulfill and allow the subscription, it answers by sending a SUBSCRIBED message to the Subscriber

    [SUBSCRIBED, SUBSCRIBE.Request|id, Subscription|id]

where

Example

    [33, 713845233, 5512315355]

9.1.3. Subscribe ERROR

When the request for subscription cannot be fulfilled by the Broker, the Broker sends back an ERROR message to the Subscriber

    [ERROR, SUBSCRIBE, SUBSCRIBE.Request|id, Details|dict,
        Error|uri]

where

Example

    [8, 32, 713845233, {}, "wamp.error.not_authorized"]

9.1.4. UNSUBSCRIBE

When a Subscriber is no longer interested in receiving events for a subscription it sends an UNSUBSCRIBE message

    [UNSUBSCRIBE, Request|id, SUBSCRIBED.Subscription|id]

where

Example

    [34, 85346237, 5512315355]

9.1.5. UNSUBSCRIBED

Upon successful unsubscription, the Broker sends an UNSUBSCRIBED message to the Subscriber

    [UNSUBSCRIBED, UNSUBSCRIBE.Request|id]

where

Example

    [35, 85346237]

9.1.6. Unsubscribe ERROR

When the request fails, the Broker sends an ERROR

    [ERROR, UNSUBSCRIBE, UNSUBSCRIBE.Request|id, Details|dict,
        Error|uri]

where

Example

    [8, 34, 85346237, {}, "wamp.error.no_such_subscription"]

9.2. Publishing and Events

The message flow between Publishers, a Broker and Subscribers for publishing to topics and dispatching events involves the following messages:

  1. PUBLISH
  2. PUBLISHED
  3. EVENT
  4. ERROR

    ,---------.          ,------.          ,----------.
    |Publisher|          |Broker|          |Subscriber|
    `----+----'          `--+---'          `----+-----'
         |     PUBLISH      |                   |
         |------------------>                   |
         |                  |                   |
         |PUBLISHED or ERROR|                   |
         |<------------------                   |
         |                  |                   |
         |                  |       EVENT       |
         |                  | ------------------>
    ,----+----.          ,--+---.          ,----+-----.
    |Publisher|          |Broker|          |Subscriber|
    `---------'          `------'          `----------'

9.2.1. PUBLISH

When a Publisher requests to publish an event to some topic, it sends a PUBLISH message to a Broker:

    [PUBLISH, Request|id, Options|dict, Topic|uri]

or

    [PUBLISH, Request|id, Options|dict, Topic|uri, Arguments|list]

or

    [PUBLISH, Request|id, Options|dict, Topic|uri, Arguments|list,
        ArgumentsKw|dict]

where

If the Broker is able to fulfill and allowing the publication, the Broker will send the event to all current Subscribers of the topic of the published event.

By default, publications are unacknowledged, and the Broker will not respond, whether the publication was successful indeed or not. This behavior can be changed with the option PUBLISH.Options.acknowledge|bool (see below).

Example

    [16, 239714735, {}, "com.myapp.mytopic1"]

Example

    [16, 239714735, {}, "com.myapp.mytopic1", ["Hello, world!"]]

Example

    [16, 239714735, {}, "com.myapp.mytopic1", [], {"color": "orange",
        "sizes": [23, 42, 7]}]

9.2.2. PUBLISHED

If the Broker is able to fulfill and allowing the publication, and PUBLISH.Options.acknowledge == true, the Broker replies by sending a PUBLISHED message to the Publisher:

    [PUBLISHED, PUBLISH.Request|id, Publication|id]

where

Example

    [17, 239714735, 4429313566]

9.2.3. Publish ERROR

When the request for publication cannot be fulfilled by the Broker, and PUBLISH.Options.acknowledge == true, the Broker sends back an ERROR message to the Publisher

    [ERROR, PUBLISH, PUBLISH.Request|id, Details|dict, Error|uri]

where

Example

    [8, 16, 239714735, {}, "wamp.error.not_authorized"]

9.2.4. EVENT

When a publication is successful and a Broker dispatches the event, it determines a list of receivers for the event based on Subscribers for the topic published to and, possibly, other information in the event.

Note that the Publisher of an event will never receive the published event even if the Publisher is also a Subscriber of the topic published to.

When a Subscriber is deemed to be a receiver, the Broker sends the Subscriber an EVENT message:

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
        Details|dict]

or

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
        Details|dict, PUBLISH.Arguments|list]

or

    [EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id,
    Details|dict, PUBLISH.Arguments|list, PUBLISH.ArgumentKw|dict]

where

Example

    [36, 5512315355, 4429313566, {}]

Example

    [36, 5512315355, 4429313566, {}, ["Hello, world!"]]

Example

    [36, 5512315355, 4429313566, {}, [], {"color": "orange",
        "sizes": [23, 42, 7]}]

10. Remote Procedure Calls

All of the following features for Remote Procedure Calls are mandatory for WAMP Basic Profile implementations supporting the respective roles.

10.1. Registering and Unregistering

The message flow between Callees and a Dealer for registering and unregistering endpoints to be called over RPC involves the following messages:

  1. REGISTER
  2. REGISTERED
  3. UNREGISTER
  4. UNREGISTERED
  5. ERROR

    ,------.          ,------.               ,------.
    |Caller|          |Dealer|               |Callee|
    `--+---'          `--+---'               `--+---'
       |                 |                      |
       |                 |                      |
       |                 |       REGISTER       |
       |                 | <---------------------
       |                 |                      |
       |                 |  REGISTERED or ERROR |
       |                 | --------------------->
       |                 |                      |
       |                 |                      |
       |                 |                      |
       |                 |                      |
       |                 |                      |
       |                 |      UNREGISTER      |
       |                 | <---------------------
       |                 |                      |
       |                 | UNREGISTERED or ERROR|
       |                 | --------------------->
    ,--+---.          ,--+---.               ,--+---.
    |Caller|          |Dealer|               |Callee|
    `------'          `------'               `------'

10.1.1. REGISTER

A Callee announces the availability of an endpoint implementing a procedure with a Dealer by sending a REGISTER message:

    [REGISTER, Request|id, Options|dict, Procedure|uri]

where

Example

    [64, 25349185, {}, "com.myapp.myprocedure1"]

10.1.2. REGISTERED

If the Dealer is able to fulfill and allowing the registration, it answers by sending a REGISTERED message to the Callee:

    [REGISTERED, REGISTER.Request|id, Registration|id]

where

Example

    [65, 25349185, 2103333224]

10.1.3. Register ERROR

When the request for registration cannot be fulfilled by the Dealer, the Dealer sends back an ERROR message to the Callee:

    [ERROR, REGISTER, REGISTER.Request|id, Details|dict, Error|uri]

where

Example

    [8, 64, 25349185, {}, "wamp.error.procedure_already_exists"]

10.1.4. UNREGISTER

When a Callee is no longer willing to provide an implementation of the registered procedure, it sends an UNREGISTER message to the Dealer:

    [UNREGISTER, Request|id, REGISTERED.Registration|id]

where

Example

    [66, 788923562, 2103333224]

10.1.5. UNREGISTERED

Upon successful unregistration, the Dealer sends an UNREGISTERED message to the Callee:

    [UNREGISTERED, UNREGISTER.Request|id]

where

Example

    [67, 788923562]

10.1.6. Unregister ERROR

When the unregistration request fails, the Dealer sends an ERROR message:

    [ERROR, UNREGISTER, UNREGISTER.Request|id, Details|dict,
        Error|uri]

where

Example

    [8, 66, 788923562, {}, "wamp.error.no_such_registration"]

10.2. Calling and Invocations

The message flow between Callers, a Dealer and Callees for calling procedures and invoking endpoints involves the following messages:

  1. CALL
  2. RESULT
  3. INVOCATION
  4. YIELD
  5. ERROR

    ,------.          ,------.          ,------.
    |Caller|          |Dealer|          |Callee|
    `--+---'          `--+---'          `--+---'
       |       CALL      |                 |
       | ---------------->                 |
       |                 |                 |
       |                 |    INVOCATION   |
       |                 | ---------------->
       |                 |                 |
       |                 |  YIELD or ERROR |
       |                 | <----------------
       |                 |                 |
       | RESULT or ERROR |                 |
       | <----------------                 |
    ,--+---.          ,--+---.          ,--+---.
    |Caller|          |Dealer|          |Callee|
    `------'          `------'          `------'

The execution of remote procedure calls is asynchronous, and there may be more than one call outstanding. A call is called outstanding (from the point of view of the Caller), when a (final) result or error has not yet been received by the Caller.

10.2.1. CALL

When a Caller wishes to call a remote procedure, it sends a CALL message to a Dealer:

    [CALL, Request|id, Options|dict, Procedure|uri]

or

    [CALL, Request|id, Options|dict, Procedure|uri, Arguments|list]

or

    [CALL, Request|id, Options|dict, Procedure|uri, Arguments|list,
        ArgumentsKw|dict]

where

Example

    [48, 7814135, {}, "com.myapp.ping"]

Example

    [48, 7814135, {}, "com.myapp.echo", ["Hello, world!"]]

Example

    [48, 7814135, {}, "com.myapp.add2", [23, 7]]

Example

    [48, 7814135, {}, "com.myapp.user.new", ["johnny"],
        {"firstname": "John", "surname": "Doe"}]

10.2.2. INVOCATION

If the Dealer is able to fulfill (mediate) the call and it allows the call, it sends a INVOCATION message to the respective Callee implementing the procedure:

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict]

or

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict, CALL.Arguments|list]

or

    [INVOCATION, Request|id, REGISTERED.Registration|id,
        Details|dict, CALL.Arguments|list, CALL.ArgumentsKw|dict]

where

Example

    [68, 6131533, 9823526, {}]

Example

    [68, 6131533, 9823527, {}, ["Hello, world!"]]

Example

    [68, 6131533, 9823528, {}, [23, 7]]

Example

    [68, 6131533, 9823529, {}, ["johnny"], {"firstname": "John",
        "surname": "Doe"}]

10.2.3. YIELD

If the Callee is able to successfully process and finish the execution of the call, it answers by sending a YIELD message to the Dealer:

    [YIELD, INVOCATION.Request|id, Options|dict]

or

    [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list]

or

    [YIELD, INVOCATION.Request|id, Options|dict, Arguments|list,
        ArgumentsKw|dict]

where

Example

    [70, 6131533, {}]

Example

    [70, 6131533, {}, ["Hello, world!"]]

Example

    [70, 6131533, {}, [30]]

Example

    [70, 6131533, {}, [], {"userid": 123, "karma": 10}]

10.2.4. RESULT

The Dealer will then send a RESULT message to the original Caller:

    [RESULT, CALL.Request|id, Details|dict]

or

    [RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list]

or

    [RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list,
        YIELD.ArgumentsKw|dict]

where

Example

    [50, 7814135, {}]

Example

    [50, 7814135, {}, ["Hello, world!"]]

Example

    [50, 7814135, {}, [30]]

Example

    [50, 7814135, {}, [], {"userid": 123, "karma": 10}]

10.2.5. Invocation ERROR

If the Callee is unable to process or finish the execution of the call, or the application code implementing the procedure raises an exception or otherwise runs into an error, the Callee sends an ERROR message to the Dealer:

    [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict,
        Error|uri]

or

    [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict,
    Error|uri, Arguments|list]

or

    [ERROR, INVOCATION, INVOCATION.Request|id, Details|dict,
        Error|uri, Arguments|list, ArgumentsKw|dict]

where

Example

    [8, 68, 6131533, {}, "com.myapp.error.object_write_protected",
        ["Object is write protected."], {"severity": 3}]

10.2.6. Call ERROR

The Dealer will then send a ERROR message to the original Caller:

    [ERROR, CALL, CALL.Request|id, Details|dict, Error|uri]

or

    [ERROR, CALL, CALL.Request|id, Details|dict, Error|uri,
        Arguments|list]

or

    [ERROR, CALL, CALL.Request|id, Details|dict, Error|uri,
        Arguments|list, ArgumentsKw|dict]

where

Example

    [8, 48, 7814135, {}, "com.myapp.error.object_write_protected",
        ["Object is write protected."], {"severity": 3}]

If the original call already failed at the Dealer before the call would have been forwarded to any Callee, the Dealer will send an ERROR message to the Caller:

    [ERROR, CALL, CALL.Request|id, Details|dict, Error|uri]

Example

    [8, 48, 7814135, {}, "wamp.error.no_such_procedure"]

11. Predefined URIs

WAMP pre-defines the following error URIs for the basic and for the advanced profile. WAMP peers MUST use only the defined error messages.

11.1. Basic Profile

11.1.1. Incorrect URIs

When a Peer provides an incorrect URI for any URI-based attribute of a WAMP message (e.g. realm, topic), then the other Peer MUST respond with an ERROR message and give the following Error URI:

    wamp.error.invalid_uri

11.1.2. Interaction

Peer provided an incorrect URI for any URI-based attribute of WAMP message, such as realm, topic or procedure

    wamp.error.invalid_uri

A Dealer could not perform a call, since no procedure is currently registered under the given URI.

    wamp.error.no_such_procedure

A procedure could not be registered, since a procedure with the given URI is already registered.

    wamp.error.procedure_already_exists

A Dealer could not perform an unregister, since the given registration is not active.

    wamp.error.no_such_registration

A Broker could not perform an unsubscribe, since the given subscription is not active.

    wamp.error.no_such_subscription

A call failed since the given argument types or values are not acceptable to the called procedure. In this case the Callee may throw this error. Alternatively a Router may throw this error if it performed payload validation of a call, call result, call error or publish, and the payload did not conform to the requirements.

    wamp.error.invalid_argument

11.1.3. Session Close

The Peer is shutting down completely - used as a GOODBYE (or ABORT) reason.

    wamp.error.system_shutdown

The Peer want to leave the realm - used as a GOODBYE reason.

    wamp.error.close_realm

A Peer acknowledges ending of a session - used as a GOODBYE reply reason.

    wamp.error.goodbye_and_out

11.1.4. Authorization

A join, call, register, publish or subscribe failed, since the Peer is not authorized to perform the operation.

    wamp.error.not_authorized

A Dealer or Broker could not determine if the Peer is authorized to perform a join, call, register, publish or subscribe, since the authorization operation itself failed. E.g. a custom authorizer did run into an error.

    wamp.error.authorization_failed

Peer wanted to join a non-existing realm (and the Router did not allow to auto-create the realm).

    wamp.error.no_such_realm

A Peer was to be authenticated under a Role that does not (or no longer) exists on the Router. For example, the Peer was successfully authenticated, but the Role configured does not exists - hence there is some misconfiguration in the Router.

    wamp.error.no_such_role

11.2. Advanced Profile

A Dealer or Callee canceled a call previously issued

    wamp.error.canceled

A Peer requested an interaction with an option that was disallowed by the Router

    wamp.error.option_not_allowed

A Dealer could not perform a call, since a procedure with the given URI is registered, but Callee Black- and Whitelisting and/or Caller Exclusion lead to the exclusion of (any) Callee providing the procedure.

    wamp.error.no_eligible_callee

A Router rejected client request to disclose its identity

    wamp.error.option_disallowed.disclose_me

A Router encountered a network failure

    wamp.error.network_failure

12. Ordering Guarantees

All WAMP implementations, in particular Routers MUST support the following ordering guarantees.

12.1. Publish & Subscribe Ordering

Regarding Publish & Subscribe, the ordering guarantees are as follows:

If Subscriber A is subscribed to both Topic 1 and Topic 2, and Publisher B first publishes an Event 1 to Topic 1 and then an Event 2 to Topic 2, then Subscriber A will first receive Event 1 and then Event 2. This also holds if Topic 1 and Topic 2 are identical.

In other words, WAMP guarantees ordering of events between any given pair of Publisher and Subscriber.

Further, if Subscriber A subscribes to Topic 1, the SUBSCRIBED message will be sent by the Broker to Subscriber A before any EVENT message for Topic 1.

There is no guarantee regarding the order of return for multiple subsequent subscribe requests. A subscribe request might require the Broker to do a time-consuming lookup in some database, whereas another subscribe request second might be permissible immediately.

12.2. Remote Procedure Call Ordering

Regarding Remote Procedure Calls, the ordering guarantees are as follows:

If Callee A has registered endpoints for both Procedure 1 and Procedure 2, and Caller B first issues a Call 1 to Procedure 1 and then a Call 2 to Procedure 2, and both calls are routed to Callee A, then Callee A will first receive an invocation corresponding to Call 1 and then Call 2. This also holds if Procedure 1 and Procedure 2 are identical.

In other words, WAMP guarantees ordering of invocations between any given pair of Caller and Callee.

There are no guarantees on the order of call results and errors in relation to different calls, since the execution of calls upon different invocations of endpoints in Callees are running independently. A first call might require an expensive, long-running computation, whereas a second, subsequent call might finish immediately.

Further, if Callee A registers for Procedure 1, the REGISTERED message will be sent by Dealer to Callee A before any INVOCATION message for Procedure 1.

There is no guarantee regarding the order of return for multiple subsequent register requests. A register request might require the Broker to do a time-consuming lookup in some database, whereas another register request second might be permissible immediately.

13. Security Model

The following discusses the security model for the Basic Profile. Any changes or extensions to this for the Advanced Profile are discussed further on as part of the Advanced Profile definition.

13.1. Transport Encryption and Integrity

WAMP transports may provide (optional) transport-level encryption and integrity verification. If so, encryption and integrity is point-to-point: between a Client and the Router it is connected to.

Transport-level encryption and integrity is solely at the transport-level and transparent to WAMP. WAMP itself deliberately does not specify any kind of transport-level encryption.

Implementations that offer TCP based transport such as WAMP-over-WebSocket or WAMP-over-RawSocket SHOULD implement Transport Layer Security (TLS).

WAMP deployments are encouraged to stick to a TLS-only policy with the TLS code and setup being hardened.

Further, when a Client connects to a Router over a local-only transport such as Unix domain sockets, the integrity of the data transmitted is implicit (the OS kernel is trusted), and the privacy of the data transmitted can be assured using file system permissions (no one can tap a Unix domain socket without appropriate permissions or being root).

13.2. Router Authentication

To authenticate Routers to Clients, deployments MUST run TLS and Clients MUST verify the Router server certificate presented. WAMP itself does not provide mechanisms to authenticate a Router (only a Client).

The verification of the Router server certificate can happen

  1. against a certificate trust database that comes with the Clients operating system
  2. against an issuing certificate/key hard-wired into the Client
  3. by using new mechanisms like DNS-based Authentication of Named Enitities (DNSSEC)/TLSA

Further, when a Client connects to a Router over a local-only transport such as Unix domain sockets, the file system permissions can be used to create implicit trust. E.g. if only the OS user under which the Router runs has the permission to create a Unix domain socket under a specific path, Clients connecting to that path can trust in the router authenticity.

13.3. Client Authentication

Authentication of a Client to a Router at the WAMP level is not part of the basic profile.

When running over TLS, a Router MAY authenticate a Client at the transport level by doing a client certificate based authentication.

13.3.1. Routers are trusted

Routers are trusted by Clients.

In particular, Routers can read (and modify) any application payload transmitted in events, calls, call results and call errors (the Arguments or ArgumentsKw message fields).

Hence, Routers do not provide confidentiality with respect to application payload, and also do not provide authenticity or integrity of application payloads that could be verified by a receiving Client.

Routers need to read the application payloads in cases of automatic conversion between different serialization formats.

Further, Routers are trusted to actually perform routing as specified. E.g. a Client that publishes an event has to trust a Router that the event is actually dispatched to all (eligible) Subscribers by the Router.

A rogue Router might deny normal routing operation without a Client taking notice.

14. Advanced Profile

While implementations MUST implement the subset of the Basic Profile necessary for the particular set of WAMP roles they provide, they MAY implement any subset of features from the Advanced Profile. Implementers SHOULD implement the maximum of features possible considering the aims of an implementation.

14.1. Messages

The Advanced Profile defines the following additional messages which are explained in detail in separate sections.

14.1.1. Message Definitions

The following 4 additional message types MAY be used in the Advanced Profile.

14.1.1.1. CHALLENGE

The CHALLENGE message is used with certain Authentication Methods. During authenticated session establishment, a Router sends a challenge message.

    [CHALLENGE, AuthMethod|string, Extra|dict]

14.1.1.2. AUTHENTICATE

The AUTHENTICATE message is used with certain Authentication Methods. A Client having received a challenge is expected to respond by sending a signature or token.

    [AUTHENTICATE, Signature|string, Extra|dict]

14.1.1.3. CANCEL

The CANCEL message is used with the Call Canceling advanced feature. A Caller can cancel and issued call actively by sending a cancel message to the Dealer.

    [CANCEL, CALL.Request|id, Options|dict]

14.1.1.4. INTERRUPT

The INTERRUPT message is used with the Call Canceling advanced feature. Upon receiving a cancel for a pending call, a Dealer will issue an interrupt to the Callee.

    [INTERRUPT, INVOCATION.Request|id, Options|dict]

14.1.2. Message Codes and Direction

The following table list the message type code for the OPTIONAL messages defined in this part of the document and their direction between peer roles.

Cod Message Pub Brk Subs Calr Dealr Callee
4 CHALLENGE Rx Tx Rx Rx Tx Rx
5 AUTHENTICATE Tx Rx Tx Tx Rx Tx
49 CANCEL Tx Rx
69 INTERRUPT Tx Rx

14.2. Features

Support for advanced features must be announced by the peers which implement them. The following is a complete list of advanced features currently defined or proposed.

Status Description
sketch There is a rough description of an itch to scratch, but the feature use case isn't clear, and there is no protocol proposal at all.
alpha The feature use case is still fuzzy and/or the feature definition is unclear, but there is at least a protocol level proposal.
beta The feature use case is clearly defined and the feature definition in the spec is sufficient to write a prototype implementation. The feature definition and details may still be incomplete and change.
stable The feature definition in the spec is complete and stable and the feature use case is field proven in real applications. There are multiple, interoperatble implementations.

14.2.1. RPC Features

Feature Status P B S Cr D Ce
progressive_call_results beta X X X
progressive_calls sketch X X X
call_timeout alpha X X X
call_canceling alpha X X X
caller_identification alpha X X X
call_trustlevels alpha X X
registration_meta_api beta X
pattern_based_registration beta X X
shared_registration beta X X
sharded_registration alpha X X
registration_revocation alpha X X
procedure_reflection sketch X

14.2.2. PubSub Features

Feature Status P B S Cr D Ce
subscriber_blackwhite_listing stable X X
publisher_exclusion stable X X
publisher_identification alpha X X X
publication_trustlevels alpha X X
subscription_meta_api beta X
pattern_based_subscription beta X X
sharded_subscription alpha X X
event_history alpha X X
topic_reflection sketch X

14.2.3. Other Advanced Features

Feature Status
challenge-response authentication beta
cookie authentication beta
ticket authentication beta
rawsocket transport stable
batched WS transport sketch
longpoll transport beta
session meta api beta

14.3. Advanced RPC Features

14.3.1. Progressive Call Results

14.3.1.1. Feature Definition

A procedure implemented by a Callee and registered at a Dealer may produce progressive results. Progressive results can e.g. be used to return partial results for long-running operations, or to chunk the transmission of larger results sets.

The message flow for progressive results involves:

 ,------.           ,------.          ,------.
 |Caller|           |Dealer|          |Callee|
 `--+---'           `--+---'          `--+---'
    |       CALL       |                 |
    | ----------------->                 |
    |                  |                 |
    |                  |    INVOCATION   |
    |                  | ---------------->
    |                  |                 |
    |                  | YIELD (progress)|
    |                  | <----------------
    |                  |                 |
    | RESULT (progress)|                 |
    | <-----------------                 |
    |                  |                 |
    |                  | YIELD (progress)|
    |                  | <----------------
    |                  |                 |
    | RESULT (progress)|                 |
    | <-----------------                 |
    |                  |                 |
    |                  |                 |
    |       ...        |       ...       |
    |                  |                 |
    |                  |  YIELD or ERROR |
    |                  | <----------------
    |                  |                 |
    |  RESULT or ERROR |                 |
    | <-----------------                 |
 ,--+---.           ,--+---.          ,--+---.
 |Caller|           |Dealer|          |Callee|
 `------'           `------'          `------'

A Caller indicates its willingness to receive progressive results by setting

    CALL.Options.receive_progress|bool := true

Example. Caller-to-Dealer CALL

    [
        48,
        77133,
        {
            "receive_progress": true
        },
        "com.myapp.compute_revenue",
        [2010, 2011, 2012]
    ]

If the Callee supports progressive calls, the Dealer will forward the Caller's willingness to receive progressive results by setting

    INVOCATION.Details.receive_progress|bool := true

Example. Dealer-to-Callee INVOCATION

    [
        68,
        87683,
        324,
        {
            "receive_progress": true
        },
        [2010, 2011, 2012]
    ]

An endpoint implementing the procedure produces progressive results by sending YIELD messages to the Dealer with

    YIELD.Options.progress|bool := true

Example. Callee-to-Dealer progressive YIELDs

    [
        70,
        87683,
        {
            "progress": true
        },
        ["Y2010", 120]
    ]
    [
        70,
        87683,
        {
            "progress": true
        },
        ["Y2011", 205]
    ]

Upon receiving an YIELD message from a Callee with YIELD.Options.progress == true (for a call that is still ongoing), the Dealer will immediately send a RESULT message to the original Caller with

    RESULT.Details.progress|bool := true

Example. Dealer-to-Caller progressive RESULTs

    [
        50,
        77133,
        {
            "progress": true
        },
        ["Y2010", 120]
    ]
    [
        50,
        77133,
        {
            "progress": true
        },
        ["Y2011", 205]
    ]

...

An invocation MUST always end in either a normal RESULT or ERROR message being sent by the Callee and received by the Dealer.

Example. Callee-to-Dealer final YIELD

    [
        70,
        87683,
        {},
        ["Total", 490]
    ]

Example. Callee-to-Dealer final ERROR

    [
        4,
        87683,
        {},
        "com.myapp.invalid_revenue_year",
        [1830]
    ]

A call MUST always end in either a normal RESULT or ERROR message being sent by the Dealer and received by the Caller.

Example. Dealer-to-Caller final RESULT

    [
        50,
        77133,
        {},
        ["Total", 490]
    ]

Example. Dealer-to-Caller final ERROR

    [
        4,
        77133,
        {},
        "com.myapp.invalid_revenue_year",
        [1830]
    ]

In other words: YIELD with YIELD.Options.progress == true and RESULT with RESULT.Details.progress == true messages may only be sent during a call or invocation is still ongoing.

The final YIELD and final RESULT may also be empty, e.g. when all actual results have already been transmitted in progressive result messages.

Example. Callee-to-Dealer YIELDs

    [70, 87683, {"progress": true}, ["Y2010", 120]]
    [70, 87683, {"progress": true}, ["Y2011", 205]]
     ...
    [70, 87683, {"progress": true}, ["Total", 490]]
    [70, 87683, {}]

Example. Dealer-to-Caller RESULTs

    [50, 77133, {"progress": true}, ["Y2010", 120]]
    [50, 77133, {"progress": true}, ["Y2011", 205]]
     ...
    [50, 77133, {"progress": true}, ["Total", 490]]
    [50, 77133, {}]

The progressive YIELD and progressive RESULT may also be empty, e.g. when those messages are only used to signal that the procedure is still running and working, and the actual result is completely delivered in the final YIELD and RESULT:

Example. Callee-to-Dealer YIELDs

    [70, 87683, {"progress": true}]
    [70, 87683, {"progress": true}]
    ...
    [70, 87683, {}, [["Y2010", 120], ["Y2011", 205], ...,
        ["Total", 490]]]

Example. Dealer-to-Caller RESULTs

    [50, 77133, {"progress": true}]
    [50, 77133, {"progress": true}]
    ...
    [50, 77133, {}, [["Y2010", 120], ["Y2011", 205], ...,
        ["Total", 490]]]

Example. Callee-to-Dealer YIELDs

    [70, 87683, {"progress": true}, ["partial 1", 10]]
    [70, 87683, {"progress": true}, [], {"foo": 10,
        "bar": "partial 1"}]
     ...
    [70, 87683, {}, [1, 2, 3], {"moo": "hello"}]

Example. Dealer-to-Caller RESULTs

    [50, 77133, {"progress": true}, ["partial 1", 10]]
    [50, 77133, {"progress": true}, [], {"foo": 10,
        "bar": "partial 1"}]
     ...
    [50, 77133, {}, [1, 2, 3], {"moo": "hello"}]

Even if a Caller has indicated it's expectation to receive progressive results by setting CALL.Options.receive_progress|bool := true, a Callee is not required to produce progressive results. CALL.Options.receive_progress and INVOCATION.Details.receive_progress are simply indications that the Caller is prepared to process progressive results, should there be any produced. In other words, Callees are free to ignore such receive_progress hints at any time.

14.3.1.2. Callee

A Callee that does not support progressive results SHOULD ignore any INVOCATION.Details.receive_progress flag.

14.3.1.3. Feature Announcement

Support for this advanced feature MUST be announced by Callers (role := "caller"), Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.
         progressive_call_results|bool := true

14.3.2. Progressive Calls

14.3.2.1. Feature Definition

A procedure implemented by a Callee and registered at a Dealer may receive a progressive call. Progressive results can e.g. be used to start processing initial data where a larger data set may not yet have been generated or received by the Caller.

See this GitHub issue for more discussion: <https://github.com/wamp-proto/wamp-proto/issues/167>

14.3.3. Call Timeouts

14.3.3.1. Feature Definition

A Caller might want to issue a call providing a timeout for the call to finish.

A timeout allows to automatically cancel a call after a specified time either at the Callee or at the Dealer.

A Caller specifies a timeout by providing

    CALL.Options.timeout|integer

in ms. A timeout value of 0 deactivates automatic call timeout. This is also the default value.

The timeout option is a companion to, but slightly different from the CANCEL and INTERRUPT messages that allow a Caller and Dealer to actively cancel a call or invocation.

In fact, a timeout timer might run at three places:

14.3.3.2. Feature Announcement

Support for this feature MUST be announced by Callers (role := "caller"), Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.call_timeout|bool := true

14.3.4. Call Canceling

14.3.4.1. Feature Definition

A Caller might want to actively cancel a call that was issued, but not has yet returned. An example where this is useful could be a user triggering a long running operation and later changing his mind or no longer willing to wait.

The message flow between Callers, a Dealer and Callees for canceling remote procedure calls involves the following messages:

A call may be cancelled at the Callee

    ,------.          ,------.          ,------.
    |Caller|          |Dealer|          |Callee|
    `--+---'          `--+---'          `--+---'
       |       CALL      |                 |    
       | ---------------->                 |    
       |                 |                 |    
       |                 |    INVOCATION   |    
       |                 | ---------------->    
       |                 |                 |    
       |      CANCEL     |                 |    
       | ---------------->                 |    
       |                 |                 |    
       |                 |    INTERRUPT    |    
       |                 | ---------------->    
       |                 |                 |    
       |                 |      ERROR      |    
       |                 | <----------------    
       |                 |                 |    
       |      ERROR      |                 |    
       | <----------------                 |    
    ,--+---.          ,--+---.          ,--+---.
    |Caller|          |Dealer|          |Callee|
    `------'          `------'          `------'

A call may be cancelled at the Dealer

    ,------.          ,------.          ,------.
    |Caller|          |Dealer|          |Callee|
    `--+---'          `--+---'          `--+---'
       |       CALL      |                 |    
       | ---------------->                 |    
       |                 |                 |    
       |                 |    INVOCATION   |    
       |                 | ---------------->    
       |                 |                 |    
       |      CANCEL     |                 |    
       | ---------------->                 |    
       |                 |                 |    
       |      ERROR      |                 |    
       | <----------------                 |    
       |                 |                 |    
       |                 |    INTERRUPT    |    
       |                 | ---------------->    
       |                 |                 |    
       |                 |      ERROR      |    
       |                 | <----------------    
    ,--+---.          ,--+---.          ,--+---.
    |Caller|          |Dealer|          |Callee|
    `------'          `------'          `------'

A Caller cancels a remote procedure call initiated (but not yet finished) by sending a CANCEL message to the Dealer:

    [CANCEL, CALL.Request|id, Options|dict]

A Dealer cancels an invocation of an endpoint initiated (but not yet finished) by sending a INTERRUPT message to the Callee:

    [INTERRUPT, INVOCATION.Request|id, Options|dict]

Options:

    CANCEL.Options.mode|string == "skip" | "kill" | "killnowait"

14.3.4.2. Feature Announcement

Support for this feature MUST be announced by Callers (role := "caller"), Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.call_canceling|bool := true

14.3.5. Caller Identification

14.3.5.1. Feature Definition

A Caller MAY request the disclosure of its identity (its WAMP session ID) to endpoints of a routed call via

    CALL.Options.disclose_me|bool := true

Example

    [48, 7814135, {"disclose_me": true}, "com.myapp.echo",
        ["Hello, world!"]]

If above call is issued by a Caller with WAMP session ID 3335656, the Dealer sends an INVOCATION message to Callee with the Caller's WAMP session ID in INVOCATION.Details.caller:

Example

    [68, 6131533, 9823526, {"caller": 3335656}, ["Hello, world!"]]

Note that a Dealer MAY disclose the identity of a Caller even without the Caller having explicitly requested to do so when the Dealer configuration (for the called procedure) is setup to do so.

A Dealer MAY deny a Caller's request to disclose its identity:

Example

    [8, 7814135, "wamp.error.disclose_me.not_allowed"]

A Callee MAY request the disclosure of caller identity via

    REGISTER.Options.disclose_caller|bool := true

Example

    [64, 927639114088448, {"disclose_caller":true},
        "com.maypp.add2"]

With the above registration, the registered procedure is called with the caller's sessionID as part of the call details object.

14.3.5.2. Feature Announcement

Support for this feature MUST be announced by Callers (role := "caller"), Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.
         caller_identification|bool := true

14.3.6. Call Trust Levels

14.3.6.1. Feature Defintion

A Dealer may be configured to automatically assign trust levels to calls issued by Callers according to the Dealer configuration on a per-procedure basis and/or depending on the application defined role of the (authenticated) Caller.

A Dealer supporting trust level will provide

    INVOCATION.Details.trustlevel|integer

in an INVOCATION message sent to a Callee. The trustlevel 0 means lowest trust, and higher integers represent (application-defined) higher levels of trust.

Example

    [68, 6131533, 9823526, {"trustlevel": 2}, ["Hello, world!"]]

In above event, the Dealer has (by configuration and/or other information) deemed the call (and hence the invocation) to be of trustlevel 2.

14.3.6.2. Feature Announcement

Support for this feature MUST be announced by Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.call_trustlevels|bool := true

14.3.7. Registration Meta API

14.3.7.1. Feature Definition

14.3.7.1.1. Introduction

Registration Meta Events are fired when registrations are first created, when Callees are attached (removed) to (from) a registration, and when registrations are finally destroyed.

Furthermore, WAMP allows actively retrieving information about registrations via Registration Meta Procedures.

Meta-events are created by the router itself. This means that the events as well as the data received when calling a meta-procedure can be accorded the same trust level as the router.

14.3.7.1.2. Registration Meta Events

A client can subscribe to the following registration meta-events, which cover the lifecycle of a registration:

A wamp.registration.on_register event MUST be fired subsequent to a wamp.registration.on_create event, since the first registration results in both the creation of the registration and the addition of a session.

Similarly, the wamp.registration.on_delete event MUST be preceded by a wamp.registration.on_unregister event.

Registration Meta Events MUST be dispatched by the router to the same realm as the WAMP session which triggered the event.

14.3.7.1.2.1. wamp.registration.on_create

Fired when a registration is created through a registration request for an URI which was previously without a registration.

Event Arguments

Object Schemas

    RegistrationDetails :=
    {
        "id": registration|id,
        "created": time_created|iso_8601_string,
        "uri": procedure|uri,
        "match": match_policy|string,
        "invoke": invocation_policy|string
    }

See Pattern-based Registrations for a description of match_policy.

14.3.7.1.2.2. wamp.registration.on_register

Fired when a session is added to a registration.

Event Arguments

14.3.7.1.2.3. wamp.registration.on_unregister

Fired when a session is removed from a subscription.

Event Arguments

14.3.7.1.2.4. wamp.registration.on_delete

Fired when a registration is deleted after the last session attached to it has been removed.

Event Arguments

14.3.7.1.3. Registration Meta-Procedures

A client can actively retrieve information about registrations via the following meta-procedures:

14.3.7.1.3.1. wamp.registration.list

Retrieves registration IDs listed according to match policies.

Arguments

Results

Object Schemas

    RegistrationLists :=
    {
        "exact": registration_ids|list,
        "prefix": registration_ids|list,
        "wildcard": registration_ids|list
    }

See Pattern-based Registrations for a description of match policies.

14.3.7.1.3.2. wamp.registration.lookup

Obtains the registration (if any) managing a procedure, according to some match policy.

Arguments

Results

14.3.7.1.3.3. wamp.registration.match

Obtains the registration best matching a given procedure URI.

Arguments

Results

14.3.7.1.3.4. wamp.registration.get

Retrieves information on a particular registration.

Arguments

Results

Error URIs

Object Schemas

    RegistrationDetails :=
    {
        "id": registration|id,
        "created": time_created|iso_8601_string,
        "uri": procedure|uri,
        "match": match_policy|string,
        "invoke": invocation_policy|string
    }

See Pattern-based Registrations for a description of match policies.

NOTE: invocation_policy IS NOT YET DESCRIBED IN THE ADVANCED SPEC

14.3.7.1.3.5. wamp.registration.list_callees

Retrieves a list of session IDs for sessions currently attached to the registration.

Arguments

Results

Error URIs

14.3.7.1.3.6. wamp.registration.count_callees

Obtains the number of sessions currently attached to a registration.

Arguments

Results

Error URIs

14.3.7.2. Feature Announcement

Support for this feature MUST be announced by a Dealers (role := "dealer") via:

    HELLO.Details.roles.<role>.features.
        registration_meta_api|bool := true

Example

Here is a WELCOME message from a Router with support for both the Broker and Dealer role, and with support for Registration Meta API:

    [
        2,
        4580268554656113,
        {
            "authid":"OL3AeppwDLXiAAPbqm9IVhnw",
            "authrole": "anonymous",
            "authmethod": "anonymous",
            "roles": {
                "broker": {
                    "features": {
                    }
                },
                "dealer": {
                    "features": {
                        "registration_meta_api": true
                    }
                }
            }
        }
    ]

14.3.8. Pattern-based Registrations

14.3.8.1. Feature Definition

14.3.8.1.1. Introduction

By default, Callees register procedures with exact matching policy. That is a call will only be routed to a Callee by the Dealer if the procedure called (CALL.Procedure) exactly matches the endpoint registered (REGISTER.Procedure).

A Callee might want to register procedures based on a pattern. This can be useful to reduce the number of individual registrations to be set up or to subscribe to a open set of topics, not known beforehand by the Subscriber.

If the Dealer and the Callee support pattern-based registrations, this matching can happen by

14.3.8.1.2. Prefix Matching

A Callee requests prefix-matching policy with a registration request by setting

    REGISTER.Options.match|string := "prefix"

Example

    [
        64,
        612352435,
        {
            "match": "prefix"
        },
        "com.myapp.myobject1"
    ]

When a prefix-matching policy is in place, any call with a procedure that has REGISTER.Procedure as a prefix will match the registration, and potentially be routed to Callees on that registration.

In above example, the following calls with CALL.Procedure

will all apply for call routing. A call with one of the following CALL.Procedure

will not apply.

14.3.8.1.3. Wildcard Matching

A Callee requests wildcard-matching policy with a registration request by setting

    REGISTER.Options.match|string := "wildcard"

Wildcard-matching allows to provide wildcards for whole URI components.

Example

    [
        64,
        612352435,
        {
            "match": "wildcard"
        },
        "com.myapp..myprocedure1"
    ]

In the above registration request, the 3rd URI component is empty, which signals a wildcard in that URI component position. In this example, calls with CALL.Procedure e.g.

will all apply for call routing. Calls with CALL.Procedure e.g.

will not apply for call routing.

When a single call matches more than one of a Callees registrations, the call MAY be routed for invocation on multiple registrations, depending on call settings.

14.3.8.1.4. General

14.3.8.1.4.1. No set semantics

Since each Callee's' registrations "stands on it's own", there is no set semantics implied by pattern-based registrations.

E.g. a Callee cannot register to a broad pattern, and then unregister from a subset of that broad pattern to form a more complex registration. Each registration is separate.

14.3.8.1.4.2. Calls matching multiple registrations

The behavior when a single call matches more than one of a Callee's registrations or more than one registration in general is still being discussed.

14.3.8.1.4.3. Concrete procedure called

If an endpoint was registered with a pattern-based matching policy, a Dealer MUST supply the original CALL.Procedure as provided by the Caller in

    INVOCATION.Details.procedure

to the Callee.

Example

    [
        68,
        6131533,
        9823527,
        {
            "procedure": "com.myapp.procedure.proc1"
        },
        ["Hello, world!"]
    ]

14.3.8.2. Feature Announcement

Support for this feature MUST be announced by Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.
        pattern_based_registration|bool := true

14.3.9. Shared Registration

Feature status: alpha

14.3.9.1. Feature Definition

As a default, only a single Callee may register a procedure for an URI.

There are use cases where more flexibility is required. As an example, for an application component with a high computing load, several instances may run, and load balancing of calls across these may be desired. As another example, in an application a second or third component providing a procedure may run, which are only to be called in case the primary component is no longer reachable (hot standby).

When shared registrations are supported, then the first Callee to register a procedure for a particular URI MAY determine that additional registrations for this URI are allowed, and what Invocation Rules to apply in case such additional registrations are made.

This is done through setting

    REGISTER.Options.invoke|string := <invocation_policy>

where <invocation_policy> is one of

If the option is not set, 'single' is applied as a default.

With 'single', the Dealer MUST fail all subsequent attempts to register a procedure for the URI while the registration remains in existence.

With the other values, the Dealer MUST fail all subsequent attempst to register a procedure for the URI where the value for this option does not match that of the initial registration.

14.3.9.1.1. Load Balancing

For sets of registrations registered using either 'roundrobin' or 'random', load balancing is performed across calls to the URI.

For 'roundrobin', callees are picked subsequently from the list of registrations (ordered by the order of registration), with the picking looping back to the beginning of the list once the end has been reached.

For 'random' a callee is picked randomly from the list of registrations for each call.

14.3.9.1.2. Hot Stand-By

For sets of registrations registered using either 'first' or 'last', the first respectively last callee on the current list of registrations (ordered by the order of registration) is called.

14.3.9.2. Feature Announcement

Support for this feature MUST be announced by Callees (role := "callee") and Dealers (role := "dealer") via

    HELLO.Details.roles.<role>.features.
        shared_registration|bool := true

14.3.10. Sharded Registration

Feature status: sketch

14.3.10.1. Feature Definition

Sharded Registrations are intended to allow calling a procedure which is offered by a sharded database, by routing the call to a single shard.

14.3.10.2. "Partitioned" Calls

If CALL.Options.runmode == "partition", then CALL.Options.rkey MUST be present.

The call is then routed to all endpoints that were registered ..

The call is then processed as for "All" Calls.

14.3.10.3. Feature Announcement

Support for this feature MUST be announced by Callers (role := "caller"), Callees (role := "callee") and Dealers (role := "dealer") via

HELLO.Details.roles.<role>.features.sharded_registration|bool := true

14.3.11. Registration Revocation

14.3.11.1. Feature Definition

Actively and forcefully revoke a previously granted registration from a session.

14.3.11.2. Feature Announcement

14.3.12. Procedure Reflection

Feature status: sketch

Reflection denotes the ability of WAMP peers to examine the procedures, topics and errors provided or used by other peers.

I.e. a WAMP Caller, Callee, Subscriber or Publisher may be interested in retrieving a machine readable list and description of WAMP procedures and topics it is authorized to access or provide in the context of a WAMP session with a Dealer or Broker.

Reflection may be useful in the following cases:

WAMP predefines the following procedures for performing run-time reflection on WAMP peers which act as Brokers and/or Dealers.

Predefined WAMP reflection procedures to list resources by type:

    wamp.reflection.topic.list
    wamp.reflection.procedure.list
    wamp.reflection.error.list

Predefined WAMP reflection procedures to describe resources by type:

    wamp.reflection.topic.describe
    wamp.reflection.procedure.describe
    wamp.reflection.error.describe

A peer that acts as a Broker SHOULD announce support for the reflection API by sending

    HELLO.Details.roles.broker.reflection|bool := true

A peer that acts as a Dealer SHOULD announce support for the reflection API by sending

    HELLO.Details.roles.dealer.reflection|bool := true

Reflection

A topic or procedure is defined for reflection:

    wamp.reflect.define

A topic or procedure was asked to be described (reflected upon):

    wamp.reflect.describe

Reflection

A topic or procedure has been defined for reflection:

    wamp.reflect.on_define

A topic or procedure has been unfined from reflection:

    wamp.reflect.on_undefine

14.4. Advanced PubSub Features

14.4.1. Subscriber Black- and Whitelisting

14.4.1.1. Introduction

Subscriber Black- and Whitelisting is an advanced Broker feature where a Publisher is able to restrict the set of receivers of a published event.

Under normal Publish & Subscriber event dispatching, a Broker will dispatch a published event to all (authorized) Subscribers other than the Publisher itself. This set of receivers can be further reduced on a per-publication basis by the Publisher using Subscriber Black- and Whitelisting.

The Publisher can explicitly exclude Subscribers based on WAMP sessionid, authid or authrole. This is referred to as Blacklisting.

A Publisher may also explicitly define a eligible list of *Subscribers** based on WAMP sessionid, authid or authrole. This is referred to as Whitelisting.

14.4.1.2. Use Cases

14.4.1.2.1. Avoiding Callers from being self-notified

Consider an application that exposes a procedure to update a product price. The procedure might not only actually update the product price (e.g. in a backend database), but additionally publish an event with the updated product price, so that all application components get notified actively of the new price.

However, the application might want to exclude the originator of the product price update (the Caller of the price update procedure) from receiving the update event - as the originator naturally already knows the new price, and might get confused when it receives an update the Caller has triggered himself.

The product price update procedure can use PUBLISH.Options.exclude|list[int] to exclude the Caller of the procedure.

A similar approach can be used for other CRUD-like procedures.

14.4.1.2.2. Restricting receivers of sensitive information

Consider an application with users that have different authroles, such as "manager" and "staff" that publishes events with updates to "customers". The topics being published to could be structured like

    com.example.myapp.customer.<customer ID>

The application might want to restrict the receivers of customer updates depending on the authrole of the user. E.g. a user authenticated under authrole "manager" might be allowed to receive any kind of customer update, including personal and business sensitive information. A user under authrole "staff" might only be allowed to receive a subset of events.

The application can publish all customer updates to the same topic com.example.myapp.customer.<customer ID> and use PUBLISH.Options.eligible_authrole|list[string] to safely restrict the set of actual receivers as desired.

14.4.1.3. Feature Definition

A Publisher may restrict the actual receivers of an event from the set of Subscribers through the use of

PUBLISH.Options.exclude is a list of integers with WAMP sessionids providing an explicit list of (potential) Subscribers that won't receive a published event, even though they may be subscribed. In other words, PUBLISH.Options.exclude is a blacklist of (potential) Subscribers.

PUBLISH.Options.eligible is a list of integeres with WAMP WAMP sessionids providing an explicit list of (potential) Subscribers that are allowed to receive a published event. In other words, PUBLISH.Options.eligible is a whitelist of (potential) Subscribers.

The exclude_authid, exclude_authrole, eligible_authid and eligible_authrole options work similar, but not on the basis of WAMP sessionid, but authid and authrole.

An (authorized) Subscriber to topic T will receive an event published to T if and only if all of the following statements hold true:

  1. if there is an eligible attribute present, the Subscriber's sessionid is in this list
  2. if there is an eligible_authid attribute present, the Subscriber's authid is in this list
  3. if there is an eligible_authrole attribute present, the Subscriber's authrole is in this list
  4. if there is an exclude attribute present, the Subscriber's sessionid is NOT in this list
  5. if there is an exclude_authid attribute present, the Subscriber's authid is NOT in this list
  6. if there is an exclude_authrole attribute present, the Subscriber's authrole is NOT in this list

For example, if both PUBLISH.Options.exclude and PUBLISH.Options.eligible are present, the Broker will dispatch events published only to Subscribers that are not explicitly excluded in PUBLISH.Options.exclude and which are explicitly eligible via PUBLISH.Options.eligible.

Example

    [
       16,
       239714735,
       {
          "exclude": [
             7891255,
             1245751
          ]
       },
       "com.myapp.mytopic1",
       [
          "Hello, world!"
       ]
    ]

The above event will get dispatched to all Subscribers of com.myapp.mytopic1, but not WAMP sessions with IDs 7891255 or 1245751 (and also not the publishing session).

Example

    [
       16,
       239714735,
       {
          "eligible": [
             7891255,
             1245751
          ]
       },
       "com.myapp.mytopic1",
       [
          "Hello, world!"
       ]
    ]

The above event will get dispatched to WAMP sessions with IDs 7891255 or 1245751 only - but only if those are actually subscribed to the topic com.myapp.mytopic1.

Example

    [
       16,
       239714735,
       {
          "eligible": [
             7891255,
             1245751,
             9912315
          ],
          "exclude": [
             7891255
          ]
       },
       "com.myapp.mytopic1",
       [
          "Hello, world!"
       ]
    ]

The above event will get dispatched to WAMP sessions with IDs 1245751 or 9912315 only, since 7891255 is excluded - but only if those are actually subscribed to the topic com.myapp.mytopic1.

14.4.1.4. Feature Announcement

Support for this feature MUST be announced by Publishers (role := "publisher") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.
        subscriber_blackwhite_listing|bool := true

14.4.2. Publisher Exclusion

14.4.2.1. Feature Definition

By default, a Publisher of an event will not itself receive an event published, even when subscribed to the Topic the Publisher is publishing to. This behavior can be overridden using this feature.

To override the exclusion of a publisher from it's own publication, the PUBLISH message must include the following option:

    PUBLISH.Options.exclude_me|bool

When publishing with PUBLISH.Options.exclude_me := false, the Publisher of the event will receive that event, if it is subscribed to the Topic published to.

Example

    [
        16,
        239714735,
        {
            "exclude_me": false
        },
        "com.myapp.mytopic1",
        ["Hello, world!"]
    ]

In this example, the Publisher will receive the published event, if it is subscribed to com.myapp.mytopic1.

14.4.2.2. Feature Announcement

Support for this feature MUST be announced by Publishers (role := "publisher") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.
        publisher_exclusion|bool := true

14.4.3. Publisher Identification

14.4.3.1. Feature Definition

A Publisher may request the disclosure of its identity (its WAMP session ID) to receivers of a published event by setting

    PUBLISH.Options.disclose_me|bool := true

Example

    [16, 239714735, {"disclose_me": true}, "com.myapp.mytopic1",
        ["Hello, world!"]]

If above event is published by a Publisher with WAMP session ID 3335656, the Broker would send an EVENT message to Subscribers with the Publisher's WAMP session ID in EVENT.Details.publisher:

Example

    [36, 5512315355, 4429313566, {"publisher": 3335656},
        ["Hello, world!"]]

Note that a Broker may deny a Publisher's request to disclose its identity:

Example

    [8, 239714735, {}, "wamp.error.option_disallowed.disclose_me"]

A Broker may also (automatically) disclose the identity of a Publisher even without the Publisher having explicitly requested to do so when the Broker configuration (for the publication topic) is set up to do so.

14.4.3.2. Feature Announcement

Support for this feature MUST be announced by Publishers (role := "publisher"), Brokers (role := "broker") and Subscribers (role := "subscriber") via

    HELLO.Details.roles.<role>.features.
        publisher_identification|bool := true

14.4.4. Publication Trust Levels

14.4.4.1. Feature Definition

A Broker may be configured to automatically assign trust levels to events published by Publishers according to the Broker configuration on a per-topic basis and/or depending on the application defined role of the (authenticated) Publisher.

A Broker supporting trust level will provide

    EVENT.Details.trustlevel|integer

in an EVENT message sent to a Subscriber. The trustlevel 0 means lowest trust, and higher integers represent (application-defined) higher levels of trust.

Example

    [36, 5512315355, 4429313566, {"trustlevel": 2}, 
        ["Hello, world!"]]

In above event, the Broker has (by configuration and/or other information) deemed the event publication to be of trustlevel 2.

14.4.4.2. Feature Announcement

Support for this feature MUST be announced by Subscribers (role := "subscriber") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.
        publication_trustlevels|bool := true

14.4.5. Subscription Meta API

Within an application, it may be desirable for a publisher to know whether a publication to a specific topic currently makes sense, i.e. whether there are any subscribers who would receive an event based on the publication. It may also be desirable to keep a current count of subscribers to a topic to then be able to filter out any subscribers who are not supposed to receive an event.

Subscription meta-events are fired when topics are first created, when clients subscribe/unsubscribe to them, and when topics are deleted. WAMP allows retrieving information about subscriptions via subscription meta-procedures.

Support for this feature MUST be announced by Brokers via

    HELLO.Details.roles.broker.features.subscription_meta_api|
        bool := true

Meta-events are created by the router itself. This means that the events as well as the data received when calling a meta-procedure can be accorded the same trust level as the router.

14.4.5.1. Subscription Meta-Events

A client can subscribe to the following session meta-events, which cover the lifecycle of a subscription:

A wamp.subscription.on_subscribe event MUST always be fired subsequent to a wamp.subscription.on_create event, since the first subscribe results in both the creation of the subscription and the addition of a session. Similarly, the wamp.subscription.on_delete event MUST always be preceded by a wamp.subscription.on_unsubscribe event.

The WAMP subscription meta events shall be dispatched by the router to the same realm as the WAMP session which triggered the event.

14.4.5.1.1. Meta-Event Specifications

14.4.5.1.1.1. wamp.subscription.on_create

Fired when a subscription is created through a subscription request for a topic which was previously without subscribers.

Event Arguments

Object Schemas

      SubscriptionDetails :=
      {
          "id": subscription|id,
          "created": time_created|iso_8601_string,
          "uri": topic|uri,
          "match": match_policy|string
      }

See Section 14.4.6 for a description of match_policy.

14.4.5.1.1.2. wamp.subscription.on_subscribe

Fired when a session is added to a subscription.

Event Arguments

14.4.5.1.1.3. wamp.subscription.on_unsubscribe

Fired when a session is removed from a subscription.

Event Arguments

14.4.5.1.1.4. wamp.subscription.on_delete

Fired when a subscription is deleted after the last session attached to it has been removed.

Arguments

14.4.5.2. Subscription Meta-Procedures

A client can actively retrieve information about subscriptions via the following meta-procedures:

14.4.5.2.1. Meta-Procedure Specifications

14.4.5.2.1.1. wamp.subscription.list

Retrieves subscription IDs listed according to match policies.

Arguments

Results

Object Schemas

      SubscriptionLists :=
      {
          "exact": subscription_ids|list,
          "prefix": subscription_ids|list,
          "wildcard": subscription_ids|list
      }

See Section 14.4.6 for information on match policies.

14.4.5.2.1.2. wamp.subscription.lookup

Obtains the subscription (if any) managing a topic, according to some match policy.

Arguments

Results

14.4.5.2.1.3. wamp.subscription.match

Retrieves a list of IDs of subscriptions matching a topic URI, irrespective of match policy.

Arguments

Results

14.4.5.2.1.4. wamp.subscription.get

Retrieves information on a particular subscription.

Arguments

Results

Error URIs

Object Schemas

      SubscriptionDetails :=
      {
          "id": subscription|id,
          "created": time_created|iso_8601_string,
          "uri": topic|uri,
          "match": match_policy|string
      }

See Section 14.4.6 for information on match policies.

14.4.5.2.1.5. wamp.subscription.list_subscribers

Retrieves a list of session IDs for sessions currently attached to the subscription.

Arguments

Results

Error URIs

14.4.5.2.1.6. wamp.subscription.count_subscribers

Obtains the number of sessions currently attached to a subscription.

Arguments

Results

Error URIs

14.4.6. Pattern-based Subscriptions

14.4.6.1. Introdution

By default, Subscribers subscribe to topics with exact matching policy. That is an event will only be dispatched to a Subscriber by the Broker if the topic published to (PUBLISH.Topic) exactly matches the topic subscribed to (SUBSCRIBE.Topic).

A Subscriber might want to subscribe to topics based on a pattern. This can be useful to reduce the number of individual subscriptions to be set up and to subscribe to topics the Subscriber is not aware of at the time of subscription, or which do not yet exist at this time.

If the Broker and the Subscriber support pattern-based subscriptions, this matching can happen by

14.4.6.2. Prefix Matching

A Subscriber requests prefix-matching policy with a subscription request by setting

    SUBSCRIBE.Options.match|string := "prefix"

Example

    [
        32,
        912873614,
        {
            "match": "prefix"
        },
        "com.myapp.topic.emergency"
    ]

When a prefix-matching policy is in place, any event with a topic that has SUBSCRIBE.Topic as a prefix will match the subscription, and potentially be delivered to Subscribers on the subscription.

In the above example, events with PUBLISH.Topic

will all apply for dispatching. An event with PUBLISH.Topic e.g. com.myapp.topic.emerge will not apply.

14.4.6.3. Wildcard Matching

A Subscriber requests wildcard-matching policy with a subscription request by setting

    SUBSCRIBE.Options.match|string := "wildcard"

Wildcard-matching allows to provide wildcards for whole URI components.

Example

    [
        32,
        912873614,
        {
            "match": "wildcard"
        },
        "com.myapp..userevent"
    ]

In above subscription request, the 3rd URI component is empty, which signals a wildcard in that URI component position. In this example, events with PUBLISH.Topic

will all apply for dispatching. Events with PUBLISH.Topic

will not apply for dispatching.

14.4.6.4. General

14.4.6.4.1. No set semantics

Since each Subscriber's subscription "stands on its own", there is no set semantics implied by pattern-based subscriptions.

E.g. a Subscriber cannot subscribe to a broad pattern, and then unsubscribe from a subset of that broad pattern to form a more complex subscription. Each subscription is separate.

14.4.6.4.2. Events matching multiple subscriptions

When a single event matches more than one of a Subscriber's subscriptions, the event will be delivered for each subscription.

The Subscriber can detect the delivery of that same event on multiple subscriptions via EVENT.PUBLISHED.Publication, which will be identical.

14.4.6.4.3. Concrete topic published to

If a subscription was established with a pattern-based matching policy, a Broker MUST supply the original PUBLISH.Topic as provided by the Publisher in

    EVENT.Details.topic|uri

to the Subscribers.

Example

    [
        36,
        5512315355,
        4429313566,
        {
            "topic": "com.myapp.topic.emergency.category.severe"
        },
        ["Hello, world!"]
    ]

14.4.6.5. Feature Announcement

Support for this feature MUST be announced by Subscribers (role := "subscriber") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.
        pattern_based_subscription|bool := true

14.4.7. Sharded Subscriptions

Feature status: alpha

Support for this feature MUST be announced by Publishers (role := "publisher"), Subscribers (role := "subscriber") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.shareded_subscriptions|
        bool := true

Resource keys: PUBLISH.Options.rkey|string is a stable, technical resource key.

Example

    [16, 239714735, {"rkey": "sn239019"}, "com.myapp.sensor.sn239019. 
        temperature", [33.9]]

Node keys: SUBSCRIBE.Options.nkey|string is a stable, technical node key.

Example

    [32, 912873614, {"match": "wildcard", "nkey": "node23"}, 
        "com.myapp.sensor..temperature"]

14.4.8. Event History

14.4.8.1. Feature Definition

Instead of complex QoS for message delivery, a Broker may provide message history. A Subscriber is responsible to handle overlaps (duplicates) when it wants "exactly-once" message processing across restarts.

The Broker may allow for configuration on a per-topic basis.

The event history may be transient or persistent message history (surviving Broker restarts).

A Broker that implements event history must (also) announce role HELLO.roles.callee, indicate HELLO.roles.broker.history == 1 and provide the following (builtin) procedures.

A Caller can request message history by calling the Broker procedure

    wamp.topic.history.last

with Arguments = [topic|uri, limit|integer] where

or by calling

    wamp.topic.history.since

with Arguments = [topic|uri, timestamp|string] where

or by calling

    wamp.topic.history.after

with Arguments = [topic|uri, publication|id]

FIXME

  1. Should we use topic|uri or subscription|id in Arguments?
  2. Can wamp.topic.history.after be implemented (efficiently) at all?
  3. How does that interact with pattern-based subscriptions?
  4. The same question as with the subscriber lists applies where: to stay within our separation of roles, we need a broker + a separate peer which implements the callee role. Here we do not have a mechanism to get the history from the broker.
  5. How are black/whitelisted sessionIDs treated? A client which requests event history will have a different sessionID than on previous connections, and may receive events for which it was excluded in the previous session, or not receive events for which it was whitelisted. - see <https://github.com/wamp-proto/wamp-proto/issues/206>

14.4.8.2. Feature Announcement

Support for this feature MUST be announced by Subscribers (role := "subscriber") and Brokers (role := "broker") via

    HELLO.Details.roles.<role>.features.event_history|bool := true

14.4.9. Registration Revocation

14.4.9.1. Feature Definition

Actively and forcefully revoke a previously granted subscription from a session.

14.4.9.2. Feature Announcement

14.4.10. Topic Reflection

14.4.11. Testament

14.4.11.1. Feature Definition

When a WAMP client disconnects, or the WAMP session is destroyed, it may want to notify other subscribers or publish some fixed data. Since a client may disconnect uncleanly, this can't be done reliably by them. A Testament, however, set on the server, can be reliably sent by the Broker once either the WAMP session has detached or the client connection has been lost, and allows this functionality. It can be triggered when a Session is either detached (the client has disconnected from it, or frozen it, in the case of Session Resumption) or destroyed (when the WAMP session no longer exists on the server).

This allows clients that otherwise would not be able to know when other clients disconnect get a notification (for example, by using the WAMP Session Meta API) with a format the disconnected client chose.

14.4.11.2. Testament Meta Procedures

A Client can call the following procedures to set/flush Testaments:

14.4.11.2.1. wamp.session.add_testament

Adds a new testament:

Positional arguments

  1. topic|uri - the topic to publish the event on
  2. args|list - positional arguments for the event
  3. kwargs|dict - keyword arguments for the event

Keyword arguments

  1. publish_options|dict - options for the event when it is published -- see Publish.Options. Not all options may be honoured (for example, acknowledge). By default, there are no options.
  2. scope|string - When the testament should be published. Valid values are detatched (when the WAMP session is detatched, for example, when using Event Retention) or destroyed (when the WAMP session is finalised and destroyed on the Broker). Default MUST be destroyed.

wamp.session.add_testament does not return a value.

14.4.11.2.2. wamp.session.flush_testaments

Removes testaments for the given scope:

Keyword arguments

  1. scope|string - Which set of testaments to be removed. Valid values are the same as wamp.session.add_testament, and the default MUST be destroyed.

wamp.session.flush_testaments does not return a value.

14.4.11.3. Testaments in Use

A Client that wishes to send some form of data when their Session ends unexpectedly or their Transport becomes lost can set a testament using the WAMP Testament Meta API, when a Router supports it. For example, a client may call add_testament (this example uses the implicit scope option of destroyed):

yield self.call('wamp.session.add_testament',
                'com.myapp.mytopic', ['Seeya!'], {'my_name': 'app1'})

The Router will then store this information on the WAMP Session, either in a detatched or destroyed bucket, in the order they were added. A client MUST be able to set multiple testaments per-scope. If the Router does not support Session Resumption (therefore removing the distinction between a detached and destroyed session), it MUST still use these two separate buckets to allow wamp.session.flush_testaments to work.

When a Session is detatched, the Router will inspect it for any Testaments in the detached scope, and publish them in the order that the Router recieved them, on the specified topic, with the specified arguments, keyword arguments, and publish options. The Router MAY ignore publish options that do not make sense for a Testament (for example, acknowledged publishes).

When a Session is going to be destroyed, the Router will inspect it for any Testaments in the destroyed scope, and publish them in the same way as it would for the detached scope, in the order that they were recieved.

A Router that does not allow Session Resumption MUST send detatched-scope Testaments before destroyed-scope Testaments.

A Client can also clear testaments if the information is no longer relevant (for example, it is shutting down completely cleanly). For example, a client may call wamp.session.flush_testaments:

yield self.call('wamp.session.flush_testaments', scope='detatched')
yield self.call('wamp.session.flush_testaments', scope='destroyed')

The Router will then flush all Testaments stored for the given scope.

14.4.11.4. Feature Announcement

Support for this feature MUST be announced by Dealers (role := "dealer") via

    HELLO.Details.roles.dealer.features.
        testament_meta_api|bool := true

14.5. Other Advanced Features

14.5.1. Session Meta API

14.5.1.1. Introduction

WAMP enables the monitoring of when sessions join a realm on the router or when they leave it via Session Meta Events. It also allows retrieving information about currently connected sessions via Session Meta Procedures.

Meta events are created by the router itself. This means that the events, as well as the data received when calling a meta procedure, can be accorded the same trust level as the router.

14.5.1.2. Session Meta Events

A client can subscribe to the following session meta-events, which cover the lifecycle of a session:

Session Meta Events MUST be dispatched by the Router to the same realm as the WAMP session which triggered the event.

14.5.1.2.1. wamp.session.on_join

Fired when a session joins a realm on the router. The event payload consists of a single positional argument details|dict:

14.5.1.2.2. wamp.session.on_leave

Fired when a session leaves a realm on the router or is disconnected. The event payload consists of a single positional argument session|id with the session ID of the session that left.

14.5.1.3. Session Meta Procedures

A client can actively retrieve information about sessions via the following meta-procedures:

Session meta procedures MUST be registered by the Router on the same realm as the WAMP session about which information is retrieved.

14.5.1.3.1. wamp.session.count

Obtains the number of sessions currently attached to the realm:

Positional arguments

  1. filter_authroles|list[string] - Optional filter: if provided, only count sessions with an authrole from this list.

Positional results

  1. count|int - The number of sessions currently attached to the realm.

14.5.1.3.2. wamp.session.list

Retrieves a list of the session IDs for all sessions currently attached to the realm.

Positional arguments

  1. filter_authroles|list[string] - Optional filter: if provided, only count sessions with an authrole from this list.

Positional results

  1. session_ids|list - List of WAMP session IDs (order undefined).

14.5.1.3.3. wamp.session.get

Retrieves information on a specific session.

Positional arguments

  1. session|id - The session ID of the session to retrieve details for.

Positional results

  1. details|dict - Information on a particular session:

Errors

14.5.1.4. Feature Announcement

Support for this feature MUST be announced by both Dealers and Brokers via:

    HELLO.Details.roles.<role>.features.
        session_meta_api|bool := true

Example

Here is a WELCOME message from a Router with support for both the Broker and Dealer role, and with support for Session Meta API:

    [
        2,
        4580268554656113,
        {
            "authid":"OL3AeppwDLXiAAPbqm9IVhnw",
            "authrole": "anonymous",
            "authmethod": "anonymous",
            "roles": {
                "broker": {
                    "features": {
                        "session_meta_api": true
                    }
                },
                "dealer": {
                    "features": {
                        "session_meta_api": true
                    }
                }
            }
        }
    ]

14.5.2. Authentication

Authentication is a complex area.

Some applications might want to leverage authentication information coming from the transport underlying WAMP, e.g. HTTP cookies or TLS certificates.

Some transports might imply trust or implicit authentication by their very nature, e.g. Unix domain sockets with appropriate file system permissions in place.

Other application might want to perform their own authentication using external mechanisms (completely outside and independent of WAMP).

Some applications might want to perform their own authentication schemes by using basic WAMP mechanisms, e.g. by using application-defined remote procedure calls.

And some applications might want to use a transport independent scheme, nevertheless predefined by WAMP.

14.5.2.1. WAMP-level Authentication

The message flow between Clients and Routers for establishing and tearing down sessions MAY involve the following messages which authenticate a session:

  1. CHALLENGE
  2. AUTHENTICATE

     ,------.          ,------.
     |Client|          |Router|
     `--+---'          `--+---'
        |      HELLO      |    
        | ---------------->    
        |                 |    
        |    CHALLENGE    |    
        | <----------------    
        |                 |    
        |   AUTHENTICATE  |    
        | ---------------->    
        |                 |    
        | WELCOME or ABORT|    
        | <----------------    
     ,--+---.          ,--+---.
     |Client|          |Router|
     `------'          `------'

Concrete use of CHALLENGE and AUTHENTICATE messages depends on the specific authentication method.

See Section 14.5.2.3 or Section 14.5.2.4 for the use in these authentication methods.

If two-factor authentication is desired, then two subsequent rounds of CHALLENGE and RESPONSE may be employed.

14.5.2.1.1. CHALLENGE

An authentication MAY be required for the establishment of a session. Such requirement MAY be based on the Realm the connection is requested for.

To request authentication, the Router MUST send a CHALLENGE message to the Endpoint.

    [CHALLENGE, AuthMethod|string, Extra|dict]

14.5.2.1.2. AUTHENTICATE

In response to a CHALLENGE message, the Client MUST send an AUTHENTICATE message.

    [AUTHENTICATE, Signature|string, Extra|dict]

If the authentication succeeds, the Router MUST send a WELCOME message, else it MUST send an ABORT message.

14.5.2.2. Transport-level Authentication

14.5.2.2.1. Cookie-based Authentication

When running WAMP over WebSocket, the transport provides HTTP client cookies during the WebSocket opening handshake. The cookies can be used to authenticate one peer (the client) against the other (the server). The other authentication direction cannot be supported by cookies.

This transport-level authentication information may be forward to the WAMP level within HELLO.Details.transport.auth|any in the client-to-server direction.

14.5.2.2.2. TLS Certificate Authentication

When running WAMP over a TLS (either secure WebSocket or raw TCP) transport, a peer may authenticate to the other via the TLS certificate mechanism. A server might authenticate to the client, and a client may authenticate to the server (TLS client-certificate based authentication).

This transport-level authentication information may be forward to the WAMP level within HELLO.Details.transport.auth|any in both directions (if available).

14.5.2.3. Challenge Response Authentication

WAMP Challenge-Response ("WAMP-CRA") authentication is a simple, secure authentication mechanism using a shared secret. The client and the server share a secret. The secret never travels the wire, hence WAMP-CRA can be used via non-TLS connections. The actual pre-sharing of the secret is outside the scope of the authentication mechanism.

A typical authentication begins with the client sending a HELLO message specifying the wampcra method as (one of) the authentication methods:

    [1, "realm1",
        {
            "roles": ...,
            "authmethods": ["wampcra"],
            "authid": "peter"
        }
    ]

The HELLO.Details.authmethods|list is used by the client to announce the authentication methods it is prepared to perform. For WAMP-CRA, this MUST include "wampcra".

The HELLO.Details.authid|string is the authentication ID (e.g. username) the client wishes to authenticate as. For WAMP-CRA, this MUST be provided.

If the server is unwilling or unable to perform WAMP-CRA authentication, it MAY either skip forward trying other authentication methods (if the client announced any) or send an ABORT message.

If the server is willing to let the client authenticate using WAMP-CRA, and the server recognizes the provided authid, it MUST send a CHALLENGE message:

    [4, "wampcra",
        {
            "challenge": "{ \"nonce\": \"LHRTC9zeOIrt_9U3\", 
                \"authprovider\": \"userdb\", \"authid\": \"peter\",
                \"timestamp\": \"2014-06-22T16:36:25.448Z\", 
                \"authrole\": \"user\", \"authmethod\": \"wampcra\", 
                \"session\": 3251278072152162}"
        }
    ]

The CHALLENGE.Details.challenge|string is a string the client needs to create a signature for. The string MUST BE a JSON serialized object which MUST contain:

  1. authid|string: The authentication ID the client will be authenticated as when the authentication succeeds.
  2. authrole|string: The authentication role the client will be authenticated as when the authentication succeeds.
  3. authmethod|string: The authentication methods, here "wampcra"
  4. authprovider|string: The actual provider of authentication. For WAMP-CRA, this can be freely chosen by the app, e.g. userdb.
  5. nonce|string: A random value.
  6. timestamp|string: The UTC timestamp (ISO8601 format) the authentication was started, e.g. 2014-06-22T16:51:41.643Z.
  7. session|int: The WAMP session ID that will be assigned to the session once it is authenticated successfully.

The client needs to compute the signature as follows:

    signature := HMAC[SHA256]_{secret} (challenge)

That is, compute the HMAC-SHA256 using the shared secret over the challenge.

After computing the signature, the client will send an AUTHENTICATE message containing the signature:

    [5, "gir1mSx+deCDUV7wRM5SGIn/+R/ClqLZuH4m7FJeBVI=", {}]

The server will then check if

If the authentication succeeds, the server will finally respond with a WELCOME message:

    [2, 3251278072152162,
        {
            "authid": "peter",
            "authrole": "user",
            "authmethod": "wampcra",
            "authprovider": "userdb",
            "roles": ...
        }
    ]

The WELCOME.Details again contain the actual authentication information active.

If the authentication fails, the server will response with an ABORT message.

14.5.2.3.1. Server-side Verification

The challenge sent during WAMP-CRA contains

  1. random information (the nonce) to make WAMP-CRA robust against replay attacks
  2. timestamp information (the timestamp) to allow WAMP-CRA timeout on authentication requests that took too long
  3. session information (the session) to bind the authentication to a WAMP session ID
  4. all the authentication information that relates to authorization like authid and authrole

14.5.2.3.2. Three-legged Authentication

The signing of the challenge sent by the server usually is done directly on the client. However, this is no strict requirement.

E.g. a client might forward the challenge to another party (hence the "three-legged") for creating the signature. This can be used when the client was previously already authenticated to that third party, and WAMP-CRA should run piggy packed on that authentication.

The third party would, upon receiving a signing request, simply check if the client is already authenticated, and if so, create a signature for WAMP-CRA.

In this case, the secret is actually shared between the WAMP server who wants to authenticate clients using WAMP-CRA and the third party server, who shares a secret with the WAMP server.

This scenario is also the reason the challenge sent with WAMP-CRA is not simply a random value, but a JSON serialized object containing sufficient authentication information for the thrid party to check.

14.5.2.3.3. Password Salting

WAMP-CRA operates using a shared secret. While the secret is never sent over the wire, a shared secret often requires storage of that secret on the client and the server - and storing a password verbatim (unencrypted) is not recommended in general.

WAMP-CRA allows the use of salted passwords following the PBKDF2 key derivation scheme. With salted passwords, the password itself is never stored, but only a key derived from the password and a password salt. This derived key is then practically working as the new shared secret.

When the password is salted, the server will during WAMP-CRA send a CHALLENGE message containing additional information:

    [4, "wampcra",
        {
            "challenge": "{ \"nonce\": \"LHRTC9zeOIrt_9U3\", 
                \"authprovider\": \"userdb\", \"authid\": \"peter\",
                \"timestamp\": \"2014-06-22T16:36:25.448Z\", 
                \"authrole\": \"user\", \"authmethod\": \"wampcra\", 
                \"session\": 3251278072152162}",
            "salt": "salt123",
            "keylen": 32,
            "iterations": 1000
        }
    ]

The CHALLENGE.Details.salt|string is the password salt in use. The CHALLENGE.Details.keylen|int and CHALLENGE.Details.iterations|int are parameters for the PBKDF2 algorithm.

14.5.2.4. Ticket-based Authentication

With Ticket-based authentication, the client needs to present the server an authentication "ticket" - some magic value to authenticate itself to the server.

This "ticket" could be a long-lived, pre-agreed secret (e.g. a user password) or a short-lived authentication token (like a Kerberos token). WAMP does not care or interpret the ticket presented by the client.

A typical authentication begins with the client sending a HELLO message specifying the ticket method as (one of) the authentication methods:

    [1, "realm1",
      {
        "roles": ...,
        "authmethods": ["ticket"],
        "authid": "joe"
      }
    ]

The HELLO.Details.authmethods|list is used by the client to announce the authentication methods it is prepared to perform. For Ticket-based, this MUST include "ticket".

The HELLO.Details.authid|string is the authentication ID (e.g. username) the client wishes to authenticate as. For Ticket-based authentication, this MUST be provided.

If the server is unwilling or unable to perform Ticket-based authentication, it'll either skip forward trying other authentication methods (if the client announced any) or send an ABORT message.

If the server is willing to let the client authenticate using a ticket and the server recognizes the provided authid, it'll send a CHALLENGE message:

    [4, "ticket", {}]

The client will send an AUTHENTICATE message containing a ticket:

    [5, "secret!!!", {}]

The server will then check if the ticket provided is permissible (for the authid given).

If the authentication succeeds, the server will finally respond with a WELCOME message:

    [2, 3251278072152162,
      {
        "authid": "joe",
        "authrole": "user",
        "authmethod": "ticket",
        "authprovider": "static",
        "roles": ...
      }
    ]

where

  1. authid|string: The authentication ID the client was (actually) authenticated as.
  2. authrole|string: The authentication role the client was authenticated for.
  3. authmethod|string: The authentication method, here "ticket"
  4. authprovider|string: The actual provider of authentication. For Ticket-based authentication, this can be freely chosen by the app, e.g. static or dynamic.

The WELCOME.Details again contain the actual authentication information active. If the authentication fails, the server will response with an ABORT message.

14.5.3. Alternative Transports

The only requirements that WAMP expects from a transport are: the transport must be message-based, bidirectional, reliable and ordered. This allows WAMP to run over different transports without any impact at the application layer.

Besides the WebSocket transport, the following WAMP transports are currently specified:

14.5.3.1. RawSocket Transport

WAMP-over-RawSocket is an (alternative) transport for WAMP that uses length-prefixed, binary messages - a message framing different from WebSocket.

Compared to WAMP-over-WebSocket, WAMP-over-RawSocket is simple to implement, since there is no need to implement the WebSocket protocol which has some features that make it non-trivial (like a full HTTP-based opening handshake, message fragmentation, masking and variable length integers).

WAMP-over-RawSocket has even lower overhead than WebSocket, which can be desirable in particular when running on local connections like loopback TCP or Unix domain sockets. It is also expected to allow implementations in microcontrollers in under 2KB RAM.

WAMP-over-RawSocket can run over TCP, TLS, Unix domain sockets or any reliable streaming underlying transport. When run over TLS on the standard port for secure HTTPS (443), it is also able to traverse most locked down networking environments such as enterprise or mobile networks (unless man-in-the-middle TLS intercepting proxies are in use).

However, WAMP-over-RawSocket cannot be used with Web browser clients, since browsers do not allow raw TCP connections. Browser extensions would do, but those need to be installed in a browser. WAMP-over-RawSocket also (currently) does not support transport-level compression as WebSocket does provide (permessage-deflate WebSocket extension).

14.5.3.1.1. Endianess

WAMP-over-RawSocket uses network byte order ("big-endian"). That means, given a unsigned 32 bit integer

    0x 11 22 33 44

the first octet sent out to (or received from) the wire is 0x11 and the last octet sent out (or received) is 0x44.

Here is how you would convert octets received from the wire into an integer in Python:

    <CODE BEGINS>
    import struct
    
    octets_received = b"\x11\x22\x33\x44"
    i = struct.unpack(">L", octets_received)[0]
    <CODE ENDS>

The integer received has the value 287454020.

And here is how you would send out an integer to the wire in Python:

    <CODE BEGINS>
    octets_to_be_send = struct.pack(">L", i)
    <CODE ENDS>

The octets to be sent are b"\x11\x22\x33\x44".

14.5.3.1.2. Handshake

Client-to-Router Request

WAMP-over-RawSocket starts with a handshake where the client connecting to a router sends 4 octets:

    MSB                                 LSB
    31                                    0
    0111 1111 LLLL SSSS RRRR RRRR RRRR RRRR

The first octet is a magic octet with value 0x7F. This value is chosen to avoid any possible collision with the first octet of a valid HTTP request (see here and here). No valid HTTP request can have 0x7F as its first octet.

The second octet consists of a 4 bit LENGTH field and a 4 bit SERIALIZER field.

The LENGTH value is used by the Client to signal the maximum message length of messages it is willing to receive. When the handshake completes successfully, a Router MUST NOT send messages larger than this size.

The possible values for LENGTH are:

     0: 2**9 octets
     1: 2**10 octets
    ...
    15: 2**24 octets

This means a Client can choose the maximum message length between 512 and 16M octets.

The SERIALIZER value is used by the Client to request a specific serializer to be used. When the handshake completes successfully, the Client and Router will use the serializer requested by the Client.

The possible values for SERIALIZER are:

    0: illegal
    1: JSON
    2: MessagePack
    3 - 15: reserved for future serializers

Here is a Python program that prints all (currently) permissible values for the second octet:

    <CODE BEGINS>
    SERMAP = {
       1: 'json',
       2: 'messagepack'
    }

    ## map serializer / max. msg length to RawSocket handshake  
    ## request or success reply (2nd octet)
    ##
    for ser in SERMAP:
       for l in range(16):
          octet_2 = (l << 4) | ser
          print("serializer: {}, maxlen: {} => 
              0x{:02x}".format(SERMAP[ser], 2 ** (l + 9), octet_2))
    <CODE ENDS>

The third and forth octet are reserved and MUST be all zeros for now.

Router-to-Client Reply

After a Client has connected to a Router, the Router will first receive the 4 octets handshake request from the Client.

If the first octet differs from 0x7F, it is not a WAMP-over-RawSocket request. Unless the Router also supports other transports on the connecting port (such as WebSocket or LongPoll), the Router MUST fail the connection.

Here is an example of how a Router could parse the second octet in a Clients handshake request:

    <CODE BEGINS>
    ## map RawSocket handshake request (2nd octet) to 
    ## serializer / max. msg length
    ##
    for i in range(256):
       ser_id = i & 0x0f
       if ser_id != 0:
          ser = SERMAP.get(ser_id, 'currently undefined')
          maxlen = 2 ** ((i >> 4) + 9)
          print("{:02x} => serializer: {}, maxlen: {}".
              format(i, ser, maxlen))
       else:
          print("fail the connection: illegal serializer value")
    <CODE ENDS>

When the Router is willing to speak the serializer requested by the Client, it will answer with a 4 octets response of identical structure as the Client request:

    MSB                                 LSB
    31                                    0
    0111 1111 LLLL SSSS RRRR RRRR RRRR RRRR

Again, the first octet MUST be the value 0x7F. The third and forth octets are reserved and MUST be all zeros for now.

In the second octet, the Router MUST echo the serializer value in SERIALIZER as requested by the Client.

Similar to the Client, the Router sets the LENGTH field to request a limit on the length of messages sent by the Client.

During the connection, Router MUST NOT send messages to the Client longer than the LENGTH requested by the Client, and the Client MUST NOT send messages larger than the maximum requested by the Router in it's handshake reply.

If a message received during a connection exceeds the limit requested, a Peer MUST fail the connection.

When the Router is unable to speak the serializer requested by the Client, or it is denying the Client for other reasons, the Router replies with an error:

    MSB                                 LSB
    31                                    0
    0111 1111 EEEE 0000 RRRR RRRR RRRR RRRR

An error reply has 4 octets: the first octet is again the magic 0x7F, and the third and forth octet are reserved and MUST all be zeros for now.

The second octet has its lower 4 bits zero'ed (which distinguishes the reply from an success/accepting reply) and the upper 4 bits encode the error:

    0: illegal (must not be used)
    1: serializer unsupported
    2: maximum message length unacceptable
    3: use of reserved bits (unsupported feature)
    4: maximum connection count reached
    5 - 15: reserved for future errors

Here is an example of how a Router might create the second octet in an error response:

    <CODE BEGINS>
    ERRMAP = {
       0: "illegal (must not be used)",
       1: "serializer unsupported",
       2: "maximum message length unacceptable",
       3: "use of reserved bits (unsupported feature)",
       4: "maximum connection count reached"
    }

    ## map error to RawSocket handshake error reply (2nd octet)
    ##
    for err in ERRMAP:
       octet_2 = err << 4
       print("error: {} => 0x{:02x}").format(ERRMAP[err], err)
    <CODE ENDS>

The Client - after having sent its handshake request - will wait for the 4 octets from Router handshake reply.

Here is an example of how a Client might parse the second octet in a Router handshake reply:

    <CODE BEGINS>
    ## map RawSocket handshake reply (2nd octet)
    ##
    for i in range(256):
       ser_id = i & 0x0f
       if ser_id:
          ## verify the serializer is the one we requested! 
          ## if not, fail the connection!
          ser = SERMAP.get(ser_id, 'currently undefined')
          maxlen = 2 ** ((i >> 4) + 9)
          print("{:02x} => serializer: {}, maxlen: {}".
              format(i, ser, maxlen))
       else:
          err = i >> 4
          print("error: {}".format(ERRMAP.get(err, 
              'currently undefined')))
    <CODE ENDS>

14.5.3.1.3. Serialization

To send a WAMP message, the message is serialized according to the WAMP serializer agreed in the handshake (e.g. JSON or MessagePack).

The length of the serialized messages in octets MUST NOT exceed the maximum requested by the Peer.

If the serialized length exceed the maximum requested, the WAMP message can not be sent to the Peer. Handling situations like the latter is left to the implementation.

E.g. a Router that is to forward a WAMP EVENT to a Client which exceeds the maximum length requested by the Client when serialized might:

14.5.3.1.4. Framing

The serialized octets for a message to be sent are prefixed with exactly 4 octets.

    MSB                                 LSB
    31                                    0
    RRRR RTTT LLLL LLLL LLLL LLLL LLLL LLLL

The first octet has the following structure

    MSB   LSB
    7       0
    RRRR RTTT

The five bits RRRRR are reserved for future use and MUST be all zeros for now.

The three bits TTT encode the type of the transport message:

    0: regular WAMP message
    1: PING
    2: PONG
    3-7: reserved

The three remaining octets constitute an unsigned 24 bit integer that provides the length of transport message payload following, excluding the 4 octets that constitute the prefix.

For a regular WAMP message (TTT == 0), the length is the length of the serialized WAMP message: the number of octets after serialization (excluding the 4 octets of the prefix).

For a PING message (TTT == 1), the length is the length of the arbitrary payload that follows. A Peer MUST reply to each PING by sending exactly one PONG immediately, and the PONG MUST echo back the payload of the PING exactly.

For receiving messages with WAMP-over-RawSocket, a Peer will usually read exactly 4 octets from the incoming stream, decode the transport level message type and payload length, and then receive as many octets as the length was giving.

When the transport level message type indicates a regular WAMP message, the transport level message payload is unserialized according to the serializer agreed in the handshake and the processed at the WAMP level.

14.5.3.2. Batched WebSocket Transport for WAMP

WAMP-over-Batched-WebSocket is a variant of WAMP-over-WebSocket where multiple WAMP messages are sent in one WebSocket message.

Using WAMP message batching can increase wire level efficiency further. In particular when using TLS and the WebSocket implementation is forcing every WebSocket message into a new TLS segment.

WAMP-over-Batched-WebSocket is negotiated between Peers in the WebSocket opening handshake by agreeing on one of the following WebSocket subprotocols:

Batching with JSON works by serializing each WAMP message to JSON as normally, appending the single ASCII control character \30 (record separator) octet 0x1e to each serialized messages, and packing a sequence of such serialized messages into a single WebSocket message:

    Serialized JSON WAMP Msg 1 | 0x1e | 
        Serialized JSON WAMP Msg 2 | 0x1e | ...

Batching with MessagePack works by serializing each WAMP message to MessagePack as normally, prepending a 32 bit unsigned integer (4 octets in big-endian byte order) with the length of the serialized MessagePack message (excluding the 4 octets for the length prefix), and packing a sequence of such serialized (length-prefixed) messages into a single WebSocket message:

    Length of Msg 1 serialization (uint32) | 
        serialized MessagePack WAMP Msg 1 | ...

With batched transport, even if only a single WAMP message is to be sent in a WebSocket message, the (single) WAMP message needs to be framed as described above. In other words, a single WAMP message is sent as a batch of length 1. Sending a batch of length 0 (no WAMP message) is illegal and a Peer MUST fail the transport upon receiving such a transport message.

14.5.3.3. A HTTP Longpoll Transport for WAMP

The Long-Poll Transport is able to transmit a WAMP session over plain old HTTP 1.0/1.1. This is realized by the Client issuing HTTP/POSTs requests, one for sending, and one for receiving. Those latter requests are kept open at the server when there are no messages currently pending to be received.

Opening a Session

With the Long-Poll Transport, a Client opens a new WAMP session by sending a HTTP/POST request to a well-known URL, e.g.

    http://mypp.com/longpoll/open

Here, http://mypp.com/longpoll is the base URL for the Long-Poll Transport and /open is a path dedicated for opening new sessions.

The HTTP/POST request SHOULD have a Content-Type header set to application/json and MUST have a request body with a JSON document that is a dictionary:

    {
       "protocols": ["wamp.2.json"]
    }

The (mandatory) protocols attribute specifies the protocols the client is willing to speak. The server will chose one from this list when establishing the session or fail the request when no protocol overlap was found.

The valid protocols are:

Returned is a JSON document containing a transport ID and the protocol to speak:

    {
       "protocol": "wamp.2.json",
       "transport": "kjmd3sBLOUnb3Fyr"
    }

As an implied side-effect, two HTTP endpoints are created

    http://mypp.com/longpoll/<transport_id>/receive
    http://mypp.com/longpoll/<transport_id>/send

where transport_id is the transport ID returned from open, e.g.

    http://mypp.com/longpoll/kjmd3sBLOUnb3Fyr/receive
    http://mypp.com/longpoll/kjmd3sBLOUnb3Fyr/send

Receiving WAMP Messages

The Client will then issue HTTP/POST requests (with empty request body) to

    http://mypp.com/longpoll/kjmd3sBLOUnb3Fyr/receive

When there are WAMP messages pending downstream, a request will return with a single WAMP message (unbatched modes) or a batch of serialized WAMP messages (batched mode).

The serialization format used is the one agreed during opening the session.

The batching uses the same scheme as with wamp.2.json.batched and wamp.2.msgpack.batched transport over WebSocket.

Sending WAMP Messages

For sending WAMP messages, the Client will issue HTTP/POST requests to

    http://mypp.com/longpoll/kjmd3sBLOUnb3Fyr/send

with request body being a single WAMP message (unbatched modes) or a batch of serialized WAMP messages (batched mode).

The serialization format used is the one agreed during opening the session.

The batching uses the same scheme as with wamp.2.json.batched and wamp.2.msgpack.batched transport over WebSocket.

Upon success, the request will return with HTTP status code 202 ("no content"). Upon error, the request will return with HTTP status code 400 ("bad request").

Closing a Session

To orderly close a session, a Client will issue a HTTP/POST to

    http://mypp.com/longpoll/kjmd3sBLOUnb3Fyr/close

with an empty request body. Upon success, the request will return with HTTP status code 202 ("no content").

14.5.3.4. Multiplexed Transport

A Transport may support the multiplexing of multiple logical transports over a single "physical" transport.

By using such a Transport, multiple WAMP sessions can be transported over a single underlying transport at the same time.

As an example, the proposed WebSocket extension "permessage-priority" would allow creating multiple logical Transports for WAMP over a single underlying WebSocket connection.

Sessions running over a multiplexed Transport are completely independent: they get assigned different session IDs, may join different realms and each session needs to authenticate itself.

Because of above, Multiplexed Transports for WAMP are actually not detailed in the WAMP spec, but a feature of the transport being used.

15. Binary conversion of JSON Strings

Binary data follows a convention for conversion to JSON strings.

A byte array is converted to a JSON string as follows:

  1. convert the byte array to a Base64 encoded (host language) string
  2. prepend the string with a \0 character
  3. serialize the string to a JSON string

where Base64 encoding follows Section 4 of [RFC4648].

Example

Consider the byte array (hex representation):

    10e3ff9053075c526f5fc06d4fe37cdb

This will get converted to Base64

    EOP/kFMHXFJvX8BtT+N82w==

prepended with \0

    \x00EOP/kFMHXFJvX8BtT+N82w==

and serialized to a JSON string

    "\\u0000EOP/kFMHXFJvX8BtT+N82w=="

A JSON string is unserialized to either a string or a byte array using the following procedure:

  1. Unserialize a JSON string to a host language (Unicode) string
  2. If the string starts with a \0 character, interpret the rest (after the first character) as Base64 and decode to a byte array
  3. Otherwise, return the Unicode string

Below are complete Python and JavaScript code examples for conversion between byte arrays and JSON strings.

15.1. Python

Here is a complete example in Python showing how byte arrays are converted to and from JSON:

    <CODE BEGINS>

    import os, base64, json, sys, binascii
    PY3 = sys.version_info >= (3,)
    if PY3:
       unicode = str

    data_in = os.urandom(16)
    print("In:   {}".format(binascii.hexlify(data_in)))

    ## encoding
    encoded = json.dumps('\0' + base64.b64encode(data_in).
                                          decode('ascii'))

    print("JSON: {}".format(encoded))

    ## decoding
    decoded = json.loads(encoded)
    if type(decoded) == unicode:
       if decoded[0] == '\0':
          data_out = base64.b64decode(decoded[1:])
       else:
          data_out = decoded

    print("Out:  {}".format(binascii.hexlify(data_out)))

    assert(data_out == data_in)

    <CODE ENDS>

15.2. JavaScript

Here is a complete example in JavaScript showing how byte arrays are converted to and from JSON:

    <CODE BEGINS>

    var data_in = new Uint8Array(new ArrayBuffer(16));

    // initialize test data
    for (var i = 0; i < data_in.length; ++i) {
       data_in[i] = i;
    }
    console.log(data_in);

    // convert byte array to raw string
    var raw_out = '';
    for (var i = 0; i < data_in.length; ++i) {
       raw_out += String.fromCharCode(data_in[i]);
    }

    // base64 encode raw string, prepend with \0
    // and serialize to JSON
    var encoded = JSON.stringify("\0" + window.btoa(raw_out));
    console.log(encoded); // "\u0000AAECAwQFBgcICQoLDA0ODw=="

    // unserialize from JSON
    var decoded = JSON.parse(encoded);

    var data_out;
    if (decoded.charCodeAt(0) === 0) {
       // strip first character and decode base64 to raw string
       var raw = window.atob(decoded.substring(1));

       // convert raw string to byte array
       var data_out = new Uint8Array(new ArrayBuffer(raw.length));
       for (var i = 0; i < raw.length; ++i) {
          data_out[i] = raw.charCodeAt(i);
       }
    } else {
       data_out = decoded;
    }

    console.log(data_out);

    <CODE ENDS>

16. Security Considerations

-- write me --

17. IANA Considerations

TBD

18. Contributors

19. Acknowledgements

WAMP was developed in an open process from the beginning, and a lot of people have contributed ideas and other feedback. Here we are listing people who have opted in to being mentioned:

20. References

20.1. Normative References

[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2003.
[RFC3986] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005.
[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006.
[RFC6455] Fette, I. and A. Melnikov, "The WebSocket Protocol", RFC 6455, DOI 10.17487/RFC6455, December 2011.

20.2. Informative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997.

Authors' Addresses

Tobias G. Oberstein Crossbar.io Technologies GmbH EMail: tobias.oberstein@crossbario.com
Alexander Goedde Crossbar.io Technologies GmbH EMail: alexander.goedde@crossbario.com