idnits 2.17.1 draft-ietf-alto-incr-update-sse-20.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 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 1016 has weird spacing: '...atesReq add;...' == Line 1026 has weird spacing: '...NString tag;]...' -- The document date (February 21, 2020) is 1525 days in the past. Is this intentional? Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) -- Possible downref: Non-RFC (?) normative reference: ref. 'SSE' -- Obsolete informational reference (is this intentional?): RFC 4960 (Obsoleted by RFC 9260) -- Obsolete informational reference (is this intentional?): RFC 7230 (Obsoleted by RFC 9110, RFC 9112) -- Obsolete informational reference (is this intentional?): RFC 7231 (Obsoleted by RFC 9110) -- Obsolete informational reference (is this intentional?): RFC 7540 (Obsoleted by RFC 9113) Summary: 2 errors (**), 0 flaws (~~), 3 warnings (==), 6 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: August 24, 2020 Yale University 6 February 21, 2020 8 ALTO Incremental Updates Using Server-Sent Events (SSE) 9 draft-ietf-alto-incr-update-sse-20 11 Abstract 13 The Application-Layer Traffic Optimization (ALTO) [RFC7285] protocol 14 provides network related information, called network information 15 resources, to client applications so that clients can make informed 16 decisions in utilizing network resources. For example, an ALTO 17 server can provide network and cost maps so that an ALTO client can 18 use the maps to determine the costs between network endpoints when 19 choosing communicating endpoints. 21 However, the ALTO protocol does not define a mechanism to allow an 22 ALTO client to obtain updates to the information resources, other 23 than by periodically re-fetching them. Because some information 24 resources (e.g., the aforementioned maps) may be large (potentially 25 tens of megabytes), and because only parts of the information 26 resources may change frequently (e.g., only some entries in a cost 27 map), complete re-fetching can be inefficient. 29 This document presents a mechanism to allow an ALTO server to push 30 updates to ALTO clients, to achieve two benefits: (1) updates can be 31 incremental, in that if only a small s ection of an information 32 resource changes, the ALTO server can send just the changes; and (2) 33 updates can be immediate, in that the ALTO server can send updates as 34 soon as they are available. 36 Requirements Language 38 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 39 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 40 document are to be interpreted as described in RFC 2119 [RFC2119]. 42 Status of This Memo 44 This Internet-Draft is submitted in full conformance with the 45 provisions of BCP 78 and BCP 79. 47 Internet-Drafts are working documents of the Internet Engineering 48 Task Force (IETF). Note that other groups may also distribute 49 working documents as Internet-Drafts. The list of current Internet- 50 Drafts is at http://datatracker.ietf.org/drafts/current/. 52 Internet-Drafts are draft documents valid for a maximum of six months 53 and may be updated, replaced, or obsoleted by other documents at any 54 time. It is inappropriate to use Internet-Drafts as reference 55 material or to cite them other than as "work in progress." 57 This Internet-Draft will expire on August 24, 2020. 59 Copyright Notice 61 Copyright (c) 2020 IETF Trust and the persons identified as the 62 document authors. All rights reserved. 64 This document is subject to BCP 78 and the IETF Trust's Legal 65 Provisions Relating to IETF Documents 66 (http://trustee.ietf.org/license-info) in effect on the date of 67 publication of this document. Please review these documents 68 carefully, as they describe your rights and restrictions with respect 69 to this document. Code Components extracted from this document must 70 include Simplified BSD License text as described in Section 4.e of 71 the Trust Legal Provisions and are provided without warranty as 72 described in the Simplified BSD License. 74 Table of Contents 76 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 77 2. Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 78 3. Background . . . . . . . . . . . . . . . . . . . . . . . . . 6 79 3.1. Incremental Encoding: JSON Merge Patch . . . . . . . . . 7 80 3.1.1. JSON Merge Patch Encoding . . . . . . . . . . . . . . 7 81 3.1.2. JSON Merge Patch ALTO Messages . . . . . . . . . . . 8 82 3.2. Incremental Encoding: JSON Patch . . . . . . . . . . . . 11 83 3.2.1. JSON Patch Encoding . . . . . . . . . . . . . . . . . 12 84 3.2.2. JSON Patch ALTO Messages . . . . . . . . . . . . . . 12 85 3.3. Multiplexing and Server Push: HTTP/2 . . . . . . . . . . 14 86 3.4. Server Push: Server-Sent Event . . . . . . . . . . . . . 15 87 4. Overview of Approach and High-level Protocol Message Flow . . 16 88 4.1. Update Stream Service Message Flow . . . . . . . . . . . 17 89 4.2. Stream Control Service Message Flow . . . . . . . . . . . 18 90 4.3. Service Announcement and Management Message Flow . . . . 19 91 5. Update Messages: Data Update and Control Update Messages . . 19 92 5.1. Generic ALTO Update Message Structure . . . . . . . . . . 19 93 5.2. ALTO Data Update Message . . . . . . . . . . . . . . . . 20 94 5.3. ALTO Control Update Message . . . . . . . . . . . . . . . 21 95 6. Update Stream Service . . . . . . . . . . . . . . . . . . . . 22 96 6.1. Media Type . . . . . . . . . . . . . . . . . . . . . . . 22 97 6.2. HTTP Method . . . . . . . . . . . . . . . . . . . . . . . 22 98 6.3. Capabilities . . . . . . . . . . . . . . . . . . . . . . 22 99 6.4. Uses . . . . . . . . . . . . . . . . . . . . . . . . . . 23 100 6.5. Request: Accept Input Parameters . . . . . . . . . . . . 24 101 6.6. Response . . . . . . . . . . . . . . . . . . . . . . . . 25 102 6.7. Additional Requirements on Update Stream Service . . . . 27 103 6.7.1. Event Sequence Requirements . . . . . . . . . . . . . 27 104 6.7.2. Cross-Stream Consistency Requirements . . . . . . . . 27 105 6.7.3. Multipart Update Requirements . . . . . . . . . . . . 28 106 6.8. Keep-Alive Messages . . . . . . . . . . . . . . . . . . . 28 107 7. Stream Control Service . . . . . . . . . . . . . . . . . . . 28 108 7.1. URI . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 109 7.2. Media Type . . . . . . . . . . . . . . . . . . . . . . . 29 110 7.3. HTTP Method . . . . . . . . . . . . . . . . . . . . . . . 29 111 7.4. IRD Capabilities & Uses . . . . . . . . . . . . . . . . . 29 112 7.5. Request: Accept Input Parameters . . . . . . . . . . . . 30 113 7.6. Response . . . . . . . . . . . . . . . . . . . . . . . . 30 114 8. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 31 115 8.1. Example: IRD Announcing Update Stream Services . . . . . 31 116 8.2. Example: Simple Network and Cost Map Updates . . . . . . 34 117 8.3. Example: Advanced Network and Cost Map Updates . . . . . 37 118 8.4. Example: Endpoint Property Updates . . . . . . . . . . . 41 119 8.5. Example: Multipart Message Updates . . . . . . . . . . . 44 120 9. Operation and Processing Considerations . . . . . . . . . . . 46 121 9.1. Considerations for Choosing Data Update Messages . . . . 46 122 9.2. Considerations for Client Processing Data Update Messages 47 123 9.3. Considerations for Updates to Filtered Cost Maps . . . . 48 124 9.4. Considerations for Updates to Ordinal Mode Costs . . . . 48 125 9.5. Considerations for SSE Text Formatting and Processing . . 49 126 10. Security Considerations . . . . . . . . . . . . . . . . . . . 49 127 10.1. Update Stream Server: Denial-of-Service Attacks . . . . 50 128 10.2. ALTO Client: Update Overloading or Instability . . . . . 50 129 10.3. Stream Control: Spoofed Control Requests . . . . . . . . 50 130 11. Requirements on Future ALTO Services to Use this Design . . . 51 131 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 51 132 13. Alternative Design Not Supported . . . . . . . . . . . . . . 53 133 13.1. Why Not Allowing Stream Restart . . . . . . . . . . . . 53 134 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 54 135 15. Contributors . . . . . . . . . . . . . . . . . . . . . . . . 54 136 16. References . . . . . . . . . . . . . . . . . . . . . . . . . 55 137 16.1. Normative References . . . . . . . . . . . . . . . . . . 55 138 16.2. Informative References . . . . . . . . . . . . . . . . . 55 139 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 56 141 1. Introduction 143 The Application-Layer Traffic Optimization (ALTO) [RFC7285] protocol 144 provides network related information called network information 145 resources to client applications so that clients may make informed 146 decisions in utilizing network resources. For example, an ALTO 147 server provides network and cost maps, where a network map partitions 148 the set of endpoints into a manageable number of sets each defined by 149 a Provider-Defined Identifier (PID), and a cost map provides directed 150 costs between PIDs. Given network and cost maps, an ALTO client can 151 obtain costs between endpoints by first using the network map to get 152 the PID for each endpoint, and then using the cost map to get the 153 costs between those PIDs. Such costs can be used by the client to 154 choose communicating endpoints with low network costs. 156 The ALTO protocol defines only an ALTO client pull model, without 157 defining a mechanism to allow an ALTO client to obtain updates to 158 network information resources, other than by periodically re-fetching 159 them. In settings where an information resource may be large but 160 only parts of it may change frequently (e.g., some entries of a cost 161 map), complete re-fetching can be inefficient. 163 This document presents a mechanism to allow an ALTO server to push 164 incremental updates to ALTO clients. Integrating server-push and 165 incremental updates provides two benefits: (1) updates can be small, 166 in that if only a small section of an information resource changes, 167 the ALTO server can send just the changes; and (2) updates can be 168 immediate, in that the ALTO server can send updates as soon as they 169 are available. 171 While primarily intended to provide updates to GET-mode network and 172 cost maps, the mechanism defined in this document can also provide 173 updates to POST-mode ALTO services, such as the ALTO endpoint 174 property and endpoint cost services. The mechanism can also support 175 new ALTO services to be defined by future extensions, but a future 176 service needs to satisfy requirements specified in Section 11. 178 The rest of this document is organized as follows. Section 3 gives 179 background on the basic techniques used in this design: (1) JSON 180 merge patch and JSON patch to allow incremental update; and (2) 181 Server-Sent Events to allow server push. With the background, 182 Section 4 gives a non-normative overview of the design. Section 5 183 defines individual messages in an update stream. Section 6 defines 184 the update stream service; Section 7 defines the stream control 185 service; Section 8 gives several examples to illustrate the two types 186 of services. Section 9 describes operation and processing 187 considerations by both ALTO servers and clients; Section 13 discusses 188 a design feature that is not supported; Section 10 discusses security 189 issues; The last two sections review the requirements for future ALTO 190 services to use SSE and IANA considerations, respectively. 192 2. Terms 194 This document uses the following terms: Update Stream, Update Stream 195 Server, Update Message, Data Update Message, Full Replacement, 196 Incremental Change, Stream Control Service, Stream Control, Stream 197 Control Server, Substream-ID, Data-ID, and Control Update Message. 199 Update Stream: An update stream is an HTTP connection between an ALTO 200 client and an ALTO server so that the server can push a sequence of 201 update messages using SSE to the client. 203 Update Stream Server: This document refers to an ALTO server 204 providing an update stream as an ALTO update stream server, or update 205 stream server for short. Note that the ALTO server mentioned in this 206 document refers to a general server that provides various kinds of 207 services; it can be an update stream server or stream control server 208 (see below); it can also be a server providing ALTO Information 209 Resource Directory (IRD). 211 Update Message: An update message is either a data update message or 212 a control update message. 214 Data Update Message: A data update message is for a single ALTO 215 information resource and sent from the update stream server to the 216 ALTO client when the resource changes. A data update message can be 217 either a full-replacement message or an incremental-change message. 218 Full replacement is a shorthand for a full-replacement message, and 219 incremental change is a shorthand for an incremental-change message. 221 Full Replacement: A full replacement for a resource encodes the 222 content of the resource in its original ALTO encoding. 224 Incremental Change: An incremental change specifies only the 225 difference between the new content and the previous version. An 226 incremental change can be encoded using either JSON merge patch or 227 JSON patch in this document. 229 Stream Control Service: An stream control service provides an HTTP 230 URI so that the ALTO client of an update stream can use it to send 231 stream control requests to the ALTO server on the addition or removal 232 of resources receiving update messages from the update stream. The 233 ALTO server creates a new stream control resource for each update 234 stream instance, assigns a unique URI to it, and sends the URI to the 235 client as the first event in the stream. (Note that the Stream 236 Control Service in ALTO has no association with the similarly named 237 Stream Control Transmission Protocol [RFC4960].) 239 Stream Control: A shorthand for stream control service. 241 Stream Control Server: An stream control server providing the stream 242 control service. 244 Substream-ID: An ALTO client can assign a unique substream-id when 245 requesting the addition of a resource receiving update messages from 246 an update stream. The server puts the substream-id in each update 247 event for that resource. Substream-id allows a client to use one 248 update stream to receive updates to multiple requests for the same 249 resource (i.e., with the same resource-id in an ALTO IRD), for 250 example, for a POST-mode resource with different input parameters. 252 Data-ID: It is a subfield of the `event` field of SSE to identify the 253 ALTO data (object) to be updated. For an ALTO resource returning a 254 multipart response, the data-id to identify the data (object) is the 255 substream-id, in addition to the content-id of the object in the 256 multipart response. The data-id of a single part response is just 257 the substream-id. 259 Control Update Message: A control update message is a message in an 260 update stream for the update stream server to notify the ALTO client 261 of related control information of the update stream. The first 262 message of an update stream is a control update message and provides 263 the URI using which the ALTO client can send stream control requests 264 to the stream control server. Additional control update messages in 265 an update stream allow the update stream server to notify the ALTO 266 client of status changes (e.g., the server will no longer send 267 updates for an information resource). 269 3. Background 271 The design requires two basic techniques: encoding of incremental 272 changes and server push. For incremental changes, existing 273 techniques include JSON merge patch and JSON patch; this design uses 274 both. For server push, existing techniques include HTTP/2 and 275 Server-Sent Event; this design adopts some design features of HTTP/2 276 but uses Server-Sent Events as the basic server-push design. The 277 rest of this section gives a non-normative summary of JSON merge 278 patch, JSON patch, HTTP/2 and SSE. 280 3.1. Incremental Encoding: JSON Merge Patch 282 To avoid always sending complete data, a server needs mechanisms to 283 encode incremental changes, and JSON merge patch is one mechanism. 284 [RFC7396] defines the encoding of incremental changes (called JSON 285 merge patch objects) to be used by the HTTP PATCH method [RFC5789]. 286 This document adopts from [RFC7396] only the JSON merge patch object 287 encoding and does not use the HTTP PATCH method. Below is a non- 288 normative summary of JSON merge patch objects; see [RFC7396] for the 289 normative definition. 291 3.1.1. JSON Merge Patch Encoding 293 Informally, a JSON merge patch object (JSON merge patch for short in 294 this document) is a JSON data structure that defines how to transform 295 one JSON value into another. Specifically, JSON merge patch treats 296 the two JSON values as trees of nested JSON objects (dictionaries of 297 name-value pairs), where the leaves are values (e.g., JSON arrays, 298 strings, numbers) other than JSON objects and the path for each leaf 299 is the sequence of keys leading to that leaf. When the second tree 300 has a different value for a leaf at a path, or adds a new leaf, the 301 JSON merge patch tree has a leaf, at that path, with the new value. 302 When a leaf in the first tree does not exist in the second tree, the 303 JSON merge patch tree has a leaf with a JSON "null" value. The JSON 304 merge patch tree does not have an entry for any leaf that has the 305 same value in both versions. 307 As a result, if all leaf values are simple scalars, JSON merge patch 308 is a quite efficient representation of incremental changes. It is 309 less efficient when leaf values are arrays, because JSON merge patch 310 replaces arrays in their entirety, even if only one entry changes. 312 Formally, the process of applying a JSON merge patch is defined by 313 the following recursive algorithm, as specified in [RFC7396]: 315 316 define MergePatch(Target, Patch) { 317 if Patch is an Object { 318 if Target is not an Object { 319 Target = {} # Ignore the contents and 320 # set it to an empty Object 321 } 322 for each Name/Value pair in Patch { 323 if Value is null { 324 if Name exists in Target { 325 remove the Name/Value pair from Target 326 } 327 } else { 328 Target[Name] = MergePatch(Target[Name], Value) 329 } 330 } 331 return Target 332 } else { 333 return Patch 334 } 335 } 336 338 Note that null as the value of a name/value pair will delete the 339 element with "name" in the original JSON value. 341 3.1.2. JSON Merge Patch ALTO Messages 343 To provide both examples of JSON merge patch and a demonstration of 344 the feasibility of applying JSON merge patch to ALTO, the sections 345 below show the application of JSON merge patch to two key ALTO 346 messages. 348 3.1.2.1. JSON Merge Patch Network Map Messages 350 Section 11.2.1.6 of [RFC7285] defines the format of an ALTO network 351 map message. Assume a simple example ALTO message sending an initial 352 network map: 354 { 355 "meta" : { 356 "vtag": { 357 "resource-id" : "my-network-map", 358 "tag" : "da65eca2eb7a10ce8b059740b0b2e3f8eb1d4785" 359 } 360 }, 361 "network-map" : { 362 "PID1" : { 363 "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25" ] 364 }, 365 "PID2" : { 366 "ipv4" : [ "198.51.100.128/25" ] 367 }, 368 "PID3" : { 369 "ipv4" : [ "0.0.0.0/0" ], 370 "ipv6" : [ "::/0" ] 371 } 372 } 373 } 375 Consider the following JSON merge patch update message, which (1) 376 adds an ipv4 prefix "193.51.100.0/25" and an ipv6 prefix 377 "2001:db8:8000::/33" to "PID1", (2) deletes "PID2", and (3) assigns a 378 new "tag" to the network map: 380 { 381 "meta" : { 382 "vtag" : { 383 "tag" : "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 384 } 385 }, 386 "network-map": { 387 "PID1" : { 388 "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25", 389 "193.51.100.0/25" ], 390 "ipv6" : [ "2001:db8:8000::/33" ] 391 }, 392 "PID2" : null 393 } 394 } 396 Applying the JSON merge patch update to the initial network map is 397 equivalent to the following ALTO network map: 399 { 400 "meta" : { 401 "vtag": { 402 "resource-id" : "my-network-map", 403 "tag" : "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 404 } 405 }, 406 "network-map" : { 407 "PID1" : { 408 "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25", 409 "193.51.100.0/25" ], 410 "ipv6" : [ "2001:db8:8000::/33" ] 411 }, 412 "PID3" : { 413 "ipv4" : [ "0.0.0.0/0" ], 414 "ipv6" : [ "::/0" ] 415 } 416 } 417 } 419 3.1.2.2. JSON Merge Patch Cost Map Messages 421 Section 11.2.3.6 of [RFC7285] defines the format of an ALTO cost map 422 message. Assume a simple example ALTO message for an initial cost 423 map: 425 { 426 "meta" : { 427 "dependent-vtags" : [ 428 {"resource-id": "my-network-map", 429 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 430 } 431 ], 432 "cost-type" : { 433 "cost-mode" : "numerical", 434 "cost-metric": "routingcost" 435 }, 436 "vtag": { 437 "resource-id" : "my-cost-map", 438 "tag" : "3ee2cb7e8d63d9fab71b9b34cbf764436315542e" 439 } 440 }, 441 "cost-map" : { 442 "PID1": { "PID1": 1, "PID2": 5, "PID3": 10 }, 443 "PID2": { "PID1": 5, "PID2": 1, "PID3": 15 }, 444 "PID3": { "PID1": 20, "PID2": 15 } 445 } 446 } 448 The following JSON merge patch message updates the example cost map 449 so that (1) the "tag" field of the cost map is updated, (2) the cost 450 of PID1->PID2 is 9 instead of 5, (3) the cost of PID3->PID1 is no 451 longer available, and (4) the cost of PID3->PID3 is defined as 1. 453 { 454 "meta" : { 455 "vtag": { 456 "tag": "c0ce023b8678a7b9ec00324673b98e54656d1f6d" 457 } 458 } 459 "cost-map" : { 460 "PID1" : { "PID2" : 9 }, 461 "PID3" : { "PID1" : null, "PID3" : 1 } 462 } 463 } 465 Hence applying the JSON merge patch to the initial cost map is 466 equivalent to the following ALTO cost map: 468 { 469 "meta" : { 470 "dependent-vtags" : [ 471 {"resource-id": "my-network-map", 472 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 473 } 474 ], 475 "cost-type" : { 476 "cost-mode" : "numerical", 477 "cost-metric": "routingcost" 478 }, 479 "vtag": { 480 "resource-id": "my-cost-map", 481 "tag": "c0ce023b8678a7b9ec00324673b98e54656d1f6d" 482 } 483 }, 484 "cost-map" : { 485 "PID1": { "PID1": 1, "PID2": 9, "PID3": 10 }, 486 "PID2": { "PID1": 5, "PID2": 1, "PID3": 15 }, 487 "PID3": { "PID2": 15, "PID3": 1 } 488 } 489 } 491 3.2. Incremental Encoding: JSON Patch 492 3.2.1. JSON Patch Encoding 494 One issue of JSON merge patch is that it does not handle array 495 changes well. In particular, JSON merge patch considers an array as 496 a single object and hence can only replace an array in its entirety. 497 When the change is to make a small change to an array such as the 498 deletion of an element from a large array, whole-array replacement is 499 inefficient. Consider the example in Section 3.1.2.1. To add a new 500 entry to the ipv4 array for PID1, the server needs to send a whole 501 new array. Another issue is that JSON merge patch cannot change a 502 value to be null, as the JSON merge patch processing algorithm 503 (MergePatch in Section 3.1.1) interprets a null as a removal 504 instruction. On the other hand, some ALTO resources can have null 505 values, and it is possible that the update will want to change the 506 new value to be null. 508 JSON patch [RFC6902] can address the preceding issues. It defines a 509 set of operators to modify a JSON object. See [RFC6902] for the 510 normative definition. 512 3.2.2. JSON Patch ALTO Messages 514 To provide both examples of JSON patch and a demonstration of the 515 difference between JSON patch and JSON merge patch, the sections 516 below show the application of JSON patch to the same updates shown in 517 Section 3.1.2. 519 3.2.2.1. JSON Patch Network Map Messages 521 First consider the same update as in Section 3.1.2.1 for the network 522 map. Below is the encoding using JSON patch: 524 [ 525 { 526 "op": "replace", 527 "path": "/meta/vtag/tag", 528 "value": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 529 }, 530 { 531 "op": "add", 532 "path": "/network-map/PID1/ipv4/2", 533 "value": "193.51.100.0/25" 534 } 535 { 536 "op": "add", 537 "path": "/network-map/PID1/ipv6", 538 "value": ["2001:db8:8000::/33"] 539 }, 540 { 541 "op": "remove", 542 "path": "/network-map/PID2" 543 } 544 ] 546 3.2.2.2. JSON Patch Cost Map Messages 548 Compared with JSON merge patch, JSON patch does not encode cost map 549 updates efficiently. Consider the cost map update shown in 550 Section 3.1.2.2, the encoding using JSON patch is: 552 [ 553 { 554 "op": "replace", 555 "path": "/meta/vtag/tag", 556 "value": "c0ce023b8678a7b9ec00324673b98e54656d1f6d" 557 }, 558 { 559 "op": "replace", 560 "path": "/cost-map/PID1/PID2", 561 "value": 9 562 }, 563 { 564 "op": "remove", 565 "path": "/cost-map/PID3/PID1" 566 }, 567 { 568 "op": "replace", 569 "path": "/cost-map/PID3/PID3", 570 "value": 1 571 } 572 ] 574 3.3. Multiplexing and Server Push: HTTP/2 576 HTTP/2 ([RFC7540]) provides two related features: multiplexing and 577 server push. In particular, HTTP/2 allows a client and a server to 578 multiplex multiple HTTP requests and responses over a single TCP 579 connection. The requests and responses can be interleaved on a block 580 (frame) by block (frame) basis, by indicating the requests and 581 responses in HTTP/2 messages, avoiding the head-of-line blocking 582 problem encountered with HTTP/1.1. To achieve the same goal, this 583 design introduces substream-id to allow a client to receive updates 584 to multiple resources. HTTP/2 also provides a Server Push facility, 585 to allow a server to send asynchronous updates. 587 Despite the two features of HTTP/2, this design chooses an HTTP/1.x 588 based design for the simplicity of HTTP/1.x. An HTTP/2 based design 589 may more likely need to be implemented using a more complex HTTP/2 590 client library. In such a case, one approach for using Server Push 591 for updates is for the update stream server to send each data update 592 message as a separate Server Push item and let the client apply those 593 updates as they arrive. An HTTP/2 client library may not necessarily 594 inform a client application when the server pushes a resource. 595 Instead, the library might cache the pushed resource, and only 596 deliver it to the client when the client explicitly requests that 597 URI. Further, it is more likely that an HTTP/2 based design may 598 encounter issues with a proxy between the client and the server, in 599 that Server Push is optional and can be disabled by any proxy between 600 the client and the server. This is not a problem for the intended 601 use of Server Push: eventually the client will request those 602 resources, so disabling Server Push just adds a delay. But this 603 means that Server Push is not suitable for resources which the client 604 does not know to request. 606 Thus this design leaves an HTTP/2 based design as a future work and 607 focuses on ALTO updates on HTTP/1.1 and SSE. 609 3.4. Server Push: Server-Sent Event 611 SSE is a technique which can work with HTTP/1.1. The following is a 612 non-normative summary of SSE; see [SSE] for its normative definition. 614 Server-Sent Events enable a server to send new data to a client by 615 "server-push". The client establishes an HTTP ([RFC7230], [RFC7231]) 616 connection to the server and keeps the connection open. The server 617 continually sends messages. Each message has one or more lines, 618 where a line is terminated by a carriage-return immediately followed 619 by a new-line, a carriage-return not immediately followed by a new- 620 line, or a new-line not immediately preceded by a carriage-return. A 621 message is terminated by a blank line (two line terminators in a 622 row). 624 Each line in a message is of the form "field-name: string value". 625 Lines with a blank field-name (that is, lines which start with a 626 colon) are ignored, as are lines which do not have a colon. The 627 protocol defines three field names: event, id, and data. If a 628 message has more than one "data" line, the value of the data field is 629 the concatenation of the values on those lines. There can be only 630 one "event" and "id" line per message. The "data" field is required; 631 the others are optional. 633 Figure 1 is a sample SSE stream, starting with the client request. 634 The server sends three events and then closes the stream. 636 (Client request) 637 GET /stream HTTP/1.1 638 Host: example.com 639 Accept: text/event-stream 641 (Server response) 642 HTTP/1.1 200 OK 643 Connection: keep-alive 644 Content-Type: text/event-stream 646 event: start 647 id: 1 648 data: hello there 650 event: middle 651 id: 2 652 data: let's chat some more ... 653 data: and more and more and ... 655 event: end 656 id: 3 657 data: goodbye 659 Figure 1: A Sample SSE stream. 661 4. Overview of Approach and High-level Protocol Message Flow 663 With the preceding background, this section now gives a non-normative 664 overview of the update mechanisms and message flow to be defined in 665 later sections of this document. Figure 2 gives the main components 666 and overall message flow. 668 ------------------------------------------------------------------ 669 | | 670 | +-------+ +-------+ 1. init request +------+ | 671 | | | | | <------------- | | | 672 | | | | | -------------> | | | 673 | 3.add/ | | | | 1'. control uri | | | 674 | remove | | | | | | | 675 | resource |Stream | |Update | | | | 676 -------->|Control| private |Stream | 2a. data update |Client| -- 677 |Server |<------->|Server | messages | | 678 -------- | | | | --------------> | | <- 679 | response | | | | --------------> | | | 680 | | | | | 2b.control update| | | 681 | +-------+ +-------+ messages +------+ | 682 | | 683 ------------------------------------------------------------------ 685 Figure 2: ALTO SSE Architecture and Message Flow. 687 4.1. Update Stream Service Message Flow 689 The building block of the update mechanism defined in this document 690 is the update stream service (defined in Section 6), where each 691 update stream service is a POST-mode service that provides update 692 streams. 694 ** Initial request: client -> update server **: 696 When an ALTO client requests an update stream service, the ALTO 697 client establishes a persistent connection to the update stream 698 server and submits an initial update-stream request (defined in 699 Section 6.5), creating an update stream. This initial request 700 creating the update stream is labeled "1. init request" in Figure 2. 702 An update stream can provide updates to both GET-mode resources, such 703 as ALTO network and cost maps, and POST-mode resources, such as ALTO 704 endpoint property service. Also, to avoid creating too many update 705 streams, this design allows an ALTO client to use one update stream 706 to receive updates to multiple requests. In particular, the client 707 may request to receive updates for the same resource but with 708 different parameters for a POST-mode resource. The updates for each 709 request is called a substream, and hence, the update server needs an 710 identifier to indicate the substream when sending an update. To 711 achieve this goal, the client assigns a unique substream-id when 712 requesting updates to a resource in an update stream, and the server 713 puts the substream-id in each update. 715 ** Data updates: update server -> client **: 717 The objective of an update stream is to continuously update the ALTO 718 client on data value changes given by the client's requests. This 719 document refers to messages sending such data-value changes as data 720 update messages (defined in Section 5.2). Although an update stream 721 may update one or more requests, each data update message updates 722 only one request and is sent as a Server-Sent Event (SSE), as defined 723 by [SSE]. A data update message is encoded either as a full 724 replacement or as an incremental change. A full replacement uses the 725 JSON message format defined by the ALTO protocol. There can be 726 multiple encodings for incremental changes. The current design 727 supports incremental changes using JSON merge patch ([RFC7396]) or 728 JSON patch ([RFC6902]) to describe the changes of the resource. 729 Future documents may define additional mechanisms for incremental 730 changes. The update stream server decides when to send data update 731 messages, and whether to send full replacements or incremental 732 changes. These decisions can vary from resource to resource and from 733 update to update. Figure 2 shows examples of data update messages 734 (labeled "2a. data update messages")in the overall message flow. 736 ** Control updates: update server -> client **: 738 An update stream can run for a long time, and hence there can be 739 status changes at the update stream server side during the lifetime 740 of an update stream; for example, the update stream server may 741 encounter an error or need to shut down for maintenance. To support 742 robust, flexible protocol design, this document allows the update 743 stream server to send control update messages (defined in 744 Section 5.3) in addition to data update messages to the ALTO client. 745 Figure 2 shows that both data updates and control updates can be sent 746 by the server to the client (labeled "2b. control update messages"). 748 4.2. Stream Control Service Message Flow 750 ** Stream control: client -> stream control server **: 752 In addition to control changes triggered from the update stream 753 server side, in a flexible design, an ALTO client may initiate 754 control changes as well, in particular, by adding or removing ALTO 755 resources receiving updates. An ALTO client initiates such changes 756 using the stream control service (defined in Section 7). Although 757 one may use a design that the client uses the same HTTP connection to 758 send the control requests, it requires stronger server support such 759 as HTTP pipeline. For more flexibility, this document introduces 760 stream control service. In particular, the update stream server of 761 an update stream uses the first message to provide the URI of the 762 stream control service (labeled "1': control uri" in Figure 2). 764 The ALTO client can then use the URI to ask the update stream server 765 to (1) send data update messages for additional resources, (2) stop 766 sending data update messages for previously requested resources, or 767 (3) gracefully stop and close the update stream altogether. 769 4.3. Service Announcement and Management Message Flow 771 ** Service announcements: IRD server -> client **: 773 An update server may provide any number of update stream services, 774 where each update stream may provide updates for a given subset of 775 the ALTO server's resources. An ALTO server's Information Resource 776 Directory (IRD) defines the update stream services and declares the 777 set of resources for which each update stream service provides 778 updates. The ALTO server selects the resource set for each update 779 stream service. It is recommended that if a resource depends on one 780 or more other resource(s) (indicated with the "uses" attribute 781 defined in [RFC7285]), these other resource(s) should also be part of 782 that update stream. Thus the update stream for a cost map should 783 also provide updates for the network map on which that cost map 784 depends. 786 ** Service management (server) **: 788 An ALTO client may request any number of update streams 789 simultaneously. Because each update stream consumes resources on the 790 update stream server, an update stream server may require client 791 authorization and/or authentication, limit the number of open update 792 streams, close inactive streams, or redirect an ALTO client to 793 another update stream server. 795 5. Update Messages: Data Update and Control Update Messages 797 This section defines the format of update messages sent from the 798 server to the client. It first defines the generic structure of 799 update messages (Section 5.1). It then defines the details of the 800 data update messages (Section 5.2) and the control update messages 801 (Section 5.3). These messages will be used in the next two sections 802 to define the Update Stream Service (Section 6) and the Stream 803 Control Service (Section 7). 805 5.1. Generic ALTO Update Message Structure 807 Both data update and control update messages from the server to the 808 client have the same basic structure: each message includes a data 809 field to provide data information, which is typically a JSON object; 810 and an event field preceding the data field, to specify the media 811 type indicating the encoding of the data field. 813 A data update message needs additional information to identify the 814 ALTO data (object) to which the update message applies. To be 815 generic, this document use a data-id to identify the ALTO data 816 (object) to be updated; see below. 818 Hence, the event field of ALTO update message can include two sub- 819 fields (media-type and data-id), where the two sub-fields are 820 separated by a comma (',', U+002C): 822 media-type [ ',' data-id ] 824 According to Section 4.2 of [RFC6838], the comma character is not 825 allowed in a media-type name. So there is no ambiguous decoding of 826 the two sub-fields. 828 Note that an update message does not use the SSE "id" field. 830 5.2. ALTO Data Update Message 832 A data update message is sent when a monitored resource changes. As 833 discussed in the preceding section, the event field of a data update 834 message includes two sub-fields: 'media-type' and 'data-id'. 836 The 'media-type' sub-field depends on whether the data update is a 837 complete specification of the identified data, or an incremental 838 patch (e.g., a JSON merge patch or JSON patch), if possible, 839 describing the changes from the last version of the data. This 840 document refers to these as full replacement and incremental change, 841 respectively. The encoding of a full replacement is defined by its 842 defining document (e.g., network and cost map messages by [RFC7285]), 843 and uses the media type defined in that document. The encoding of 844 JSON merge patch is defined by [RFC7396], with the media type 845 "application/merge-patch+json"; the encoding of JSON patch is defined 846 by [RFC6902], with media type "application/json-patch+json". 848 The `data-id` sub-field identifies the ALTO data to which the data 849 update message applies. 851 First consider the case that the resource containing only a single 852 JSON object. For example, since an ALTO client can request data 853 updates for both a cost map resource (object) and its dependent 854 network map resource (object) in the same update stream, to 855 distinguish the updates, the client assigns a substream-id for each 856 resource receiving data updates. Substream-ids MUST be unique within 857 an update stream, but need not be globally unique. A substream-id is 858 encoded as a JSON string with the same format as that of the type 859 ResourceID (Section 10.2 of [RFC7285]). The type SubstreamID is used 860 in this document to indicate a string of this format. The substream- 861 id of a single JSON object is the 'data-id'. 863 As an example, assume that the ALTO client assigns substream-id "1" 864 in its request to receive updates to the network map; and substream- 865 id "2" to the cost map. Then the substream-ids are the data-ids 866 indicating which objects will be updated. Figure 3 shows some 867 examples of ALTO data update messages: 869 event: application/alto-networkmap+json,1 870 data: { ... full network map message ... } 872 event: application/alto-costmap+json,2 873 data: { ... full cost map message ... } 875 event: application/merge-patch+json,2 876 data: { ... JSON merge patch update for the cost map ... } 878 Figure 3: Examples of ALTO data update messages. 880 Next consider the case that a resource may include multiple JSON 881 objects. This document considers the case that a resource may 882 contain multiple components (parts) and they are encoded using the 883 media type "multipart/related" [RFC2387]. Each part of this 884 multipart response MUST be an HTTP message including a Content-ID 885 header and a JSON object body. Each component requiring the update 886 stream service (defined in Section 6) MUST be identified by a unique 887 Content-ID to be defined in its defining document. 889 For a resource using the media type "multipart/related", the `data- 890 id` sub-field MUST be the concatenation of the substream-id, the '.' 891 separator (U+002E) and the unique Content-ID in order. 893 5.3. ALTO Control Update Message 895 Control update messages have the media type "application/alto- 896 updatestreamcontrol+json", and the data is of type 897 UpdateStreamControlEvent: 899 object { 900 [String control-uri;] 901 [SubstreamID started<1..*>;] 902 [SubstreamID stopped<1..*>;] 903 [String description;] 904 } UpdateStreamControlEvent; 906 control-uri: the URI providing stream control for this update stream 907 (see Section 7). The server MUST send a control update message 908 with an URI as the first event in an update stream. If the URI 909 is NULL, the update stream server does not support stream 910 control for this update stream; otherwise, the update stream 911 server provides stream control through the given URI. 913 started: a list of substream-ids of resources. It notifies the ALTO 914 client that the update stream server will start sending data 915 update messages for each resource listed. 917 stopped: a list of substream-ids of resources. It notifies the ALTO 918 client that the update stream server will no longer send data 919 update messages for the listed resources. There can be multiple 920 reasons for an update stream server to stop sending data update 921 messages for a resource, including a request from the ALTO 922 client using stream control (Section 6.7.1) or an internal 923 server event. 925 description: a non-normative text providing an explanation for the 926 control event. When an update stream server stops sending data 927 update messages for a resource, it is RECOMMENDED that the 928 update stream server use the description field to provide 929 details. 931 6. Update Stream Service 933 An update stream service returns a stream of update messages, as 934 defined in Section 5. An ALTO server's IRD (Information Resource 935 Directory) MAY define one or more update stream services, which ALTO 936 clients use to request new update stream instances. An IRD entry 937 defining an update stream service MUST define the media type, HTTP 938 method, and capabilities & uses as follows. 940 6.1. Media Type 942 The media type of an ALTO update stream service is "text/event- 943 stream", as defined by [SSE]. 945 6.2. HTTP Method 947 An ALTO update stream service is requested using the HTTP POST 948 method. 950 6.3. Capabilities 952 The capabilities are defined as an object of type 953 UpdateStreamCapabilities: 955 object { 956 IncrementalUpdateMediaTypes incremental-change-media-types; 957 Boolean support-stream-control; 958 } UpdateStreamCapabilities; 960 object-map { 961 ResourceID -> String; 962 } IncrementalUpdateMediaTypes; 964 If this update stream can provide data update messages with 965 incremental changes for a resource, the "incremental-change-media- 966 types" field has an entry for that resource-id, and the value is the 967 media-type of the incremental change. Normally this will be 968 "application/merge-patch+json", "application/json-patch+json", or 969 "application/merge-patch+json,application/json-patch+json", because, 970 as described in Section 5, they are the only incremental change types 971 defined by this document. However future extensions may define other 972 types of incremental changes. 974 When choosing the media-type to encode incremental changes for a 975 resource, the update stream server SHOULD consider the limitations of 976 the encoding. For example, when a JSON merge patch specifies that 977 the value of a field is null, its semantics is that the field is 978 removed from the target, and hence the field is no longer defined 979 (i.e., undefined); see the MergePatch algorithm in Section 3.1.1 on 980 how null value is processed. This, however, may not be the intended 981 result for the resource, when null and undefined have different 982 semantics for the resource. In such a case, the update stream server 983 SHOULD choose JSON patch over JSON merge patch. 985 The "support-stream-control" field specifies whether the given update 986 stream supports stream control. If "support-stream-control" field is 987 "true", the update stream server will uses the stream control 988 specified in this document; else, the update stream server may use 989 other mechanisms to provide the same functionality as stream control. 991 6.4. Uses 993 The "uses" attribute MUST be an array with the resource-ids of every 994 resource for which this update stream can provide updates. Each 995 resource specified in the "uses" MUST support full replacement: the 996 update stream server can always send full replacement, and the ALTO 997 client MUST accept full replacement. 999 This set may be any subset of the ALTO server's resources, and may 1000 include resources defined in linked IRDs. However, it is RECOMMENDED 1001 that the ALTO server selects a set that is closed under the resource 1002 dependency relationship. That is, if an update stream's "uses" set 1003 includes resource R1, and resource R1 depends on ("uses") resource 1004 R0, then the update stream's "uses" set SHOULD include R0 as well as 1005 R1. For example, an update stream for a cost map SHOULD also provide 1006 updates for the network map upon which that cost map depends. 1008 6.5. Request: Accept Input Parameters 1010 An ALTO client specifies the parameters for the new update stream by 1011 sending an HTTP POST body with the media type "application/alto- 1012 updatestreamparams+json". That body contains a JSON Object of type 1013 UpdateStreamReq, where: 1015 object { 1016 [AddUpdatesReq add;] 1017 [SubstreamID remove<0..*>;] 1018 } UpdateStreamReq; 1020 object-map { 1021 SubstreamID -> AddUpdateReq; 1022 } AddUpdatesReq; 1024 object { 1025 ResourceID resource-id; 1026 [JSONString tag;] 1027 [Boolean incremental-changes;] 1028 [Object input;] 1029 } AddUpdateReq; 1031 add: specifies the resources (and the parameters for the resources) 1032 for which the ALTO client wants updates. We say that the add- 1033 request creates a substream. The ALTO client MUST assign a 1034 unique substream-id (Section 5.2) for each entry, and uses those 1035 substream-ids as the keys in the "add" field. 1037 resource-id: the resource-id of an ALTO resource, and MUST be in the 1038 update stream's "uses" list (Section 6.4). If the resource-id 1039 is a GET-mode resource with a version tag (or "vtag"), as 1040 defined in Section 6.3 and Section 10.3 of [RFC7285], and the 1041 ALTO client has previously retrieved a version of that resource 1042 from the update stream server, the ALTO client MAY set the "tag" 1043 field to the tag part of the client's version of that resource. 1044 If that version is not current, the update stream server MUST 1045 send a full replacement before sending any incremental changes, 1046 as described in Section 6.7.1. If that version is still 1047 current, the update stream server MAY omit the initial full 1048 replacement. 1050 incremental-changes: the ALTO client specifies whether it is willing 1051 to receive incremental changes from the update stream server for 1052 this substream. If the "incremental-changes" field is "true", 1053 the update stream server MAY send incremental changes for this 1054 substream (assuming the update stream server supports 1055 incremental changes for that resource). In this case, the 1056 client MUST support all incremental methods from the set 1057 announced in the server's capabilities for this resource; see 1058 Section Section 6.3 for server's announcement of potential 1059 incremental methods. If a client does not support all 1060 incremental methods from the set announced in the server's 1061 capabilities, the client can set "incremental-changes" to 1062 "false", and the update stream server then MUST NOT send 1063 incremental changes for that substream. The default value for 1064 "incremental-changes" is "true", so to suppress incremental 1065 changes, the ALTO client MUST explicitly set "incremental- 1066 changes" to "false". An alternative design of incremental- 1067 changes control is a more fine-grained control, by allowing a 1068 client to select a subset of incremental methods from the set 1069 announced in the server's capabilities. But this adds 1070 complexity to the server, which is more likely to be the 1071 bottleneck. Note that the ALTO client cannot suppress full 1072 replacement. When the ALTO client sets "incremental-changes" to 1073 "false", the update stream server MUST send a full replacement 1074 instead of an incremental change to the ALTO client. The update 1075 stream server MAY wait until more changes are available, and 1076 send a single full replacement with those changes. Thus an ALTO 1077 client which declines to accept incremental changes may not get 1078 updates as quickly as an ALTO client which does. 1080 input: If the resource is a POST-mode service which requires input, 1081 the ALTO client MUST set the "input" field to a JSON Object with 1082 the parameters that the resource expects. 1084 remove: it is used in update stream control requests (Section 7), 1085 and is not allowed in the update stream request. The update 1086 stream server SHOULD ignore this field if it is included in the 1087 request. 1089 If a request has any errors, the update stream server MUST NOT create 1090 an update stream. Also, the update stream server will send an error 1091 response to the ALTO client as specified in Section 6.6. 1093 6.6. Response 1095 If the update stream request has any errors, the update stream server 1096 MUST return an HTTP "400 Bad Request" to the ALTO client. The body 1097 part of the HTTP response is the JSON object defined in Section 8.5.2 1098 in [RFC7285]. Hence, an ALTO error response has the format: 1100 HTTP/1.1 400 Bad Request 1101 Content-Length: 131 1102 Content-Type: application/alto-error+json 1103 Connection: Closed 1105 { 1106 "meta":{ 1107 "code": "E_INVALID_FIELD_VALUE", 1108 "field": "add/my-network-map/resource-id", 1109 "value": "my-networkmap/#" 1110 } 1111 } 1113 Note that "field" and "value" are optional fields. If the "value" 1114 field exists, the "field" field MUST exist. 1116 o If an update stream request does not have an "add" field 1117 specifying one or more resources, the error code of the error 1118 message MUST be E_MISSING_FIELD and the "field" field SHOULD be 1119 "add". The update stream server MUST close the stream without 1120 sending any events. 1122 o If the "resource-id" field is invalid, or is not associated with 1123 the update stream, the error code of the error message MUST be 1124 E_INVALID_FIELD_VALUE; the "field" field SHOULD be the full path 1125 of the "resource-id" field and the "value" field SHOULD be the 1126 invalid resource-id. If there are more than one invalid resource- 1127 ids, the update stream server SHOULD pick one and return it. The 1128 update stream server MUST close the stream without sending any 1129 events. 1131 o If the resource is a POST-mode service which requires input, the 1132 client MUST set the "input" field to a JSON Object with the 1133 parameters that that resource expects. If the "input" field is 1134 missing or invalid, the update stream server MUST return the same 1135 error response that that resource would return for missing or 1136 invalid input (see [RFC7285]). In this case, the update stream 1137 server MUST close the update stream without sending any events. 1138 If the input for several POST-mode resources are missing or 1139 invalid, the update stream server MUST pick one and return it. 1141 The response to a valid request is a stream of update messages. 1142 Section 5 defines the update messages, and [SSE] defines how they are 1143 encoded into a stream. 1145 An update stream server SHOULD send updates only when the underlying 1146 values change. However, it may be difficult for an update stream 1147 server to guarantee that in all circumstances. Therefore a client 1148 MUST NOT assume that an update message represents an actual change. 1150 6.7. Additional Requirements on Update Stream Service 1152 6.7.1. Event Sequence Requirements 1154 o The first event MUST be a control update message with the URI of 1155 the update stream control service Section 7 for this update 1156 stream. 1158 o As soon as possible after the ALTO client initiates the 1159 connection, the update stream server MUST send a full replacement 1160 for each resource-id requested with a version tag. In this case 1161 the update stream server MAY omit the initial full replacement for 1162 that resource, if the "tag" field the ALTO client provided for 1163 that resource-id matches the tag of the update stream's current 1164 version. 1166 o If this update stream provides update for resource-ids and R0 and 1167 R1, and if R1 depends on R0, then the update stream server MUST 1168 send the update for R0 before sending the related updates for R1. 1169 For example, suppose an update stream provides updates to a 1170 network map and its dependent cost maps. When the network map 1171 changes, the update stream server MUST send the network map update 1172 before sending the cost map updates. 1174 o When the ALTO client uses the stream control service to stop 1175 updates for one or more resources (Section 7), the ALTO client 1176 MUST send a stream control request. The update stream server MUST 1177 send a control update message whose "stopped" field has the 1178 substream-ids of all active resources. 1180 6.7.2. Cross-Stream Consistency Requirements 1182 If several ALTO clients create multiple update streams for updates to 1183 the same resource, the update stream server MUST send the same 1184 updates to all of them. However, the update stream server MAY pack 1185 data items into different patch events, as long as the net result of 1186 applying those updates is the same. 1188 For example, suppose two different ALTO clients create update streams 1189 for the same cost map, and suppose the update stream server processes 1190 three separate cost point updates with a brief pause between each 1191 update. The server MUST send all three new cost points to both 1192 clients. But the update stream server MAY send a single patch event 1193 (with all three cost points) to one ALTO client, while sending three 1194 separate patch events (with one cost point per event) to the other 1195 ALTO client. 1197 A update stream server MAY offer several different update stream 1198 resources that provide updates to the same underlying resource (that 1199 is, a resource-id may appear in the "uses" field of more than one 1200 update stream resource). In this case, those update stream resources 1201 MUST return the same update data. 1203 6.7.3. Multipart Update Requirements 1205 This design allows any valid media type for full replacement. Hence, 1206 it supports ALTO resources using multipart to contain multiple JSON 1207 objects. This realizes the push benefit, but not the incremental 1208 encoding benefit of SSE. 1210 JSON Patch and Merge Patch provide the incremental encoding benefit 1211 but can be applied to only a single JSON object. If an update stream 1212 service (1) supports a resource providing a multipart media type and 1213 (2) specifies an incremental media type for the resource in its 1214 capabilities, the server MUST (1) use substream-id.content-id in its 1215 `event` field, (2) include the content-id in the multipart message, 1216 and (3) the content identified by the content-id must be a single 1217 JSON object. 1219 6.8. Keep-Alive Messages 1221 In an SSE stream, any line which starts with a colon (U+003A) 1222 character is a comment, and an ALTO client MUST ignore that line 1223 ([SSE]). As recommended in [SSE], an update stream server SHOULD 1224 send a comment line (or an event) every 15 seconds to prevent ALTO 1225 clients and proxy servers from dropping the HTTP connection. 1227 7. Stream Control Service 1229 An stream control service allows an ALTO client to remove resources 1230 from the set of resources that are monitored by an update stream, or 1231 add additional resources to that set. The service also allows an 1232 ALTO client to gracefully shut down an update stream. 1234 When an update stream server creates a new update stream, and if the 1235 update stream server supports stream control for the update stream, 1236 the update stream server creates a stream control service for that 1237 update stream. An ALTO client uses the stream control service to 1238 remove resources from the update stream instance, or to request 1239 updates for additional resources. An ALTO client cannot obtain the 1240 stream control service through the IRD. Instead, the first event 1241 that the update stream server sends to the ALTO client has the URI 1242 for the associated stream control service (see Section 5.3). 1244 Each stream control request is an individual HTTP request. The ALTO 1245 client MAY send multiple stream control requests to the stream 1246 control server using the same HTTP connection. 1248 7.1. URI 1250 The URI for an stream control service, by itself, MUST uniquely 1251 specify the update stream instance which it controls. The stream 1252 control server MUST NOT use other properties of an HTTP request, such 1253 as cookies or the client's IP address, to determine the update 1254 stream. Furthermore, an update stream server MUST NOT reuse a 1255 control service URI once the associated update stream has been 1256 closed. 1258 The ALTO client MUST evaluate a non-absolute control URI (for 1259 example, a URI without a host, or with a relative path) in the 1260 context of the URI used to create the update stream. The stream 1261 control service's host MAY be different from the update stream's 1262 host. 1264 It is expected that the update stream server will assign a unique 1265 stream id to each update stream instance and will embed that id in 1266 the associated stream control URI. However, the exact mechanism is 1267 left to the update stream server. ALTO clients MUST NOT attempt to 1268 deduce a stream id from the control URI. 1270 To prevent an attacker from forging a stream control URI and sending 1271 bogus requests to disrupt other update streams, stream control URIs 1272 SHOULD contain sufficient random redundancy to make it difficult to 1273 guess valid URIs. 1275 7.2. Media Type 1277 An ALTO stream control response does not have a specific media type. 1279 7.3. HTTP Method 1281 An ALTO update stream control resource is requested using the HTTP 1282 POST method. 1284 7.4. IRD Capabilities & Uses 1286 None (Stream control services do not appear in the IRD). 1288 7.5. Request: Accept Input Parameters 1290 An stream control service accepts the same input media type and input 1291 parameters as the update stream service (Section 6.5). The only 1292 difference is that a stream control service also accepts the "remove" 1293 field. 1295 If specified, the "remove" field is an array of substream-ids the 1296 ALTO client previously added to this update stream. An empty 1297 "remove" array is equivalent to a list of all currently active 1298 resources; the update stream server responds by removing all 1299 resources and closing the stream. 1301 An ALTO client MAY use the "add" field to add additional resources. 1302 However, the ALTO client MUST assign a unique substream-id to each 1303 resource. Substream-ids MUST be unique over the lifetime of this 1304 update stream: an ALTO client MUST NOT reuse a previously removed 1305 substream-id. 1307 If a request has any errors, the update stream server MUST NOT add or 1308 remove any resources from the associated update stream. Also, the 1309 stream control server will return an error response to the client as 1310 specified in Section 7.6. 1312 7.6. Response 1314 The stream control server MUST process the "add" field before the 1315 "remove" field. If the request removes all active resources without 1316 adding any additional resources, the update stream server MUST close 1317 the update stream. Thus an update stream cannot have zero resources. 1319 If the request has any errors, the stream control server MUST return 1320 an HTTP "400 Bad Request" to the ALTO client. The body part of the 1321 HTTP response is the JSON object defined in Section 8.5.2 in 1322 [RFC7285]. An error response has the same format as specified in 1323 Section 6.6. Detailed error code and error information are specified 1324 as below. 1326 o If the "add" request does not satisfy the requirements in 1327 Section 6.5, the stream control server MUST return the ALTO error 1328 message defined in Section 6.6. 1330 o If any substream-id in the "remove" field was not added in a prior 1331 request, the error code of the error message MUST be 1332 E_INVALID_FIELD_VALUE; the "field" field SHOULD be "remove" and 1333 the "value" field SHOULD be the array of the invalid substream- 1334 ids. Thus it is illegal to "add" and "remove" the same substream- 1335 id in the same request. However, it is legal to remove a 1336 substream-id twice. 1338 o If any substream-id in the "add" field has been used before in 1339 this stream, the error code of the error message MUST be 1340 E_INVALID_FIELD_VALUE, the "field" field SHOULD be "add" and the 1341 "value" field SHOULD be the array of invalid substream-ids. 1343 o If the request has a non-empty "add" field and a "remove" field 1344 with an empty list of substream-ids (to replace all active 1345 resources with a new set, the client MUST explicitly enumerate the 1346 substream-ids to be removed), the error code of the error message 1347 MUST be E_INVALID_FIELD_VALUE; the "field" field SHOULD be 1348 "remove" and the "value" field SHOULD be an empty array. 1350 If the request is valid but the associated update stream has been 1351 closed. The stream control server MUST return an HTTP "404 Not 1352 Found". 1354 If the request is valid and the stream control server successfully 1355 processes the request without error, the stream control server should 1356 return either an HTTP "202 Accepted" response or an HTTP "204 No 1357 Content" response. The difference is that for the latter case, the 1358 stream control server is sure that the update stream server has also 1359 processed the request. Regardless of 202 or 204 HTTP response, the 1360 final updates of related resources will be notified by the update 1361 stream server using its control update message(s), due to our modular 1362 design. 1364 8. Examples 1366 8.1. Example: IRD Announcing Update Stream Services 1368 Below is an example IRD announcing three update stream services. The 1369 first, which is named "update-my-costs", provides updates for the 1370 network map, the "routingcost" and "hopcount" cost maps, and a 1371 filtered cost map resource. The second, which is named "update-my- 1372 prop", provides updates to the endpoint properties service. The 1373 third, which is named "update-my-pv", provides updates to a non- 1374 standard ALTO service returning a multipart response. 1376 Note that in the "update-my-costs" update stream shown in the example 1377 IRD, the update stream server uses JSON patch for network map, and it 1378 uses JSON merge patch to update the other resources. Also, the 1379 update stream will only provide full replacements for "my-simple- 1380 filtered-cost-map". 1382 Also, note that this IRD defines two filtered cost map resources. 1383 They use the same cost types, but "my-filtered-cost-map" accepts cost 1384 constraint tests, while "my-simple-filtered-cost-map" does not. To 1385 avoid the issues discussed in Section 9.3, the update stream provides 1386 updates for the second, but not the first. 1388 This IRD also announces a non-standard ALTO service, which is named 1389 "my-pv". This service accepts an extended endpoint cost request as 1390 an input and returns a multipart response including an endpoint cost 1391 resource and a property map resource. This document does not rely on 1392 any other design details of this new service. In this document, the 1393 "my-pv" service is only used to illustrate how the update stream 1394 service provides updates to an ALTO resource returning a multipart 1395 response. 1397 "my-network-map": { 1398 "uri": "http://alto.example.com/networkmap", 1399 "media-type": "application/alto-networkmap+json", 1400 }, 1401 "my-routingcost-map": { 1402 "uri": "http://alto.example.com/costmap/routingcost", 1403 "media-type": "application/alto-costmap+json", 1404 "uses": ["my-networkmap"], 1405 "capabilities": { 1406 "cost-type-names": ["num-routingcost"] 1407 } 1408 }, 1409 "my-hopcount-map": { 1410 "uri": "http://alto.example.com/costmap/hopcount", 1411 "media-type": "application/alto-costmap+json", 1412 "uses": ["my-networkmap"], 1413 "capabilities": { 1414 "cost-type-names": ["num-hopcount"] 1415 } 1416 }, 1417 "my-filtered-cost-map": { 1418 "uri": "http://alto.example.com/costmap/filtered/constraints", 1419 "media-type": "application/alto-costmap+json", 1420 "accepts": "application/alto-costmapfilter+json", 1421 "uses": ["my-networkmap"], 1422 "capabilities": { 1423 "cost-type-names": ["num-routingcost", "num-hopcount"], 1424 "cost-constraints": true 1425 } 1426 }, 1427 "my-simple-filtered-cost-map": { 1428 "uri": "http://alto.example.com/costmap/filtered/simple", 1429 "media-type": "application/alto-costmap+json", 1430 "accepts": "application/alto-costmapfilter+json", 1431 "uses": ["my-networkmap"], 1432 "capabilities": { 1433 "cost-type-names": ["num-routingcost", "num-hopcount"], 1434 "cost-constraints": false 1435 } 1436 }, 1437 "my-props": { 1438 "uri": "http://alto.example.com/properties", 1439 "media-type": "application/alto-endpointprops+json", 1440 "accepts": "application/alto-endpointpropparams+json", 1441 "capabilities": { 1442 "prop-types": ["priv:ietf-bandwidth"] 1443 } 1444 }, 1445 "my-pv": { 1446 "uri": "http://alto.example.com/endpointcost/pv", 1447 "media-type": "multipart/related; 1448 type=application/alto-endpointcost+json", 1449 "accepts": "application/alto-endpointcostparams+json", 1450 "capabilities": { 1451 "cost-type-names": [ "path-vector" ], 1452 "ane-properties": [ "maxresbw", "persistent-entities" ] 1453 } 1454 }, 1455 "update-my-costs": { 1456 "uri": "http://alto.example.com/updates/costs", 1457 "media-type": "text/event-stream", 1458 "accepts": "application/alto-updatestreamparams+json", 1459 "uses": [ 1460 "my-network-map", 1461 "my-routingcost-map", 1462 "my-hopcount-map", 1463 "my-simple-filtered-cost-map" 1464 ], 1465 "capabilities": { 1466 "incremental-change-media-types": { 1467 "my-network-map": "application/json-patch+json", 1468 "my-routingcost-map": "application/merge-patch+json", 1469 "my-hopcount-map": "application/merge-patch+json" 1470 }, 1471 "support-stream-control": true 1472 } 1473 }, 1474 "update-my-props": { 1475 "uri": "http://alto.example.com/updates/properties", 1476 "media-type": "text/event-stream", 1477 "uses": [ "my-props" ], 1478 "accepts": "application/alto-updatestreamparams+json", 1479 "capabilities": { 1480 "incremental-change-media-types": { 1481 "my-props": "application/merge-patch+json" 1482 }, 1483 "support-stream-control": true 1484 } 1485 }, 1486 "update-my-pv": { 1487 "uri": "http://alto.example.com/updates/pv", 1488 "media-type": "text/event-stream", 1489 "uses": [ "my-pv" ], 1490 "accepts": "application/alto-updatestreamparams+json", 1491 "capabilities": { 1492 "incremental-change-media-types": { 1493 "my-pv": "application/merge-patch+json" 1494 }, 1495 "support-stream-control": true 1496 } 1497 } 1499 8.2. Example: Simple Network and Cost Map Updates 1501 Given the update streams announced in the preceding example IRD, the 1502 section below shows an example of an ALTO client's request and the 1503 update stream server's immediate response, using the update stream 1504 resource "update-my-costs". In the example, the ALTO client requests 1505 updates for the network map and "routingcost" cost map, but not for 1506 the "hopcount" cost map. The ALTO client uses the ALTO server's 1507 resource-ids as the substream-ids. Because the client does not 1508 provide a "tag" for the network map, the update stream server must 1509 send a full replacement for the network map as well as for the cost 1510 map. The ALTO client does not set "incremental-changes" to "false", 1511 so it defaults to "true". Thus, the update stream server will send 1512 patch updates for the cost map and the network map. 1514 POST /updates/costs HTTP/1.1 1515 Host: alto.example.com 1516 Accept: text/event-stream,application/alto-error+json 1517 Content-Type: application/alto-updatestreamparams+json 1518 Content-Length: 155 1520 { "add": { 1521 "my-network-map": { 1522 "resource-id": "my-network-map" 1523 }, 1524 "my-routingcost-map": { 1525 "resource-id": "my-routingcost-map" 1526 } 1527 } 1528 } 1530 HTTP/1.1 200 OK 1531 Connection: keep-alive 1532 Content-Type: text/event-stream 1534 event: application/alto-updatestreamcontrol+json 1535 data: {"control-uri": 1536 data: "http://alto.example.com/updates/streams/3141592653589"} 1538 event: application/alto-networkmap+json,my-network-map 1539 data: { 1540 data: "meta" : { 1541 data: "vtag": { 1542 data: "resource-id" : "my-network-map", 1543 data: "tag" : "da65eca2eb7a10ce8b059740b0b2e3f8eb1d4785" 1544 data: } 1545 data: }, 1546 data: "network-map" : { 1547 data: "PID1" : { 1548 data: "ipv4" : [ "192.0.2.0/24", "198.51.100.0/25" ] 1549 data: }, 1550 data: "PID2" : { 1551 data: "ipv4" : [ "198.51.100.128/25" ] 1552 data: }, 1553 data: "PID3" : { 1554 data: "ipv4" : [ "0.0.0.0/0" ], 1555 data: "ipv6" : [ "::/0" ] 1556 data: } 1557 data: } 1558 data: } 1559 data: } 1561 event: application/alto-costmap+json,my-routingcost-map 1562 data: { 1563 data: "meta" : { 1564 data: "dependent-vtags" : [{ 1565 data: "resource-id": "my-network-map", 1566 data: "tag": "da65eca2eb7a10ce8b059740b0b2e3f8eb1d4785" 1567 data: }], 1568 data: "cost-type" : { 1569 data: "cost-mode" : "numerical", 1570 data: "cost-metric": "routingcost" 1571 data: }, 1572 data: "vtag": { 1573 data: "resource-id" : "my-routingcost-map", 1574 data: "tag" : "3ee2cb7e8d63d9fab71b9b34cbf764436315542e" 1575 data: } 1576 data: }, 1577 data: "cost-map" : { 1578 data: "PID1": { "PID1": 1, "PID2": 5, "PID3": 10 }, 1579 data: "PID2": { "PID1": 5, "PID2": 1, "PID3": 15 }, 1580 data: "PID3": { "PID1": 20, "PID2": 15 } 1581 data: } 1582 data: } 1584 After sending those events immediately, the update stream server will 1585 send additional events as the maps change. For example, the 1586 following represents a small change to the cost map. PID1->PID2 is 1587 changed to 9 from 5, PID3->PID1 is no longer available and PID3->PID3 1588 is now defined as 1: 1590 event: application/merge-patch+json,my-routingcost-map 1591 data: { 1592 data: "meta" : { 1593 data: "vtag": { 1594 data: "tag": "c0ce023b8678a7b9ec00324673b98e54656d1f6d" 1595 data: } 1596 data: }, 1597 data: "cost-map": { 1598 data: "PID1" : { "PID2" : 9 }, 1599 data: "PID3" : { "PID1" : null, "PID3" : 1 } 1600 data: } 1601 data: } 1603 As another example, the following represents a change to the network 1604 map: an ipv4 prefix "193.51.100.0/25" is added to PID1. It triggers 1605 changes to the cost map. The update stream server chooses to send an 1606 incremental change for the network map and send a full replacement 1607 instead of an incremental change for the cost map: 1609 event: application/json-patch+json,my-network-map 1610 data: { 1611 data: { 1612 data: "op": "replace", 1613 data: "path": "/meta/vtag/tag", 1614 data: "value" :"a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 1615 data: }, 1616 data: { 1617 data: "op": "add", 1618 data: "path": "/network-map/PID1/ipv4/2", 1619 data: "value": "193.51.100.0/25" 1620 data: } 1621 data: } 1623 event: application/alto-costmap+json,my-routingcost-map 1624 data: { 1625 data: "meta" : { 1626 data: "vtag": { 1627 data: "tag": "c0ce023b8678a7b9ec00324673b98e54656d1f6d" 1628 data: } 1629 data: }, 1630 data: "cost-map" : { 1631 data: "PID1": { "PID1": 1, "PID2": 3, "PID3": 7 }, 1632 data: "PID2": { "PID1": 12, "PID2": 1, "PID3": 9 }, 1633 data: "PID3": { "PID1": 14, "PID2": 8 } 1634 data: } 1635 data: } 1637 8.3. Example: Advanced Network and Cost Map Updates 1639 This example is similar to the previous one, except that the ALTO 1640 client requests updates for the "hopcount" cost map as well as the 1641 "routingcost" cost map and provides the current version tag of the 1642 network map, so the update stream server is not required to send the 1643 full network map data update message at the beginning of the stream. 1644 In this example, the client uses the substream-ids "net", "routing" 1645 and "hops" for those resources. The update stream server sends the 1646 stream control URI and the full cost maps, followed by updates for 1647 the network map and cost maps as they become available: 1649 POST /updates/costs HTTP/1.1 1650 Host: alto.example.com 1651 Accept: text/event-stream,application/alto-error+json 1652 Content-Type: application/alto-updatestreamparams+json 1653 Content-Length: 244 1655 { "add": { 1656 "net": { 1657 "resource-id": "my-network-map", 1658 "tag": "a10ce8b059740b0b2e3f8eb1d4785acd42231bfe" 1659 }, 1660 "routing": { 1661 "resource-id": "my-routingcost-map" 1662 }, 1663 "hops": { 1664 "resource-id": "my-hopcount-map" 1665 } 1666 } 1667 } 1669 HTTP/1.1 200 OK 1670 Connection: keep-alive 1671 Content-Type: text/event-stream 1673 event: application/alto-updatestreamcontrol+json 1674 data: {"control-uri": 1675 data: "http://alto.example.com/updates/streams/2718281828459"} 1677 event: application/alto-costmap+json,routing 1678 data: { ... full routingcost cost map message ... } 1680 event: application/alto-costmap+json,hops 1681 data: { ... full hopcount cost map message ... } 1683 (pause) 1685 event: application/merge-patch+json,routing 1686 data: {"cost-map": {"PID2" : {"PID3" : 31}}} 1688 event: application/merge-patch+json,hops 1689 data: {"cost-map": {"PID2" : {"PID3" : 4}}} 1691 If the ALTO client wishes to stop receiving updates for the 1692 "hopcount" cost map, the ALTO client can send a "remove" request on 1693 the stream control URI: 1695 POST /updates/streams/2718281828459 HTTP/1.1 1696 Host: alto.example.com 1697 Accept: text/plain,application/alto-error+json 1698 Content-Type: application/alto-updatestreamparams+json 1699 Content-Length: 24 1701 { 1702 "remove": [ "hops" ] 1703 } 1705 HTTP/1.1 204 No Content 1706 Content-Length: 0 1708 (stream closed without sending data content) 1710 The update stream server sends a "stopped" control update message on 1711 the original request stream to inform the ALTO client that updates 1712 are stopped for that resource: 1714 event: application/alto-updatestreamcontrol+json 1715 data: { 1716 data: "stopped": ["hops"] 1717 data: } 1719 Below is an example of an invalid stream control request. The 1720 "remove" field of the request includes an undefined substream-id and 1721 the stream control server will return an error response to the ALTO 1722 client. 1724 POST /updates/streams/2718281828459 HTTP/1.1 1725 Host: alto.example.com 1726 Accept: text/plain,application/alto-error+json 1727 Content-Type: application/alto-updatestreamparams+json 1728 Content-Length: 31 1729 { 1730 "remove": [ "properties" ] 1731 } 1733 HTTP/1.1 400 Bad Request 1734 Content-Length: 89 1735 Content-Type: application/alto-error+json 1737 { 1738 "meta":{ 1739 "code": "E_INVALID_FIELD_VALUE", 1740 "field": "remove", 1741 "value": "properties" 1742 } 1744 If the ALTO client no longer needs any updates, and wishes to shut 1745 the update stream down gracefully, the client can send a "remove" 1746 request with an empty array: 1748 POST /updates/streams/2718281828459 HTTP/1.1 1749 Host: alto.example.com 1750 Accept: text/plain,application/alto-error+json 1751 Content-Type: application/alto-updatestreamparams+json 1752 Content-Length: 17 1754 { 1755 "remove": [ ] 1756 } 1758 HTTP/1.1 204 No Content 1759 Content-Length: 0 1761 (stream closed without sending data content) 1763 The update stream server sends a final control update message on the 1764 original request stream to inform the ALTO client that all updates 1765 are stopped and then closes the stream: 1767 event: application/alto-updatestreamcontrol+json 1768 data: { 1769 data: "stopped": ["net", "routing"] 1770 data: } 1772 (server closes stream) 1774 8.4. Example: Endpoint Property Updates 1776 As another example, here is how an ALTO client can request updates 1777 for the property "priv:ietf-bandwidth" for one set of endpoints and 1778 "priv:ietf-load" for another. The update stream server immediately 1779 sends full replacements with the property values for all endpoints. 1780 After that, the update stream server sends data update messages for 1781 the individual endpoints as their property values change. 1783 POST /updates/properties HTTP/1.1 1784 Host: alto.example.com 1785 Accept: text/event-stream 1786 Content-Type: application/alto-updatestreamparams+json 1787 Content-Length: 511 1789 { "add": { 1790 "props-1": { 1791 "resource-id": "my-props", 1792 "input": { 1793 "properties" : [ "priv:ietf-bandwidth" ], 1794 "endpoints" : [ 1795 "ipv4:198.51.100.1", 1796 "ipv4:198.51.100.2", 1797 "ipv4:198.51.100.3" 1798 ] 1799 } 1800 }, 1801 "props-2": { 1802 "resource-id": "my-props", 1803 "input": { 1804 "properties" : [ "priv:ietf-load" ], 1805 "endpoints" : [ 1806 "ipv6:2001:db8:100::1", 1807 "ipv6:2001:db8:100::2", 1808 "ipv6:2001:db8:100::3" 1809 ] 1810 } 1811 } 1812 } 1813 } 1814 HTTP/1.1 200 OK 1815 Connection: keep-alive 1816 Content-Type: text/event-stream 1818 event: application/alto-updatestreamcontrol+json 1819 data: {"control-uri": 1820 data: "http://alto.example.com/updates/streams/1414213562373"} 1822 event: application/alto-endpointprops+json,props-1 1823 data: { "endpoint-properties": { 1824 data: "ipv4:198.51.100.1" : { "priv:ietf-bandwidth": "13" }, 1825 data: "ipv4:198.51.100.2" : { "priv:ietf-bandwidth": "42" }, 1826 data: "ipv4:198.51.100.3" : { "priv:ietf-bandwidth": "27" } 1827 data: } } 1829 event: application/alto-endpointprops+json,props-2 1830 data: { "endpoint-properties": { 1831 data: "ipv6:2001:db8:100::1" : { "priv:ietf-load": "8" }, 1832 data: "ipv6:2001:db8:100::2" : { "priv:ietf-load": "2" }, 1833 data: "ipv6:2001:db8:100::3" : { "priv:ietf-load": "9" } 1834 data: } } 1836 (pause) 1838 event: application/merge-patch+json,props-1 1839 data: { "endpoint-properties": 1840 data: {"ipv4:198.51.100.1" : {"priv:ietf-bandwidth": "3"}} 1841 data: } 1843 (pause) 1845 event: application/merge-patch+json,props-2 1846 data: { "endpoint-properties": 1847 data: {"ipv6:2001:db8:100::3" : {"priv:ietf-load": "7"}} 1848 data: } 1850 If the ALTO client needs the "bandwidth" property for additional 1851 endpoints, the ALTO client can send an "add" request on the stream 1852 control URI: 1854 POST /updates/streams/1414213562373" HTTP/1.1 1855 Host: alto.example.com 1856 Accept: text/plain,application/alto-error+json 1857 Content-Type: application/alto-updatestreamparams+json 1858 Content-Length: 448 1860 { "add": { 1861 "props-3": { 1862 "resource-id": "my-props", 1863 "input": { 1864 "properties" : [ "priv:ietf-bandwidth" ], 1865 "endpoints" : [ 1866 "ipv4:198.51.100.4", 1867 "ipv4:198.51.100.5" 1868 ] 1869 } 1870 }, 1871 "props-4": { 1872 "resource-id": "my-props", 1873 "input": { 1874 "properties" : [ "priv:ietf-load" ], 1875 "endpoints" : [ 1876 "ipv6:2001:db8:100::4", 1877 "ipv6:2001:db8:100::5" 1878 ] 1879 } 1880 } 1881 } 1882 } 1884 HTTP/1.1 204 No Content 1885 Content-Length: 0 1887 (stream closed without sending data content) 1889 The update stream server sends full replacements for the two new 1890 resources, followed by incremental changes for all four requests as 1891 they arrive: 1893 event: application/alto-endpointprops+json,props-3 1894 data: { "endpoint-properties": { 1895 data: "ipv4:198.51.100.4" : { "priv:ietf-bandwidth": "25" }, 1896 data: "ipv4:198.51.100.5" : { "priv:ietf-bandwidth": "31" }, 1897 data: } } 1899 event: application/alto-endpointprops+json,props-4 1900 data: { "endpoint-properties": { 1901 data: "ipv6:2001:db8:100::4" : { "priv:ietf-load": "6" }, 1902 data: "ipv6:2001:db8:100::5" : { "priv:ietf-load": "4" }, 1903 data: } } 1905 (pause) 1907 event: application/merge-patch+json,props-3 1908 data: { "endpoint-properties": 1909 data: {"ipv4:198.51.100.5" : {"priv:ietf-bandwidth": "15"}} 1910 data: } 1912 (pause) 1914 event: application/merge-patch+json,props-2 1915 data: { "endpoint-properties": 1916 data: {"ipv6:2001:db8:100::2" : {"priv:ietf-load": "9"}} 1917 data: } 1919 (pause) 1921 event: application/merge-patch+json,props-4 1922 data: { "endpoint-properties": 1923 data: {"ipv6:2001:db8:100::4" : {"priv:ietf-load": "3"}} 1924 data: } 1926 8.5. Example: Multipart Message Updates 1928 This example shows how an ALTO client can request a non-standard ALTO 1929 service returning a multipart response. The update stream server 1930 immediately sends full replacements of the multipart response. After 1931 that, the update stream server sends data update messages for the 1932 individual parts of the response as the ALTO data (object) in each 1933 part changes. 1935 POST /updates/pv HTTP/1.1 1936 Host: alto.example.com 1937 Accept: text/event-stream 1938 Content-Type: application/alto-updatestreamparams+json 1939 Content-Length: 382 1941 { 1942 "add": { 1943 "ecspvsub1": { 1944 "resource-id": "my-pv", 1945 "input": { 1946 "cost-type": { 1947 "cost-mode": "array", 1948 "cost-metric": "ane-path" 1949 }, 1950 "endpoints": { 1951 "srcs": [ "ipv4:192.0.2.2" ], 1952 "dsts": [ "ipv4:192.0.2.89", "ipv4:203.0.113.45" ] 1953 }, 1954 "ane-properties": [ "maxresbw", "persistent-entities" ] 1955 } 1956 } 1957 } 1958 } 1960 HTTP/1.1 200 OK 1961 Connection: keep-alive 1962 Content-Type: text/event-stream 1964 event: application/alto-updatestreamcontrol+json 1965 data: {"control-uri": "http://alto.example.com/updates/streams/1414"} 1967 event: multipart/related;boundary=example-pv; 1968 type=application/alto-endpointcost+json,ecspvsub1 1969 data: --example-pv 1970 data: Content-ID: ecsmap 1971 data: Content-Type: application/alto-endpointcost+json 1972 data: 1973 data: { ... data (object) of an endpoint cost map ... } 1974 data: --example-pv 1975 data: Content-ID: propmap 1976 data: Content-Type: application/alto-propmap+json 1977 data: 1978 data: { ... data (object) of a property map ... } 1979 data: --example-pv-- 1981 (pause) 1983 event: application/merge-patch+json,ecspvsub1.ecsmap 1984 data: { ... merge patch for updates of ecspvsub1.ecsmap ... } 1986 event: application/merge-patch+json,ecspvsub1.propmap 1987 data: { ... merge patch for updates of ecspvsub1.propmap ... } 1989 9. Operation and Processing Considerations 1991 9.1. Considerations for Choosing Data Update Messages 1993 The choice on data update messages depends on both how frequently the 1994 resources will change, and how extensive those changes will be. For 1995 stable resources with minor changes, the update stream server may 1996 choose to send incremental changes; for resources that frequently 1997 change, the update stream server may choose to send a full 1998 replacement after a while. Whether to send full replacement or 1999 incremental change depends on the update stream server. 2001 For incremental updates, this design allows both JSON patch and JSON 2002 merge patch for incremental changes. JSON merge patch is clearly 2003 superior to JSON patch for describing incremental changes to Cost 2004 Maps, Endpoint Costs, and Endpoint Properties. For these data 2005 structures, JSON merge patch is more space-efficient, as well as 2006 simpler to apply; we see no advantage to allowing a server to use 2007 JSON patch for those resources. 2009 The case is not as clear for incremental changes to network maps. 2011 First, consider small changes such as moving a prefix from one PID to 2012 another. JSON patch could encode that as a simple insertion and 2013 deletion, while JSON merge patch would have to replace the entire 2014 array of prefixes for both PIDs. On the other hand, to process a 2015 JSON patch update, the ALTO client would have to retain the indexes 2016 of the prefixes for each PID. Logically, the prefixes in a PID are 2017 an unordered set, not an array; aside from handling updates, a client 2018 has no need to retain the array indexes of the prefixes. Hence to 2019 take advantage of JSON patch for network maps, ALTO clients would 2020 have to retain additional, otherwise unnecessary, data. 2022 Second, consider more involved changes such as removing half of the 2023 prefixes from a PID. JSON merge patch would send a new array for 2024 that PID, while JSON patch would have to send a list of remove 2025 operations and delete the prefix one by one. 2027 Therefore, each update stream server may decide on its own whether to 2028 use JSON merge patch or JSON patch according to the changes in 2029 network maps. 2031 Other JSON-based incremental change formats may be introduced in the 2032 future. 2034 9.2. Considerations for Client Processing Data Update Messages 2036 In general, when an ALTO client receives a full replacement for a 2037 resource, the ALTO client should replace the current version with the 2038 new version. When an ALTO client receives an incremental change for 2039 a resource, the ALTO client should apply those patches to the current 2040 version of the resource. 2042 However, because resources can depend on other resources (e.g., cost 2043 maps depend on network maps), an ALTO client MUST NOT use a dependent 2044 resource if the resource on which it depends has changed. There are 2045 at least two ways an ALTO client can do that. The following 2046 paragraphs illustrate these techniques by referring to network and 2047 cost map messages, although these techniques apply to any dependent 2048 resources. 2050 Note that when a network map changes, the update stream server MUST 2051 send the network map update message before sending the updates for 2052 the dependent cost maps (see Section 6.7.1). 2054 One approach is for the ALTO client to save the network map update 2055 message in a buffer and continue to use the previous network map, and 2056 the associated cost maps, until the ALTO client receives the update 2057 messages for all dependent cost maps. The ALTO client then applies 2058 all network and cost map updates atomically. 2060 Alternatively, the ALTO client MAY update the network map 2061 immediately. In this case, the ALTO client MUST mark each dependent 2062 cost map as temporarily invalid and MUST NOT use that map until the 2063 ALTO client receives a cost map update message with the new network 2064 map version tag. Note that the ALTO client MUST NOT delete the cost 2065 maps, because the update stream server may send incremental changes. 2067 The update stream server SHOULD send updates for dependent resources 2068 in a timely fashion. However, if the ALTO client does not receive 2069 the expected updates, the ALTO client MUST close the update stream 2070 connection, discard the dependent resources, and reestablish the 2071 update stream. The ALTO client MAY retain the version tag of the 2072 last version of any tagged resources and give those version tags when 2073 requesting the new update stream. In this case, if a version is 2074 still current, the update stream server will not re-send that 2075 resource. 2077 Although not as efficient as possible, this recovery method is simple 2078 and reliable. 2080 9.3. Considerations for Updates to Filtered Cost Maps 2082 If an update stream provides updates to a Filtered cost map which 2083 allows constraint tests, then an ALTO client MAY request updates to a 2084 Filtered cost map request with a constraint test. In this case, when 2085 a cost changes, the update stream server MUST send an update if the 2086 new value satisfies the test. If the new value does not, whether the 2087 update stream server sends an update depends on whether the previous 2088 value satisfied the test. If it did not, the update stream server 2089 SHOULD NOT send an update to the ALTO client. But if the previous 2090 value did, then the update stream server MUST send an update with a 2091 "null" value, to inform the ALTO client that this cost no longer 2092 satisfies the criteria. 2094 An update stream server can avoid such issues by offering update 2095 streams only for filtered cost maps which do not allow constraint 2096 tests. 2098 9.4. Considerations for Updates to Ordinal Mode Costs 2100 For an ordinal mode cost map, a change to a single cost point may 2101 require updating many other costs. As an extreme example, suppose 2102 the lowest cost changes to the highest cost. For a numerical mode 2103 cost map, only that one cost changes. But for an ordinal mode cost 2104 map, every cost might change. While this document allows an update 2105 stream server to offer incremental updates for ordinal mode cost 2106 maps, update stream server implementors should be aware that 2107 incremental updates for ordinal costs are more complicated than for 2108 numerical costs, and ALTO clients should be aware that small changes 2109 may result in large updates. 2111 An update stream server can avoid this complication by only offering 2112 full replacements for ordinal cost maps. 2114 9.5. Considerations for SSE Text Formatting and Processing 2116 SSE was designed for events that consist of relatively small amounts 2117 of line-oriented text data, and SSE clients frequently read input one 2118 line-at-a-time. However, an update stream sends a full cost map as a 2119 single events, and a cost map may involve megabytes, if not tens of 2120 megabytes, of text. This has implications that the ALTO client and 2121 the update stream server may consider. 2123 First, some SSE client libraries read all data for an event into 2124 memory, and then present it to the client as a character array. 2125 However, a client may not have enough memory to hold the entire JSON 2126 text for a large cost map. Hence an ALTO client SHOULD consider 2127 using an SSE library which presents the event data in manageable 2128 chunks, so the ALTO client can parse the cost map incrementally and 2129 store the underlying data in a more compact format. 2131 Second, an SSE client library may use a low level, generic socket 2132 read library that stores each line of an event data, just in case the 2133 higher level parser may need the line delimiters as part of the 2134 protocol formatting. A server sending a complete cost map as a 2135 single line may then generate a multi-megabyte data "line", and such 2136 a long line may then require complex memory management at the client. 2137 It is RECOMMENDED that an update stream server limit the lengths of 2138 data lines. 2140 10. Security Considerations 2142 As an extension of the base ALTO protocol [RFC7285], this document 2143 fits into the architecture of the base protocol, and hence the 2144 Security Considerations (Section 15) of the base protocol fully apply 2145 when this extension is provided by an ALTO server. For example, the 2146 same authenticity and integrity considerations (Section 15.1 of 2147 [RFC7285]) still fully apply; the same considerations for the privacy 2148 of ALTO users (Section 15.4 of [RFC7285]) also still fully apply. 2150 The addition of update streams and stream control can introduce 2151 additional risks which are discussed below. 2153 10.1. Update Stream Server: Denial-of-Service Attacks 2155 Allowing persistent update stream connections enables a new class of 2156 Denial-of-Service attacks. 2158 For the update stream server, an ALTO client might create an 2159 unreasonable number of update stream connections, or add an 2160 unreasonable number of substream-ids to one update stream. 2162 To avoid these attacks on the update stream server, the server SHOULD 2163 choose to limit the number of active streams and reject new requests 2164 when that threshold is reached. An update stream server SHOULD also 2165 choose to limit the number of active substream-ids on any given 2166 stream, or limit the total number of substream-ids used over the 2167 lifetime of a stream, and reject any stream control request which 2168 would exceed those limits. In these cases, the update stream server 2169 SHOULD return the HTTP status "503 Service Unavailable". 2171 While the preceding techniques prevent update stream DoS attacks from 2172 disrupting an update stream server's other services, it does make it 2173 easier for a DoS attack to disrupt the update stream service. 2174 Therefore an update stream server MAY prefer to restrict update 2175 stream services to authorized clients, as discussed in Section 15 of 2176 [RFC7285]. 2178 Alternatively, an update stream server MAY return the HTTP status 2179 "307 Temporary Redirect" to redirect the client to another ALTO 2180 server which can better handle a large number of update streams. 2182 10.2. ALTO Client: Update Overloading or Instability 2184 The availability of continuous updates can also cause overload for an 2185 ALTO client, in particular an ALTO client with limited processing 2186 capabilities. The current design does not include any flow control 2187 mechanisms for the client to reduce the update rates from the server. 2188 Under overloading, the client MAY choose to remove the information 2189 resources with high update rates. 2191 Also, under overloading, the client may no longer be able to detect 2192 whether an information is still fresh or has become stale. In such a 2193 case, the client should be careful in how it uses the information to 2194 avoid stability or efficiency issues. 2196 10.3. Stream Control: Spoofed Control Requests 2198 An outside party which can read the update stream response, or which 2199 can observe stream control requests, can obtain the control URI and 2200 use that to send a fraudulent "remove" requests, thus disabling 2201 updates for the valid ALTO client. This can be avoided by encrypting 2202 the update stream and stream control requests (see Section 15 of 2203 [RFC7285]). Also, the update stream server echoes the "remove" 2204 requests on the update stream, so the valid ALTO client can detect 2205 unauthorized requests. 2207 11. Requirements on Future ALTO Services to Use this Design 2209 Although this design is quite flexible, it has underlying 2210 requirements. 2212 The key requirements are that (1) each data update message is for a 2213 single resource; (2) an incremental change can be applied only to a 2214 resource that is a single JSON object, as both JSON merge patch and 2215 JSON patch can apply only to a single JSON object. Hence, if a 2216 future ALTO resource can contain multiple objects, then either each 2217 individual object also has a resource-id or an extension to this 2218 design is made. 2220 At the low level encoding level, new line in SSE has its own 2221 semantics. Hence, this design requires that resource encoding does 2222 not include new lines that can confuse with SSE encoding. In 2223 particular, the data update message MUST NOT include "event: " or 2224 "data: " at a new line as part of data message. 2226 If an update stream provides updates to a filtered cost map that 2227 allows constraint tests, the requirements for such services are 2228 stated in Section 9.3. 2230 12. IANA Considerations 2232 This document defines two new media-types, "application/alto- 2233 updatestreamparams+json", as described in Section 6.5, and 2234 "application/alto-updatestreamcontrol+json", as described in 2235 Section 5.3. All other media-types used in this document have 2236 already been registered, either for ALTO, JSON merge patch, or JSON 2237 patch. 2239 Type name: application 2241 Subtype name: alto-updatestreamparams+json 2243 Required parameters: n/a 2245 Optional parameters: n/a 2246 Encoding considerations: Encoding considerations are identical to 2247 those specified for the "application/json" media type. See 2248 [RFC7159]. 2250 Security considerations: Security considerations relating to the 2251 generation and consumption of ALTO Protocol messages are discussed 2252 in Section 10 of this document and Section 15 of [RFC7285]. 2254 Interoperability considerations: This document specifies format of 2255 conforming messages and the interpretation thereof. 2257 Published specification: Section 6.5 of this document. 2259 Applications that use this media type: ALTO servers and ALTO clients 2260 either stand alone or are embedded within other applications. 2262 Additional information: 2264 Magic number(s): n/a 2266 File extension(s): This document uses the mime type to refer to 2267 protocol messages and thus does not require a file extension. 2269 Macintosh file type code(s): n/a 2271 Person & email address to contact for further information: See 2272 Authors' Addresses section. 2274 Intended usage: COMMON 2276 Restrictions on usage: n/a 2278 Author: See Authors' Addresses section. 2280 Change controller: Internet Engineering Task Force 2281 (mailto:iesg@ietf.org). 2283 Type name: application 2285 Subtype name: alto-updatestreamcontrol+json 2287 Required parameters: n/a 2289 Optional parameters: n/a 2291 Encoding considerations: Encoding considerations are identical to 2292 those specified for the "application/json" media type. See 2293 [RFC7159]. 2295 Security considerations: Security considerations relating to the 2296 generation and consumption of ALTO Protocol messages are discussed 2297 in Section 10 of this document and Section 15 of [RFC7285]. 2299 Interoperability considerations: This document specifies format of 2300 conforming messages and the interpretation thereof. 2302 Published specification: Section 5.3 of this document. 2304 Applications that use this media type: ALTO servers and ALTO clients 2305 either stand alone or are embedded within other applications. 2307 Additional information: 2309 Magic number(s): n/a 2311 File extension(s): This document uses the mime type to refer to 2312 protocol messages and thus does not require a file extension. 2314 Macintosh file type code(s): n/a 2316 Person & email address to contact for further information: See 2317 Authors' Addresses section. 2319 Intended usage: COMMON 2321 Restrictions on usage: n/a 2323 Author: See Authors' Addresses section. 2325 Change controller: Internet Engineering Task Force 2326 (mailto:iesg@ietf.org). 2328 13. Alternative Design Not Supported 2330 13.1. Why Not Allowing Stream Restart 2332 If an update stream is closed accidentally, when the ALTO client 2333 reconnects, the update stream server must resend the full maps. This 2334 is clearly inefficient. To avoid that inefficiency, the SSE 2335 specification allows an update stream server to assign an id to each 2336 event. When an ALTO client reconnects, the ALTO client can present 2337 the id of the last successfully received event, and the update stream 2338 server restarts with the next event. 2340 However, that mechanism adds additional complexity. The update 2341 stream server must save SSE messages in a buffer, in case ALTO 2342 clients reconnect. But that mechanism will never be perfect: if the 2343 ALTO client waits too long to reconnect, or if the ALTO client sends 2344 an invalid id, then the update stream server will have to resend the 2345 complete maps anyway. 2347 Furthermore, this is unlikely to be a problem in practice. ALTO 2348 clients who want continuous updates for large resources, such as full 2349 Network and cost maps, are likely to be things like P2P trackers. 2350 These ALTO clients will be well connected to the network; they will 2351 rarely drop connections. 2353 Mobile devices certainly can and do drop connections and will have to 2354 reconnect. But mobile devices will not need continuous updates for 2355 multi-megabyte cost maps. If mobile devices need continuous updates 2356 at all, they will need them for small queries, such as the costs from 2357 a small set of media servers from which the device can stream the 2358 currently playing movie. If the mobile device drops the connection 2359 and reestablishes the update stream, the update stream server will 2360 have to retransmit only a small amount of redundant data. 2362 In short, using event ids to avoid resending the full map adds a 2363 considerable amount of complexity to avoid a situation which we 2364 expect is very rare. We believe that complexity is not worth the 2365 benefit. 2367 The Update Stream service does allow the ALTO client to specify the 2368 tag of the last received version of any tagged resource, and if that 2369 is still current, the update stream server need not retransmit the 2370 full resource. Hence ALTO clients can use this to avoid 2371 retransmitting full network maps. cost maps are not tagged, so this 2372 will not work for them. Of course, the ALTO protocol could be 2373 extended by adding version tags to cost maps, which would solve the 2374 retransmission-on-reconnect problem. However, adding tags to cost 2375 maps might add a new set of complications. 2377 14. Acknowledgments 2379 Thank you to Dawn Chen (Tongji University), Shawn Lin (Tongji 2380 University) and Xiao Shi (Yale University) for their contributions to 2381 an earlier version of this document. 2383 15. Contributors 2385 Section 2, Section 5.1, Section 5.2 and Section 8.5 of this document 2386 are based on contributions from Jingxuan Jensen Zhang. 2388 16. References 2390 16.1. Normative References 2392 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 2393 Requirement Levels", RFC 2119, BCP 14, March 1997. 2395 [RFC2387] Levinson, E., "The MIME Multipart/Related Content-type", 2396 RFC 2387, BCP 14, August 1998. 2398 [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type 2399 Specifications and Registration Procedures", RFC 6838, 2400 January 2013. 2402 [RFC6902] Bryan, P. and M. Nottingham, "JavaScript Object Notation 2403 (JSON) Patch", RFC 6902, April 2013. 2405 [RFC7159] Bray, T., "The JavaScript Object Notation (JSON) Data 2406 Interchange Format", RFC 7159, March 2014. 2408 [RFC7285] Almi, R., Penno, R., Yang, Y., Kiesel, S., Previdi, S., 2409 Roome, W., Shalunov, S., and R. Woundy, "Application-Layer 2410 Traffic Optimization (ALTO) Protocol", RFC 7285, September 2411 2014. 2413 [RFC7396] Hoffman, P. and J. Snell, "JSON Merge Patch", RFC 7396, 2414 October 2014. 2416 [SSE] Hickson, I., "Server-Sent Events (W3C)", W3C 2417 Recommendation 03 February 2015, February 2015. 2419 16.2. Informative References 2421 [RFC4960] Stewart, R., "Stream Control Transmission Protocol", RFC 2422 4960, September 2007. 2424 [RFC5789] Dusseault, L. and J. Snell, "PATCH Method for HTTP", RFC 2425 5789, March 2010. 2427 [RFC7230] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 2428 (HTTP/1.1): Message Syntax and Routing", RFC 7230, June 2429 2014. 2431 [RFC7231] Fielding, R. and J. Reschke, "Hypertext Transfer Protocol 2432 (HTTP/1.1): Semantics and Content", RFC 7231, June 2014. 2434 [RFC7540] Belshe, M., Peon, R., and M. Thomson, "Hypertext Transfer 2435 Protocol Version 2 (HTTP/2)", RFC 7540, May 2015. 2437 Authors' Addresses 2439 Wendy Roome 2440 Nokia Bell Labs (Retired) 2441 124 Burlington Rd 2442 Murray Hill, NJ 07974 2443 USA 2445 Phone: +1-908-464-6975 2446 Email: wendy@wdroome.com 2448 Y. Richard Yang 2449 Yale University 2450 51 Prospect St 2451 New Haven CT 2452 USA 2454 Email: yry@cs.yale.edu