WebAPI/SimplePush: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
Line 1: Line 1:
<h2> Client Side API </h2>
== Client Side API ==
<pre>
<pre>


Line 137: Line 137:
UserAgent and AppServer will use a RESTful API to interact with the Push Server.
UserAgent and AppServer will use a RESTful API to interact with the Push Server.


=== API ===
=== Notes ===
* Requests from UserAgent to PushServer MUST provide a PushServer Generated UserAgentID (UAID) as the "X-UserAgent-ID" header.
* Requests from UserAgent to PushServer MUST provide a PushServer Generated UserAgentID (UAID) as the "X-UserAgent-ID" header.
* UserAgent requests may include a /{network} prefix to indicate a request may be handled by a third party network (e.g. <code>GET http:<i>host</i>/foonet/update</code> will return update requests for elements provided by the "foonet" sub-provider. '''TODO: The semantics of this are woefully lacking in the current state of the protocol'''
* UserAgent requests may include a /{network} prefix to indicate a request may be handled by a third party network (e.g. <code>GET http:<i>host</i>/foonet/update</code> will return update requests for elements provided by the "foonet" sub-provider. '''TODO: The semantics of this are woefully lacking in the current state of the protocol'''
Line 144: Line 144:
* On Errors, calls will return a proper error code, and where permitted, a standard JSON block containing information regarding the error. The contents of this block are not intended for end user display and have yet to be finalized.
* On Errors, calls will return a proper error code, and where permitted, a standard JSON block containing information regarding the error. The contents of this block are not intended for end user display and have yet to be finalized.


=== Registration ===
==== GET /v1/register/<channelID> ====
==== GET /v1/register/<channelID> ====
Request a new endpoint.  
Request a new endpoint.  
Line 157: Line 158:
No additional arguments are required.
No additional arguments are required.


===== Returns =====
===== Success response =====
 
  { "channelID": "<channelID provided by UA>",  
  { "channelID": "<channelID provided by UA>",  
   "pushEndpoint": "http://pushserver.provider.tld/path/to/notify"
   "pushEndpoint": "http://pushserver.provider.tld/path/to/notify"
Line 169: Line 171:
===== Errors =====
===== Errors =====


* Invalid Channel ID
* 200 and new UAID - If a server is not in recovery mode, but was in recovery mode before, it may return a new uaid that does not match the old UAID. If a UserAgent receives a new UAID, it should treat that as requiring a full Registration Sync step. In addition, it should throw away the pushEndpoint it received from the server.
* Duplicate Channel ID
* 409 - duplicate channelID. UserAgent should generate new ID and try again.
* 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.
 


===== Example =====
===== Example =====
Line 177: Line 181:
  {"channelID": "foo1234", "pushEndpoint": "http://push5.services.mozilla.org/v1/update/foo1234", "uaid": "bar5678"}
  {"channelID": "foo1234", "pushEndpoint": "http://push5.services.mozilla.org/v1/update/foo1234", "uaid": "bar5678"}


=== Unregistration ===
==== DELETE /v1/<ChannelID> ====
==== DELETE /v1/<ChannelID> ====
Delete an associated ChannelID. Subsequent calls to this ChannelID will result in a 404 status.
Delete an associated ChannelID. Subsequent calls to this ChannelID will result in a 404 status.
Line 185: Line 190:
There are no arguments for this call.
There are no arguments for this call.


===== Returns =====
===== Success response =====


On success, this returns an empty JSON object
Empty JSON object
  {}
  {}


===== Errors =====
===== Errors =====


* Not Registered
* 403 - Wrong or missing UAID
* Invalid UAID
* 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.


===== Example =====
===== Example =====
Line 200: Line 205:
  {}
  {}


=== Fetch updates ===
==== GET /v1/update ====
==== GET /v1/update ====
Return a list of known ChannelIDs and current versions. By default, this will return a list of ALL channels and known versions.  
Return a list of known ChannelIDs and current versions. By default, this will return a list of ALL channels and known versions.  
Line 207: Line 213:
  If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT
  If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT


NOTE: the X-UserAgent-ID must be provided and match the value returned by the <code>/register</code> call.
NOTE: The UserAgent should not modify its own <tt>lastModified</tt> field until a successful response is received, otherwise reliable delivery of updates will fail.


===== Arguments =====
===== Arguments =====
There are no arguments for this call.
There are no arguments for this call.


===== Returns =====
===== Success response =====
The server should return an object with the following fields:
* 200 - The server should return an object with the following fields:
 
  { "updates": [{"channelID": "id", "version": "XXX"}, ...], An association of ChannelIDs and versions that have changed since the last time the UA called /update.
    "expired": ["channelID1", "channelID2", ...], A list of ChannelIDs which have expired. The UA should remove these from its own database, and ask applications to re-register.
  }


* <tt>updates</tt> - An association of ChannelIDs and versions that have changed since the last time the UA called /update.
* 304 - No modifications since time specified in <tt>If-Modified-Since</tt> header.
* <tt>expired</tt> - A list of ChannelIDs which have expired. The UA should remove these from its own database, and ask applications to re-register.


'''TODO''' We need acknowledgement of the /update from the UA. It is possible for the response to be lost in flight and we're trying for reliable delivery.
===== Errors =====


NOTE: If the server is unable to determine previous data for this X-UserAgent-ID, it will return a 410 leading to the Registration Sync Protocol occurring.  
* 403 - Wrong or missing UAID
See <code>POST /update</code> for details.
* 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.


===== Example =====
===== Example =====
Line 230: Line 239:
               {"channelID":"bf08e25861c900c3ab343670eee1873d0b724eef","version":"1"}],
               {"channelID":"bf08e25861c900c3ab343670eee1873d0b724eef","version":"1"}],
   "expired": ["channelID1", "channelID2", ...]}
   "expired": ["channelID1", "channelID2", ...]}
=== Notify update ===
Used by App Servers '''ONLY'''. NOT to be used by UserAgents.
==== PUT /v1/update/<ChannelID> ====
Update the version of a given channel.
Arguments should be passed as standard form data (enctype: multipart/form-data)
This call does not require a X-UserAgent-ID.
===== Arguments  =====
version=<version>
The version is the AppServer specific VersionID to use. This ID is opaque to the PushServer, however it is suggested that:
* The ID be sequential.
* The ID be less than 100 characters.
* The ID should be UTF8 compliant.
===== Success response =====
This call returns an empty JSON object.
  {}
===== Errors =====
* 403 - Not authorized. May occur when the app server has been blocked because it is exhibiting suspicious behaviour. App developer should contact the push server administrator for details.
* 404 - No such push endpoint exists anymore. App Server's should remove the endpoint from their database. This can occur because the app unregistered itself, it was uninstalled, or for other reasons.
* 503 - In the event of a PushServer catastrophe, the PushServer will be in "Recovery" mode. During this time, unresolvable push endpoints will return a 503 error. App Server's SHOULD NOT consider the push endpoint as being deleted. They should continue to notify the Push Server of changes.
===== Example =====
PUT http://push.m.o/v1/update/foo1234
version=1.3
---
{}
=== Registration Sync Protocol ===
The Registration Sync Protocol is used by UserAgents to inform the Push Server of their current state in the unlikely event of a server failure. A registration sync step can only occur when the Push Server is in "recovery mode".


==== POST /v1/update ====
==== POST /v1/update ====
====== Registration Sync Protocol ======
Refresh the server from the client. This request REQUIRES a X-UserAgent-ID header.  
Refresh the server from the client. This request REQUIRES a X-UserAgent-ID header.  


This call SHOULD only be performed by the UA after a 410 response from GET /v1/update. This call presumes the PushServer is in "recovery" mode after a serious failure where data is unavailable. (e.g. after a node crash or other unexpected activity).
This call SHOULD only be performed by the UA after it receives a 410 response. This call presumes the PushServer is in "recovery mode" after a serious failure where data is unavailable. (e.g. after a node crash or other unexpected activity).


If the UserAgent attempts to POST information to the server which already has data for that X-UserAgent-ID, or the PushServer is no longer in "recovery" mode, the server will deny the request with a 403 error. In that case, the UserAgent should request re-registration for all Channels.  
If the UserAgent attempts to POST information to the server which already has data for that X-UserAgent-ID, or the PushServer is no longer in "recovery" mode, the server will deny the request with a 403 error. In that case, the UserAgent should request re-registration for all Channels.  
Line 242: Line 290:
# Send a list of <channelID, pushEndpoint, version> pairs capturing its current state to PushServer, along with the UAID.
# Send a list of <channelID, pushEndpoint, version> pairs capturing its current state to PushServer, along with the UAID.
# If the PushServer accepts the request, it replaces its records for the UAID with information from the client and begins accepting PUT /update/<ChannelID> requests from the AppServers.
# If the PushServer accepts the request, it replaces its records for the UAID with information from the client and begins accepting PUT /update/<ChannelID> requests from the AppServers.
# If the PushServer detects a duplicate UAID, it SHOULD respond with a 403 error.
# In this case, the client should invalidate its current state and ask apps application to re-register using the <tt>push-register</tt> system message. UserAgent and PushServer will now organically sync similar to standard /register calls.


===== Arguments =====
===== Arguments =====
Line 253: Line 299:
</pre>
</pre>


===== Returns =====
===== Success response =====
  {}
  {}
===== Errors =====
===== Errors =====


* 403 - The server may response with this for any reason, although usually it'll be due to duplicate UAID.
* 403 - The server may response with this for any reason, although usually it'll be due to duplicate UAID. The UserAgent should invalidate its current state and ask apps to re-register using <tt>push-register</tt>


===== Example =====
===== Example =====
Line 268: Line 315:
</pre>
</pre>


==== PUT /v1/update/<ChannelID> ====


Update the version of a given channel.
==== Server recovery mode ====


Arguments should be passed as standard form data (enctype: multipart/form-data)
When a server suffers data loss it goes into recovery mode. It maintains this recovery mode for a large window of time (1-2 days) to allow a majority of UserAgents to establish contact and rebuild state. In recovery mode the server responds to all requests from UserAgents with a 410 which indicates UserAgent should send state using POST /v1/update (See Registration Sync Protocol)
This call does not require a X-UserAgent-ID, as it may be called by the AppServer.


===== Arguments  =====
Once state is re-established for a given UAID, the server is no longer in "recovery mode" for that UAID and its associated ChannelIDs. So "recovery mode" is a UAID specific setting and not a global variable.
version=<version>


The version is the AppServer specific VersionID to use. This ID is opaque to the PushServer, however it is suggested that:
After the recovery period is up, the server goes back to "normal mode". Now, if a UserAgent (who has a prior UAID) contacts the server, the server is not aware of the UAID and responds with a new UAID. In this case, the UserAgent should invalidate all existing channelIDs and tell all apps to register again using the re-register system message.
* The ID be sequential.
* The ID be less than 100 characters.
* The ID should be UTF8 compliant.
 
===== Returns =====
In the event of a PushServer catastrophe, the PushServer will be in "Recovery" mode. During this time, unresolvable ChannelIDs will return a 503 error.
 
In non-recovery mode, unresolvable pushEndpoints will return a 404.
In this case, the app server should remove the endpoint association
 
A case can occur where the server starts in recovery mode, then after a sufficient period of time switches to non-recovery mode, but a particular UA has still not pinged it (perhaps because the UA does not have Internet access). In this case, application servers may have removed endpoint associations, so the push server needs to inform the UA about which channels were updated, but returned a 404. The UA will then request those apps to re-register.
 
The alternative to this 2 step recovery is to require all pushEndpoints to 404, and on Registration Sync, '''all apps''' are told to register again using 'push-register'.
 
This call returns an empty JSON object.
 
===== Example =====
PUT http://push.m.o/v1/update/foo1234
version=1.3
---
{}


=Flow Diagram=
=Flow Diagram=
[[Image:SimplePushFlow.png|Simple Push flow]]
[[Image:SimplePushFlow.png|Simple Push flow]]

Revision as of 19:14, 23 January 2013

Client Side API


partial interface Navigator {
  PushNotification pushNotification;
};

interface PushNotification {

  // registers to receive push notifications for a given topic
  // DOMRequest.result is a PushRegistration in case of success
  DOMRequest register();

  // registers to stop receiving push notifications for a given topic 
  // DOMRequest.result is a PushRegistration in case of success
  DOMRequest unregister(ChannelID channelID);

  // returns the list of all push registrations for this origin
  PushRegistration[] registrations();
};

interface PushRegistration {
  // this is the URL to which push notifications from the web application
  // must be sent to.
  // application should send this to the application server
  DOMString pushEndpoint;

  // undefined when obtained from register().onsuccess.
  // contains version when obtained from PushEvent
  DOMString version;
};

interface PushEvent : Event {
  PushRegistration target;
}

Client Example

App manifest


{
  ...
  "messages": [
    {"push": "/view_to_launch.html"}
    {"push-register": "/view_to_launch.html"}
  ]
}

JavaScript


var emailEndpoint, imEndpoint;

// all notifications will be sent to the system message handler.
// which is up to the U/A to implement

// apps can do something like
// This handler may be triggered *immediately* after mozSetMessageHandler is called
// so applications should ensure they are ready (UI created, state loaded etc.)
navigator.mozSetMessageHandler('push-register', {
  handleMessage: function(e) {
    // (re)issue register() calls
    // to register to listen for a notification,
    // you simply call push.register
    var reqEmail = navigator.pushNotifications.register();
    reqEmail.onsuccess = function(e) {
      emailEndpoint = e.result.pushEndpoint;
      storeOnAppServer("email", emailEndpoint);
    }

    var reqIm = navigator.pushNotifications.register();
    reqIm.onsuccess = function(e) {
      imEndpoint = e.result.pushEndpoint;
      storeOnAppServer("im", imEndpoint);
    }
  }
});

navigator.mozSetMessageHandler('push', {
  handleMessage: function(e) {
    e.target.pushEndpoint == This is the topic that is being observed
    e.target.version == This is the current version for this topic
  }
});


// to unregister, you simply call..

AppFramework.addEventListener('logout', function() {
  navigator.pushNotifications.unregister(emailEndpoint);
  navigator.pushNotifications.unregister(imEndpoint);
});

Notes

The current spec works for apps. Ideally it should work for web pages loaded in browsers as well. Current issues blocking this:

  • mozSetMessageHandler indexes by app manifest. Web pages don't have app manifests.
  • The lifetime of registrations for web pages needs specification.
  • Every instance of a web page should be treated differently. So the same URL in two tabs should have different channels (and ask permission?). Again geolocation, desktop-notification and others may provide clues)
  • In the case of the b2g browser, the browser is an app and so mozSetMessageHandler gets its manifest, and not access to the pages. We might want to bypass the browser and plug directly into the mozbrowseriframe of each tab. Again within each tab, user might navigate away from page, which may need invalidation.

UI

  • During app installation, the user agent should notify the user that the app uses push notifications, and possibly deny permission.
  • Web pages using push notification should show a doorhangar notification in the same way (look at geolocation to see how this is done).

Server API

Definitions

UserAgent
The client acting on behalf of the user and consumer of update notices
UAID
A server generated, globally unique UserAgent ID
PushServer
The server managing interactions between AppServers and the UserAgent
AppServer
The third party publisher of update notices
Channel
The flow of information from AppServer through PushServer to UserAgent
ChannelID
Unique identifier for a Channel. Generated by UserAgent for a particular application.
Endpoint
Unique URL comprising the ChannelID. Generated by PushServer and sent to application.

UserAgent and AppServer will use a RESTful API to interact with the Push Server.

Notes

  • Requests from UserAgent to PushServer MUST provide a PushServer Generated UserAgentID (UAID) as the "X-UserAgent-ID" header.
  • UserAgent requests may include a /{network} prefix to indicate a request may be handled by a third party network (e.g. GET http:host/foonet/update will return update requests for elements provided by the "foonet" sub-provider. TODO: The semantics of this are woefully lacking in the current state of the protocol
  • Calls will return standard HTTP status headers.
  • Calls will return status 200 (unless otherwise noted below).
  • On Errors, calls will return a proper error code, and where permitted, a standard JSON block containing information regarding the error. The contents of this block are not intended for end user display and have yet to be finalized.

Registration

GET /v1/register/<channelID>

Request a new endpoint.

If the X-UserAgent-ID is not provided, the UserAgent is presumed to be new and a new UAID will be generated for the UserAgent.

The PushServer SHOULD:

  • Ensure that the channelID is compliant with any formatting requirements the PushServer may have
  • Ensure that the channelID is unique for the UAID.
Arguments

No additional arguments are required.

Success response
{ "channelID": "<channelID provided by UA>", 
  "pushEndpoint": "http://pushserver.provider.tld/path/to/notify"
  "uaid": "UserAgent ID" (optional)
}

NOTE: The uaid is either the X-UserAgent-ID value echoed back, or a new X-UserAgent-ID value to be used for all subsequent calls if no X-UserAgent-ID was present.

pushEndpoint may incorporate channelID to simplify implementation and reduce state storage at server.

Errors
  • 200 and new UAID - If a server is not in recovery mode, but was in recovery mode before, it may return a new uaid that does not match the old UAID. If a UserAgent receives a new UAID, it should treat that as requiring a full Registration Sync step. In addition, it should throw away the pushEndpoint it received from the server.
  • 409 - duplicate channelID. UserAgent should generate new ID and try again.
  • 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.


Example
GET http://push.services.mozilla.org/v1/register/foo1234
---
{"channelID": "foo1234", "pushEndpoint": "http://push5.services.mozilla.org/v1/update/foo1234", "uaid": "bar5678"}

Unregistration

DELETE /v1/<ChannelID>

Delete an associated ChannelID. Subsequent calls to this ChannelID will result in a 404 status.

NOTE: the X-UserAgent-ID Header must be present and match the one associated with this ChannelID

Arguments

There are no arguments for this call.

Success response

Empty JSON object

{}
Errors
  • 403 - Wrong or missing UAID
  • 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.
Example
DELETE http://push.m.o/v1/foo1234
---
{}

Fetch updates

GET /v1/update

Return a list of known ChannelIDs and current versions. By default, this will return a list of ALL channels and known versions.

A client may provide a "If-Modified-Since" header (as specified in RFC2616), in which case the server will only return channel IDs that have been modified since the specified time. If no channels have been modified, the server will return a 304 Not Modified error.

If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

NOTE: The UserAgent should not modify its own lastModified field until a successful response is received, otherwise reliable delivery of updates will fail.

Arguments

There are no arguments for this call.

Success response
  • 200 - The server should return an object with the following fields:
 { "updates": [{"channelID": "id", "version": "XXX"}, ...], An association of ChannelIDs and versions that have changed since the last time the UA called /update.
   "expired": ["channelID1", "channelID2", ...], A list of ChannelIDs which have expired. The UA should remove these from its own database, and ask applications to re-register.
 }
  • 304 - No modifications since time specified in If-Modified-Since header.
Errors
  • 403 - Wrong or missing UAID
  • 410 - Server is in recovery mode. Start Registration Sync Protocol. See Server Recovery Mode.
Example
GET http://push.m.o/v1/update
---
{"updates": [{"channelID":"1ced595d7f6c9f60cc5c9395dc6b72aa7e1a69a7","version":"42"},
             {"channelID":"bf08e25861c900c3ab343670eee1873d0b724eef","version":"1"}],
 "expired": ["channelID1", "channelID2", ...]}

Notify update

Used by App Servers ONLY. NOT to be used by UserAgents.

PUT /v1/update/<ChannelID>

Update the version of a given channel.

Arguments should be passed as standard form data (enctype: multipart/form-data) This call does not require a X-UserAgent-ID.

Arguments
version=<version>

The version is the AppServer specific VersionID to use. This ID is opaque to the PushServer, however it is suggested that:

  • The ID be sequential.
  • The ID be less than 100 characters.
  • The ID should be UTF8 compliant.
Success response

This call returns an empty JSON object.

 {}
Errors
  • 403 - Not authorized. May occur when the app server has been blocked because it is exhibiting suspicious behaviour. App developer should contact the push server administrator for details.
  • 404 - No such push endpoint exists anymore. App Server's should remove the endpoint from their database. This can occur because the app unregistered itself, it was uninstalled, or for other reasons.
  • 503 - In the event of a PushServer catastrophe, the PushServer will be in "Recovery" mode. During this time, unresolvable push endpoints will return a 503 error. App Server's SHOULD NOT consider the push endpoint as being deleted. They should continue to notify the Push Server of changes.
Example
PUT http://push.m.o/v1/update/foo1234
version=1.3
--- 
{}

Registration Sync Protocol

The Registration Sync Protocol is used by UserAgents to inform the Push Server of their current state in the unlikely event of a server failure. A registration sync step can only occur when the Push Server is in "recovery mode".

POST /v1/update

Refresh the server from the client. This request REQUIRES a X-UserAgent-ID header.

This call SHOULD only be performed by the UA after it receives a 410 response. This call presumes the PushServer is in "recovery mode" after a serious failure where data is unavailable. (e.g. after a node crash or other unexpected activity).

If the UserAgent attempts to POST information to the server which already has data for that X-UserAgent-ID, or the PushServer is no longer in "recovery" mode, the server will deny the request with a 403 error. In that case, the UserAgent should request re-registration for all Channels.

The UserAgent SHOULD

  1. Send a list of <channelID, pushEndpoint, version> pairs capturing its current state to PushServer, along with the UAID.
  2. If the PushServer accepts the request, it replaces its records for the UAID with information from the client and begins accepting PUT /update/<ChannelID> requests from the AppServers.
Arguments

The POST body is a JSON encoded block:

{
  "channels": [{"channelID": "channelID1", "pushEndpoint": "...", "version": "version1"}, {"channelID": "channelID2", "pushEndpoint": "...", "version": "version2"}, ...]
}
Success response
{}
Errors
  • 403 - The server may response with this for any reason, although usually it'll be due to duplicate UAID. The UserAgent should invalidate its current state and ask apps to re-register using push-register
Example
POST http://push.m.o/v1/update
{"channels":[{"channelID":"1ced595d7f6c9f60cc5c9395dc6b72aa7e1a69a7","version":"42"},{"channelID":"bf08e25861c900c3ab343670eee1873d0b724eef","version":"1"}]}

---

{}


Server recovery mode

When a server suffers data loss it goes into recovery mode. It maintains this recovery mode for a large window of time (1-2 days) to allow a majority of UserAgents to establish contact and rebuild state. In recovery mode the server responds to all requests from UserAgents with a 410 which indicates UserAgent should send state using POST /v1/update (See Registration Sync Protocol)

Once state is re-established for a given UAID, the server is no longer in "recovery mode" for that UAID and its associated ChannelIDs. So "recovery mode" is a UAID specific setting and not a global variable.

After the recovery period is up, the server goes back to "normal mode". Now, if a UserAgent (who has a prior UAID) contacts the server, the server is not aware of the UAID and responds with a new UAID. In this case, the UserAgent should invalidate all existing channelIDs and tell all apps to register again using the re-register system message.

Flow Diagram

Simple Push flow