In WebPush, the Push Message is used to wake UA code. Firefox
OS uses the the WebPush API for its UA subscription API.

Currently the Mozilla Push Service supports a proprietary protocol
using a websocket between the UA and the Push Service.

WebPush Proprietary Protocol

This documents the current Push Service Protocol used between the UA and
the Push Service.

The protocol uses a websocket that carries JSON messages in a mostly
request/response style format. The only exception is that after the Hello
response the Push Server will send any stored notifications as well as new
notifications when they arrive.

All websocket connections are secured with TLS (wss://). The Push Server
maintains a list of all previously seen UAID's and notifications for UA's that
came in while the UA was disconnected. There is no authentication for a given
UAID when reconnecting.

It is required that ChannelID's and UAID's be UUID's.

Messages

All messages are encoded as JSON. All messages MUST have the following fields:

messageType string

Defines the message type

Handshake

After the WebSocket is established, the UserAgent begins communication by
sending a hello message. The hello message contains the UAID if the UserAgent
has one, either generated by the UserAgent for the first handshake or returned
by the server from an earlier handshake. The UserAgent also transmits the
channelIDs it knows so the server may synchronize its state.

The server MAY respect this UAID, but it is at liberty to ask the UserAgent to
change its UAID in the response.

If the UserAgent receives a new UAID, it MUST delete all existing channelIDs and
their associated versions. It MAY then wake up all registered applications
immediately or at a later date by sending them a push-register message.

A repeated hello message on an established channel may result in the server
disconnecting the client for bad behavior.

The handshake is considered complete, once the UserAgent has received a reply.

An UserAgent MUST transmit a hello message only once on its WebSocket. If the
handshake is not completed in the first try, it MUST disconnect the WebSocket
and begin a new connection.

NOTE: Applications may request registrations or unregistrations from the
UserAgent, before or when the handshake is in progress. The UserAgent MAY buffer
these or report errors to the application. But it MUST NOT send these requests
to the PushServer until the handshake is completed.

UserAgent -> PushServer

messageType = "hello"

Begin handshake

uaid string REQUIRED

If the UserAgent has a previously assigned UAID, it should send it. Otherwise
send an empty string.

channelIDs list of strings REQUIRED

If the UserAgent has a list of channelIDs it wants to be notified of, it must
pass these, otherwise an empty list.

use_webpush bool OPTIONAL

If the UserAgent wants the WebPush data support for notifications it
may include this field with a value of true. This field may appear for legacy reasons.

Extra fields: The UserAgent MAY pass any extra JSON data to the PushServer. This
data may include information required to wake up the UserAgent out-of-band. The
PushServer MAY ignore this data.

Register

The Register message is used by the UserAgent to request that the PushServer
notify it when a channel changes. Since channelIDs are associated with only one
UAID, this effectively creates the channel, while unregister destroys the
channel.

The channelID is chosen by the UserAgent because it also acts like a nonce for
the Register message itself. Because of this PushServers MAY respond out of
order to multiple register messages or messages may be lost without compromising
correctness of the protocol.

The request is considered successful only after a response is received with a
status code of 200. On success the UserAgent MUST:

Update its persistent storage based on the response

Notify the application of a successful registration.

On error, the UserAgent MUST notify the application as soon as possible.

NOTE: The register call is made by the UserAgent on behalf of an
application. The UserAgent SHOULD have reasonable timeouts in place so that
the application is not kept waiting for too long if the server does not
respond or the UserAgent has to retry the connection.

UserAgent -> PushServer

messageType = "register"

channelID string REQUIRED

A unique identifier generated by the UserAgent, distinct from any existing
channelIDs it has registered. It is RECOMMENDED that this is a UUIDv4 token.

PushServer -> UserAgent

This MUST be the same as the channelID sent by the UserAgent in the register
request that this message is a response to.

status number REQUIRED

Used to indicate success/failure. MUST be one of:

200 - OK. Success. Idempotent: If the PushServer receives a register for the
same channelID from a UserAgent which already has a registration for the
channelID, it should still respond with success.

409 - Conflict. The chosen ChannelID is already in use and NOT associated
with this UserAgent. UserAgent SHOULD retry with a new ChannelID as soon as
possible.

500 - Internal server error. Database out of space or offline. Disk space
full or whatever other reason due to which the PushServer could not grant
this registration. UserAgent SHOULD avoid retrying immediately.

pushEndpoint string REQUIRED

Should be the URL sent to the application by the UserAgent. AppServers will
contact the PushServer at this URL to update the version of the channel
identified by channelID.

Unregister

The unregister is required only between the App and the UserAgent, so that the
UserAgent stops notifying the App when the App is no longer interested in a
pushEndpoint.

The unregister is also useful to the AppServer, because it should stop sending
notifications to an endpoint the App is no longer monitoring. Even then, it is
really an optimization so that the AppServer need not have some sort of garbage
collection mechanism to clean up endpoints at intervals of time.

The PushServer MUST implement unregister, but need not rely on it. Well behaved
AppServers will stop notifying it of unregistered endpoints automatically. Well
behaved UserAgents won't notify their apps of unregistered updates either. So
the PushServer can continue to process notifications and pass them on to
UserAgents, when it has not been told about the unregistration.

When an App calls unregister(endpoint) it is RECOMMENDED that the UserAgent
follow these steps:

Remove its local registration first, for example from the database.
This will allow it to immediately start ignoring updates.

PushServer -> UserAgent

This MUST be the same as the channelID sent by the UserAgent in the
unregister request that this message is a response to.

status number REQUIRED

Used to indicate success/failure. MUST be one of:

200 - OK. Success. Idempotent: If the PushServer receives a unregister for a
non-existent channelID it should respond with success. If the channelID is
associated with a DIFFERENT UAID, it MUST NOT delete the channelID, but
still MUST respond with success to this UserAgent.

500 - Internal server error. Database offline or whatever other reason due
to which the PushServer could not grant this unregistration. UserAgent
SHOULD avoid retrying immediately.

Ping

The connection to the Push Server may be lost due to network issues. When the
UserAgent detects loss of network, it should reconnect. There are situations in
which the TCP connection dies without either end discovering it immediately. The
UserAgent MAY send a ping approximately every 30 minutes and expect a reply
from the server in a reasonable time (The Mozilla UserAgent uses 10 seconds). If
no data is received, the connection should be presumed closed and a new
connection started.

A UserAgent MUST NOT send a Ping more frequently than once a minute or its
connection MAY be dropped.

The UserAgent should consider normal communications as an indication that the
socket is working properly. It SHOULD send the ping packet only if no activity
has occurred in the past 30 minutes.

Note: This section is included for relevant historical purposes as the
current implementation sends WebSocket Ping frames every 5 minutes which is
sufficient to keep the connection alive. As such, client-sent Ping's are no
longer needed.

UserAgent -> PushServer

The 2-character string {} is sent. This is a valid JSON object that requires no
alternative processing on the server, while keeping transmission size small.

PushServer -> UserAgent

The PushServer may reply with any data. The UserAgent is only concerned about
the state of the connection. The PushServer may deliver pending notifications or
other information. If there is no pending information to be sent, it is
RECOMMENDED that the PushServer also reply with the string {}.

Notification

AppServer -> PushServer

The AppServer MUST make a HTTP PUT request to the Endpoint received from the
App, or a HTTP POST if using the WebPush extension.

If no request body is present, the server MAY presume the version to be the
current server UTC.

If the request body is present, the request MUST contain the string "version=N"
and the Content-Type MUST be application/x-www-form-urlencoded.

PushServer -> AppServer

The HTTP response status code indicates if the request was successful.

200 - OK. The PushServer will attempt to deliver a notification to the
associated UserAgent.

500 - Something went wrong with the server. Rare, but the AppServer should try
again.

The HTTP response body SHOULD be empty.

PushServer -> UserAgent

Notifications are acknowledged by the UserAgent. PushServers should retry unacknowledged notifications every 60 seconds. If the version of an unacknowledged notification is updated, the PushServer MAY queue up a new notification for this channelID and the new version, and remove the old notification from the pending queue.

messageType = "notification"

The following attributes are present
in each notification. A
notification message is sent for every stored notification individually, as well
as new notifications.

channelID string REQUIRED

ChannelID of the notification

version string REQUIRED

Version of the notification sent

headers map OPTIONAL

Encryption headers sent along with the data. Present only if data was sent.

UserAgent -> PushServer

It is RECOMMENDED that the UserAgent try to batch all pending acknowledgements
into fewer messages if bandwidth is a concern. The ack MUST be sent as soon as
the message has been processed, otherwise the
Push Server MAY cease sending notifications to avoid holding excessive client
state.

messageType = "ack"

updates list

The list contains one or more {"channelID": channelID, "version": N} pairs.