OpenAjax Hub Best Practices

From MemberWiki

Jump to: navigation, search

Contents

10 OpenAjax Hub Best Practices

2009.02.09 Howard: Created this page

This chapter identifies various best practices associated with publishing and subscribing to topics using the OpenAjax Hub.

Event names

Is this sufficient for Hub 1.1? Do we need more in the area of topic namespace management?

[HUB10]

Event names may use any (Unicode) character permitted by the JavaScript language, but there are various factors that developers need to take into account:

  • The OpenAjax Hub uses the period character (".") as a token separator character (see discussion above about tokenization)
  • Each token within an event name MUST consist of at least one character. For example, the event name "a..b" is invalid because the middle token has no characters.
  • The OpenAjax Hub uses the asterisk character ("*") to indicate wildcards (see discussion above about wildcards).
  • Wildcard specifications MUST appear within a token only as a single "*" or a double "**". For example, the event names org.example.*, org.*.foo, and org.example.** are valid, but the event name aaa.bb*cc MUST NOT be treated as a valid wildcard specification because the "*" is mixed with other characters.
  • A double asterisk wildcard value ("**") MUST NOT appear except as the final token in the event name. For example, org.example.** is valid but org.**.foo MUST NOT be treated as a valid wildcard specification.
  • While any Unicode character permitted by the JavaScript language is valid in an event name, it is recommended that developers SHOULD avoid event names that might lead to human error (e.g., spaces at beginning or end of topic might lead to confusion); prove problematic to automated processing (e.g., quotes, less-than or greater-than symbols are special characters for HTML and XML); or prove problematic for transmission through emails or via system copy/paste facilities (e.g., newline characters). It is therefore recommended that event names avoid the use of control characters (e.g., 0x01), quote characters (single or double quotes), whitespace characters (leading space, trailing space, tabs or newlines), or punctuation characters (e.g., parentheses, less-than, greater-than).
  • To avoid potential event name conflicts with other components, it is recommended that event names begin with a registered internet domain expressed in reverse order, such as org.openajax.registerLibrary.
  • It is recommended that event names are tokenized to maximize usefulness in wildcarding scenarios, while taking into account that there is likely a slight performance impact for names with many tokens (e.g., a.b.c.d.e.f.g.h.i.j might require the Hub invokes 10 levels of recursive function calls)
  • The latest releases of browsers have good support for Unicode, but there are known bugs with Unicode support beyond the ASCII range in previous browser releases. Therefore, if event names include characters outside the ASCII range, be sure to test across all target browsers. (This problem should go away over the course of time.)

Undetermined order, asynchronous execution of callback functions

[HUB10] [HUB11]

While Hub implementations SHOULD normally deliver messages in a simple time-ordered manner, developers MUST NOT depend on any particular invocation order as a number of different operational factors can impact the order in which messages are delivered.

While Hub implementations SHOULD normally invoke subscriber callback functions as soon as possible, which in some cases translates into immediate execution, developers SHOULD NOT depend on immediate execution of subscriber callback functions as there are various scenarios where subscriber callback functions might execute asynchronously.

Is the following paragraph OK?

(It should be noted that implementations of the Hub will use different techniques on different browsers to pass messages between client components, especially when using the Managed Hub. As a result, even if an implementation of the Hub uses synchronous techniques on one browser, it might use asynchronous techniques on a different browser. Therefore, it is dangerous to make assumptions regarding synchronous message delivery.)

Callbacks should not throw exceptions

[HUB10]

Publishers and subscribers SHOULD NOT use exceptions as part of the protocol by which they communicate with each other and share information. Hub implementations are not required to transmit exceptions from subscribers to a given publisher.

As a result, applications that rely on exceptions to communicate responses back to the publisher will not be portable and publishers SHOULD NOT design their events such that subscribers are instructed to throw particular exceptions in particular cases.

[HUB11]

The OpenAjax Hub API specification defines a number of callback functions, including subscription callbacks, onComplete functions, onConnect functions and the like. The API specification requires that these functions NOT throw exceptions. If a callback function throws an exception, arbitrary behavior may occur. Your callback functions SHOULD therefore contain code that catches and handles all exceptions.

In particular, subscribers MUST NOT rely on exceptions to communicate with publishers. When an Iframe Container is used, the IframeHubClient.publish operation is often implemented such that it returns before the subscriber callback is invoked. Also, the Manager Application typically inserts logic through which all communication between publishers and subscribers must pass. Therefore, even if the specifications allowed subscribers to throw exceptions, exceptions thrown by a subscriber generally would not be received by the publisher.

2009.02.07 Howard: Added the HUB11 section. Needs review. 2009.02.08 Jon: Cleaned up the wording in the last paragraph.

Subscriber callback function guidelines

[HUB10]

Subscriber callbacks often execute within the single-threaded browser JavaScript context and therefore SHOULD execute and return quickly to prevent the Web page from becoming unresponsive.

Subscriber callbacks functions MAY invoke other OpenAjax Hub services as part of their processing. For example, they may publish events, even on the same topic name (but beware of infinite recursion). They may also subscribe to topic names, including the same topic name. And they may unsubscribe, including the same subscription or other subscriptions to the same topic name.

Note that all of the same guidelines that ordinarily apply to published events (e.g., general guideline about publisher/subscriber independence) also apply to events published by subscriber callback functions.

[HUB11]

Add to the above:

OpenAjax Hub 1.1 adds a number of additional callback functions, including functions for handling errors, onComplete functions, and others.

All OpenAjax Hub API calls are legal within these callback functions, as long as the state of the hub permits the execution of the API functions. So, for example, the onComplete callback associated with HubClient.connect() can call HubClient.subscribe, HubClient.publish, HubClient.unsubscribe and even HubClient.disconnect().

In the Inline Container case, callbacks associated with HubClient can legally invoke HubClient, Container and Manager functions.

2009.02.07 Howard: The Hub11 text that I added needs to be combined with the Hub10 text in a single coherent section, and this needs to be cleaned up and provided with more examples. Possibly a diagram is in order.

General guideline: publisher/subscriber independence

[HUB10]

As a general rule, publishers and subscribers SHOULD be designed to operate independently and SHOULD NOT assume that publishers and subscribers share the same JavaScript environment. Publishers SHOULD NOT pass references to JavaScript objects within publisherData and instead pass the values of those objects.

[HUB11]

As a general rule, publishers and subscribers SHOULD be designed to operate independently and SHOULD NOT assume that publishers and subscribers share the same JavaScript environment. This is especially true in the Managed Hub case, because when the Iframe Container is used, Client Applications are isolated inside iframes and have no access whatsoever to each other's or the Manager's JavaScript environment.

2009.02.07 Howard: Added Hub11 section. Also removed comment about not passing object references, since I think we say somewhere that we want publisherData values to be JSON serializable.

General guideline: read-only publisherData

[HUB10]

Developers need to be aware that the contents of parameter publisherData that is passed to a subscriber callback function SHOULD be passed by value (see general guidelines above). However, in some scenario's (see next section) some of the publisher data might be references to objects which might be live data fields that are critical to other JavaScript logic used within the given Web page. Because of this, callback functions SHOULD treat publisherData as read-only and therefore, as a general rule, not change its contents.

Scenario when it is appropriate to have read/write sections in publisherData

2009.02.07 Howard: In 1.1, we should simply state that that applications SHOULD NOT rely on subscribers being allowed to write to publisherData. Since this is a Best Practices chapter, we should give our readers practices designed to maximize security, reusability, flexibility, utility, etc. As a Best Practice, application components SHOULD use publish() to send events to other application components. They SHOULD NOT rely on the data-delivery quirks of theproprietary, implementation-specific communication protocol that a Container uses to communicate with its HubClient. Read-write areas in the publisherData fall into this category because they assume that the data is passed by reference rather than by value. This assumption is invalid for Iframe Containers and, I imagine, for any other implementation of secure sandboxes. Everyone probably remembers that when this topic was discussed during the 1.0 spec process, I opposed telling people that read-write areas in publisherData were a safe and reasonable approach. This is because I knew they would never work for Iframe Containers; any application that relies on this behavior will be very difficult to migrate to a secure Managed Hub implementation. I am leaving this comment as a RED COMMENT rather than replacing the text below, because I know that some folks felt strongly that we should allow Hub 1.0 applications to use writeable publishData.


[HUB10] [HUB11]

Added "particularly when using the Unmanaged Hub (i.e., of the Managed Hub)"

In certain workflows where the developer has full control of the execution context, particularly when using the Unmanaged Hub (i.e., instead of the Managed Hub), it can be appropriate to loosen the two general rules above (i.e., publisher/subscriber independence and read-only publisherData). One scenario is when the developer knows that the publisher logic and subscriber logic share the same JavaScript environment, such as operating within the same browser frame, and that subscriber callbacks are invoked and return synchronously (i.e., immediate execution). In this case, subscriber callback functions MAY modify particular areas within publisherData that have been documented to be read-write. For example, perhaps there is a boolean flag in publisherData that is initialized to false and but which callbacks are instructed to set to true in particular situations.

Is the following paragraph OK?

When using Managed Hub, it is common that client components will be isolated into separate Iframes, each with their own JavaScript environment. When this happens, a copy of the message payload will be passed to the subscriber function (i.e., pass-by-value). Furthermore, it should be noted that implementations of the Managed Hub may use different techniques on different browsers, where pass-by-reference techniques are used on some browsers, but to pass-by-value techniques are used on other browsers. Because of these considerations, when using the Managed Hub, in nearly all scenarios, callback functions SHOULD treat publisherData as read-only.

Responding to FramePhishing alerts

2009.02.08 Howard: I have added this section. Needs review.

An instance of IframeContainer may raise a FramePhishing security alert when the iframe's src attribute is changed unexpectedly, as by a frame phishing attack.

A Manager Application SHOULD respond to this security alert by immediately using removeContainer to remove the IframeContainer instance and thus prevent users from being tricked into entering sensitive information into the phishing page within the iframe.

The Manager Application SHOULD then alert the user to the phishing attack.

A Manager Application MIGHT also take steps such as the following:

  • Recreate the IframeContainer OR
  • Remove all IframeContainer instances (assuming that the attack came from some other IframeContainer) OR
  • Remove all IframeContainer instances and close all sub-windows and iframes (assuming that the attack might have come from something other than a Container) OR
  • Abort by removing all sensitive information, logging out of all sessions, closing all sub-windows and rendering an error page (conservative behavior if the source of the attack is completely unknown).

How to Handle LoadTimeout

2009.02.08 Howard: I have added this section. Needs review.

In IframeContainer implementations, the LoadTimeout security alert is part of the mechanism for preventing frame phishing attacks. A Container raises the LoadTimeout security alert to notify the Manager Application that the Container's client application has failed to connect as expected. This might be an innocent delay, e.g. the server might be very slow, but in many cases it constitutes evidence that a frame phishing attack occurred before the client could call connect().

When a LoadTimeout security alert occurs, several responses are possible:

  • "Strict" response: respond to a LoadTimeout as though a frame phishing attack has been detected. OR
  • "Second chance" response, consisting of the following steps:
    • Warn the user that the container is not yet ready
    • Start a timer
    • Wait for the client to connect (Container.onConnect callback) or the timer to fire.
    • If the client connects, everything is okay. Stop the timer.
    • If the timer fires, respond as though a LoadTimeout as though a frame phishing attack has been detected.

Clients in IframeContainer should connect immediately

2009.02.08 Howard: I have added this section. Needs review.

To ensure that the Container does not raise a security alert of type LoadTimeout, client components should execute HubClient.connect() as quickly as possible after they are instantiated.

Handle onDisconnect for all IframeContainer instances

2009.02.08 Howard: I have added this section. Needs review.

After an Iframe Container disconnects, the Container is no longer able to detect frame phishing attacks on the iframe. If this might make it possible for a phisher to trick a user into entering sensitive information into a phishing page in the iframe, then a Manager Application SHOULD do the following:

  • It SHOULD register an onDisconnect callback function in the params object of the IframeContainer constructor.
  • The onDisconnect callback, which is invoked when the client application disconnects, SHOULD remove the IframeContainer, thus destroying the iframe. If the iframe no longer exists, then it cannot be used in a frame phishing attack.

2009.02.08 Howard: There are cases where other behavior is acceptable. I am thinking about the impact of these cases and will report on this soon.

2009.02.09 Jon: Add the word "immediately" between the two words "SHOULD remove"?

IframeContainer clients should not change the iframe src URL

2009.02.08 Howard: I have added this section. Needs review.

2009.02.09 Jon: Do we need to provide an API such that an iframe can modify its URL? My feeling is not in Hub 1.1

On some browsers (Safari, Chrome and some versions of other browsers), an IframeContainer instance uses the URL's fragment identifier to communicate with the HubClient instance within the iframe.

If a client application within an iframe tries to modify the URL of the iframe that contains it, this may either disrupt communication between the IframeContainer and the HubClient or cause the whole client application to be unloaded, resulting in a FramePhishing security alert.

Thus, client applications sandboxed within IframeContainer instances SHOULD NOT try to change the iframe URL.

If iframe src changes are unavoidable, the iframe client SHOULD ask the Manager Application to change the URL, rather than changing the URL itself.

"Polite" vs "abrupt" removal of Containers

2009.02.09 Howard: This section is new.

A container could be removed in one of two ways:

  • "Abrupt": Immediately destroy the Container. If the Container is an IframeContainer, then immediately destroy the iframe. Do not give the Container's client any advance warning; just destroy the Container.
  • "Polite": Send a "shutdown" message to the client, telling it to clean itself up and shut down gracefully. When the client has finished its cleanup, the client should call disconnect(), causing the Manager Application to call ManagedHub.removeContainer and destroy the client.

Abrupt removal

Manager Applications SHOULD support the abrupt case so that an IframeContainer can be removed even if the client in the iframe is hung, broken, busy, malicious, etc. Manager Applications SHOULD use the abrupt approach to remove clients that are suspected of being hostile or of being the victims of frame phishing (see above).

An abrupt shutdown consists simply of calling ManagedHub.removeContainer, which performs an immediate and forceful shutdown that destroys the Container. The "remove" operation automatically destroys all subscriptions that the Container created in the ManagedHub. If the Container instance is an IframeContainer, then the "remove" operation also destroys the iframe, thus eliminating anything running in the iframe.

In the abrupt case, the Manager Application does not give the client any warning that it will be destroyed, does not negotiate with the client and does not wait for the client to clean itself up or to agree to be removed.

Polite removal

Abrupt removal is necessary in some cases, but it has some serious drawbacks. It does not permit a Client Application to clean itself up gracefully; an abruptly terminated Client Application cannot terminate any login sessions, comet connections or other application state, which may waste server resources (a kind of "resource leak").

There are plenty of scenarios in which abrupt removal is NOT required, and in which the Container can be removed in a more "polite" manner. For example, if a used clicks on a "close button" in the chrome around a gadget, the shutdown and removal of the gadget should probably be as graceful as possible.

A polite shutdown SHOULD involve the following steps: 1. Using publish, the Manager Application sends a message known as a "shutdown" message to the client component. As far as the hub knows, the shutdown message is simply another data message. It has no special semantics. 2. The client component receives the shutdown message. It responds by cleaning up its state (comet connections, server state, etc.). 3. After all of this cleanup (which might have involved asynchronous operations) is completed, the client component calls HubClient.disconnect 4. After the client disconnects, the Container detects the disconnect (possibly asynchronously) and invokes the Manager Application's onDisconnect callback function. 5. The onDisconnect function calls ManagedHub.removeContainer, abruptly removing the Container. 6. Because the client cleaned up all relevant state before calling disconnect, abrupt removal no longer causes "resource leaks."

When to use which

Polite removal allows for graceful shutdown of the client; abrupt removal does not. Therefore, use abrupt removal in situations in which shutdown must be immediate, e.g. cases involving a SecurityAlert, or cases where resource leaks are not a problem. A more polite approach is probably best in most other cases.


<--previous       contents--^       next-->
Personal tools