idnits 2.17.1 draft-ietf-alto-incr-update-sse-05.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack separate sections for Informative/Normative References. All references will be assumed normative when checking for downward references. ** The abstract seems to contain references ([RFC7285]), which it shouldn't. Please replace those with straight textual mentions of the documents in question. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year == Line 575 has weird spacing: '...atesReq add;...' -- The exact meaning of the all-uppercase expression 'MAY NOT' is not defined in RFC 2119. If it is intended as a requirements expression, it should be rewritten using one of the combinations defined in RFC 2119; otherwise it should not be all-uppercase. == The expression 'MAY NOT', while looking like RFC 2119 requirements text, is not defined in RFC 2119, and should not be used. Consider using 'MUST NOT' instead (if that is what you mean). Found 'MAY NOT' in this paragraph: As described below, each control request adds resources to the set of monitored resources, or removes previously added resources, or does both. Each control request is a separate HTTP request; the client MAY NOT stream multiple control requests in one HTTP request. However, if the client and server support HTTP Keep-Alive ([RFC7230]), the client MAY send multiple HTTP requests on the same TCP/IP connection. -- The document date (March 29, 2017) is 2578 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) == Missing Reference: 'Name' is mentioned on line 331, but not defined == Unused Reference: 'RFC7232' is defined on line 1728, but no explicit reference was found in the text == Unused Reference: 'RFC7233' is defined on line 1731, but no explicit reference was found in the text == Unused Reference: 'RFC7234' is defined on line 1734, but no explicit reference was found in the text == Unused Reference: 'RFC7235' is defined on line 1738, but no explicit reference was found in the text ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7231 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7232 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7233 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7234 (Obsoleted by RFC 9111) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) ** Obsolete normative reference: RFC 7540 (Obsoleted by RFC 9113) -- Possible downref: Non-RFC (?) normative reference: ref. 'SSE' Summary: 10 errors (**), 0 flaws (~~), 8 warnings (==), 4 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 ALTO WG W. Roome 3 Internet-Draft Nokia Bell Labs 4 Intended status: Standards Track Y. Yang 5 Expires: September 30, 2017 Tongji/Yale University 6 March 29, 2017 8 ALTO Incremental Updates Using Server-Sent Events (SSE) 9 draft-ietf-alto-incr-update-sse-05 11 Abstract 13 The Application-Layer Traffic Optimization (ALTO) [RFC7285] protocol 14 provides network related information to client applications so that 15 clients may make informed decisions. To that end, an ALTO Server 16 provides Network and Cost Maps. Using those maps, an ALTO Client can 17 determine the costs between endpoints. 19 However, the ALTO protocol does not define a mechanism to allow an 20 ALTO client to obtain updates to those maps, other than by 21 periodically re-fetching them. Because the maps may be large 22 (potentially tens of megabytes), and because only parts of the maps 23 may change frequently (especially Cost Maps), that can be extremely 24 inefficient. 26 Therefore this document presents a mechanism to allow an ALTO Server 27 to provide updates to ALTO Clients. Updates can be both immediate, 28 in that the server can send updates as soon as they are available, 29 and incremental, in that if only a small section of a map changes, 30 the server can send just the changes. 32 Requirements Language 34 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 35 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 36 document are to be interpreted as described in RFC 2119 [RFC2119]. 38 Status of This Memo 40 This Internet-Draft is submitted in full conformance with the 41 provisions of BCP 78 and BCP 79. 43 Internet-Drafts are working documents of the Internet Engineering 44 Task Force (IETF). Note that other groups may also distribute 45 working documents as Internet-Drafts. The list of current Internet- 46 Drafts is at http://datatracker.ietf.org/drafts/current/. 48 Internet-Drafts are draft documents valid for a maximum of six months 49 and may be updated, replaced, or obsoleted by other documents at any 50 time. It is inappropriate to use Internet-Drafts as reference 51 material or to cite them other than as "work in progress." 53 This Internet-Draft will expire on September 30, 2017. 55 Copyright Notice 57 Copyright (c) 2017 IETF Trust and the persons identified as the 58 document authors. All rights reserved. 60 This document is subject to BCP 78 and the IETF Trust's Legal 61 Provisions Relating to IETF Documents 62 (http://trustee.ietf.org/license-info) in effect on the date of 63 publication of this document. Please review these documents 64 carefully, as they describe your rights and restrictions with respect 65 to this document. Code Components extracted from this document must 66 include Simplified BSD License text as described in Section 4.e of 67 the Trust Legal Provisions and are provided without warranty as 68 described in the Simplified BSD License. 70 Table of Contents 72 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 73 2. Overview of Approach . . . . . . . . . . . . . . . . . . . . 4 74 3. Changes Since Version -01 . . . . . . . . . . . . . . . . . . 5 75 4. Overview of Server-Sent Events (SSEs) . . . . . . . . . . . . 5 76 5. Incremental Update Message Format . . . . . . . . . . . . . . 7 77 5.1. Overview of JSON Merge Patch . . . . . . . . . . . . . . 7 78 5.2. JSON Merge Patch Applied to Network Map Messages . . . . 8 79 5.3. JSON Merge Patch Applied to Cost Map Messages . . . . . . 10 80 6. ALTO Event Stream . . . . . . . . . . . . . . . . . . . . . . 11 81 6.1. ALTO Event Format . . . . . . . . . . . . . . . . . . . . 11 82 6.2. ALTO Update Events . . . . . . . . . . . . . . . . . . . 12 83 6.3. ALTO Control Events . . . . . . . . . . . . . . . . . . . 12 84 7. Update Stream Service . . . . . . . . . . . . . . . . . . . . 13 85 7.1. Media Type . . . . . . . . . . . . . . . . . . . . . . . 13 86 7.2. HTTP Method . . . . . . . . . . . . . . . . . . . . . . . 13 87 7.3. Accept Input Parameters . . . . . . . . . . . . . . . . . 13 88 7.4. Capabilities . . . . . . . . . . . . . . . . . . . . . . 15 89 7.5. Uses . . . . . . . . . . . . . . . . . . . . . . . . . . 16 90 7.6. Response . . . . . . . . . . . . . . . . . . . . . . . . 16 91 7.6.1. Keep-Alive Messages . . . . . . . . . . . . . . . . . 16 92 7.6.2. Event Sequence Requirements . . . . . . . . . . . . . 16 93 7.6.3. Cross-Stream Consistency Requirements . . . . . . . . 17 94 8. Update Stream Controller . . . . . . . . . . . . . . . . . . 18 95 8.1. URI . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 96 8.2. Media Type . . . . . . . . . . . . . . . . . . . . . . . 19 97 8.3. HTTP Method . . . . . . . . . . . . . . . . . . . . . . . 19 98 8.4. Accept Input Parameters . . . . . . . . . . . . . . . . . 19 99 8.5. Capabilities & Uses . . . . . . . . . . . . . . . . . . . 20 100 8.6. Response . . . . . . . . . . . . . . . . . . . . . . . . 20 101 9. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 20 102 9.1. Example: Simple Network and Cost Map Updates . . . . . . 20 103 9.2. Example: Advanced Network and Cost Map Updates . . . . . 22 104 9.3. Example: Endpoint Property Updates . . . . . . . . . . . 24 105 9.4. IRD Example . . . . . . . . . . . . . . . . . . . . . . . 28 106 10. Client Actions When Receiving Update Messages . . . . . . . . 30 107 11. Design Decisions and Discussions . . . . . . . . . . . . . . 31 108 11.1. HTTP/2 Server-Push . . . . . . . . . . . . . . . . . . . 31 109 11.2. Not Allowing Stream Restart . . . . . . . . . . . . . . 32 110 11.3. Is Incremental Update Useful for Network Maps? . . . . . 33 111 11.4. Other Incremental Update Message Types . . . . . . . . . 34 112 12. Miscellaneous Considerations . . . . . . . . . . . . . . . . 34 113 12.1. Considerations For Updates To Filtered Cost Maps . . . . 34 114 12.2. Considerations For Incremental Updates To Ordinal Mode 115 Costs . . . . . . . . . . . . . . . . . . . . . . . . . 35 116 12.3. Considerations Related to SSE Line Lengths . . . . . . . 35 117 13. Security Considerations . . . . . . . . . . . . . . . . . . . 36 118 13.1. Denial-of-Service Attacks . . . . . . . . . . . . . . . 36 119 13.2. Spoofed Control Requests . . . . . . . . . . . . . . . . 36 120 13.3. Privacy . . . . . . . . . . . . . . . . . . . . . . . . 36 121 14. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 36 122 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 39 123 Appendix A. Acknowledgments . . . . . . . . . . . . . . . . . . 40 124 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 40 126 1. Introduction 128 The Application-Layer Traffic Optimization (ALTO) [RFC7285] protocol 129 provides network related information to client applications so that 130 clients may make informed decisions. To that end, an ALTO Server 131 provides Network and Cost Maps, where a Network Map partitions the 132 set of endpoints into a manageable number of Provider-Defined 133 Identifiers (PIDs), and a Cost Map provides directed costs between 134 PIDs. Given Network and Cost Maps, an ALTO Client can obtain costs 135 between endpoints by using the Network Map to get the PID for each 136 endpoint, and then using the Cost Map to get the costs between those 137 PIDs. 139 However, the ALTO protocol does not define a mechanism to allow a 140 client to obtain updates to those maps, other than by periodically 141 re-fetching them. Because the maps may be large (potentially tens of 142 megabytes), and because parts of the maps may change frequently 143 (especially Cost Maps), that can be extremely inefficient. 145 Therefore this document presents a mechanism to allow an ALTO Server 146 to provide incremental updates to ALTO Clients. Updates can be both 147 immediate, in that the server can send updates as soon as they are 148 available, and incremental, in that if only a small section of a map 149 changes, the server can send just the changes. 151 While primarily intended to provide updates to GET-mode Network and 152 Cost Maps, the mechanism defined in this document can also provide 153 updates to other ALTO resource, including POST-mode services such as 154 Endpoint Property and Endpoint Cost Services, as well as potentially 155 new ALTO services to be defined by future extensions. 157 The rest of this document is organized as follows. Section 2 gives 158 an overview of the incremental update approach, which is based on 159 Server-Sent Events (SSEs). Section 4 and Section 5 give SSEs and 160 JSON Merge Patch, the technologies on which ALTO updates are based. 161 Section 6 defines the update events, Section 7 and Section 8 define 162 the update services themselves, and Section 9 gives several examples. 163 Section 10 describes how a client should handle incoming updates. 164 Section 11 and Section 12 discuss the design decisions behind this 165 update mechanism and other considerations. The remaining sections 166 review the security and IANA considerations. 168 2. Overview of Approach 170 This section presents a non-normative overview of the update 171 mechanism to be defined in this document. 173 An ALTO Server can offer one or more Update Stream resources, where 174 each Update Stream resource (or Update Stream for short) is a POST- 175 mode service that returns a continuous sequence of update messages 176 for one or more ALTO resources. An Update Stream can provide updates 177 to both GET-mode resources, such as Network and Cost Maps, and POST- 178 mode resources, such as Endpoint Property Services. 180 Each update message updates one resource, and is sent as a Server- 181 Sent Event (SSE), as defined by [SSE]. An update message is either a 182 full replacement or an incremental change. A full-replacement update 183 uses the JSON message format defined by the ALTO protocol. There can 184 be multiple incremental update mechanisms. The current design 185 achieves incremental-update using JSON Merge Patch ([RFC7396]), to 186 describe the changes to the resource. Future documents may define 187 additional mechanisms such as JSON Patch. The ALTO Server decides 188 when to send update messages, and whether to send full replacements 189 or incremental updates. These decisions can vary from resource to 190 resource and from update to update. 192 An ALTO Server may offer any number of Update Stream resources, for 193 any subset of the server's resources. An ALTO Server's Information 194 Resource Directory (IRD) defines the Update Stream resources, and 195 declares the set of resources for which each Update Stream provides 196 updates. The server selects the resource set for each stream. It is 197 recommended that if a resource depends on one or more other 198 resource(s) (indicated with the "uses" attribute defined in 199 [RFC7285]), these other resource(s) should also be part of that 200 stream. Thus the Update Stream for a Cost Map should also provide 201 updates for the Network Map on which that Cost Map depends. 203 When an ALTO Client requests an Update Stream resource, the client 204 establishes a new persistent connection to the server. The server 205 responds by sending an event with the URI of a stream-control 206 resource for this update stream. The control URI allows a client to 207 modify the newly-created update stream. For example, the client can 208 ask the server to send update events for additional resources, to 209 stop sending update events for previously requested resources, or to 210 gracefully stop and close the update stream altogether. 212 A client may request any number of Update Streams simultaneously. 213 Because each stream consumes resources on the server, a server may 214 limit the number of open Update Streams, may close inactive streams, 215 may provide Update Streams via other processors, or may require 216 client authorization/authentication. 218 3. Changes Since Version -01 220 o Defined a new "Stream Control" resource (Section 8) to allow 221 clients to add or remove resources from a previously created 222 Update Stream. The ALTO Server creates a new Stream Control 223 resource for each Update Stream instance, assigns a unique URI to 224 it, and sends the URI to the client as the first event in the 225 stream. 227 o The client now assigns a unique client-id to each resource in an 228 update stream. The server puts the client-id in each update event 229 for that resource (before, the server used the server's resource- 230 id). This allows a client to use one stream to get updates to two 231 different Endpoint Cost requests (before, that required two 232 separate streams). 234 4. Overview of Server-Sent Events (SSEs) 236 The following is a non-normative summary of Server-Sent Events 237 (SSEs); see [SSE] for its normative definition. 239 Server-Sent Events enable a server to send new data to a client by 240 "server-push". The client establishes an HTTP ([RFC7230], [RFC7231]) 241 connection to the server, and keeps the connection open. The server 242 continually sends messages. Each message has one or more lines, 243 where a line is terminated by a carriage-return immediately followed 244 by a new-line, a carriage-return not immediately followed by a new- 245 line, or a new-line not immediately preceded by a carriage-return. A 246 message is terminated by a blank line (two line terminators in a 247 row). 249 Each line in a message is of the form "field-name: string value". 250 Lines with a blank field-name (that is, lines which start with a 251 colon) are ignored, as are lines which do not have a colon. The 252 protocol defines three field names: event, id, and data. If a 253 message has more than one "data" line, the value of the data field is 254 the concatenation of the values on those lines. There can be only 255 one "event" or "id" line per message. The "data" field is required; 256 the others are optional. 258 Figure 1 is a sample SSE stream, starting with the client request. 259 The server sends three events and then closes the stream. 261 (Client request) 262 GET /stream HTTP/1.1 263 Host: example.com 264 Accept: text/event-stream 266 (Server response) 267 HTTP/1.1 200 OK 268 Connection: keep-alive 269 Content-Type: text/event-stream 271 event: start 272 id: 1 273 data: hello there 275 event: middle 276 id: 2 277 data: let's chat some more ... 278 data: and more and more and ... 280 event: end 281 id: 3 282 data: good bye 284 Figure 1: A Sample SSE stream. 286 5. Incremental Update Message Format 288 5.1. Overview of JSON Merge Patch 290 The following is a non-normative summary of JSON Merge Patch. See 291 [RFC7396] for the normative definition. 293 JSON Merge Patch is intended to allow applications to update server 294 resources via the HTTP PATCH method [RFC5789]. This document adopts 295 the JSON Merge Patch message format to encode the changes, but uses a 296 different transport mechanism. 298 Informally, a Merge Patch object is a JSON data structure that 299 defines how to transform one JSON value into another. Merge Patch 300 treats the two JSON values as trees of nested JSON Objects 301 (dictionaries of name-value pairs), where the leaves are values other 302 than JSON Objects (e.g., JSON Arrays, Strings, Numbers, etc.), and 303 the path for each leaf is the sequence of keys leading to that leaf. 304 When the second tree has a different value for a leaf at a path, or 305 adds a new leaf, the Merge Patch tree has a leaf, at that path, with 306 the new value. When a leaf in the first tree does not exist in the 307 second tree, the Merge Patch tree has a leaf with a JSON "null" 308 value. The Merge Patch tree does not have an entry for any leaf that 309 has the same value in both versions. 311 As a result, if all leaf values are simple scalars, JSON Merge Patch 312 is a very efficient representation of the change. It is less 313 efficient when leaf values are arrays, because JSON Merge Patch 314 replaces arrays in their entirety, even if only one entry changes. 316 Formally, the process of applying a Merge Patch is defined by the 317 following recursive algorithm, as specified in [RFC7396]: 319 define MergePatch(Target, Patch) { 320 if Patch is an Object { 321 if Target is not an Object { 322 Target = {} # Ignore the contents and 323 # set it to an empty Object 324 } 325 for each Name/Value pair in Patch { 326 if Value is null { 327 if Name exists in Target { 328 remove the Name/Value pair from Target 329 } 330 } else { 331 Target[Name] = MergePatch(Target[Name], Value) 332 } 333 } 334 return Target 335 } else { 336 return Patch 337 } 338 } 340 Note that null as the value of a name/value pair will delete the 341 element with "name" in the original JSON value. 343 5.2. JSON Merge Patch Applied to Network Map Messages 345 Section 11.2.1.6 of [RFC7285] defines the format of a Network Map 346 message. Here is a simple example: 348 { 349 "meta" : { 350 "vtag": { 351 "resource-id" : "my-network-map", 352 "tag" : "da65eca2eb7a10ce8b059740b0b2e3f8eb1d4785" 353 } 354 }, 355 "network-map" : { 356 "PID1" : { 357 "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25" ] 358 }, 359 "PID2" : { 360 "ipv4" : [ "198.51.100.128/25" ] 361 }, 362 "PID3" : { 363 "ipv4" : [ "0.0.0.0/0" ], 364 "ipv6" : [ "::/0" ] 365 } 366 } 367 } 369 When applied to that message, the following Merge Patch update 370 message adds the ipv6 prefix "2001:db8:8000::/33" to "PID1", deletes 371 "PID2", and assigns a new "tag" to the Network Map: 373 { 374 "meta" : { 375 "vtag" : { 376 "tag" : "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 377 } 378 }, 379 "network-map": { 380 "PID1" : { 381 "ipv6" : [ "2001:db8:8000::/33" ] 382 }, 383 "PID2" : null 384 } 385 } 387 Here is the updated Network Map: 389 { 390 "meta" : { 391 "vtag": { 392 "resource-id" : "my-network-map", 393 "tag" : "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 394 } 395 }, 396 "network-map" : { 397 "PID1" : { 398 "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25" ], 399 "ipv6" : [ "2001:db8:8000::/33" ] 400 }, 401 "PID3" : { 402 "ipv4" : [ "0.0.0.0/0" ], 403 "ipv6" : [ "::/0" ] 404 } 405 } 406 } 408 5.3. JSON Merge Patch Applied to Cost Map Messages 410 Section 11.2.3.6 of [RFC7285] defines the format of a Cost Map 411 message. Here is a simple example: 413 { 414 "meta" : { 415 "dependent-vtags" : [ 416 {"resource-id": "my-network-map", 417 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 418 } 419 ], 420 "cost-type" : { 421 "cost-mode" : "numerical", 422 "cost-metric": "routingcost" 423 } 424 }, 425 "cost-map" : { 426 "PID1": { "PID1": 1, "PID2": 5, "PID3": 10 }, 427 "PID2": { "PID1": 5, "PID2": 1, "PID3": 15 }, 428 "PID3": { "PID1": 20, "PID2": 15 } 429 } 430 } 432 The following Merge Patch message updates the example cost map so 433 that PID1->PID2 is 9 instead of 5, PID3->PID1 is no longer available, 434 and PID3->PID3 is now defined as 1: 436 { 437 "cost-map" : { 438 "PID1" : { "PID2" : 9 }, 439 "PID3" : { "PID1" : null, "PID3" : 1 } 440 } 441 } 443 Here is the updated cost map: 445 { 446 "meta" : { 447 "dependent-vtags" : [ 448 {"resource-id": "my-network-map", 449 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 450 } 451 ], 452 "cost-type" : { 453 "cost-mode" : "numerical", 454 "cost-metric": "routingcost" 455 } 456 }, 457 "cost-map" : { 458 "PID1": { "PID1": 1, "PID2": 9, "PID3": 10 }, 459 "PID2": { "PID1": 5, "PID2": 1, "PID3": 15 }, 460 "PID3": { "PID2": 15, "PID3": 1 } 461 } 462 } 464 6. ALTO Event Stream 466 The Update Stream service (Section 7) returns a stream of Update 467 Events (Section 6.2) and Control Events (Section 6.3). 469 6.1. ALTO Event Format 471 Update and Control Events have the same basic structure. The data 472 field is a JSON object, and the event field contains the media type 473 of the data field, and an optional client id. Update Events use the 474 client id to identify the ALTO resource to which the update message 475 applies. Client ids MUST follow the rules for ALTO ResourceIds (see 476 {10.2} of [RFC7285]. Client ids MUST be unique within an Update 477 Stream, but need not be globally unique. For example, if a client 478 requests updates for both a Cost Map and its Network Map, the client 479 might assign id "1" to the Network Map and "2" to the Cost Map. 480 Alternatively, the client could use the ALTO resource ids for those 481 two maps. 483 JSON specifications use the type ClientId for a client-id. 485 The two sub-fields of the event field are encoded as comma-separated 486 strings: 488 media-type [ ',' client-id ] 490 Note that media type names may not contain a comma (character code 491 0x2c). 493 The Update Stream Service does not use the SSE "id" field. 495 6.2. ALTO Update Events 497 The Update Stream Service sends an update event when a monitored 498 resource changes. The data is either a complete specification of the 499 resource, or else a JSON Merge Patch object describing the changes 500 from the last version. We will refer to these as full-replacement 501 and Merge Patch messages, respectively. The data objects in full- 502 replacement messages are defined by [RFC7285]; examples are Network 503 and Cost Map messages. They have the media types defined in that 504 document. The data objects in Merge Patch messages are defined by 505 [RFC7396], and they have the media type "application/merge- 506 patch+json", as defined by [RFC7396]. 508 Figure 2 shows some examples of ALTO update events: 510 event: application/alto-networkmap+json,1 511 data: { ... full Network Map message ... } 513 event: application/alto-costmap+json,2 514 data: { ... full Cost Map message ... } 516 event: application/merge-patch+json,2 517 data: { ... Merge Patch update for the Cost Map ... } 519 Figure 2: Examples of ALTO update events. 521 6.3. ALTO Control Events 523 Control events have the media type "application/alto- 524 updatestreamcontrol+json", and the data is of type 525 UpdateStreamControlEvent: 527 object { 528 [String control-uri;] 529 [String remove<1..*>;] 530 } UpdateStreamControlEvent; 532 The "control-uri" field is the URI of the Stream Control resource for 533 this Update Stream (Section 8). The ALTO server MUST send a control 534 event with that URI as the first event in an Update Stream. 536 The "remove" field is a list of client-ids of resources for which the 537 server will no longer send updates. The server sends this event 538 after processing a Stream Controller request to remove those 539 resources (Section 7.6.2). 541 7. Update Stream Service 543 An Update Stream returns a stream of SSE messages, as defined in 544 Section 6. An ALTO Server's IRD (Information Resource Directory) MAY 545 define one or more Update Stream resources, which clients use to 546 request new Update Stream instances. 548 When a server creates a new Update Stream, it also creates a new 549 Stream Controller for that Update Stream. A client uses that Stream 550 Controller to remove resources from the Update Stream instance, or to 551 request updates for additional resources. A client cannot obtain the 552 Stream Controller through the IRD. Instead, the first event that the 553 server sends to the client has the URI for the associated controller 554 (see Section 6.3. 556 Section 8 describes the Stream Controller. 558 7.1. Media Type 560 The media type of an ALTO Update Stream resource is "text/event- 561 stream", as defined by [SSE]. 563 7.2. HTTP Method 565 An ALTO Update Stream is requested using the HTTP POST method. 567 7.3. Accept Input Parameters 569 An ALTO Client specifies the parameters for the new Update Stream by 570 sending an HTTP POST body with the media type "application/alto- 571 updatestreamparams+json". That body contains a JSON Object of type 572 UpdateStreamReq, where: 574 object { 575 [AddUpdatesReq add;] 576 [ClientId remove<0..*>;] 577 } UpdateStreamReq; 579 object-map { 580 ClientId -> AddUpdateReq; 581 } AddUpdatesReq; 583 object { 584 String resource-id; 585 [String tag;] 586 [Boolean incremental-updates;] 587 [Object input;] 588 } AddUpdateReq; 590 The "add" field specifies the resources for which the client wants 591 updates, and has one entry for each resource. The client creates a 592 unique client-id (Section 6.1) for each such resource, and uses those 593 client-ids as the keys in the "add" field. 595 An Update Stream request MUST have an "add" field specifying one or 596 more resources. If it does not, the server MUST return an 597 E_INVALID_FIELD_VALUE error response (see Section 8.5.2 of 598 [RFC7285]), and MUST close the stream without sending any events. 600 The "resource-id" field is the resource-id of an ALTO resource, and 601 MUST be in the Update Stream's "uses" list (see Section 7.5). If any 602 resource-id is invalid, or is not associated with this Update Stream, 603 the server MUST return an E_INVALID_FIELD_VALUE error response (see 604 Section 8.5.2 of [RFC7285]), and MUST close the stream without 605 sending any events. 607 If the resource-id is a GET-mode resource with a version tag (or 608 "vtag"), as defined in Sections 6.3 and 10.3 of [RFC7285], and if the 609 client has previously retrieved a version of that resource from the 610 server, the client MAY set the "tag" field to the tag part of the 611 client's version of that resource. If that version is not current, 612 the server MUST send a full-replacement update before sending any 613 incremental updates, as described in Section 7.6.2. If that version 614 is still current, the ALTO Server MAY omit the initial full- 615 replacement update. 617 If the "incremental-updates" field for a resource-id is "true", the 618 server MAY send incremental update events for this resource-id 619 (assuming the server supports incremental updates for that resource; 620 see Section 7.4). If the "incremental-updates" field is "false", the 621 ALTO Server MUST NOT send incremental update events for that 622 resource. In this case, whenever a change occurs, the server MUST 623 send a full-replacement update instead of an incremental update. The 624 server MAY wait until more changes are available, and send a single 625 full-replacement update with those changes. Thus an ALTO Client 626 which declines to accept incremental updates may not get updates as 627 quickly as a client which does. 629 The default for "incremental-updates" is "true", so to suppress 630 incremental updates, the client MUST explicitly set "incremental- 631 updates" to "false". Note that the client cannot suppress full- 632 replacement update events. 634 If the resource is a POST-mode service which requires input, the 635 client MUST set the "input" field to a JSON Object with the 636 parameters that resource expects. If the "input" field is missing or 637 invalid, the ALTO Server MUST return the same error response that 638 that resource would return for missing or invalid input (see 639 [RFC7285]). In this case, the server MUST close the Update Stream 640 without sending any events. If the inputs for several POST-mode 641 resources are missing or invalid, the server MUST pick one error 642 response and return it. 644 The "remove" field is used in Stream Controller requests (see 645 Section 8), and is not allowed in the Update Stream request. If the 646 "remove" field exists, the server MUST return an 647 E_INVALID_FIELD_VALUE error response (see Section 8.5.2 of 648 [RFC7285]), and MUST close the stream without sending any events. 650 7.4. Capabilities 652 The capabilities are defined by an object of type 653 UpdateStreamCapabilities: 655 object { 656 IncrementalUpdateMediaTypes incremental-update-media-types; 657 } UpdateStreamCapabilities; 659 object-map { 660 ResourceID -> String; 661 } IncrementalUpdateMediaTypes; 663 If this Update Stream can provide incremental update events for a 664 resource, the "incremental-update-media-types" field has an entry for 665 that resource-id, and the value is the media-type of the incremental 666 update message. Normally this will be "application/merge- 667 patch+json", because, as described in Section 6, JSON Merge Patch is 668 the only incremental update event type defined by this document. 670 However future extensions may define other types of incremental 671 updates. 673 7.5. Uses 675 The "uses" attribute MUST be an array with the resource-ids of every 676 resource for which this stream can provide updates. 678 This set may be any subset of the ALTO Server's resources, and may 679 include resources defined in linked IRDs. However, it is RECOMMENDED 680 that the ALTO Server select a set that is closed under the resource 681 dependency relationship. That is, if an Update Stream's "uses" set 682 includes resource R1, and resource R1 depends on ("uses") resource 683 R0, then the Update Stream's "uses" set should include R0 as well as 684 R1. For example, an Update Stream for a Cost Map SHOULD also provide 685 updates for the Network Map upon which that Cost Map depends. 687 7.6. Response 689 The response is a stream of SSE update events. Section 6 defines the 690 events, and [SSE] defines how they are encoded into a stream. 692 An ALTO server SHOULD send updates only when the underlying values 693 change. However, it may be difficult for a server to guarantee that 694 in all circumstances. Therefore a client MUST NOT assume that an SSE 695 update event represents an actual change. 697 There are additional requirements on the server's response, as 698 described below. 700 7.6.1. Keep-Alive Messages 702 In an SSE stream, any line which starts with a colon (U+003A) 703 character is a comment, and an ALTO Client MUST ignore that line 704 ([SSE]). As recommended in [SSE], an ALTO Server SHOULD send a 705 comment line (or an event) every 15 seconds to prevent clients and 706 proxy servers from dropping the HTTP connection. 708 7.6.2. Event Sequence Requirements 710 o The first event MUST be a control event with the URI of the Stream 711 Controller (Section 8) for this Update Stream (Section 6.3). 713 o As soon as possible after the client initiates the connection, the 714 ALTO Server MUST send a full-replacement update event for each 715 resource-id requested by the client. The only exception is for a 716 GET-mode resource with a version tag. In this case the server MAY 717 omit the initial full-replacement event for that resource if the 718 "tag" field the client provided for that resource-id matches the 719 tag of the server's current version. 721 o If this stream provides updates for resource-ids R0 and R1, and if 722 R1 depends on R0, then the ALTO Server MUST send the update for R0 723 before sending the related update for R1. For example, suppose a 724 stream provides updates to a Network Map and its dependent Cost 725 Maps. When the Network Map changes, the ALTO Server MUST send the 726 Network Map update before sending the Cost Map updates. 728 o If this stream provides updates for resource-ids R0 and R1, and if 729 R1 depends on R0, then the ALTO Server SHOULD send an update for 730 R1 as soon as possible after sending the update for R0. For 731 example, when a Network Map changes, the ALTO Server SHOULD send 732 update events for the dependent Cost Maps as soon as possible 733 after the update event for the Network Map. 735 o When the client uses the Stream Controller to stop updates for one 736 or more resources (Section 8), the ALTO Server MUST send a control 737 event (Section 6.3) whose "remove" field has the client-ids of 738 those resources. If the client uses the Stream Controller to 739 terminate all active resources and close the stream, the server 740 MUST send a control event whose "remove" field has the client-ids 741 of all active resources. 743 7.6.3. Cross-Stream Consistency Requirements 745 If several clients create Update Streams for updates to the same 746 resource, the server MUST send the same updates to all of them. 747 However, the server MAY pack data items into different Merge Patch 748 events, as long as the net result of applying those updates is the 749 same. 751 For example, suppose two different clients create Update Streams for 752 the same Cost Map, and suppose the ALTO Server processes three 753 separate cost point updates with a brief pause between each update. 754 The server MUST send all three new cost points to both clients. But 755 the server MAY send a single Merge Patch event (with all three cost 756 points) to one client, while sending three separate Merge Patch 757 events (with one cost point per event) to the other client. 759 A server MAY offer several different Update Stream resources that 760 provide updates to the same underlying resource (that is, a resource- 761 id may appear in the "uses" field of more than one Update Stream 762 resource). In this case, those Update Stream resources MUST return 763 the same update data. 765 8. Update Stream Controller 767 An Update Stream Controller allows a client to remove resources from 768 the set of resources that are monitored by an Update Stream, or add 769 additional resources to that set. The controller also allows a 770 client to gracefully shutdown an Update Stream. 772 The Stream Controller is not obtained from the ALTO Server's IRD. 773 Instead, when a client requests a new Update Stream, the server 774 creates a new controller for that stream, and sends its URI to the 775 client as the first event in the Update Stream (Section 7.6.2). 777 As described below, each control request adds resources to the set of 778 monitored resources, or removes previously added resources, or does 779 both. Each control request is a separate HTTP request; the client 780 MAY NOT stream multiple control requests in one HTTP request. 781 However, if the client and server support HTTP Keep-Alive 782 ([RFC7230]), the client MAY send multiple HTTP requests on the same 783 TCP/IP connection. 785 8.1. URI 787 The URI for a Stream Controller, by itself, MUST uniquely specify the 788 Update Stream instance which it controls. The server MUST NOT use 789 other properties of an HTTP request, such as cookies or the client's 790 IP address, to determine the Update Stream. Furthermore, a server 791 MUST NOT re-use a controller URI once the associated Update Stream 792 has been closed. 794 The client MUST evaluate a non-absolute controller URI (for example, 795 a URI without a host, or with a relative path) in the context of the 796 URI used to create the Update Stream. The controller's host MAY be 797 different from the Update Stream's host. 799 It is expected that the server will assign a unique stream id to each 800 Update Stream instance, and will embed that id in the associated 801 Stream Controller URI. However, the exact mechanism is left to the 802 server. Clients MUST NOT attempt to deduce a stream id from the 803 controller URI. 805 To prevent an attacker from forging a Stream Controller URI and 806 sending bogus requests to disrupt other Update Streams, Stream 807 Controller URIs SHOULD contain sufficient random redundancy to make 808 it difficult to guess valid URIs. 810 8.2. Media Type 812 An ALTO Stream Controller response does not have a specific media 813 type. If a request is successful, the server returns an HTTP "204 No 814 Content" response. If a request is unsuccessful, the server returns 815 an ALTO error response (Section 8.5.2 of [RFC7285]) 817 8.3. HTTP Method 819 An ALTO Update Stream Controller request uses the POST method. 821 8.4. Accept Input Parameters 823 A Stream Controller accepts the same input media type and input 824 parameters as the Update Stream Service (Section 7.3). The only 825 difference is that a Stream Controller also accepts the "remove" 826 field. 828 If specified, the "remove" field is an array of client-ids the client 829 previously added to this Update Stream. An empty "remove" array is 830 equivalent to a list of all currently active resources; the server 831 responds by removing all resources and closing the stream. 833 A client MAY use the "add" field to add additional resources. 834 However, the client MUST assign a unique client-id to each resource. 835 Client-ids MUST be unique over the lifetime of this Update Stream: a 836 client MUST NOT re-use a previously removed client-id. 838 If a request has any error, the server MUST NOT add or remove any 839 resources from the associated Update Stream. In particular, 841 o Each "add" request must satisfy the requirements in Section 7.3. 842 If not, the server MUST return the error response defined in 843 Section 7.3. 845 o As described in Section 7.6.2, for each "add" request, the ALTO 846 Server MUST send a full-replacement update event for that resource 847 before sending any incremental updates. The only exception is for 848 a GET-mode resource with a version tag. In this case the server 849 MAY omit the full-replacement event for that resource if the "tag" 850 field the client provided matches the server's current version. 852 o The server MUST return an E_INVALID_FIELD_VALUE error if a client- 853 id in the "remove" field was not added in a prior request. Thus 854 it is illegal to "add" and "remove" the same client-id in the same 855 request. However, it is legal to remove a client-id twice. 857 o The server MUST return an E_INVALID_FIELD_VALUE error if a client- 858 id in the "add" field has been used before in this stream. 860 o The server MUST return an E_INVALID_FIELD_VALUE error if the 861 request has a non-empty "add" field and a "remove" field with an 862 empty list of client-ids (to replace all active resources with a 863 new set, the client MUST explicitly enumerate the client-ids to be 864 removed). 866 o If the associated Update Stream has been closed, the server MUST 867 return either an ALTO E_INVALID_FIELD_VALUE error, or else an HTTP 868 error, such as "404 Not Found". 870 8.5. Capabilities & Uses 872 None (Stream Controllers do not appear in the IRD). 874 8.6. Response 876 If a request is successful, the server returns an HTTP "204 No 877 Content" response with no data. If there are any errors, the server 878 MUST return the appropriate error code, and MUST NOT add or remove 879 any resources from the Update Stream. Thus control requests are 880 atomic: they cannot partially succeed. 882 The server MUST process the "add" field before the "remove" field. 883 If the request removes all active resources without adding any 884 additional resources, the server MUST close the Update Stream. Thus 885 an Update Stream cannot have zero resources. 887 Whenever a server removes resources as a result of a Stream 888 Controller request, the server MUST send the corresponding "remove" 889 Control Events (Section 6.3) on the Update Stream. If one control 890 request removes several resources, the server MAY send one Control 891 Event for all those resources, or a separate event for each removed 892 resource, or any combination thereof. 894 9. Examples 896 9.1. Example: Simple Network and Cost Map Updates 898 Here is an example of a client's request and the server's immediate 899 response, using the Update Stream resource "update-my-costs" defined 900 in the IRD in Section 9.4. The client requests updates for the 901 Network Map and "routingcost" Cost Map, but not for the "hopcount" 902 Cost Map. The client uses the server's resource-ids as the client- 903 ids. Because the client does not provide a "tag" for the Network 904 Map, the server must send a full update for the Network Map as well 905 as for the Cost Map. The client does not set "incremental-updates" 906 to "false", so it defaults to "true". Thus server will send Merge 907 Patch updates for the Cost Map, but not for the Network Map, because 908 this Update Stream resource does not provide incremental updates for 909 the Network Map. 911 POST /updates/costs HTTP/1.1 912 Host: alto.example.com 913 Accept: text/event-stream,application/alto-error+json 914 Content-Type: application/alto-updatestreamparams+json 915 Content-Length: ### 917 { "add": { 918 "my-network-map": { 919 "resource-id": "my-network-map" 920 }, 921 "my-routingcost-map": { 922 "resource-id": "my-routingcost-map" 923 } 924 } 925 } 927 HTTP/1.1 200 OK 928 Connection: keep-alive 929 Content-Type: text/event-stream 931 event: application/alto-updatestreamcontrol+json 932 data: {"control-uri": 933 data: "http://alto.example.com/updates/streams/3141592653589"} 935 event: application/alto-networkmap+json,my-network-map 936 data: { ... full Network Map message ... } 938 event: application/alto-costmap+json,my-routingcost-map 939 data: { ... full routingcost Cost Map message ... } 941 After sending those events immediately, the ALTO Server will send 942 additional events as the maps change. For example, the following 943 represents a small change to the Cost Map: 945 event: application/merge-patch+json,my-routingcost-map 946 data: {"cost-map": {"PID1" : {"PID2" : 9}}} 948 If a major change to the Network Map occurs, the ALTO Server MAY 949 choose to send full Network and Cost Map messages rather than Merge 950 Patch messages: 952 event: application/alto-networkmap+json,my-network-map 953 data: { ... full Network Map message ... } 955 event: application/alto-costmap+json,my-routingcost-map 956 data: { ... full Cost Map message ... } 958 9.2. Example: Advanced Network and Cost Map Updates 960 This example is similar to the previous one, except that the client 961 requests updates for the "hopcount" Cost Map as well as the 962 "routingcost" Cost Map, and provides the current version tag of the 963 Network Map, so the server is not required to send the full Network 964 Map update event at the beginning of the stream. In this example, 965 the client uses the client-ids "net", "routing" and "hops" for those 966 resources. The ALTO Server sends the stream id and the full Cost 967 Maps, followed by updates for the Network Map and Cost Maps as they 968 become available: 970 POST /updates/costs HTTP/1.1 971 Host: alto.example.com 972 Accept: text/event-stream,application/alto-error+json 973 Content-Type: application/alto-updatestreamparams+json 974 Content-Length: ### 976 { "add": { 977 "net": { 978 "resource-id": "my-network-map". 979 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 980 }, 981 "routing": { 982 "resource-id": "my-routingcost-map" 983 }, 984 "hops": { 985 "resource-id": "my-hopcount-map" 986 } 987 } 988 } 989 HTTP/1.1 200 OK 990 Connection: keep-alive 991 Content-Type: text/event-stream 993 event: application/alto-updatestreamcontrol+json 994 data: {"control-uri": 995 data: "http://alto.example.com/updates/streams/2718281828459"} 997 event: application/alto-costmap+json,routing 998 data: { ... full routingcost Cost Map message ... } 1000 event: application/alto-costmap+json,hops 1001 data: { ... full hopcount Cost Map message ... } 1003 (pause) 1005 event: application/merge-patch+json,routing 1006 data: {"cost-map": {"PID2" : {"PID3" : 31}}} 1008 event: application/merge-patch+json,hops 1009 data: {"cost-map": {"PID2" : {"PID3" : 4}}} 1011 If the client wishes to stop receiving updates for the "hopcount" 1012 Cost Map, the client can send a "remove" request on the Stream 1013 Controller URI: 1015 POST /updates/streams/2718281828459" HTTP/1.1 1016 Host: alto.example.com 1017 Accept: text/plain,application/alto-error+json 1018 Content-Type: application/alto-updatestreamparams+json 1019 Content-Length: ### 1021 { 1022 "remove": [ "hops" ] 1023 } 1025 HTTP/1.1 204 No Content 1026 Content-Length: 0 1028 (stream closed without sending data content) 1030 The ALTO Server sends a "remove" control event on the original 1031 request stream to inform the client that updates are stopped for that 1032 resource: 1034 event: application/alto-updatestreamcontrol+json 1035 data: { "remove": ["hops"] } 1037 If the client no longer needs any updates, and wishes to shut the 1038 Update Stream down gracefully, the client can send a "remove" request 1039 with an empty array: 1041 POST /updates/streams/2718281828459" HTTP/1.1 1042 Host: alto.example.com 1043 Accept: text/plain,application/alto-error+json 1044 Content-Type: application/alto-updatestreamparams+json 1045 Content-Length: ### 1047 { 1048 "remove": [ ] 1049 } 1051 HTTP/1.1 204 No Content 1052 Content-Length: 0 1054 (stream closed without sending data content) 1056 The ALTO Server sends a final "remove" control event on the original 1057 request stream to inform the client that all updates are stopped, and 1058 then closes the stream: 1060 event: application/alto-updatestreamcontrol+json 1061 data: { "remove": ["net", "routing"] } 1063 (server closes stream) 1065 9.3. Example: Endpoint Property Updates 1067 As another example, here is how a client can request updates for the 1068 property "priv:ietf-bandwidth" for one set of endpoints, and 1069 "priv:ietf-load" for another. The ALTO Server immediately sends 1070 full-replacement messages with the property values for all endpoints. 1071 After that, the server sends update events for the individual 1072 endpoints as their property values change. 1074 POST /updates/properties HTTP/1.1 1075 Host: alto.example.com 1076 Accept: text/event-stream 1077 Content-Type: application/alto-updatestreamparams+json 1078 Content-Length: ### 1080 { "add": { 1081 "props-1": { 1082 "resource-id": "my-props", 1083 "input": { 1084 "properties" : [ "priv:ietf-bandwidth" ], 1085 "endpoints" : [ 1086 "ipv4:198.51.100.1", 1087 "ipv4:198.51.100.2", 1088 "ipv4:198.51.100.3" 1089 ] 1090 } 1091 }, 1092 "props-2": { 1093 "resource-id": "my-props", 1094 "input": { 1095 "properties" : [ "priv:ietf-load" ], 1096 "endpoints" : [ 1097 "ipv6:2001:db8:100::1", 1098 "ipv6:2001:db8:100::2", 1099 "ipv6:2001:db8:100::3", 1100 ] 1101 } 1102 }, 1103 } 1104 } 1105 HTTP/1.1 200 OK 1106 Connection: keep-alive 1107 Content-Type: text/event-stream 1109 event: application/alto-updatestreamcontrol+json 1110 data: {"control-uri": 1111 data: "http://alto.example.com/updates/streams/1414213562373"} 1113 event: application/alto-endpointprops+json,props-1 1114 data: { "endpoint-properties": { 1115 data: "ipv4:198.51.100.1" : { "priv:ietf-bandwidth": "13" }, 1116 data: "ipv4:198.51.100.2" : { "priv:ietf-bandwidth": "42" }, 1117 data: "ipv4:198.51.100.3" : { "priv:ietf-bandwidth": "27" } 1118 data: } } 1120 event: application/alto-endpointprops+json,props-2 1121 data: { "endpoint-properties": { 1122 data: "ipv6:2001:db8:100::1" : { "priv:ietf-load": "8" }, 1123 data: "ipv6:2001:db8:100::2" : { "priv:ietf-load": "2" }, 1124 data: "ipv6:2001:db8:100::3" : { "priv:ietf-load": "9" } 1125 data: } } 1127 (pause) 1129 event: application/merge-patch+json,props-1 1130 data: { "endpoint-properties": 1131 data: {"ipv4:198.51.100.1" : {"priv:ietf-bandwidth": "3"}} 1132 data: } 1134 (pause) 1136 event: application/merge-patch+json,props-2 1137 data: { "endpoint-properties": 1138 data: {"ipv6:2001:db8:100::3" : {"priv:ietf-load": "7"}} 1139 data: } 1141 If the client needs the "bandwidth" property for additional 1142 endpoints, the client can send a "add" request on the Stream 1143 Controller URI: 1145 POST /updates/streams/1414213562373" HTTP/1.1 1146 Host: alto.example.com 1147 Accept: text/plain,application/alto-error+json 1148 Content-Type: application/alto-updatestreamparams+json 1149 Content-Length: ### 1151 { "add": { 1152 "props-3": { 1153 "resource-id": "my-props", 1154 "input": { 1155 "properties" : [ "priv:ietf-bandwidth" ], 1156 "endpoints" : [ 1157 "ipv4:198.51.100.4", 1158 "ipv4:198.51.100.5", 1159 ] 1160 } 1161 }, 1162 "props-4": { 1163 "resource-id": "my-props", 1164 "input": { 1165 "properties" : [ "priv:ietf-load" ], 1166 "endpoints" : [ 1167 "ipv6:2001:db8:100::4", 1168 "ipv6:2001:db8:100::5", 1169 ] 1170 } 1171 }, 1172 } 1173 } 1175 HTTP/1.1 204 No Content 1176 Content-Length: 0 1178 (stream closed without sending data content) 1180 The ALTO Server sends full replacement events for the two new 1181 resources, followed by incremental updates for all four requests as 1182 they arrive: 1184 event: application/alto-endpointprops+json,props-3 1185 data: { "endpoint-properties": { 1186 data: "ipv4:198.51.100.4" : { "priv:ietf-bandwidth": "25" }, 1187 data: "ipv4:198.51.100.5" : { "priv:ietf-bandwidth": "31" }, 1188 data: } } 1190 event: application/alto-endpointprops+json,props-4 1191 data: { "endpoint-properties": { 1192 data: "ipv6:2001:db8:100::4" : { "priv:ietf-load": "6" }, 1193 data: "ipv6:2001:db8:100::5" : { "priv:ietf-load": "4" }, 1194 data: } } 1196 (pause) 1198 event: application/merge-patch+json,props-3 1199 data: { "endpoint-properties": 1200 data: {"ipv4:198.51.100.5" : {"priv:ietf-bandwidth": "15"}} 1201 data: } 1203 (pause) 1205 event: application/merge-patch+json,props-2 1206 data: { "endpoint-properties": 1207 data: {"ipv6:2001:db8:100::2" : {"priv:ietf-load": "9"}} 1208 data: } 1210 (pause) 1212 event: application/merge-patch+json,props-4 1213 data: { "endpoint-properties": 1214 data: {"ipv6:2001:db8:100::4" : {"priv:ietf-load": "3"}} 1215 data: } 1217 9.4. IRD Example 1219 Here is an example of an IRD that offers two Update Stream services. 1220 The first provides updates for the Network Map, the "routingcost" and 1221 "hopcount" Cost Maps, and a Filtered Cost Map resource. The second 1222 Update Stream provides updates to the Endpoint Properties service. 1224 Note that this IRD defines two Filtered Cost Map resources. They use 1225 the same cost types, but "my-filtered-cost-map" accepts cost 1226 constraint tests, while "my-simple-filtered-cost-map" does not. To 1227 avoid the issues discussed in Section 12.1, the Update Stream 1228 provides updates for the second, but not the first. 1230 "my-network-map": { 1231 "uri": "http://alto.example.com/networkmap", 1232 "media-type": "application/alto-networkmap+json", 1233 }, 1234 "my-routingcost-map": { 1235 "uri": "http://alto.example.com/costmap/routingcost", 1236 "media-type": "application/alto-costmap+json", 1237 "uses": ["my-networkmap"], 1238 "capabilities": { 1239 "cost-type-names": ["num-routingcost"] 1240 } 1241 }, 1242 "my-hopcount-map": { 1243 "uri": "http://alto.example.com/costmap/hopcount", 1244 "media-type": "application/alto-costmap+json", 1245 "uses": ["my-networkmap"], 1246 "capabilities": { 1247 "cost-type-names": ["num-hopcount"] 1248 } 1249 }, 1250 "my-filtered-cost-map": { 1251 "uri": "http://alto.example.com/costmap/filtered/constraints", 1252 "media-type": "application/alto-costmap+json", 1253 "accepts": "application/alto-costmapfilter+json", 1254 "uses": ["my-networkmap"], 1255 "capabilities": { 1256 "cost-type-names": ["num-routingcost", "num-hopcount"], 1257 "cost-constraints": true 1258 } 1259 }, 1260 "my-simple-filtered-cost-map": { 1261 "uri": "http://alto.example.com/costmap/filtered/simple", 1262 "media-type": "application/alto-costmap+json", 1263 "accepts": "application/alto-costmapfilter+json", 1264 "uses": ["my-networkmap"], 1265 "capabilities": { 1266 "cost-type-names": ["num-routingcost", "num-hopcount"], 1267 "cost-constraints": false 1268 } 1269 }, 1270 "my-props": { 1271 "uri": "http://alto.example.com/properties", 1272 "media-type": "application/alto-endpointprops+json", 1273 "accepts": "application/alto-endpointpropparams+json", 1274 "capabilities": { 1275 "prop-types": ["priv:ietf-bandwidth"] 1276 } 1277 }, 1278 "update-my-costs": { 1279 "uri": "http://alto.example.com/updates/costs", 1280 "media-type": "text/event-stream", 1281 "accepts": "application/alto-updatestreamparams+json", 1282 "uses": [ 1283 "my-network-map", 1284 "my-routingcost-map", 1285 "my-hopcount-map", 1286 "my-simple-filtered-cost-map" 1287 ], 1288 "capabilities": { 1289 "incremental-update-media-types": { 1290 "my-routingcost-map": application/merge-patch+json", 1291 "my-hopcount-map": "application/merge-patch+json" 1292 } 1293 } 1294 }, 1295 "update-my-props": { 1296 "uri": "http://alto.example.com/updates/properties", 1297 "media-type": "text/event-stream", 1298 "uses": [ "my-props" ], 1299 "accepts": "application/alto-updatestreamparams+json", 1300 "capabilities": { 1301 "incremental-update-media-types": { 1302 "my-props": "application/merge-patch+json" 1303 } 1304 } 1305 } 1307 10. Client Actions When Receiving Update Messages 1309 In general, when a client receives a full-replacement update message 1310 for a resource, the client should replace the current version with 1311 the new version. When a client receives a Merge Patch update message 1312 for a resource, the client should apply those patches to the current 1313 version of the resource. 1315 However, because resources can depend on other resources (e.g., Cost 1316 Maps depend on Network Maps), an ALTO Client MUST NOT use a dependent 1317 resource if the resource on which it depends has changed. There are 1318 at least two ways a client can do that. We will illustrate these 1319 techniques by referring to Network and Cost Map messages, although 1320 these techniques apply to any dependent resources. 1322 Note that when a Network Map changes, the ALTO Server MUST send the 1323 Network Map update message before sending the updates for the 1324 dependent Cost Maps (see Section 7.6.2). 1326 One approach is for the ALTO Client to save the Network Map update 1327 message in a buffer, and continue to use the previous Network Map, 1328 and the associated Cost Maps, until the client receives the update 1329 messages for all dependent Cost Maps. The client then applies all 1330 Network and Cost Map updates atomically. 1332 Alternatively, the client MAY update the Network Map immediately. In 1333 this case, the client MUST mark each dependent Cost Map as 1334 temporarily invalid, and MUST NOT use that map until the client 1335 receives a Cost Map update message with the new Network Map version 1336 tag. Note that the client MUST NOT delete the Cost Maps, because the 1337 server may send Merge Patch update messages. 1339 The ALTO Server SHOULD send updates for dependent resources in a 1340 timely fashion. However, if the client does not receive the expected 1341 updates, the client MUST close the Update Stream connection, discard 1342 the dependent resources, and reestablish the Update Stream. The 1343 client MAY retain the version tag of the last version of any tagged 1344 resources, and give those version tags when requesting the new Update 1345 Stream. In this case, if a version is still current, the ALTO Server 1346 will not re-send that resource. 1348 Although not as efficient as possible, this recovery method is simple 1349 and reliable. 1351 11. Design Decisions and Discussions 1353 11.1. HTTP/2 Server-Push 1355 HTTP/2 ([RFC7540]) provides a Server Push facility. Although the 1356 name implies that it might be useful for sending asynchronous updates 1357 from the server to the client, in reality Server Push is not well 1358 suited for that task. To see why it is not, here is a quick summary 1359 of HTTP/2. 1361 HTTP/2 allows a client and server to multiplex many HTTP requests and 1362 responses over a single TCP connection. The requests and responses 1363 can be interleaved on a block by block basis, avoiding the head-of- 1364 line blocking problem encountered with the Keep-Alive mechanism in 1365 HTTP/1.1. Server Push allows the server to send a resource (an 1366 image, a CSS file, a javascript file, etc.) to the client before the 1367 client explicitly requests it. A server can only push cacheable GET- 1368 mode resources. By pushing a resource, the server implicitly tells 1369 the client, "Add this resource to your cache, because a resource you 1370 have requested needs it." 1372 One approach for using Server Push for ALTO updates is for the server 1373 to send each update event as a separate Server Push item, and let the 1374 client apply those updates as they arrive. Unfortunately there are 1375 several problems with that approach. 1377 First, HTTP/2 does not guarantee that pushed resources are delivered 1378 to the client in the order they were sent by the client, so each 1379 update event would need a sequence number, and the client would have 1380 to re-sequence them. 1382 Second, an HTTP/2-aware client library will not necessarily inform a 1383 client application when the server pushes a resource. Instead, the 1384 library might cache the pushed resource, and only deliver it to the 1385 client when the client explicitly requests that URI. 1387 But the third problem is the most significant: Server Push is 1388 optional, and can be disabled by any proxy between the client and the 1389 server. This is not a problem for the intended use of Server Push: 1390 eventually the client will request those resources, so disabling 1391 Server Push just adds a delay. But this means that Server Push is 1392 not suitable for resources which the client does not know to request. 1394 Thus we do not believe HTTP/2 Server Push is suitable for delivering 1395 asynchronous updates. Hence we have chosen to base ALTO updates on 1396 HTTP/1.1 and SSE. 1398 11.2. Not Allowing Stream Restart 1400 If an update stream is closed accidentally, when the client 1401 reconnects, the server must resend the full maps. This is clearly 1402 inefficient. To avoid that inefficiency, the SSE specification 1403 allows a server to assign an id to each event. When a client 1404 reconnects, the client can present the id of the last successfully 1405 received event, and the server restarts with the next event. 1407 However, that mechanism adds additional complexity. The server must 1408 save SSE messages in a buffer, in case clients reconnect. But that 1409 mechanism will never be perfect: if the client waits too long to 1410 reconnect, or if the client sends an invalid id, then the server will 1411 have to resend the complete maps anyway. 1413 Furthermore, this is unlikely to be a problem in practice. Clients 1414 who want continuous updates for large resources, such as full Network 1415 and Cost Maps, are likely to be things like P2P trackers. These 1416 clients will be well connected to the network; they will rarely drop 1417 connections. 1419 Mobile devices certainly can and do drop connections, and will have 1420 to reconnect. But mobile devices will not need continuous updates 1421 for multi-megabyte Cost Maps. If mobile devices need continuous 1422 updates at all, they will need them for small queries, such as the 1423 costs from a small set of media servers from which the device can 1424 stream the currently playing movie. If the mobile device drops the 1425 connection and reestablishes the Update Stream, the ALTO Server will 1426 have to retransmit only a small amount of redundant data. 1428 In short, using event ids to avoid resending the full map adds a 1429 considerable amount of complexity to avoid a situation which we 1430 expect is very rare. We believe that complexity is not worth the 1431 benefit. 1433 The Update Stream service does allow the client to specify the tag of 1434 the last received version of any tagged resource, and if that is 1435 still current, the server need not retransmit the full resource. 1436 Hence clients can use this to avoid retransmitting full Network Maps. 1437 Cost Maps are not tagged, so this will not work for them. Of course, 1438 the ALTO protocol could be extended by adding version tags to Cost 1439 Maps, which would solve the retransmission-on-reconnect problem. 1440 However, adding tags to Cost Maps might add a new set of 1441 complications. 1443 11.3. Is Incremental Update Useful for Network Maps? 1445 It is not clear whether incremental updates (that is, Merge Patch 1446 updates) are useful for Network Maps. For minor changes, such as 1447 moving a prefix from one PID to another, they can be useful. But 1448 more involved changes to the Network Map are likely to be "flag 1449 days": they represent a completely new Network Map, rather than a 1450 simple, well-defined change. 1452 At this point we do not have sufficient experience with ALTO 1453 deployments to know how frequently Network Maps will change, or how 1454 extensive those changes will be. For example, suppose a link goes 1455 down and the network uses an alternative route. This is a frequent 1456 occurrence. If an ALTO Server models that by moving prefixes from 1457 one PID to another, then Network Maps will change frequently. 1458 However, an ALTO Server might model that as a change in costs between 1459 PIDs, rather than a change in the PID definitions. If a server takes 1460 that approach, simple routing changes will affect Cost Maps, but not 1461 Network Maps. 1463 So while we allow a server to use Merge Patch on Network Maps, we do 1464 not require the server to do so. Each server may decide on its own 1465 whether to use Merge Patch for Network Maps. 1467 This is not to say that Network Map updates are not useful. Clearly 1468 Network Maps will change, and update events are necessary to inform 1469 clients of the new map. Further, there maybe another incremental 1470 update encoding that is better suited for updating Networks Maps; see 1471 the discussions in the next section. 1473 11.4. Other Incremental Update Message Types 1475 Other JSON-based incremental update formats have been defined, in 1476 particular JSON Patch ([RFC6902]). The update events defined in this 1477 document have the media-type of the update data. JSON Patch has its 1478 own media type ("application/json-patch+json"), so this update 1479 mechanism could easily be extended to allow servers to use JSON Patch 1480 for incremental updates. 1482 However, we think that JSON Merge Patch is clearly superior to JSON 1483 Patch for describing incremental updates to Cost Maps, Endpoint 1484 Costs, and Endpoint Properties. For these data structures, JSON 1485 Merge Patch is more space-efficient, as well as simpler to apply; we 1486 see no advantage to allowing a server to use JSON Patch for those 1487 resources. 1489 The case is not as clear for incremental updates to Network Maps. 1490 For example, suppose a prefix moves from one PID to another. JSON 1491 Patch could encode that as a simple insertion and deletion, while 1492 Merge Patch would have to replace the entire array of prefixes for 1493 both PIDs. On the other hand, to process a JSON Patch update, the 1494 client would have to retain the indexes of the prefixes for each PID. 1495 Logically, the prefixes in a PID are an unordered set, not an array; 1496 aside from handling updates, a client has no need to retain the array 1497 indexes of the prefixes. Hence to take advantage of JSON Patch for 1498 Network Maps, clients would have to retain additional, otherwise 1499 unnecessary, data. 1501 However, it is entirely possible that JSON Patch will be appropriate 1502 for describing incremental updates to new, as yet undefined ALTO 1503 resources. In this case, the extensions defining those new resources 1504 can use the update framework defined in this document, but recommend 1505 using JSON Patch, or some other method, to describe the incremental 1506 changes. 1508 12. Miscellaneous Considerations 1510 12.1. Considerations For Updates To Filtered Cost Maps 1512 If an Update Stream provides updates to a Filtered Cost Map which 1513 allows constraint tests, then a client MAY request updates to a 1514 Filtered Cost Map request with a constraint test. In this case, when 1515 a cost changes, the server MUST send an update if the new value 1516 satisfies the test. If the new value does not, whether the server 1517 sends an update depends on whether the previous value satisfied the 1518 test. If it did not, the server SHOULD NOT send an update to the 1519 client. But if the previous value did, then the server MUST send an 1520 update with a "null" value, to inform the client that this cost no 1521 longer satisfies the criteria. 1523 An ALTO Server can avoid such issues by offering Update Streams only 1524 for Filtered Cost Maps which do not allow constraint tests. 1526 12.2. Considerations For Incremental Updates To Ordinal Mode Costs 1528 For an ordinal mode cost map, a change to a single cost point may 1529 require updating many other costs. As an extreme example, suppose 1530 the lowest cost changes to the highest cost. For a numerical mode 1531 cost map, only that one cost changes. But for an ordinal mode cost 1532 map, every cost might change. While this document allows a server to 1533 offer incremental updates for ordinal mode cost maps, server 1534 implementors should be aware that incremental updates for ordinal 1535 costs are more complicated than for numerical costs, and clients 1536 should be aware that small changes may result in large updates. 1538 An ALTO Server can avoid this complication by only offering full 1539 replacement updates for ordinal cost maps. 1541 12.3. Considerations Related to SSE Line Lengths 1543 SSE was designed for events that consist of relatively small amounts 1544 of line-oriented text data, and SSE clients frequently read input one 1545 line-at-a-time. However, an Update Stream sends full cost maps as 1546 single events, and a cost map may involve megabytes, if not tens of 1547 megabytes, of text. This has implications for both the ALTO Server 1548 and Client. 1550 First, SSE clients might not be able to handle a multi-megabyte data 1551 "line". Hence it is RECOMMENDED that an ALTO server limit data lines 1552 to at most 2,000 characters. 1554 Second, some SSE client packages read all the data for an event into 1555 memory, and then present it to the client as a single character 1556 array. However, a client computer may not have enough memory to hold 1557 the entire JSON text for a large cost map. Hence an ALTO client 1558 SHOULD consider using an SSE library which presents the event data in 1559 manageable chunks, so the client can parse the cost map incrementally 1560 and store the underlying data in a more compact format. 1562 13. Security Considerations 1564 13.1. Denial-of-Service Attacks 1566 Allowing persistent update stream connections enables a new class of 1567 Denial-of-Service attacks. A client might create an unreasonable 1568 number of update stream connections, or add an unreasonable number of 1569 client-ids to one update stream. To avoid those attacks, an ALTO 1570 Server MAY choose to limit the number of active streams, and reject 1571 new requests when that threshold is reached. A server MAY also chose 1572 to limit the number of active client-ids on any given stream, or 1573 limit the total number of client-ids used over the lifetime of a 1574 stream, and reject any stream control request which would exceed 1575 those limits. In these cases, the server SHOULD return the HTTP 1576 status "503 Service Unavailable". 1578 While this technique prevents Update Stream DoS attacks from 1579 disrupting an ALTO Server's other services, it does make it easier 1580 for a DoS attack to disrupt the Update Stream service. Therefore a 1581 server may prefer to restrict Update Stream services to authorized 1582 clients, as discussed in Section 15 of [RFC7285]. 1584 Alternatively an ALTO Server MAY return the HTTP status "307 1585 Temporary Redirect" to redirect the client to another ALTO Server 1586 which can better handle a large number of update streams. 1588 13.2. Spoofed Control Requests 1590 An outside party which can read the update stream response, or which 1591 can observe stream control requests, can obtain the controller URI 1592 and use that to send a fraudulent "remove" requests, thus disabling 1593 updates for the valid client. This can be avoided by encrypting the 1594 Update Stream and Stream Controller requests (see Section 15 of 1595 [RFC7285]). Also, the ALTO Server echoes the "remove" requests on 1596 the update stream, so the valid client can detect unauthorized 1597 requests. 1599 13.3. Privacy 1601 This extension does not introduce any privacy issues not already 1602 present in the ALTO protocol. 1604 14. IANA Considerations 1606 This document defines two new media-types, "application/alto- 1607 updatestreamparams+json", as described in Section 7.3, and 1608 "application/alto-updatestreamcontrol+json", as described in 1609 Section 6.3. All other media-types used in this document have 1610 already been registered, either for ALTO or JSON Merge Patch. 1612 Type name: application 1614 Subtype name: alto-updatestreamparams+json 1616 Required parameters: n/a 1618 Optional parameters: n/a 1620 Encoding considerations: Encoding considerations are identical to 1621 those specified for the "application/json" media type. See 1622 [RFC7159]. 1624 Security considerations: Security considerations relating to the 1625 generation and consumption of ALTO Protocol messages are discussed 1626 in Section 13 of this document and Section 15 of [RFC7285]. 1628 Interoperability considerations: This document specifies format of 1629 conforming messages and the interpretation thereof. 1631 Published specification: Section 7.3 of this document. 1633 Applications that use this media type: ALTO servers and ALTO clients 1634 either stand alone or are embedded within other applications. 1636 Additional information: 1638 Magic number(s): n/a 1640 File extension(s): This document uses the mime type to refer to 1641 protocol messages and thus does not require a file extension. 1643 Macintosh file type code(s): n/a 1645 Person & email address to contact for further information: See 1646 Authors' Addresses section. 1648 Intended usage: COMMON 1650 Restrictions on usage: n/a 1652 Author: See Authors' Addresses section. 1654 Change controller: Internet Engineering Task Force 1655 (mailto:iesg@ietf.org). 1657 Type name: application 1659 Subtype name: alto-updatestreamcontrol+json 1661 Required parameters: n/a 1663 Optional parameters: n/a 1665 Encoding considerations: Encoding considerations are identical to 1666 those specified for the "application/json" media type. See 1667 [RFC7159]. 1669 Security considerations: Security considerations relating to the 1670 generation and consumption of ALTO Protocol messages are discussed 1671 in Section 13 of this document and Section 15 of [RFC7285]. 1673 Interoperability considerations: This document specifies format of 1674 conforming messages and the interpretation thereof. 1676 Published specification: Section 6.3 of this document. 1678 Applications that use this media type: ALTO servers and ALTO clients 1679 either stand alone or are embedded within other applications. 1681 Additional information: 1683 Magic number(s): n/a 1685 File extension(s): This document uses the mime type to refer to 1686 protocol messages and thus does not require a file extension. 1688 Macintosh file type code(s): n/a 1690 Person & email address to contact for further information: See 1691 Authors' Addresses section. 1693 Intended usage: COMMON 1695 Restrictions on usage: n/a 1697 Author: See Authors' Addresses section. 1699 Change controller: Internet Engineering Task Force 1700 (mailto:iesg@ietf.org). 1702 15. References 1704 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1705 Requirement Levels", RFC 2119, BCP 14, March 1997. 1707 [RFC5789] Dusseault, L. and J. Snell, "PATCH Method for HTTP", 1708 RFC 5789, March 2010. 1710 [RFC6902] Bryan, P. and M. Nottingham, "JavaScript Object Notation 1711 (JSON) Patch", RFC 6902, April 2013. 1713 [RFC7159] Bray, T., "The JavaScript Object Notation (JSON) Data 1714 Interchange Format", RFC 7159, March 2014. 1716 [RFC7285] Almi, R., Penno, R., Yang, Y., Kiesel, S., Previdi, S., 1717 Roome, W., Shalunov, S., and R. Woundy, "Application-Layer 1718 Traffic Optimization (ALTO) Protocol", RFC 7285, September 1719 2014. 1721 [RFC7230] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 1722 (HTTP/1.1): Message Syntax and Routing", RFC 7230, June 1723 2014. 1725 [RFC7231] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 1726 (HTTP/1.1): Semantics and Content", RFC 7231, June 2014. 1728 [RFC7232] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 1729 (HTTP/1.1): Conditional Requests", RFC 7232, June 2014. 1731 [RFC7233] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 1732 (HTTP/1.1): Range Requests", RFC 7233, June 2014. 1734 [RFC7234] Fielding, R., Nottingham, M., and J. Reschke, "Hypertext 1735 Transfer Protocol (HTTP/1.1): Caching", RFC 7234, June 1736 2014. 1738 [RFC7235] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 1739 (HTTP/1.1): Authentication", RFC 7235, June 2014. 1741 [RFC7396] Hoffman, P. and J. Snell, "JSON Merge Patch", RFC 7396, 1742 October 2014. 1744 [RFC7540] Belshe, M., Peon, R., and M. Thomson, "Hypertext Transfer 1745 Protocol Version 2 (HTTP/2)", RFC 7540, May 2015. 1747 [SSE] Hickson, I., "Server-Sent Events (W3C)", W3C 1748 Recommendation 03 February 2015, February 2015. 1750 Appendix A. Acknowledgments 1752 Thank you to Xiao Shi (Yale University) for his contributions to an 1753 earlier version of this document. 1755 Authors' Addresses 1757 Wendy Roome 1758 Nokia Bell Labs 1759 600 Mountain Ave, Rm 3B-324 1760 Murray Hill, NJ 07974 1761 USA 1763 Phone: +1-908-582-7974 1764 Email: wendy@wdroome.com 1766 Y. Richard Yang 1767 Tongji/Yale University 1768 51 Prospect St 1769 New Haven CT 1770 USA 1772 Email: yang.r.yang@gmail.com