idnits 2.17.1 draft-toomim-httpbis-range-patch-00.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 : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (Nov 18, 2019) is 1620 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 7233 (Obsoleted by RFC 9110) == Outdated reference: A later version (-04) exists of draft-toomim-httpbis-braid-http-00 -- Obsolete informational reference (is this intentional?): RFC 2616 (Obsoleted by RFC 7230, RFC 7231, RFC 7232, RFC 7233, RFC 7234, RFC 7235) Summary: 1 error (**), 0 flaws (~~), 2 warnings (==), 2 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 1 Internet-Draft M. Milutinovic 2 Expires: Mar 16, 2020 UC Berkeley 3 Intended status: Proposed Standard M. Toomim 4 Invisible College 5 B. Bellomy 6 Invisible College 7 Nov 18, 2019 9 Range Patch 10 draft-toomim-httpbis-range-patch-00 12 Abstract 14 A uniform approach for expressing changes to state over HTTP. 16 Status of this Memo 18 This Internet-Draft is submitted in full conformance with the 19 provisions of BCP 78 and BCP 79. 21 Internet-Drafts are working documents of the Internet Engineering 22 Task Force (IETF), its areas, and its working groups. Note that 23 other groups may also distribute working documents as 24 Internet-Drafts. The list of current Internet-Drafts is at 25 http://datatracker.ietf.org/drafts/current/. 27 Internet-Drafts are draft documents valid for a maximum of six months 28 and may be updated, replaced, or obsoleted by other documents at any 29 time. It is inappropriate to use Internet-Drafts as reference 30 material or to cite them other than as "work in progress." 32 The list of current Internet-Drafts can be accessed at 33 https://www.ietf.org/1id-abstracts.html 35 The list of Internet-Draft Shadow Directories can be accessed at 36 https://www.ietf.org/shadow.html 37 Table of Contents 39 1. Introduction ....................................................3 40 2. Range Patch .....................................................3 41 2.1. Multiple Range Patches .....................................5 42 2.2. Stand-Alone Range Patch ....................................5 43 2.3. URI Fragment Identifiers ...................................6 44 3. Range Units .....................................................7 45 3.1. Bytes Range Unit ...........................................7 46 3.2. JSON Range Unit ............................................8 47 3.3. Lines Range Unit ..........................................10 48 4. IANA Considerations ............................................11 49 4.1. Range Unit Registrations ..................................11 50 4.2. The +patch Structured Syntax Suffix .......................12 51 5. Checking Capabilities ..........................................13 52 6. Race Conditions ................................................14 53 7. Security Considerations ........................................14 54 8. Conventions ....................................................14 55 9. Copyright Notice ...............................................14 56 10. References ....................................................15 57 10.1. Normative References .....................................15 58 10.2. Informative References ...................................15 59 1. Introduction 61 This documents describes a uniform approach for expressing changes to 62 state over HTTP. It builds upon [RFC7233] and details how patches 63 can be defined using range units, ranges, and content. Any patch is 64 expressed in the form: 66 "range X in units Y of the data was replaced with content Z" 68 Range units define how original content (being patched) should be 69 parsed to obtain a region of the content which is being patched, and 70 then how that region is replaced with new content. 72 2. Range Patch 74 [RFC7233] effectively already defines how a patch operating on byte 75 units can be represented over HTTP, using Content-Range, 76 Content-Type, and Content-Length HTTP headers. Example: 78 HTTP/1.1 206 Partial Content 79 Date: Wed, 15 Nov 1995 06:25:24 GMT 80 Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT 81 Content-Range: bytes 21010-47021/47022 82 Content-Length: 26012 83 Content-Type: image/gif 85 ... 26012 bytes of partial image data ... 87 The same approach can be used to describe a range inside content 88 interpreted not as bytes, but, for example, as JSON [RFC8259] or 89 JSON-compatible structure. We define such JSON range unit in 90 Section 4.1. For example, given the following JSON document: 92 {"foo": {"bar": [ 93 {"some": "thing"}, 94 {"no": "thing"}, 95 {"mo": "re"}, 96 {"baz": {"1": {"two": "tree"}}} 97 ]}} 99 One might make the following request: 101 GET /api/document/1 HTTP/1.1 102 Host: example.com 103 Accept: application/json 104 Range: json=/foo/bar/3/baz 105 And receive the following response: 107 HTTP/1.1 206 Partial Content 108 Date: Thu, 31 Oct 2019 07:51:08 GMT 109 Last-Modified: Thu, 18 Oct 2019 17:44:39 GMT 110 Content-Range: json /foo/bar/3/baz 111 Content-Length: 22 112 Content-Type: application/json 114 {"1": {"two": "tree"}} 116 [RFC7233] defines and allows a Range header only for the GET request 117 method. In this document, we define the behavior for other request 118 methods. Which methods a given resource supports and which 119 methods accept range patches as defined in this document is left to 120 the server to define. 122 When issuing a non-GET request to a resource, a range patch can be 123 provided using Range header field. 125 PATCH /api/image/1 HTTP/1.1 126 Host: example.com 127 Range: bytes=21010-47021 128 Content-Length: 26012 129 Content-Type: image/gif 131 ... 26012 bytes of new partial image data ... 133 And for JSON: 135 PATCH /api/document/1 HTTP/1.1 136 Host: example.com 137 Range: json=/foo/bar/3/baz 138 Content-Length: 25 139 Content-Type: application/json 141 {"2": {"three": "flour"}} 143 A patch with empty contents corresponds to deletion of existing 144 content at the specified range. A patch with a zero-length range but 145 non-empty contents corresponds to inserting content immediately 146 before the location of the zero-length range. A patch with non-empty 147 contents at a non-zero-length range corresponds to replacing existing 148 content at the range with new content. 150 When server supports Range header with non-GET requests, server MUST 151 NOT ignore the Range header when used with a non-GET request. When 152 server does not support Range header with non-GET requests, a server 153 SHOULD generate a 416 (Range Not Satisfiable) or a 400 (Bad Request) 154 response when a non-GET request with a Range header is made. Proxies 155 SHOULD NOT drop Range header for non-GET requests. To assure correct 156 handling of non-GET requests with the Range header, requester can 157 check server's support for it as described in Section 5. 159 2.1. Multiple Range Patches 161 Multiple range patches can also be combined in one request. This can 162 be done by reusing [RFC7233] for transferring multiple parts using 163 multipart/byteranges payload as described in Section 4.1. of 164 [RFC7233]. 166 When issuing a non-GET request to a resource, multiple range patches 167 can be provided as well: 169 PATCH /api/document/1 HTTP/1.1 170 Host: example.com 171 Content-Length: 200 172 Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES 174 --THIS_STRING_SEPARATES 175 Content-Type: application/json 176 Range: json=/foo/bar/2/mo 178 42 179 --THIS_STRING_SEPARATES 180 Content-Type: application/json 181 Range: json=/foo/bar/1/no 183 "person" 185 2.2. Stand-Alone Range Patch 187 When range patches are transmitted outside of HTTP session, a 188 stand-alone range patch format can be used. For example, in this 189 format a patch can be stored in a file, send to a mailing list, or a 190 code version control system can display the patch in the range patch 191 format. The format reuses structure from HTTP and consists of 192 headers separated from the patch body by an empty line. Only 193 Content-Range header is required. Example: 195 Content-Range: json /foo/bar/3/baz 197 {"1": {"two": "tree"}} 199 Additional headers can be provided. This can be used even for 200 multiple range patches. In such case the patch starts with 201 Content-Type header defining the boundary. Example: 203 Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES 205 --THIS_STRING_SEPARATES 206 Content-Range: json /foo/bar/2/mo 208 42 209 --THIS_STRING_SEPARATES 210 Content-Range: json /foo/bar/1/no 212 "person" 213 Stand-alone range patches can be transmitted over HTTP as-is as well. 214 This can be used to provide the patch which has been used in a 215 previous non-GET request. A Content-Type with "+patch" suffix 216 identifies such stand-alone range patch. For example, the patch used 217 in the PATCH request example above could be retrieved as: 219 HTTP/1.1 200 OK 220 Date: Thu, 31 Oct 2019 07:51:08 GMT 221 Last-Modified: Thu, 18 Oct 2019 17:44:39 GMT 222 Content-Length: 62 223 Content-Type: application/json+patch 225 Content-Range: json /foo/bar/3/baz 227 {"2": {"three": "flour"}} 229 Stand-alone range patches are binary data. 231 2.3. URI Fragment Identifiers 233 For media types which support range patches, ranges can be used as 234 URI fragment identifies as well. For example, URI: 236 /api/document/1#json=/foo/bar/0 238 identifies a fragment with the following content: 240 {"some": "thing"} 242 Multiple ranges are supported as well and they identify multiple 243 fragments: 245 /api/document/1#json=/foo/bar/0,/foo/bar/1 246 3. Range Units 248 Range units define how content is parsed into a structure. They 249 define a corresponding range specification which is a string 250 describing range under the unit. 252 Different range units can be compatible with content expresses 253 through different media types. 255 3.1. Bytes Range Unit 257 Bytes range unit is already specified in [RFC7233]. We extend it by 258 allowing a zero-length range using a zero-length-byte-range-spec. 260 zero-length-byte-range-spec = 1*DIGIT 262 A zero-length range is a byte offset used to identify a location 263 immediately before which new content can be inserted with a patch. 265 Additionally, we note that the range "-0" is allowed, is a 266 zero-length range, and identifies a location immediately after the 267 last byte of data. This allows appending bytes to data. 269 Note that bytes range unit operates on encoded content as specified 270 in any Content-Encoding header. That holds both for GET and non-GET 271 requests. 273 3.2. JSON Range Unit 275 JSON range unit operates on JSON and JSON-compatible data structures. 276 Its range specification is based on JSON pointer as described in 277 [RFC6901]. The content of the range MUST always be a valid JSON by 278 itself. JSON range unit is identified with "json". 280 JSON pointer provides capabilities to identify a single element of a 281 data structure. Here we extend it to allow a range of elements for 282 arrays and strings, by extending the scheme how reference token 283 modifies which value is referenced from Section 4 of [RFC6901]: 285 o If the currently referenced value is a JSON array, the reference 286 token can be compromised of two sets of digits (according to the 287 ABNF syntax for array indices as specified in Section 4 of 288 [RFC6901]), delimited by the character "-". Each set of digits 289 represent an unsigned base-10 integer value. The first integer 290 value MUST be smaller than the number of elements in the array. The 291 second integer value MUST be smaller than or equal to the number of 292 elements in the array. The second integer value MUST be larger than 293 or equal to the first integer value. If any of these requirements 294 are violated, an error condition is raised. 296 The new referenced value is a new array with a subset of elements 297 starting at the zero-based index of the first integer value, and 298 ending at the element before the zero-based index of the second 299 integer value (the first index is inclusive, the second index is 300 exclusive). 302 o If the currently referenced value is a JSON array, the reference 303 token can be the character "-". The new referenced value is a 304 zero-length array corresponding to the position immediately after 305 the end of the current array. This design makes such JSON pointer 306 compatible with the use of JSON pointers in JSON Patch [RFC6902]. 307 This allows appending array elements to an array. 309 o If the currently referenced value is a JSON string, the scheme for 310 JSON arrays is used to index into a string and makes the new 311 referenced value a substring of the currently referenced value. 312 String indexing is done by code units. 314 A range of elements can be specified only as the last reference token 315 in JSON range. It follows that a range of elements can be specified 316 only once. 318 For example, given the JSON document: 320 { 321 "foo": [ 322 "bar", 323 "baz", 324 "bax" 325 ] 326 } 328 The following JSON strings evaluate to the accompanying JSON values: 330 "/foo" ["bar", "baz"] 331 "/foo/0" "bar" 332 "/foo/0-1" ["bar"] 333 "/foo/1-3" ["baz", "bax"] 334 "/foo/1-1" [] 335 "/foo/-" [] 336 "/foo/3-3" // error 337 "/foo/4-4" // error 338 "/foo/1-0" // error 339 "/foo/1-4" // error 340 "/foo/1-3/0" // error 341 "/foo/0/1-3" "ar" 343 JSON ranges "/foo/1-1" and "/foo/-" are on its own of little utility, 344 but serve as a zero-length range to identify a location immediately 345 before which new content can be inserted with a patch. 347 JSON range unit operates always on non-encoded content, ignoring any 348 Content-Encoding header. That holds both for GET and non-GET 349 requests. 351 3.3. Lines Range Unit 353 For textual contents lines range unit operates on lines. Line 354 positions are numbered starting with zero (with line position zero 355 always being identical with character position zero). Ranges 356 identified by lines include the line endings. If a content does not 357 contain any line endings, then it consists of a single (the first) 358 line. 360 Implementers should be aware of the fact that line endings in textual 361 contents can be represented by other characters or character 362 sequences than CR+LF. Besides the CR and LF, there are also NEL and 363 CR+NEL. In general, the encoding of line endings can also depend on 364 the character encoding of textual contents, and implementations have 365 to take this into account where necessary. 367 Lines range unit is identified with "lines". Lines range 368 specification is defined by: 370 lines-range-spec = first-line "-" second-line 371 first-line = 1*DIGIT 372 second-line = 1*DIGIT 374 Each lines range consists of two sets of digits, delimited by a 375 character "-". Each set of digits represent an unsigned base-10 376 integer value. The first integer value MUST be smaller than the 377 number of lines in contents. The second integer value MUST be 378 smaller than or equal to the number of lines in contents. The second 379 integer value MUST be larger than or equal to the first integer 380 value. 382 The range are lines starting at the line corresponding to the first 383 integer value, and ending at the line before the line corresponding 384 to the second integer value (the first integer is inclusive, the 385 second integer is exclusive). 387 Lines range where the first and second integer value are equal are 388 empty and are on its own of little utility, but serve as a 389 zero-length range to identify a location immediately before which new 390 content can be inserted with a patch. 392 Additionally, lines range specification can be the character "-", 393 representing a zero-length range, and identifies a location 394 immediately after the last line of textual contents. This allows 395 appending lines to textual contents. 397 Lines range unit operates always on non-encoded content, ignoring any 398 Content-Encoding header. That holds both for GET and non-GET 399 requests. 401 4. IANA Considerations 403 4.1. Range Unit Registrations 405 This document registers the following range units: 407 +-------------+---------------------------------------+-------------+ 408 | Range Unit | Description | Reference | 409 | Name | | | 410 +-------------+---------------------------------------+-------------+ 411 | json | a JSON pointer range on JSON and | Section 3.2 | 412 | | JSON-compatible data structures | | 413 +-------------+---------------------------------------+-------------+ 414 | lines | a range of lines of textual contents | Section 3.3 | 415 +-------------+---------------------------------------+-------------+ 417 The change controller is: "IETF (iesg@ietf.org) - Internet 418 Engineering Task Force". 420 4.2. The +patch Structured Syntax Suffix 422 This document registers the following media type structured syntax 423 suffix: 425 Name: Range patch 427 +suffix: +patch 429 References: See Section 2.2 of this document. 431 Encoding considerations: Stand-alone range patches are binary data. 433 Fragment identifier considerations: 435 The syntax and semantics of fragment identifiers specified for 436 +patch SHOULD be as specified for range patches themselves. (At 437 publication of this document, there is no fragment identification 438 syntax defined for range patches themselves.) 440 The syntax and semantics for fragment identifiers for a specific 441 "xxx/yyy+patch" SHOULD be processed as follows: 443 For cases defined in +patch, where the fragment identifier 444 resolves per the +patch rules, then process as specified in 445 +patch. 447 For cases defined in +patch, where the fragment identifier does 448 not resolve per the +patch rules, then such fragment SHOULD 449 identifies a fragment which is obtained by intersection of the 450 fragment identifier and the underlying range patch range 451 specification for "xxx/yyy+patch". 453 For cases not defined in +patch, then such fragment SHOULD 454 identifies a fragment which is obtained by intersection of the 455 fragment identifier and the underlying range patch range 456 specification for "xxx/yyy+patch". 458 Interoperability considerations: n/a 460 Security considerations: See Section 7 of this document. 462 Contact: IETF HTTP Working Group (ietf-http-wg@w3.org) 464 Author/Change controller: 466 IETF (iesg@ietf.org) - Internet Engineering Task Force 467 5. Checking Capabilities 469 A server may support or not support non-GET requests with a Range 470 header. The default behavior of servers is simply to ignore unknown 471 or unsupported headers. In the case of a range patch, this 472 implies that a request issuing a patch to a specific subsection of a 473 resource might be interpreted by a server as a request to overwrite 474 the entire resource with the patch, leaving the resource in a 475 corrupted state. 477 To determine whether or not the server can fulfill such a request 478 correctly, the requester may first issue an OPTIONS request: 480 OPTIONS /api/document/1 481 Range-Request-Method: PATCH 482 Range-Request-Units: json,bytes 484 To which the server may reply in the affirmative: 486 HTTP/1.1 204 No Content 487 Connection: keep-alive 488 Range-Request-Allow-Methods: PATCH 489 Range-Request-Allow-Units: json,bytes 490 Version: 33a64df551425fcc55e4d42a148795d9f25f89d4 492 In the partial negative: 494 HTTP/1.1 204 No Content 495 Connection: keep-alive 496 Range-Request-Allow-Methods: PATCH 497 Range-Request-Allow-Units: json 498 Version: 33a64df551425fcc55e4d42a148795d9f25f89d4 500 Or in the complete negative: 502 HTTP/1.1 204 No Content 503 Connection: keep-alive 504 Range-Request-Allow-Methods: 505 Range-Request-Allow-Units: 507 Empty header fields are allowed per [RFC2616] section 2.1. 509 Also note the presence of the Version header, discussed in section 510 6. The server may preemptively send this to obviate the need for 511 another GET prior to a range patch request. 513 6. Race Conditions 515 As with standard PUT, POST, and PATCH requests, a non-GET request 516 with a Range header carries the risk of a mid-air collision with 517 another simultaneous request. If one requester updates a resource, 518 and another requester, not being aware of that update, issues a 519 second update, the resource may be left in an unexpected state. 521 Standard PUT, POST, and PATCH requests handle this with the ETag and 522 If-Match headers. However, these headers vary based on the 523 Content-Encoding of the request. Alternatively, requests can use the 524 Versioning in [Braid-HTTP] to determine the ordering of simultaneous 525 requests, and can specify consistency guarantees with [Merge-Types]. 527 The server may return a Version header in response to HTTP requests 528 directed at a given resource. Correspondingly, when issuing a range 529 patch, the requester may include a Version header containing the 530 version of the resource it intends to update. If the server cannot 531 merge the patch at the given version, it must return a 409 Conflict 532 response. 534 7. Security Considerations 536 Both GET and non-GET requests with a Range header are potentially 537 susceptible to denial-of-service attacks because the effort required 538 to compute the patch or apply the patch. 540 8. Conventions 542 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 543 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 544 document are to be interpreted as described in [RFC2119]. 546 9. Copyright Notice 548 Copyright (c) 2019 IETF Trust and the persons identified as the 549 document authors. All rights reserved. 551 This document is subject to BCP 78 and the IETF Trust's Legal 552 Provisions Relating to IETF Documents 553 (http://trustee.ietf.org/license-info) in effect on the date of 554 publication of this document. Please review these documents 555 carefully, as they describe your rights and restrictions with respect 556 to this document. Code Components extracted from this document must 557 include Simplified BSD License text as described in Section 4.e of 558 the Trust Legal Provisions and are provided without warranty as 559 described in the Simplified BSD License. 561 10. References 563 10.1. Normative References 565 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 566 Requirement Levels", BCP 14, RFC 2119, March 1997. 568 [RFC7233] Fielding, R., Lafon, Y., and J. Reschke, "Hypertext 569 Transfer Protocol (HTTP/1.1): Range Requests", RFC 7233, 570 June 2014. 572 [RFC6901] Bryan, P., Zyp, K., and M. Nottingham, "JavaScript Object 573 Notation (JSON) Pointer", RFC 6901, April 2013. 575 [RFC6902] Bryan, P., and M. Nottingham, "JavaScript Object Notation 576 (JSON) Patch", RFC 6902, April 2013. 578 10.2. Informative References 580 [Merge-Types] draft-toomim-httpbis-merge-types-00 582 [Braid-HTTP] draft-toomim-httpbis-braid-http-00 584 [RFC8259] T. Bray, "The JavaScript Object Notation (JSON) Data 585 Interchange Format", RFC 8259, December 2017. 587 [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., 588 Masinter, L., Leach, P., and T. Berners-Lee, 589 "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, 590 June 1999. 592 Authors' Addresses 594 For more information, the authors of this document are best contacted 595 via Internet mail: 597 Mitar Milutinovic 598 UC Berkeley, EECS Department 599 775 Soda Hall #1776 600 Berkeley, CA 94720-1776 602 EMail: mitar.ietf@tnode.com 603 Web: https://mitar.tnode.com/ 605 Michael Toomim 606 Invisible College, Berkeley 607 2053 Berkeley Way 608 Berkeley, CA 94704 610 EMail: toomim@gmail.com 611 Web: https://invisible.college/@toomim 613 Bryn Bellomy 614 Invisible College, Berkeley 615 2053 Berkeley Way 616 Berkeley, CA 94704 618 EMail: bryn@signals.io 619 Web: https://invisible.college/@bryn