idnits 2.17.1 draft-hartke-t2trg-ciri-01.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 (February 6, 2019) is 1906 days in the past. Is this intentional? Checking references for intended status: Experimental ---------------------------------------------------------------------------- == Outdated reference: A later version (-08) exists of draft-ietf-cbor-cddl-06 ** Obsolete normative reference: RFC 7049 (Obsoleted by RFC 8949) -- Obsolete informational reference (is this intentional?): RFC 7230 (Obsoleted by RFC 9110, RFC 9112) Summary: 1 error (**), 0 flaws (~~), 2 warnings (==), 2 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Thing-to-Thing Research Group K. Hartke 3 Internet-Draft Ericsson 4 Intended status: Experimental February 6, 2019 5 Expires: August 10, 2019 7 Constrained Internationalized Resource Identifiers 8 draft-hartke-t2trg-ciri-01 10 Abstract 12 Constrained Internationalized Resource Identifiers are an alternate 13 serialization of Uniform Resource Identifiers (URIs) that encodes the 14 URI components in Concise Binary Object Representation (CBOR) instead 15 of a string of characters. This simplifies parsing, reference 16 resolution, and comparison of URIs in environments with severe 17 limitations on processing power, code size, and memory size. 19 Status of This Memo 21 This Internet-Draft is submitted in full conformance with the 22 provisions of BCP 78 and BCP 79. 24 Internet-Drafts are working documents of the Internet Engineering 25 Task Force (IETF). Note that other groups may also distribute 26 working documents as Internet-Drafts. The list of current Internet- 27 Drafts is at https://datatracker.ietf.org/drafts/current/. 29 Internet-Drafts are draft documents valid for a maximum of six months 30 and may be updated, replaced, or obsoleted by other documents at any 31 time. It is inappropriate to use Internet-Drafts as reference 32 material or to cite them other than as "work in progress." 34 This Internet-Draft will expire on August 10, 2019. 36 Copyright Notice 38 Copyright (c) 2019 IETF Trust and the persons identified as the 39 document authors. All rights reserved. 41 This document is subject to BCP 78 and the IETF Trust's Legal 42 Provisions Relating to IETF Documents 43 (https://trustee.ietf.org/license-info) in effect on the date of 44 publication of this document. Please review these documents 45 carefully, as they describe your rights and restrictions with respect 46 to this document. Code Components extracted from this document must 47 include Simplified BSD License text as described in Section 4.e of 48 the Trust Legal Provisions and are provided without warranty as 49 described in the Simplified BSD License. 51 Table of Contents 53 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 54 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3 55 2. Data Model . . . . . . . . . . . . . . . . . . . . . . . . . 3 56 2.1. Options . . . . . . . . . . . . . . . . . . . . . . . . . 3 57 2.2. Option Sequences . . . . . . . . . . . . . . . . . . . . 5 58 3. CBOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 59 4. Python . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 60 4.1. Reference Resolution . . . . . . . . . . . . . . . . . . 9 61 4.2. URI Recomposition . . . . . . . . . . . . . . . . . . . . 10 62 4.3. CoAP Encoding . . . . . . . . . . . . . . . . . . . . . . 12 63 5. Security Considerations . . . . . . . . . . . . . . . . . . . 14 64 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 14 65 7. References . . . . . . . . . . . . . . . . . . . . . . . . . 14 66 7.1. Normative References . . . . . . . . . . . . . . . . . . 14 67 7.2. Informative References . . . . . . . . . . . . . . . . . 15 68 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 15 69 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 15 71 1. Introduction 73 Uniform Resource Identifier (URI) references [RFC3986] are the 74 standard way to link to resources in hypertext formats such as HTML 75 [W3C.REC-html52-20171214] or the HTTP "Link" header field [RFC8288]. 76 A URI reference is either a URI or a relative reference that must be 77 resolved against a base URI. 79 URI references are strings of characters chosen from the repertoire 80 of US-ASCII characters. The individual components of a URI reference 81 are delimited by a number of reserved characters, which necessitates 82 the use of percent-encoding when these reserved characters are used 83 in a non-delimiting function. One component can also contain special 84 dot-segments that affect how the component is to be interpreted. The 85 resolution of URI references involves parsing the character string 86 into its components, combining those components with the components 87 of a base URI, merging path components, removing dot-segments, and 88 recomposing the result back into a character string. 90 Overall, the proper processing of URIs is quite complicated. This 91 can be a problem in particular in constrained environments [RFC7228], 92 where devices often have severe code size limitations. As a result, 93 many implementations in these environments choose to support only an 94 ad-hoc, informally-specified, bug-ridden, non-interoperable subset of 95 half of the URI standard. 97 This document introduces Constrained Internationalized Resource 98 Identifier (CIRI) references, an alternate serialization of URI 99 references that encodes the URI components in Concise Binary Object 100 Representation (CBOR) [RFC7049] instead of a string of characters. 101 Assuming an implementation of CBOR is already present on a device, 102 typical operations on URI references such as parsing, reference 103 resolution, and comparison can be implemented more easily than for 104 character strings. A full implementation that covers all corner 105 cases is intended to be implementable in a relatively small amount of 106 code. 108 As a result of the simplification, CIRI references are not capable of 109 expressing all URI references permitted by the syntax of RFC 3986. 110 (Hence the "constrained" in "Constrained Internationalized Resource 111 Identifiers".) The supported subset includes all Constrained 112 Application Protocol (CoAP) URIs [RFC7252], most Hypertext Transfer 113 Protocol (HTTP) URIs [RFC7230], and many other URIs that function as 114 resource locators. 116 1.1. Notational Conventions 118 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 119 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 120 "OPTIONAL" in this document are to be interpreted as described in BCP 121 14 [RFC2119] [RFC8174] when, and only when, they appear in all 122 capitals, as shown here. 124 Terms defined in this document appear in _cursive_ where they are 125 introduced. 127 2. Data Model 129 The data model for CIRI references is very similar to the 130 serialization of the request URI in CoAP messages [RFC7252]: The 131 components of a URI reference are encoded as a sequence of _options_, 132 where each path segment and query parameter becomes its own option. 133 Every option consists of an _option number_ identifying the type of 134 option (scheme, host name, path segment, etc.) and an _option value_. 136 2.1. Options 138 The following types of options are defined: 140 scheme 141 Specifies the URI scheme. The option value can be any Unicode 142 string matching the "scheme" rule described in Section 3.1 of RFC 143 3986 [RFC3986]. 145 host.name 146 Specifies the host of the URI authority as a registered name. The 147 option value can be any Unicode string matching the specifications 148 of the URI scheme. 150 host.ip 151 Specifies the host of the URI authority as an IPv4 address or an 152 IPv6 address. The option value is a byte string with a length of 153 either 4 or 16 bytes, respectively. 155 port 156 Specifies the port number of the URI authority. The option value 157 is an integer in the range from 0 to 65535. 159 path.type 160 Specifies the type of the URI path for reference resolution. The 161 option value is an integer in the range from 0 to 127, named as 162 follows: 164 0 - absolute-path 165 1 - append-relation 166 2 - append-path 167 3 - relative-path 168 4 - relative-path-1up 169 5 - relative-path-2up 170 6 - relative-path-3up 171 7 - relative-path-4up 172 ... 174 path 175 Specifies one segment of the URI path. The option value can be 176 any Unicode string with the exception of "." and "..". This 177 option can occur more than once. 179 query 180 Specifies one argument of the URI query. The option value can be 181 any Unicode string. This option can occur more than once. 183 fragment 184 Specifies the fragment identifier. The option value can be any 185 Unicode string. 187 No percent-encoding is performed in option values. 189 2.2. Option Sequences 191 _ host.name _ 192 ____ scheme __/ \___ port _ 193 \ \________/ \__ host.ip __/ / \ 194 \__________________________/ ________/ 195 \ / ________ _________ 196 \ / / \ / \ 197 \__________ path.type __\_\_ path _/__\_ query _/__ fragment __ 198 \___________/ \________/ \_________/ \__________/ 200 Figure 1: Structure of a Well-Formed Sequence of Options 202 A sequence of options is considered _well-formed_ if: 204 o the sequence of options is empty or starts with a "scheme", 205 "host.name", "host.ip", "port", "path.type", "path", "query", or 206 "fragment" option; 208 o any "scheme" option is followed by either a "host.name" or a 209 "host.ip" option; 211 o any "host.name" option is followed by a "port" option; 213 o any "host.ip" option is followed by a "port" option; 215 o any "port" option is followed by a "path", "query", or "fragment" 216 option or is at the end of the sequence; 218 o any "path.type" option is followed by a "path", "query", or 219 "fragment" option or is at the end of the sequence; 221 o any "path" option is followed by a "path", "query", or "fragment" 222 option or is at the end of the sequence; 224 o any "query" option is followed by a "query" or "fragment" option 225 or is at the end of the sequence; and 227 o any "fragment" option is at the end of the sequence. 229 A well-formed sequence of options is considered _absolute_ if the 230 sequence of options starts with a "scheme" option. 232 A well-formed sequence of options is considered _relative_ if the 233 sequence of options is empty or starts with an option other than a 234 "scheme" option. 236 An absolute sequence of options is considered _normalized_ if the 237 result of resolving the sequence of options against any base is equal 238 to the input. (It doesn't matter what base it is resolved against, 239 since it is already absolute.) 241 The following operations can be performed on a sequence of options: 243 resolve(href, base) 244 Resolves a well-formed sequence of options `href` against an 245 absolute sequence of options `base`. This operation MUST be 246 performed by applying any algorithm that is functionally 247 equivalent to the reference implementation in Section 4.1 of this 248 document. 250 relative(href, base) 251 Makes an absolute sequence of options `href` relative to an 252 absolute sequence of options `base`. This operation MUST be 253 performed by applying any algorithm that returns a sequence of 254 options such that `resolve(relative(h, b), b)` is equal to `h` 255 given the same `b`. 257 recompose(href) 258 Recomposes a URI from an absolute sequence of options `href`. This 259 operation MUST be performed by applying any algorithm that is 260 functionally equivalent to the reference implementation in 261 Section 4.2 of this document. 263 To reduce variability, it is RECOMMENDED to uppercase the letters 264 in the hexadecimal notation when percent-encoding octets [RFC3986] 265 and to follow the recommendations of Section 4 of RFC 5952 for the 266 text representation of IPv6 addresses [RFC5952]. 268 decompose(str) 269 Decomposes a URI `str` into a sequence of options. This operation 270 MUST be performed by applying any algorithm that returns a 271 sequence of options such that `recompose(decompose(x))` is 272 equivalent to `x`. 274 coap(href) 275 Constructs CoAP options from an absolute, normalized sequence of 276 options. This operation MUST be performed by recomposing the 277 sequence of options to a URI (as described above) and decomposing 278 the URI into CoAP options (as specified in Section 6.4 of RFC 279 7252). A concise implementation of this algorithm is illustrated 280 in Section 4.3 of this document. 282 3. CBOR 284 In Concise Binary Object Representation (CBOR) [RFC7049], a sequence 285 of options is encoded as an array that contains the option numbers 286 and option values in alternating order. 288 The structure can be described in the Concise Data Definition 289 Language (CDDL) [I-D.ietf-cbor-cddl] as follows: 291 ciri = [?(scheme: 1, text .regexp "[A-Za-z][A-Za-z0-9+.-]*"), 292 ?(host.name: 2, text // 293 host.ip: 3, bytes .size 4 / bytes .size 16), 294 ?(port: 4, 0..65535), 295 ?(path.type: 5, 0..127), 296 *(path: 6, text), 297 *(query: 7, text), 298 ?(fragment: 8, text)] 300 Example: 302 [1, "coap", 3, h'20010DB8000000000000000000000001', 4, 5683, 6, 303 ".well-known", 6, "core"] 305 [5, 0, 6, ".well-known", 6, "core", 7, "rt=temperature-c"] 307 4. Python 309 In Python, a sequence of options is encoded as a list of tuples, 310 where each tuple contains one option number and one option value. 312 The following Python 3.6 code illustrates how to check a sequence of 313 options for being well-formed, absolute, and relative. 315 317 import enum 319 class Option(enum.IntEnum): 320 _BEGIN = 0 321 SCHEME = 1 322 HOST_NAME = 2 323 HOST_IP = 3 324 PORT = 4 325 PATH_TYPE = 5 326 PATH = 6 327 QUERY = 7 328 FRAGMENT = 8 329 _END = 9 331 class PathType(enum.IntEnum): 332 ABSOLUTE_PATH = 0 333 APPEND_RELATION = 1 334 APPEND_PATH = 2 335 RELATIVE_PATH = 3 336 RELATIVE_PATH_1UP = 4 337 RELATIVE_PATH_2UP = 5 338 RELATIVE_PATH_3UP = 6 339 RELATIVE_PATH_4UP = 7 341 _TRANSITIONS = ([Option.SCHEME, Option.HOST_NAME, Option.HOST_IP, 342 Option.PORT, Option.PATH_TYPE, Option.PATH, Option.QUERY, 343 Option.FRAGMENT, Option._END], 344 [Option.HOST_NAME, Option.HOST_IP], 345 [Option.PORT], 346 [Option.PORT], 347 [Option.PATH, Option.QUERY, Option.FRAGMENT, Option._END], 348 [Option.PATH, Option.QUERY, Option.FRAGMENT, Option._END], 349 [Option.PATH, Option.QUERY, Option.FRAGMENT, Option._END], 350 [Option.QUERY, Option.FRAGMENT, Option._END], 351 [Option._END]) 353 def is_well_formed(href): 354 previous = Option._BEGIN 355 for option, _ in href: 356 if option not in _TRANSITIONS[previous]: 357 return False 358 previous = option 359 if Option._END not in _TRANSITIONS[previous]: 360 return False 361 return True 363 def is_absolute(href): 364 return is_well_formed(href) and \ 365 (len(href) != 0 and href[0][0] == Option.SCHEME) 367 def is_relative(href): 368 return is_well_formed(href) and \ 369 (len(href) == 0 or href[0][0] != Option.SCHEME) 371 373 Examples: 375 [(Option.SCHEME, "coap"), (Option.HOST_IP, b"\x20\x01\x0D\xB8\x00\ 376 x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), (Option.PORT, 377 5683), (Option.PATH, ".well-known"), (Option.PATH, "core")] 379 [(Option.PATH_TYPE, PathType.ABSOLUTE_PATH), (Option.PATH, ".well- 380 known"), (Option.PATH, "core"), (Option.QUERY, "rt=temperature- 381 c")] 383 4.1. Reference Resolution 385 The following Python 3.6 code defines how to resolve a sequence of 386 options that might be relative to a given base. 388 390 def resolve(base, href, relation=0): 391 if not is_absolute(base) or not is_well_formed(href): 392 return None 393 result = [] 394 option = Option.FRAGMENT 395 if len(href) != 0: 396 option = href[0][0] 397 if option == Option.HOST_IP: 398 option = Option.HOST_NAME 399 elif option == Option.PATH_TYPE: 400 type = href[0][1] 401 href = href[1:] 402 elif option == Option.PATH: 403 type = PathType.RELATIVE_PATH 404 option = Option.PATH_TYPE 405 if option != Option.PATH_TYPE or type == PathType.ABSOLUTE_PATH: 406 _copy_until(base, result, option) 407 else: 408 _copy_until(base, result, Option.QUERY) 409 if type == PathType.APPEND_RELATION: 410 _append_and_normalize(result, Option.PATH, str(relation)) 411 while type > PathType.APPEND_PATH: 412 if len(result) == 0 or result[-1][0] != Option.PATH: 413 break 414 del result[-1] 415 type -= 1 416 _copy_until(href, result, Option._END) 417 _append_and_normalize(result, Option._END, None) 418 return result 420 def _copy_until(input, output, end): 421 for option, value in input: 422 if option >= end: 423 break 424 _append_and_normalize(output, option, value) 426 def _append_and_normalize(output, option, value): 428 if option > Option.PATH: 429 if len(output) >= 2 and \ 430 output[-1] == (Option.PATH, '') and ( 431 output[-2][0] < Option.PATH_TYPE or ( 432 output[-2][0] == Option.PATH_TYPE and 433 output[-2][1] == PathType.ABSOLUTE_PATH)): 434 del output[-1] 435 if option > Option.FRAGMENT: 436 return 437 output.append((option, value)) 439 441 4.2. URI Recomposition 443 The following Python 3.6 code defines how to recompose a URI from an 444 absolute sequence of options. 446 448 def recompose(href): 449 if not is_absolute(href): 450 return None 451 result = '' 452 no_path = True 453 first_query = True 454 for option, value in href: 455 if option == Option.SCHEME: 456 result += value + ':' 457 elif option == Option.HOST_NAME: 458 result += '//' + _encode_reg_name(value) 459 elif option == Option.HOST_IP: 460 result += '//' + _encode_ip_address(value) 461 elif option == Option.PORT: 462 result += ':' + _encode_port(value) 463 elif option == Option.PATH: 464 result += '/' + _encode_path_segment(value) 465 no_path = False 466 elif option == Option.QUERY: 467 if no_path: 468 result += '/' 469 no_path = False 470 result += '?' if first_query else '&' 471 result += _encode_query_argument(value) 472 first_query = False 473 elif option == Option.FRAGMENT: 474 if no_path: 475 result += '/' 476 no_path = False 477 result += '#' + _encode_fragment(value) 478 if no_path: 479 result += '/' 480 no_path = False 481 return result 483 def _encode_reg_name(s): 484 return ''.join(c if _is_reg_name_char(c) 485 else _encode_pct(c) for c in s) 487 def _encode_ip_address(b): 488 if len(b) == 4: 489 return '.'.join(str(c) for c in b) 490 elif len(b) == 16: 491 return '[' + ... + ']' # see RFC 5952 493 def _encode_port(p): 494 return str(p) 496 def _encode_path_segment(s): 497 return ''.join(c if _is_segment_char(c) 498 else _encode_pct(c) for c in s) 500 def _encode_query_argument(s): 501 return ''.join(c if _is_query_char(c) and c not in '&' 502 else _encode_pct(c) for c in s) 504 def _encode_fragment(s): 505 return ''.join(c if _is_fragment_char(c) 506 else _encode_pct(c) for c in s) 508 def _encode_pct(s): 509 return ''.join('%{0:0>2X}'.format(c) for c in s.encode('utf-8')) 511 def _is_reg_name_char(c): 512 return _is_unreserved(c) or _is_sub_delim(c) 514 def _is_segment_char(c): 515 return _is_pchar(c) 517 def _is_query_char(c): 518 return _is_pchar(c) or c in '/?' 520 def _is_fragment_char(c): 521 return _is_pchar(c) or c in '/?' 523 def _is_pchar(c): 525 return _is_unreserved(c) or _is_sub_delim(c) or c in ':@' 527 def _is_unreserved(c): 528 return _is_alpha(c) or _is_digit(c) or c in '-._~' 530 def _is_alpha(c): 531 return c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \ 532 'abcdefghijklmnopqrstuvwxyz' 534 def _is_digit(c): 535 return c in '0123456789' 537 def _is_sub_delim(c): 538 return c in '!$&\'()*+,;=' 540 542 4.3. CoAP Encoding 544 The following Python 3.6 code illustrates how to construct CoAP 545 options from an absolute sequence of options. For simplicity, the 546 code does not omit CoAP options with their default value. 548 550 def coap(href, to_proxy=False): 551 if not is_absolute(href): 552 return None 553 result = b'' 554 previous = 0 555 for option, value in href: 556 if option == Option.SCHEME: 557 pass 558 elif option == Option.HOST_NAME: 559 opt = 3 # Uri-Host 560 val = value.encode('utf-8') 561 result += _encode_coap_option(opt - previous, val) 562 previous = opt 563 elif option == Option.HOST_IP: 564 opt = 3 # Uri-Host 565 if len(value) == 4: 566 val = '.'.join(str(c) for c in value).encode('utf-8') 567 elif len(value) == 16: 568 val = b'[' + ... + b']' # see RFC 5952 569 result += _encode_coap_option(opt - previous, val) 570 previous = opt 571 elif option == Option.PORT: 572 opt = 7 # Uri-Port 573 val = value.to_bytes((value.bit_length() + 7) // 8, 'big') 574 result += _encode_coap_option(opt - previous, val) 575 previous = opt 576 elif option == Option.PATH: 577 opt = 11 # Uri-Path 578 val = value.encode('utf-8') 579 result += _encode_coap_option(opt - previous, val) 580 previous = opt 581 elif option == Option.QUERY: 582 opt = 15 # Uri-Query 583 val = value.encode('utf-8') 584 result += _encode_coap_option(opt - previous, val) 585 previous = opt 586 elif option == Option.FRAGMENT: 587 pass 588 if to_proxy: 589 (option, value) = href[0] 590 opt = 39 # Proxy-Scheme 591 val = value.encode('utf-8') 592 result += _encode_coap_option(opt - previous, val) 593 previous = opt 594 return result 596 def _encode_coap_option(delta, value): 597 length = len(value) 598 delta_nibble = _encode_coap_option_nibble(delta) 599 length_nibble = _encode_coap_option_nibble(length) 600 result = bytes([delta_nibble << 4 | length_nibble]) 601 if delta_nibble == 13: 602 delta -= 13 603 result += bytes([delta]) 604 elif delta_nibble == 14: 605 delta -= 256 + 13 606 result += bytes([delta >> 8, delta & 255]) 607 if length_nibble == 13: 608 length -= 13 609 result += bytes([length]) 610 elif length_nibble == 14: 611 length -= 256 + 13 612 result += bytes([length >> 8, length & 255]) 613 result += value 614 return result 616 def _encode_coap_option_nibble(n): 617 if n < 13: 618 return n 619 elif n < 256 + 13: 620 return 13 622 elif n < 65536 + 256 + 13: 623 return 14 625 627 5. Security Considerations 629 Parsers must operate on input that is assumed to be untrusted. This 630 means that parsers MUST fail gracefully in the face of malicious 631 inputs. Additionally, parsers MUST be prepared to deal with resource 632 exhaustion (e.g., resulting from the allocation of big data items) or 633 exhaustion of the call stack (stack overflow). See Section 8 of RFC 634 7049 [RFC7049] for security considerations relating to CBOR. 636 The security considerations discussed in Section 7 of RFC 3986 637 [RFC3986] also apply to Constrained Internationalized Resource 638 Identifiers. 640 6. IANA Considerations 642 This document has no IANA actions. 644 7. References 646 7.1. Normative References 648 [I-D.ietf-cbor-cddl] 649 Birkholz, H., Vigano, C., and C. Bormann, "Concise data 650 definition language (CDDL): a notational convention to 651 express CBOR and JSON data structures", draft-ietf-cbor- 652 cddl-06 (work in progress), November 2018. 654 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 655 Requirement Levels", BCP 14, RFC 2119, 656 DOI 10.17487/RFC2119, March 1997, 657 . 659 [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform 660 Resource Identifier (URI): Generic Syntax", STD 66, 661 RFC 3986, DOI 10.17487/RFC3986, January 2005, 662 . 664 [RFC7049] Bormann, C. and P. Hoffman, "Concise Binary Object 665 Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049, 666 October 2013, . 668 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 669 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 670 May 2017, . 672 7.2. Informative References 674 [RFC5952] Kawamura, S. and M. Kawashima, "A Recommendation for IPv6 675 Address Text Representation", RFC 5952, 676 DOI 10.17487/RFC5952, August 2010, 677 . 679 [RFC7228] Bormann, C., Ersue, M., and A. Keranen, "Terminology for 680 Constrained-Node Networks", RFC 7228, 681 DOI 10.17487/RFC7228, May 2014, 682 . 684 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 685 Protocol (HTTP/1.1): Message Syntax and Routing", 686 RFC 7230, DOI 10.17487/RFC7230, June 2014, 687 . 689 [RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained 690 Application Protocol (CoAP)", RFC 7252, 691 DOI 10.17487/RFC7252, June 2014, 692 . 694 [RFC8288] Nottingham, M., "Web Linking", RFC 8288, 695 DOI 10.17487/RFC8288, October 2017, 696 . 698 [W3C.REC-html52-20171214] 699 Faulkner, S., Eicholz, A., Leithead, T., Danilo, A., and 700 S. Moon, "HTML 5.2", World Wide Web Consortium 701 Recommendation REC-html52-20171214, December 2017, 702 . 704 Acknowledgements 706 Thanks to Christian Amsuess, Ari Keranen, and Dave Thaler for helpful 707 comments and discussions that have shaped the document. 709 Author's Address 710 Klaus Hartke 711 Ericsson 712 Torshamnsgatan 23 713 Stockholm SE-16483 714 Sweden 716 Email: klaus.hartke@ericsson.com