Application-Layer Traffic Optimization (ALTO) Incremental Updates Using Server-Sent Events (SSE)
Extracted elements (31)
Stream restart is explicitly not supported: once an update stream is closed, the client must create a new one. This avoids the complexity of tracking which updates were missed during a gap and simplifies server state management.
The design adopts SSE over HTTP/1.x rather than HTTP/2 server push because HTTP/2 client libraries may cache pushed resources without notifying the application, proxies may disable server push, and HTTP/1.x-compatible implementations are simpler to build with standard libraries.
The 'incremental-changes' parameter is a binary true/false flag rather than a per-method selection, because allowing clients to pick a subset of the server's incremental methods would add complexity to the server, which is the more constrained resource.
The substream-id mechanism is introduced to multiplex updates for multiple resources—including multiple POST-mode requests with different inputs—over a single update stream, achieving the same goal as HTTP/2 stream multiplexing while remaining compatible with HTTP/1.x.
For multipart resources, incremental patches (JSON patch or merge patch) apply to individual parts rather than the whole multipart message. Each part must have a static Content-ID in the initial full message, and incremental update events use 'substream-id.content-id' as the data-id.
JSON merge patch is superior to JSON patch for cost maps, endpoint costs, and endpoint properties because it is more space-efficient and simpler to apply. For network maps, the choice is less clear: JSON patch handles prefix-level array changes efficiently but requires clients to retain array indexes they would not otherwise need.
An ALTO client MUST NOT use a dependent resource (e.g., a cost map) after its dependency (e.g., the network map) has changed but before the dependent resource's corresponding update has been received and applied.
An update stream server SHOULD send a comment line or an event every 15 seconds as an SSE keep-alive to prevent ALTO clients and proxy servers from dropping the HTTP connection.
If an ALTO client sets 'incremental-changes' to true, it MUST support all incremental methods listed in the server's capabilities for that resource. If the server sends full replacement when 'incremental-changes' is false, it MAY wait and batch multiple changes into one replacement.
If multiple ALTO clients create update streams from the same update stream resource with identical parameters, the server MUST send the same updates to all of them, though it MAY pack changes into different patch events per client provided the net result is identical.
If no version tag is provided in an AddUpdateReq, the server MUST send a full replacement for that resource before any incremental changes. If a valid current tag is provided and the client accepts incremental changes, the server MAY omit the initial full replacement.
On any request error, the update stream server MUST NOT create an update stream and MUST return HTTP 400 with an ALTO error body. Specific error codes include E_MISSING_FIELD (no 'add' field) and E_INVALID_FIELD_VALUE (bad resource-id or invalid input).
Substream-ids MUST be unique within the scope of an update stream and MUST NOT be reused after removal over the lifetime of the same update stream, though they need not be globally unique.
The first event sent by the update stream server MUST be a control update message carrying the URI of the stream control service (or null if stream control is not supported). No data update events may precede it.
The stream control server MUST process the 'add' field before the 'remove' field. If the result would be zero active resources, the update stream server MUST close the update stream; a stream cannot have zero resources.
The stream control URI MUST by itself uniquely identify the update stream instance; the server MUST NOT use cookies or client IP to determine the stream, and MUST NOT reuse a control URI after the associated stream is closed.
The 'uses' attribute of an update stream service MUST list every resource for which the stream can provide updates, and each listed resource MUST support full replacement. It is RECOMMENDED that this set be closed under resource dependency relationships.
When a JSON merge patch update would set a field to null but the resource distinguishes null from undefined, the server MUST choose JSON patch instead of JSON merge patch; if JSON patch is not supported, the server must send a full replacement.
When an update stream covers resources R0 and R1 where R1 depends on R0, the server MUST send the update for R0 before sending related updates for R1. For example, a network map update MUST precede dependent cost map updates.
An ALTO update message uses the SSE 'event' field to carry two comma-separated subfields: 'media-type' and 'data-id'. The SSE 'id' field is not used. The comma separator is unambiguous because RFC 6838 prohibits commas in media-type names.
The Stream Control Service allows an ALTO client to dynamically add or remove resources from a running update stream, or shut it down gracefully. Its URI is delivered as the first SSE event on the stream and does not appear in the IRD.
The Update Stream Service is a POST-mode ALTO service that returns a persistent SSE stream of update messages. It is announced in the IRD with media type 'text/event-stream', HTTP method POST, and capabilities including 'incremental-change-media-types' and 'support-stream-control'.
The UpdateStreamControlEvent object (media type 'application/alto-updatestreamcontrol+json') carries: control-uri (sent once as the first event), started (list of substream-ids newly sending updates), stopped (list of substream-ids no longer sending updates), and an optional human-readable description.
The UpdateStreamReq body (media type 'application/alto-updatestreamparams+json') carries an 'add' map (SubstreamID -> AddUpdateReq) specifying resources to monitor. Each AddUpdateReq includes resource-id, optional version tag, optional incremental-changes Boolean, and optional input for POST-mode resources.
UpdateStreamCapabilities declares 'incremental-change-media-types' (a map from resource-id to supported incremental media types such as 'application/merge-patch+json' and/or 'application/json-patch+json') and a Boolean 'support-stream-control' field.
IANA registers the media type 'application/alto-updatestreamcontrol+json' for control update messages (UpdateStreamControlEvent) sent by the update stream server to the ALTO client, as defined in Section 5.3.
IANA registers the media type 'application/alto-updatestreamparams+json' for the JSON request body of an ALTO update stream service, as defined in Section 6.5.
An ALTO client may become overloaded or unstable if an update stream server sends updates too frequently or in excessively large messages. Clients should implement rate-limiting or load-shedding to protect against update overloading.
An attacker may forge stream control requests to disrupt other clients' update streams. The server SHOULD use HTTPS to protect the control URI in transit and SHOULD assign sufficiently random control URIs to resist guessing, and SHOULD detect repeated failed attempts.
An update stream server is vulnerable to resource exhaustion DoS if many clients open streams simultaneously. Mitigations include requiring client authentication/authorization, limiting concurrent open streams per client, closing inactive streams, and redirecting clients to other servers.
The data-id in the SSE 'event' field is the substream-id for single-part resources, or the concatenation 'substream-id.content-id' (separator U+002E) for each part of a multipart/related resource. Full format: 'media-type,data-id'.