RFC 8075

Guidelines for Mapping Implementations: HTTP to the Constrained Application Protocol (CoAP)

๐Ÿ“… published February 2017, from ietf

Okay bestie, let's get into it! โœจ This is part 1 of 8, so hold tight, there's more coming. ๐ŸŽ€

The title block is giving the whole vibe, so here's the tea. ๐Ÿซ– This is RFC 8075, titled "Guidelines for Mapping Implementations: HTTP to the Constrained Application Protocol (CoAP)". ๐Ÿ’– It was written by A. Castellani (University of Padova), S. Loreto (Ericsson), A. Rahman (InterDigital Communications, LLC), T. Fossati (Nokia), and E. Dijk (Philips Lighting). ๐Ÿงš It's a Standards Track document, dated February 2017, with ISSN 2070-1721. ๐ŸŒˆ It doesn't obsolete or update any other RFCs, so it's a clean slate, no drama. ๐Ÿ’…

Abstract

okay so the abstract is the quick pitch. ๐Ÿฆ‹ This doc is basically a reference guide for building a cross-protocol network proxy that translates from HTTP to CoAP. โœจ The goal is that an HTTP client can reach a CoAP server through that proxy, no cap. ๐Ÿซถ It explains how an HTTP request turns into a CoAP request, and how the CoAP response gets turned back into an HTTP response. ๐Ÿ”ฅ It also covers guidance on status code, URI, and media type mappings, plus extra interworking advice. ๐Ÿ‘‘ Lowkey the whole point is making this interop smooth. ๐Ÿ’œ

Status of This Memo

ngl this section is the official paperwork, but it's still iconic. ๐Ÿ’… It says this is an Internet Standards Track document. ๐ŸŒธ It's a product of the Internet Engineering Task Force (IETF), it represents the consensus of the IETF community, it got public review, and the Internet Engineering Steering Group (IESG) approved it for publication. ๐ŸŽ€ If you want more on Internet Standards, check Section 2 of RFC 7841. ๐Ÿฆ‹ For the current status, errata, and where to send feedback, head to http://www.rfc-editor.org/info/rfc8075. โœจ

okay this bit is the legal stuff, and it's important, so read it. ๐Ÿ’– The document is Copyright (c) 2017 IETF Trust and the persons identified as the document authors. All rights reserved. ๐Ÿ”ฅ It's subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as in effect on the date of publication. ๐ŸŒˆ Please review those carefully, bestie, because they describe your rights and restrictions. ๐Ÿซถ Any Code Components pulled out of this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Simplified BSD License. ๐Ÿ’…

Table of Contents

Here's the full map of the doc, with page numbers exactly as the original has them. ๐Ÿ—บ๏ธ

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   5
3.  HTTP-to-CoAP Proxy  . . . . . . . . . . . . . . . . . . . . .   6
4.  Use Cases . . . . . . . . . . . . . . . . . . . . . . . . . .   7
5.  URI Mapping . . . . . . . . . . . . . . . . . . . . . . . . .   7
  5.1.  URI Terminology . . . . . . . . . . . . . . . . . . . . .   8
  5.2.  Null Mapping  . . . . . . . . . . . . . . . . . . . . . .   9
  5.3.  Default Mapping . . . . . . . . . . . . . . . . . . . . .   9
    5.3.1.  Optional Scheme Omission  . . . . . . . . . . . . . .   9
    5.3.2.  Encoding Caveats  . . . . . . . . . . . . . . . . . .  10
  5.4.  URI Mapping Template  . . . . . . . . . . . . . . . . . .  10
    5.4.1.  Simple Form . . . . . . . . . . . . . . . . . . . . .  10
    5.4.2.  Enhanced Form . . . . . . . . . . . . . . . . . . . .  12
  5.5.  Discovery . . . . . . . . . . . . . . . . . . . . . . . .  13
    5.5.1.  Examples  . . . . . . . . . . . . . . . . . . . . . .  14
6.  Media Type Mapping  . . . . . . . . . . . . . . . . . . . . .  15
  6.1.  Overview  . . . . . . . . . . . . . . . . . . . . . . . .  15
  6.2.  'application/coap-payload' Media Type . . . . . . . . . .  16
  6.3.  Loose Media Type Mapping  . . . . . . . . . . . . . . . .  17
  6.4.  Media Type to Content-Format Mapping Algorithm  . . . . .  18
  6.5.  Content Transcoding . . . . . . . . . . . . . . . . . . .  19
    6.5.1.  General . . . . . . . . . . . . . . . . . . . . . . .  19
    6.5.2.  CoRE Link Format  . . . . . . . . . . . . . . . . . .  20
  6.6.  Diagnostic Payloads . . . . . . . . . . . . . . . . . . .  20
7.  Response Code Mapping . . . . . . . . . . . . . . . . . . . .  21
8.  Additional Mapping Guidelines . . . . . . . . . . . . . . . .  23
  8.1.  Caching and Congestion Control  . . . . . . . . . . . . .  23
  8.2.  Cache Refresh via Observe . . . . . . . . . . . . . . . .  24
  8.3.  Use of CoAP Block-Wise Transfer . . . . . . . . . . . . .  24
  8.4.  CoAP Multicast  . . . . . . . . . . . . . . . . . . . . .  25
  8.5.  Timeouts  . . . . . . . . . . . . . . . . . . . . . . . .  26
9.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  26
  9.1.  New 'core.hc' Resource Type . . . . . . . . . . . . . . .  26
  9.2.  New 'coap-payload' Internet Media Type  . . . . . . . . .  26
10. Security Considerations . . . . . . . . . . . . . . . . . . .  28
  10.1.  Multicast  . . . . . . . . . . . . . . . . . . . . . . .  29
  10.2.  Traffic Overflow . . . . . . . . . . . . . . . . . . . .  29
  10.3.  Handling Secured Exchanges . . . . . . . . . . . . . . .  30
  10.4.  URI Mapping  . . . . . . . . . . . . . . . . . . . . . .  30
11. References  . . . . . . . . . . . . . . . . . . . . . . . . .  31
  11.1.  Normative References . . . . . . . . . . . . . . . . . .  31
  11.2.  Informative References . . . . . . . . . . . . . . . . .  32
Appendix A.  Media Type Mapping Source Code . . . . . . . . . . .  35
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . .  39
Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  40

1. Introduction โœจ

okay so the big picture is that CoAP (the Constrained Application Protocol, [RFC7252]) was built with two goals in mind. ๐Ÿฆ‹ First, it's an application protocol made for constrained environments. ๐ŸŒธ Second, it's meant to slot easily into REST-based architectures like the web, which is the Representational State Transfer (REST) [Fielding] vibe. ๐Ÿ’– That second goal is why CoAP was designed to play nicely with HTTP [RFC7230] through an intermediary proxy that does the cross-protocol conversion. ๐Ÿซถ

Section 10 of [RFC7252] covers the basics of both the CoAP-to-HTTP and HTTP-to-CoAP cross-protocol mapping process. ๐Ÿ’… BUT, bestie, [RFC7252] mostly focuses on basic request method mapping and simple response code mapping, and it leaves a whole lot of proxy details for later. ๐Ÿ”ฅ So a big goal of this document is to set a consistent set of guidelines that an HTTP-to-CoAP proxy implementation should adhere to. ๐Ÿ‘‘ The key benefit is less variation between proxies, which means better interoperability between an HTTP client and a CoAP server, no matter which proxy does the mapping. ๐ŸŒˆ (Like, a proxy from vendor A that follows these guidelines can be swapped out for a vendor B proxy that also follows them, and the API semantics don't break. ๐ŸŽ€)

This document describes HTTP mappings for protocol elements defined in the base CoAP specification [RFC7252] and in the CoAP block-wise transfer specification [RFC7959]. ๐Ÿงš Any CoAP extensions (new methods, response codes, options, content-formats) are responsible for describing their own HTTP mappings, if they apply. โญ

Here's how the rest of the doc is laid out, bestie:

  • Section 2 defines proxy terminology; ๐Ÿ“–
  • Section 3 introduces the HTTP-to-CoAP proxy; ๐Ÿฆ‹
  • Section 4 lists use cases where HTTP clients need to contact CoAP servers; ๐Ÿ’œ
  • Section 5 introduces a null, default, and advanced HTTP-to-CoAP URI mapping syntax; ๐ŸŒธ
  • Section 6 describes how to map HTTP media types to CoAP content-formats, and vice versa; ๐ŸŽ€
  • Section 7 describes how to map CoAP responses to HTTP responses; โœจ
  • Section 8 describes additional mapping guidelines related to caching, congestion, multicast, timeouts, etc.; and ๐Ÿซถ
  • Section 10 discusses the possible security impact of HTTP-to-CoAP protocol mapping. ๐Ÿ’€

2. Terminology ๐ŸŽ€

okay so this section is where we get our vocab straight. ๐Ÿ’…

The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. ๐Ÿ”ฅ

This spec requires readers to be familiar with the vocabulary and concepts in [RFC7228], especially the terms "constrained nodes" and "constrained networks". ๐ŸŒˆ Readers MUST also be familiar with all the terminology of the normative references listed in this document, especially [RFC7252] (CoAP) and [RFC7230] (HTTP). ๐Ÿ‘‘ On top of that, this spec uses the following terms:

HC Proxy ๐Ÿ’– : A proxy doing a cross-protocol mapping, which in this doc means an HTTP-to-CoAP (HC) mapping. ๐Ÿซถ Specifically, the HC Proxy acts as an HTTP server and a CoAP client. ๐Ÿฆ‹ It can take on the role of a forward, reverse, or interception Proxy. โœจ

Application Level Gateway (ALG) ๐Ÿงš : An application-specific translation agent that lets an application on a host in one address realm connect to its counterpart on a host in a different realm, transparently. ๐ŸŒธ See Section 2.9 of [RFC2663]. ๐Ÿ’…

forward-proxy ๐ŸŒท : A message-forwarding agent that the HTTP client selects, usually through local configuration rules, to receive requests for some type(s) of absolute URI and to try to satisfy those requests by translating them to the protocol the absolute URI indicates. ๐ŸŽ€ The user agent decides (is willing) to use the proxy as the forwarding/dereferencing agent for a predefined subset of the URI space. ๐Ÿ’œ In [RFC7230], this is called a "proxy". ๐Ÿ”ฅ [RFC7252] defines forward-proxy similarly. ๐ŸŒˆ

reverse-proxy ๐Ÿฆ‹ : As in [RFC7230], a receiving agent that sits as a layer above some other server(s) and translates the received requests into the underlying server's protocol. โœจ A reverse-proxy behaves as an origin (HTTP) server on its connection from the HTTP client. ๐Ÿ‘‘ The HTTP client uses the "origin-form" (Section 5.3.1 of [RFC7230]) as a request-target URI. ๐Ÿซถ (Note that a reverse-proxy looks like an origin server to an HTTP client, while a forward-proxy does not. ๐Ÿ’… So when a client talks to a reverse-proxy, it might not even realise it's talking to a proxy at all. ๐Ÿ™ˆ)

interception proxy ๐Ÿ“ : As in [RFC3040], a proxy that receives inbound HTTP traffic through traffic redirection, and the HTTP client is none the wiser. ๐Ÿ’– It's transparent to the HTTP client. โœจ


That's part 1 done, bestie! ๐Ÿ’œ Reply for part 2 when you're ready and we'll keep the slay going. ๐Ÿซถ

3. HTTP-to-CoAP Proxy โœจ

okay so the HC Proxy is the bestie in the middle ๐Ÿงš An HTTP client shows up wanting a resource that lives on a CoAP server, and the HC Proxy takes that HTTP request, maps it into the matching CoAP request, and forwards it to the right CoAP server. Then it takes the CoAP response, maps it back into an HTTP response, and sends it home to the HTTP client ๐Ÿ’Œ

Section 10.2 of [RFC7252] already lays down the basic normative requirements for HTTP-to-CoAP mapping ๐Ÿ“œ This document adds extra details and guidance for building an HC Proxy, so it's like the sequel with the good tips ๐Ÿ’…

                                               Constrained Network
                                              .-------------------.
                                             /      .------.       \
                                            /       | CoAP |        \
                                           /        |server|         \
                                          ||        '------'         ||
                                          ||                         ||
     .--------.  HTTP Request   .------------.  CoAP Req  .------.   ||
     |  HTTP  |---------------->|HTTP-to-CoAP|----------->| CoAP |   ||
     | Client |<----------------|   Proxy    |<-----------|server|   ||
     '--------'  HTTP Response  '------------'  CoAP Resp '------'   ||
                                          ||                         ||
                                          ||   .------.              ||
                                          ||   | CoAP |              ||
                                           \   |server|  .------.    /
                                            \  '------'  | CoAP |   /
                                             \           |server|  /
                                              \          '------' /
                                               '-----------------'

             Figure 1: HTTP-To-CoAP Proxy Deployment Scenario

Figure 1 is the vibe check for a typical setup ๐Ÿ‘€ The HC Proxy sits right on the edge of the constrained network domain and acts as an ALG, which is basically a gatekeeper ๐Ÿšช It only lets one very specific kind of traffic through, meaning authorized inbound HTTP requests and their matching outbound CoAP responses. Everything else stays segregated inside its own network segment ๐Ÿ”’ iykyk ๐Ÿฆ‹

4. Use Cases

okay so let's look at a few situations where HTTP-to-CoAP translation might actually come in clutch ๐ŸŽ€ There are three use cases:

  1. Legacy building control application without CoAP: A building control app that only speaks HTTP, not CoAP, can check the status of CoAP sensors and/or control actuators through an HC Proxy ๐Ÿข
  2. Making sensor data available to third parties on the web: For demo or public interest purposes, an HC Proxy may be set up to expose a CoAP sensor's contents to the whole world via the web (HTTP and/or HTTPS) ๐ŸŒ Some sensors only accept secure 'coaps' requests, so the proxy gets configured to translate requests to those devices accordingly ๐Ÿ” The HC Proxy is also configured to only pass through GET requests, all in order to protect the constrained network ๐Ÿ›ก๏ธ
  3. Smartphone and home sensor: A smartphone can directly access a CoAP home sensor using a mutually authenticated 'https' request ๐Ÿ“ฑ This works provided its home router runs an HC Proxy and is configured with the appropriate certificate ๐Ÿชช An HTML5 [W3C.REC-html5-20141028] app on the smartphone can provide a friendly UI using the standard (HTTP) networking functions of HTML5 โœจ

A key point across these use cases is what the URI looks like when the HTTP client sends its request to the HC Proxy ๐Ÿ‘€ In use case #1, there will be no information related to 'coap' or 'coaps' embedded in the HTTP URI, because it's a legacy HTTP client sending the request ๐Ÿ™ˆ Use case #2 is also expected to be similar. In contrast, in use case #3, it is likely that the HTTP client will specifically embed information related to 'coap' or 'coaps' in the HTTP URI of the request to the HC Proxy ๐Ÿ’œ


5. URI Mapping ๐Ÿ—บ๏ธ

Okay so technically a CoAP URI could be used directly by an HTTP client to dereference a CoAP resource through an HC Proxy ๐Ÿค“ BUT the reality is that all major web browsers, networking libraries, and command-line tools do not allow making HTTP requests using URIs with a scheme of 'coap' or 'coaps' ๐Ÿ’€ Main character problem, honestly.

So web apps need to embed or "pack" a CoAP URI into an HTTP URI so it can be (non-destructively) transported from the HTTP client to the HC Proxy ๐Ÿ“ฆ Then the HC Proxy can "unpack" the CoAP URI and dereference it with a CoAP request to the target server ๐ŸŽ

URI mapping is the term this document uses for turning the URI of a CoAP resource into an HTTP URI so that:

  • The requesting HTTP client can handle it; and
  • The receiving HC Proxy can extract the intended CoAP URI unambiguously.

The rest of this section covers:

  • The default mechanism for mapping a CoAP URI into an HTTP URI;
  • The URI Template format used to express a class of CoAP-HTTP URI mapping functions; and
  • The discovery mechanism based on "Constrained RESTful Environments (CoRE) Link Format" [RFC6690] through which HC Proxy clients can dynamically learn about the supported URI mapping template(s), as well as the URI where the HC Proxy function is anchored ๐Ÿงญ

5.1. URI Terminology

In the rest of this section, these terms have a special meaning ๐Ÿ“–

HC Proxy URI: : URI that refers to the HC Proxy function. It conforms to syntax defined in Section 2.7 of [RFC7230].

Target CoAP URI: : URI that refers to the (final) CoAP resource that has to be dereferenced. It conforms to syntax defined in Section 6 of [RFC7252]. Specifically, its scheme is either 'coap' or 'coaps'.

Hosting HTTP URI: : URI that conforms to syntax in Section 2.7 of [RFC7230]. Its authority component refers to an HC Proxy, whereas a path and/or query component(s) embed the information used by an HC Proxy to extract the Target CoAP URI.

5.2. Null Mapping

The null mapping is the case where there is no Target CoAP URI appended to the HC Proxy URI ๐Ÿซฅ In other words, it's a "pure" HTTP URI that gets sent to the HC Proxy. This would typically happen in situations like use case #1 described in Section 4, and the proxy would typically be a reverse-proxy ๐Ÿ” In this scenario, the HC Proxy will determine through its own private algorithms what the Target CoAP URI should be ๐Ÿคซ

5.3. Default Mapping

The default mapping is for the Target CoAP URI to be appended as is (with the only caveat discussed in Section 5.3.2) to the HC Proxy URI, forming the Hosting HTTP URI ๐Ÿงฉ This is the effective request URI (see Section 5.5 of [RFC7230]) that the HTTP client then sends in the HTTP request to the HC Proxy ๐Ÿ“จ

For example: given an HC Proxy URI https://p.example.com/hc/ and a Target CoAP URI coap://s.example.com/light, the resulting Hosting HTTP URI would be https://p.example.com/hc/coap://s.example.com/light โœจ

Provided a correct Target CoAP URI, the Hosting HTTP URI from the default mapping will be a syntactically valid HTTP URI ๐Ÿ’ฏ Furthermore, the Target CoAP URI can always be extracted unambiguously from the Hosting HTTP URI ๐Ÿ™Œ

There is no default for the HC Proxy URI ๐Ÿซถ So it's either known in advance (like a configuration preset) or dynamically discovered using the mechanism described in Section 5.5.

The default URI mapping function SHOULD be implemented and SHOULD be activated by default in an HC Proxy, unless there are valid reasons (e.g., application specific) to use a different mapping function ๐Ÿ’œ

5.3.1. Optional Scheme Omission

When constructing a Hosting HTTP URI by embedding a Target CoAP URI, the scheme (i.e., 'coap' or 'coaps'), the scheme component delimiter (":"), and the double slash ("//") preceding the authority MAY be omitted if a local default (not defined by this document) applies ๐ŸŒธ If there's no prior mutual agreement between the client and the HC Proxy, then a Target CoAP URI without the scheme component is syntactically incorrect, and therefore:

  • It MUST NOT be emitted by clients; and
  • It MUST elicit a suitable client error status (i.e., 4xx) by the HC Proxy.
Heads up bestie: without a prior agreement, a scheme-less Target CoAP URI is a no-go ๐Ÿšซ Clients must not send it, and the HC Proxy must answer with a suitable 4xx client error status ๐Ÿ˜ญ

5.3.2. Encoding Caveats

When the authority of the Target CoAP URI is given as an IPv6address, the surrounding square brackets must be percent-encoded in the Hosting HTTP URI, in order to comply with the syntax defined in Section 3.3. of [RFC3986] for a URI path segment ๐ŸŽ€ For example: coap://[2001:db8::1]/light?on becomes https://p.example.com/hc/coap://%5B2001:db8::1%5D/light?on. (Note that the percent-encoded square brackets shall be reverted to their non-percent-encoded form when the HC Proxy unpacks the Target CoAP URI ๐Ÿ”“)

Everything else can be safely copied verbatim from the Target CoAP URI to the Hosting HTTP URI ๐Ÿซง

5.4. URI Mapping Template

This section defines a format for the URI Template [RFC6570] used by an HC Proxy to tell its clients what syntax to expect for the Hosting HTTP URI ๐Ÿ“‹ The HTTP client can then use that to construct the effective request URI to send in the HTTP request to the HC Proxy ๐Ÿš€

When instantiated, a URI mapping template is always concatenated to an HC Proxy URI provided by the HC Proxy via discovery (see Section 5.5), or by other means ๐Ÿ”—

A simple form (Section 5.4.1) and an enhanced form (Section 5.4.2) are provided to fit different users' requirements ๐Ÿ“

Both forms are expressed as Level 2 URI Templates [RFC6570] to take care of the expansion of values that are allowed to include reserved URI characters ๐Ÿงš The syntax of all URI formats is specified in this section in Augmented Backus-Naur Form (ABNF) [RFC5234].

5.4.1. Simple Form

The simple form MUST be used for mappings where the Target CoAP URI is going to be copied (using rules of Section 5.3.2) at some fixed position into the Hosting HTTP URI ๐Ÿ’…

The "tu" template variable is defined below using the ABNF rules from [RFC3986], Sections 3.2.2, 3.2.3, 3.3, and 3.4. It is intended to be used in a template definition to represent a Target CoAP URI ๐Ÿง 

  tu = [ ( "coap:" / "coaps:" ) "//" ] host [ ":" port ] path-abempty
       [ "?" query ]

Note that the same considerations as in Section 5.3.1 apply, in that the CoAP scheme may be omitted from the Hosting HTTP URI ๐ŸŒˆ

5.4.1.1. Examples โœจ

okay so all of these examples use https://p.example.com/hc/ as the HC Proxy URI ๐ŸŽ€ and each one has its own mapping template, a Target CoAP URI, and the Hosting HTTP URI it produces. they all bend away from the default template in Section 5.3 on purpose, so you can see the template variables doing their thing ๐Ÿ’…

  1. Target CoAP URI is a query argument of the Hosting HTTP URI:
?target_uri={+tu}

coap://s.example.com/light

=> https://p.example.com/hc/?target_uri=coap://s.example.com/light

whereas

coaps://s.example.com/light

=> https://p.example.com/hc/?target_uri=coaps://s.example.com/light
  1. Target CoAP URI in the path component of the Hosting HTTP URI:
forward/{+tu}

coap://s.example.com/light

=> https://p.example.com/hc/forward/coap://s.example.com/light

whereas

coaps://s.example.com/light

=> https://p.example.com/hc/forward/coaps://s.example.com/light
  1. Target CoAP URI is a query argument of the Hosting HTTP URI, and the client decides to omit the scheme because a default is agreed beforehand between client and proxy ๐Ÿฆ‹:
?coap_uri={+tu}

coap://s.example.com/light

=> https://p.example.com/hc/?coap_uri=s.example.com/light

5.4.2. Enhanced Form ๐ŸŒธ

the enhanced form is for the fancier mappings of the Target CoAP URI into the Hosting HTTP URI, the ones that just don't fit in the simple form ๐Ÿงš

There MUST be at most one instance of each of the following template variables in a URI mapping template definition:

s  = "coap" / "coaps" ; from [RFC7252], Sections 6.1 and 6.2
hp = host [":" port]  ; from [RFC3986], Sections 3.2.2 and 3.2.3
p  = path-abempty     ; from [RFC3986], Section 3.3
q  = query            ; from [RFC3986], Section 3.4
qq = [ "?" query ]    ; qq is empty if and only if 'query' is empty

the qq form is used when the path and the (optional) query components get copied verbatim from the Target CoAP URI into the Hosting HTTP URI, i.e., as {+p}{+qq}. the q form is for when the query and path get mapped as separate entities, like coap_path={+p}&coap_query={+q}. so q and qq MUST be used in mutual exclusion in a template definition ๐Ÿ™…โ€โ™€๏ธ no mixing them up!!

5.4.2.1. Examples ๐Ÿ’–

all of these examples use https://p.example.com/hc/ as the HC Proxy URI, same as before โœจ

  1. Target CoAP URI components in path segments, with the optional query in the query component:
{+s}/{+hp}{+p}{+qq}

coap://s.example.com/light

=> https://p.example.com/hc/coap/s.example.com/light

whereas

coap://s.example.com/light?on

=> https://p.example.com/hc/coap/s.example.com/light?on
  1. Target CoAP URI components split into individual query arguments ๐Ÿ“:
?s={+s}&hp={+hp}&p={+p}&q={+q}

coap://s.example.com/light

=> https://p.example.com/hc/?s=coap&hp=s.example.com&p=/light&q=

whereas

coaps://s.example.com/light?on

=> https://p.example.com/hc/?s=coaps&hp=s.example.com&p=/light&q=on

5.5. Discovery ๐Ÿ”

so the HC Proxy SHOULD publish info about where the proxy function lives and what syntax it uses, through the CoRE Link Format [RFC6690] interface. this lets site-specific needs get met while third parties can still find the proxy function ๐Ÿซถ

to make that happen, this document defines a new Resource Type, core.hc. you can use it as the value for the rt attribute in a query to the /.well-known/core resource, and that tells you where the HC Proxy function is anchored, which is the HC Proxy URI ๐Ÿ—บ๏ธ

the new target attribute hct also shows up here. it MAY be returned in a core.hc link to give you the URI mapping template for the mapping resource. if no hct attribute shows up in a returned link, the default template from Section 5.3, i.e., {+tu}, MUST be assumed. and if there IS an hct attribute, the client MUST use it to build a Hosting HTTP URI ๐Ÿ’…

the URI mapping SHOULD be discoverable (as specified in [RFC6690]) on both the HTTP and the CoAP side of the HC Proxy, with one big difference ๐Ÿ‘‘. on the CoAP side, the link for the core.hc resource always needs an explicit anchor parameter pointing at the HTTP origin [RFC6454]. on the HTTP side, the context URI of the link can just equal the HTTP origin of the discovery request, and then the anchor parameter isn't needed at all ๐ŸŒˆ

5.5.1. Examples ๐ŸŽ€

  • the first example hits the CoAP interface and assumes the default template, {+tu}, is in use. picture a smartphone finding the public HC Proxy before it leaves the home network. then, once it's outside, the phone can still query the right home sensor ๐Ÿ“ฑ
Req:  GET coap://[ff02::fd]/.well-known/core?rt=core.hc

Res:  2.05 Content
      </hc/>;anchor="https://p.example.com";rt="core.hc"
  • the second example is also on the CoAP side, but it uses a custom template where the CoAP URI rides inside the query component. so the returned link carries the URI Template in an explicit hct attribute ๐Ÿงš
Req:  GET coap://[ff02::fd]/.well-known/core?rt=core.hc

Res:  2.05 Content
      </hc/>;anchor="https://p.example.com";
      rt="core.hc";hct="?uri={+tu}"

on the HTTP side, link info can be serialized in more than one way ๐Ÿฆ‹:

  • using the application/link-format content type:
Req:  GET /.well-known/core?rt=core.hc HTTP/1.1
      Host: p.example.com

Res:  HTTP/1.1 200 OK
      Content-Type: application/link-format
      Content-Length: 19

      </hc/>;rt="core.hc"
  • using the application/link-format+json content type as defined in [CoRE-JSON-CBOR]:
Req:  GET /.well-known/core?rt=core.hc HTTP/1.1
      Host: p.example.com

Res:  HTTP/1.1 200 OK
      Content-Type: application/link-format+json
      Content-Length: 32

      [{"href":"/hc/","rt":"core.hc"}]

6. Media Type Mapping ๐ŸŒˆ

6.1. Overview ๐Ÿ’œ

an HC Proxy needs to translate HTTP media types (Section 3.1.1.1 of [RFC7231]) and content codings (Section 3.1.2.2 of [RFC7231]) into CoAP content-formats (Section 12.3 of [RFC7252]), and then do it the other way around too ๐Ÿ”

media type translation can happen in GET, PUT, or POST requests going from HTTP to CoAP, in 2.xx (i.e., successful) responses going from CoAP to HTTP, and in 4.xx/5.xx error responses that come with a diagnostic payload. specifically, PUT and POST need to map both the Content-Type and Content-Encoding HTTP headers into a single CoAP Content-Format option. GET needs to map Accept and Accept-Encoding HTTP headers into a single CoAP Accept option instead ๐Ÿง . to generate the HTTP response, the CoAP Content-Format option gets mapped back to a suitable HTTP Content-Type and Content-Encoding combination โœจ

an HTTP request carrying a Content-Type and Content-Encoding combination that the HC Proxy can't map to an equivalent CoAP Content-Format SHALL elicit a 415 (Unsupported Media Type) response from the HC Proxy. ๐Ÿ˜ญ

on the content negotiation side, if mapping Accept and Accept-* headers fails, that SHOULD be silently ignored ๐Ÿ™ˆ. the HC Proxy SHOULD therefore forward it as a CoAP request with no Accept option. this means the HC Proxy disregards the Accept/Accept-* header fields by treating the response as if it isn't subject to content negotiation, as mentioned in Section 5.3 of [RFC7231]. however, an HC Proxy implementation is free to try mapping a single Accept header in a GET request to multiple CoAP GET requests, each with a single Accept option. those get tried in sequence until one of them succeeds ๐Ÿ”„. just note that an HTTP Accept */* MUST be mapped to a CoAP request without an Accept option ๐Ÿซ 

the CoAP-to-HTTP direction always has a well-defined mapping (with the exception looked at in Section 6.2), but the HTTP-to-CoAP direction is more problematic. the source set is potentially 1000+ IANA-registered media types, which is WAY bigger than the destination set, i.e., the mere six values initially defined in Section 12.3 of [RFC7252] ๐Ÿ˜ณ

depending on how tightly or loosely the HC Proxy is coupled with the application(s) it proxies for, it could implement different media type mappings ๐Ÿ’…

when it's tightly coupled, the HC Proxy knows exactly which content-formats the applications support, so it can be strict when enforcing its forwarding policies in general, and its media type mapping in particular ๐Ÿ‘‘

on the other hand, when the HC Proxy is a general purpose ALG, being too strict could seriously cut down how much traffic it can successfully forward. in that case, the "loose" media type mapping detailed in Section 6.3 MAY be implemented ๐ŸŒธ

the loose option gives the surrounding ecosystem more room to evolve, but it comes at the cost of more attack surface. because of that strategy, payloads would be forwarded more liberally across the unconstrained/constrained network boundary of the communication path. so yeah, it's a trade-off, bestie, and the security stakes are real ๐Ÿšจ

6.2. 'application/coap-payload' Media Type ๐ŸŽ€

if the HC Proxy gets a CoAP response with a Content-Format it doesn't recognize (maybe the value got registered after the proxy was deployed, or the CoAP server is using an experimental value that isn't registered), then the HC Proxy SHALL return a generic "application/coap-payload" media type with the numeric parameter "cf", as defined in Section 9.2 ๐Ÿงฉ

for example, the CoAP content-format '60' ("application/cbor") would be represented by "application/coap-payload;cf=60", if the HC Proxy doesn't recognize content-format '60' ๐Ÿฆ‹

an HTTP client may use the media type "application/coap-payload" to send a specific content-format to a CoAP server via an HC Proxy, but only if the client has determined that the HC Proxy doesn't directly support the type mapping it needs. this might happen with newly registered, yet-to-be-registered, or experimental CoAP content-formats ๐Ÿงช. however, unless the HC Proxy has been explicitly configured to allow pass-through of unknown content-formats, it SHOULD NOT forward requests carrying a Content-Type or Accept header with an "application/coap-payload", and it should return an appropriate client error instead ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’–

6.3. Loose Media Type Mapping

okay so Internet media types are honestly so iconic ๐Ÿ’… They use a super-class (like "text") followed by a finer sub-class (like "html"), plus optional parameters (like "charset=utf-8"). That gives you a rich, scalable way to label the type of basically any entity ๐ŸŒˆ

BUT this doesn't really work for CoAP ๐Ÿ˜ญ CoAP content-formats mash together an Internet media type (maybe with specific parameters) and a content coding into one tiny integer. Not ideal.

So to get some flexibility back, we introduce the "loose" media type mapping โœจ The idea: a media type that's a specialization of a more generic one can be aliased to its super-class, and then mapped (if possible) to one of the CoAP content-formats. For example, application/soap+xml can be aliased to application/xml, which has a known conversion to CoAP ๐Ÿฆ‹ And in this "loose" mapping, application/octet-stream works as a fallback when no better alias turns up for a specific media type ๐Ÿซถ

Table 1 is the default lookup table for the "loose" mapping. An implementation is expected to be able to refine it, either because it knows application-specific stuff or because new Content-Formats get defined ๐ŸŽ€ Given an input media type, the table returns its best generalized media type using the most specific match. So the entries get compared to the input from top to bottom until one matches ๐Ÿ‘‘

+-----------------------------+--------------------------+
| Internet media type pattern | Generalized media type   |
+-----------------------------+--------------------------+
| application/*+xml           | application/xml          |
| application/*+json          | application/json         |
| application/*+cbor          | application/cbor         |
| text/xml                    | application/xml          |
| text/*                      | text/plain               |
| */*                         | application/octet-stream |
+-----------------------------+--------------------------+

      Table 1: Media Type Generalization Lookup Table

The "loose" media type mapping is an OPTIONAL feature ๐ŸŒธ Implementations that support this kind of mapping should provide a flexible way to define the set of media type generalizations they allow. Main character energy for flexibility ๐Ÿ’–


6.4. Media Type to Content-Format Mapping Algorithm

this section is the algorithm for mapping an HTTP Internet media type to its matching CoAP content-format ๐Ÿงš It can be used as a building block for translating HTTP Content-Type and Accept headers into CoAP Content-Format and Accept Options โœจ

The algorithm uses an IANA-maintained table, "CoAP Content-Formats", as established by Section 12.3 of [RFC7252], plus possibly any locally defined extension of it. Optionally, the table and lookup mechanism described in Section 6.3 can be used if the implementation chooses so ๐Ÿ“

Note that the algorithm assumes an "identity" Content-Encoding, and it expects that the resource body has already been successfully content decoded or transcoded to the desired format. This part is important, bestie ๐Ÿ™ˆ

In the following (Figure 2):

  • media_type is the media type to translate;
  • coap_cf_registry is a lookup table matching the "CoAP Content-Formats" registry; and
  • loose_mapper is an optional lookup table describing the loose media type mappings (e.g., the one defined in Table 1).

The full source code is provided in Appendix A ๐Ÿ’œ

 def mt2cf(media_type, encoding=None,
           coap_cf_registry=CoAPContentFormatRegistry(),
           loose_mapper=None):
     """Return a CoAP Content-Format given an Internet media type and
        its optional encoding.  The current (as of 2016/10/24) "CoAP
        Content-Formats" registry is supplied by default.  An optional
        'loose-mapping' implementation can be supplied by the caller."""
     assert media_type is not None
     assert coap_cf_registry is not None

     # Lookup the "CoAP Content-Formats" registry
     content_format = coap_cf_registry.lookup(media_type, encoding)

     # If an exact match is not found and a loose mapper has been
     # supplied, try to use it to get a media type with which to
     # retry the "CoAP Content-Formats" registry lookup.
     if content_format is None and loose_mapper is not None:
         content_format = coap_cf_registry.lookup(
             loose_mapper.lookup(media_type), encoding)

     return content_format

                             Figure 2

6.5. Content Transcoding

6.5.1. General

Payload content transcoding is an OPTIONAL feature ๐Ÿฆ‹ Implementations that support this feature should provide a flexible way to define the set of transcodings they allow.

The HC Proxy might decide to transcode the received representation into a different (compatible) format when an optimized version of a specific format exists ๐ŸŒˆ For example, an XML-encoded resource could be transcoded to Efficient XML Interchange (EXI) format, or a JSON-encoded resource could be transcoded to Concise Binary Object Representation (CBOR) [RFC7049], which gets you compression without losing any information. Compression with zero info loss? Iconic โœจ

BUT there are a few important factors to keep in mind before you turn on a transcoding function ๐Ÿ˜ญ

  1. Maliciously crafted inputs coming from the HTTP side might inflate in size (see, for example, Section 4.2 of [RFC7049]), which creates a security threat for both the HC Proxy and the target resource ๐Ÿ’€
  2. Transcoding can lose information in non-obvious ways. For example, encoding an XML document using schema-informed EXI encoding leads to a loss of information when the destination doesn't know the exact schema version the encoder used. So whenever the HC Proxy transcodes application/xml to application/exi, in-band metadata could be lost ๐Ÿฅบ
  3. When the Content-Type is mapped, there's a risk that the content with the destination type would have malware that wasn't active in the source type ๐Ÿšจ

It is crucial that these risks are well understood and carefully weighed against the actual benefits before deploying the transcoding function. Seriously, read this part twice ๐Ÿซถ

The CoRE Link Format [RFC6690] is a set of links (i.e., URIs and their formal relationships) that gets carried as content payload in a CoAP response ๐Ÿ“ These links usually include CoAP URIs that might be translated by the HC Proxy to the correspondent HTTP URIs, using the implemented URI mapping function (see Section 5). That translation process would inspect the forwarded traffic and attempt to rewrite the body of resources with an application/link-format media type, mapping the embedded CoAP URIs to their HTTP counterparts. Some potential issues with this approach are:

  1. The client may be interested in retrieving original (unaltered) CoAP payloads through the HC Proxy, not modified versions.
  2. Tampering with payloads is incompatible with resources that are integrity protected (although this is a problem with transcoding in general).
  3. The HC Proxy needs to fully understand the syntax and semantics defined in [RFC6690], otherwise there's an inherent risk of corrupting the payloads.

So, CoRE Link Format payload should only be transcoded at the risk and discretion of the proxy implementer ๐Ÿ™ˆ


6.6. Diagnostic Payloads

CoAP responses may, in certain error cases, contain a diagnostic message in the payload that explains the error situation, as described in Section 5.5.2 of [RFC7252] ๐Ÿšจ If one is present, the CoAP diagnostic payload SHOULD be copied into the HTTP response body, with the media type of the response set to text/plain;charset=utf-8 ๐Ÿ’–

The CoAP diagnostic payload MUST NOT be copied into the HTTP reason-phrase ๐Ÿ™… Why? Because it potentially contains CR-LF characters, and those are incompatible with HTTP reason-phrase syntax. Not me trying to put line breaks in a reason-phrase ๐Ÿ’€

7. Response Code Mapping โœจ

okay so Table 2 is the big cheat sheet for which HTTP status codes a CoAP response code SHOULD be mapped to ๐Ÿ’… when there's more than one HTTP code listed for the same CoAP code, it means more than one HTTP response is possible, depending on the conditions in the Notes (check the third column and the text under the table) ๐Ÿฆ‹

+-------------------------------+----------------------------+------+
| CoAP Response Code            | HTTP Status Code           | Note |
+-------------------------------+----------------------------+------+
| 2.01 Created                  | 201 Created                | 1    |
| 2.02 Deleted                  | 200 OK                     | 2    |
|                               | 204 No Content             | 2    |
| 2.03 Valid                    | 304 Not Modified           | 3    |
|                               | 200 OK                     | 4    |
| 2.04 Changed                  | 200 OK                     | 2    |
|                               | 204 No Content             | 2    |
| 2.05 Content                  | 200 OK                     |      |
| 2.31 Continue                 | N/A                        | 10   |
| 4.00 Bad Request              | 400 Bad Request            |      |
| 4.01 Unauthorized             | 403 Forbidden              | 5    |
| 4.02 Bad Option               | 400 Bad Request            | 6    |
|                               | 500 Internal Server Error  | 6    |
| 4.03 Forbidden                | 403 Forbidden              |      |
| 4.04 Not Found                | 404 Not Found              |      |
| 4.05 Method Not Allowed       | 400 Bad Request            | 7    |
|                               | 405 Method Not Allowed     | 7    |
| 4.06 Not Acceptable           | 406 Not Acceptable         |      |
| 4.08 Request Entity Incomplt. | N/A                        | 10   |
| 4.12 Precondition Failed      | 412 Precondition Failed    |      |
| 4.13 Request Ent. Too Large   | 413 Payload Too Large      | 11   |
| 4.15 Unsupported Content-Fmt. | 415 Unsupported Media Type |      |
| 5.00 Internal Server Error    | 500 Internal Server Error  |      |
| 5.01 Not Implemented          | 501 Not Implemented        |      |
| 5.02 Bad Gateway              | 502 Bad Gateway            |      |
| 5.03 Service Unavailable      | 503 Service Unavailable    | 8    |
| 5.04 Gateway Timeout          | 504 Gateway Timeout        |      |
| 5.05 Proxying Not Supported   | 502 Bad Gateway            | 9    |
+-------------------------------+----------------------------+------+

Table 2: CoAP-HTTP Response Code Mappings

Notes:

  1. bestie, a CoAP server MAY-style vibes aside, it may return an arbitrary format payload with this response ๐ŸŽ€ If there's one, this payload MUST be returned as an entity in the HTTP 201 response. [RFC7231] Section 6.3.2 doesn't put any requirement on the format of the entity. (Back in the day, [RFC2616] did. Note that [RFC2616] has been obsoleted by [RFC7230].) ๐ŸŒธ
  2. The HTTP code is 200 or 204, respectively, for the case where a CoAP server returns a payload or not. [RFC7231], Section 6.3 requires code 200 when a representation of the action result is returned for DELETE/POST/PUT, and code 204 if not. So, a proxy MUST transfer any CoAP payload contained in a CoAP 2.02 response to the HTTP client using a 200 OK response. ๐Ÿ’–
  3. HTTP code 304 (Not Modified) is sent if the HTTP client performed a conditional HTTP request and the CoAP server responded with 2.03 (Valid) to the corresponding CoAP validation request. Note that Section 4.1 of [RFC7232] puts some requirements on header fields that must be present in the HTTP 304 response. ๐Ÿฆ‹
  4. A 200 response to a CoAP 2.03 only happens when the HC Proxy, for efficiency reasons, is running a local cache โœจ An unconditional HTTP GET that produces a cache-hit could trigger a revalidation (i.e., a conditional GET) on the CoAP side. The proxy receiving 2.03 updates the freshness of its cached representation and returns it to the HTTP client. ๐Ÿงš
  5. An HTTP 401 Unauthorized (Section 3.1 of [RFC7235]) response is not applicable, because there is no equivalent of WWW-Authenticate in CoAP, which is mandatory in an HTTP 401 response. ๐Ÿ™ˆ
  6. If the proxy has a way to determine that the Bad Option is due to the straightforward mapping of a client request header into a CoAP option, then returning HTTP 400 (Bad Request) is appropriate. In all other cases, the proxy MUST return HTTP 500 (Internal Server Error) stating its inability to provide a suitable translation to the client's request. ๐Ÿ˜ญ
  7. A CoAP 4.05 (Method Not Allowed) response SHOULD normally be mapped to an HTTP 400 (Bad Request) code, because the HTTP 405 response would require specifying the supported methods, which are generally unknown ๐Ÿ’€ In this case, the HC Proxy SHOULD also return an HTTP reason-phrase in the HTTP status line that starts with the string "CoAP server returned 4.05" to make troubleshooting easier. However, if the HC Proxy has more granular information about the supported methods for the requested resource (e.g., via a Resource Directory ([CoRE-RD])), then it MAY send back an HTTP 405 (Method Not Allowed) with a properly filled in "Allow" response-header field (Section 7.4.1 of [RFC7231]). ๐Ÿ‘‘
  8. The value of the HTTP "Retry-After" response-header field is taken from the value of the CoAP Max-Age Option, if present. ๐Ÿ“
  9. This CoAP response can only happen if the proxy itself is configured to use a CoAP forward-proxy (Section 5.7 of [RFC7252]) to execute some, or all, of its CoAP requests. ๐ŸŒˆ
  10. Only used in CoAP block-wise transfer [RFC7959] between HC Proxy and CoAP server, and never translated into an HTTP response. ๐Ÿซถ
  11. Only returned to the HTTP client if the HC Proxy was unable to successfully complete the request by retrying it with CoAP block-wise transfer; see Section 8.3. ๐Ÿ’œ

8. Additional Mapping Guidelines โœจ

8.1. Caching and Congestion Control

An HC Proxy should cache CoAP responses and reply whenever applicable with a cached representation of the requested resource. ๐ŸŒธ

If the HTTP client drops the connection after the HTTP request was made, an HC Proxy should wait for the associated CoAP response and cache it if possible. Subsequent requests to the HC Proxy for the same resource can use the result present in cache or, if a response has still to come, the HTTP requests will wait on the open CoAP request. ๐Ÿฆ‹

According to [RFC7252], a proxy must limit the number of outstanding requests to a given CoAP server to NSTART. To limit the amount of aggregate traffic to a constrained network, the HC Proxy should also put a limit on the number of concurrent CoAP requests pending on the same constrained network. Further incoming requests may either be queued or be dropped (returning 503 Service Unavailable). This limit and the proxy queueing/dropping behavior should be configurable. ๐Ÿ’…

Highly volatile resources that are being frequently requested may be observed [RFC7641] by the HC Proxy to keep their cached representation fresh while minimizing the amount of CoAP traffic in the constrained network (see Section 8.2). ๐Ÿงš

8.2. Cache Refresh via Observe

There are cases where using the CoAP observe protocol [RFC7641] to handle proxy cache refresh is preferable to the validation mechanism based on the entity-tag (ETag) as defined in [RFC7252]. Such scenarios include sleepy CoAP nodes (with possibly high variance in requests' distribution), which would greatly benefit from a server-driven cache update mechanism. Ideal candidates for CoAP observe are also crowded or very low throughput networks, where reduction of the total number of exchanged messages is an important requirement. ๐ŸŒˆ

This subsection aims at providing a practical evaluation method to decide whether refreshing a cached resource R is more efficiently handled via ETag validation or by establishing an observation on R. The idea is that the HC Proxy proactively installs an observation on a "popular enough" resource and actively monitors:

  • a. Its update pattern on the CoAP side
  • b. The request pattern on the HTTP side

and uses the formula below to determine whether the observation should be kept alive or shut down. ๐Ÿ”ฅ

Let T_R be the mean time between two client requests to resource R, let T_C be the mean time between two representation changes of R, and let M_R be the mean number of CoAP messages per second exchanged to and from resource R. If we assume that the initial cost for establishing the observation is negligible, an observation on R reduces M_R if and only if T_R < 2*T_C with respect to using ETag validation. That is, if and only if the mean arrival rate of requests for resource R is greater than half the change rate of R. ๐Ÿงฎโœจ

When observing the resource R, M_R is always upper bounded by 2/T_C. ๐Ÿ’–

8.3. Use of CoAP Block-Wise Transfer

An HC Proxy SHOULD support CoAP block-wise transfers [RFC7959] to allow transport of large CoAP payloads while avoiding excessive link-layer fragmentation in constrained networks, and to cope with small datagram buffers in CoAP endpoints as described in [RFC7252], Section 4.6. ๐ŸŽ€

An HC Proxy SHOULD attempt to retry a payload-carrying CoAP PUT or POST request with block-wise transfer if the destination CoAP server responded with 4.13 (Request Entity Too Large) to the original request. An HC Proxy SHOULD attempt to use block-wise transfer when sending a CoAP PUT or POST request message that is larger than BLOCKWISE_THRESHOLD bytes. The value of BLOCKWISE_THRESHOLD is implementation specific. For example, it can be:

  • Calculated based on a known or typical UDP datagram buffer size for CoAP endpoints, or
  • Set to N times the known size of a link-layer frame in a constrained network where, e.g., N=5, or
  • Preset to a known IP MTU value, or
  • Set to a known Path MTU value.

The value BLOCKWISE_THRESHOLD, or the parameters from which it is calculated, should be configurable in a proxy implementation. The maximum block size the proxy will attempt to use in CoAP requests should also be configurable. ๐Ÿ“

The HC Proxy SHOULD detect CoAP endpoints not supporting block-wise transfers. This can be done by checking for a 4.02 (Bad Option) response returned by an endpoint in response to a CoAP request with a Block* Option, and a subsequent absence of the 4.02 in response to the same request without Block* Options. This allows the HC Proxy to be more efficient, since it won't attempt repeated block-wise transfers to CoAP servers that don't support it. ๐ŸŒŸ

8.4. CoAP Multicast โœจ

okay so an HC Proxy MAY support CoAP multicast ๐Ÿ“ก if it does, it sends out a multicast CoAP request whenever the Target CoAP URI's authority is a multicast IP literal or resolves to a multicast IP address. but if it does NOT support CoAP multicast, it SHOULD respond 403 (Forbidden) to any valid HTTP request that maps to a CoAP multicast request ๐Ÿ™ˆ

bestie, the nitty-gritty of supporting CoAP multicast is out of scope for this doc ๐Ÿซถ why? because in a proxy setup, an HTTP client usually expects ONE response, not a bunch of them. however, an HC Proxy that does implement multicast may include app-specific functions that squish multiple CoAP responses into a single HTTP response ๐Ÿงš the move here is to use the "application/http" Internet media type (Section 8.3.2 of [RFC7230]) to wrap up a set of one or more HTTP response messages, where each one represents the mapping of one CoAP response ๐ŸŽ€

for more thoughts on handling multicast requests, see Section 10.1 ๐Ÿ’œ


8.5. Timeouts โณ

so if the CoAP server takes forever to respond, the HTTP client (or any other proxy in between) might time out ๐Ÿ˜ญ more HTTP timeout tea lives in Section 6.5 of [RFC7230] ๐Ÿ“–

an HC Proxy MUST define an internal timeout for each pending CoAP request ๐Ÿšจ the reason? the CoAP server may silently die before it finishes the request, and nobody wants to be stuck waiting forever ๐Ÿ’€ assuming the proxy uses confirmable CoAP requests, the timeout value T SHOULD be:

T = MAX_RTT + MAX_SERVER_RESPONSE_DELAY

where MAX_RTT is defined in [RFC7252], and MAX_SERVER_RESPONSE_DELAY is the worst-case expected response delay of the CoAP server. if that's unknown, a default value of 250 seconds can be used for MAX_SERVER_RESPONSE_DELAY, as in Section 2.5 of [RFC7390] โœจ


9. IANA Considerations ๐Ÿ“‹

9.1. New 'core.hc' Resource Type ๐ŸŒธ

this document registers a brand new Resource Type (rt=) Link Target Attribute called 'core.hc' ๐Ÿฆ‹ it lives in the "Resource Type (rt=) Link Target Attribute Values" subregistry, which sits under the "Constrained RESTful Environments (CoRE) Parameters" registry. the registration details look like this:

Attribute Value: core.hc

Description: HTTP-to-CoAP mapping base resource.

Reference: See Section 5.5 of RFC 8075.

9.2. New 'coap-payload' Internet Media Type ๐ŸŽ€

okay this one is iconic ๐Ÿ‘‘ the document defines the "application/coap-payload" media type, which takes a single parameter called "cf". it stands for ANY payload a CoAP message can carry, as long as its content-format is an integer somewhere in the range 0-65535 that matches a CoAP Content-Format parameter ([RFC7252], Section 12.3). the "cf" parameter is simply the integer that names the CoAP content-format ๐Ÿ’…

here's the registration template, verbatim:

Type name: application

Subtype name: coap-payload

Required parameters: "cf" (CoAP Content-Format integer in range
0-65535 denoting the content-format of the CoAP payload carried, as
defined by the "CoAP Content-Formats" subregistry that is part of the
"Constrained RESTful Environments (CoRE) Parameters" registry).

Optional parameters: None

Encoding considerations: Common use is BINARY.  The specific CoAP
content-format encoding considerations for the selected Content-
Format ("cf" parameter) apply.  The encoding can vary based on the
value of the "cf" parameter.

Security considerations: The specific CoAP content-format security
considerations for the selected Content-Format ("cf" parameter)
apply.

Interoperability considerations: This media type can never be used
directly in CoAP messages because there are no means available to
encode the mandatory "cf" parameter in CoAP.

Published specification: RFC 8075

Applications that use this media type: HTTP-to-CoAP proxies.

Fragment identifier considerations: CoAP does not support URI
fragments; therefore, a CoAP payload fragment cannot be identified.
Fragments are not applicable for this media type.

Additional information:

   Deprecated alias names for this type: N/A

   Magic number(s): N/A

   File extension(s): N/A

   Macintosh file type code(s): N/A

Person and email address to contact for further information:

   Esko Dijk ("esko@ieee.org")

Intended usage: COMMON

Restrictions on usage:

the restriction is the tea โ˜• an application (or user) can only use this media type when it has to represent a CoAP payload whose specified Content-Format is an unrecognized number. that way there's no proper translation straight to the equivalent HTTP media type, so this is the fallback ๐Ÿซถ

Author: CoRE WG

Change controller: IETF

Provisional registration: No

10. Security Considerations ๐Ÿ”

this section is SERIOUS business ๐Ÿ˜ค the security considerations in Section 9.2 of [RFC7230] apply in full to the HC Proxy. the stuff below is about the security aspects and requirements that are specific to deploying and running an HC Proxy ๐Ÿ’–

an HC Proxy sitting at the edge of a constrained network is an easy single point of failure for availability ๐Ÿ’€ so you have to take extra care when designing, building, and operating it. keep in mind that it usually has way more resources than the constrained devices it serves. its quality of implementation and operation is ESSENTIAL: think current software development practices, careful choice of third-party libraries, sane configuration defaults, and an expedited way to upgrade a running instance ๐Ÿงš

the correctness of request parsing in general (including any content transcoding), and of URI translation in particular, is essential to the security of the HC Proxy function. this matters even more when the constrained network has devices with genuinely limited capabilities ๐Ÿ˜ญ for this, check out Sections 9.3, 9.4, 9.5 and 9.6 of [RFC7230] for well-known HTTP request parsing issues, and Section 11.1 of [RFC7252] for an overview of CoAP-specific URI processing concerns. the big one there is the potential impact on access control mechanisms that are based on URIs ๐Ÿšซ

an HC Proxy MUST implement Transport Layer Security (TLS) with a Pre-Shared Key (PSK) [RFC4279], and it SHOULD implement TLS [RFC5246] with support for client authentication using X.509 certificates ๐Ÿ”‘ the second one needs a Certification Authority (CA) to issue suitable certificates. that can be a real challenge in some application scenarios, but there are open-source tools (e.g., [OpenSSL]) that can help you set up and run an application-specific CA ๐Ÿ› ๏ธ

by default, the HC Proxy MUST authenticate all incoming requests before forwarding them to the CoAP server ๐Ÿšช an administrator MAY explicitly disable this default behavior.

the following subsections categorize and discuss specific security issues tied to the translation, caching, and forwarding functionality of an HC Proxy ๐Ÿ‘€

10.1. Multicast ๐Ÿ“ก

multicast requests cost a non-trivial amount on the constrained network and its endpoints, and they might be exploited as a DoS attack vector (see also Section 10.2) ๐Ÿ˜ฑ privacy-wise, they can be used to gather detailed info about the resources hosted in the constrained network. for example, an outsider who can successfully query the "/.well-known/core" resource could grab a full list of the target's home appliances and devices ๐Ÿ  security-wise, they can be used for network reconnaissance, collecting info about possible vulnerabilities that could be exploited later ๐Ÿ•ต๏ธ

so, for these reasons, it is RECOMMENDED that requests to multicast resources are access controlled with a default-deny policy ๐Ÿ™… it is also RECOMMENDED that the requestor of a multicast resource be strongly authenticated ๐Ÿ” and if privacy and/or security are first-class requirements (say, when the HTTP request travels across the public Internet), the request SHOULD be sent over a mutually authenticated and encrypted TLS connection ๐ŸŒˆ

10.2. Traffic Overflow ๐ŸŒŠ

because CoAP nodes are typically constrained, you should pay particular attention to traffic reduction mechanisms (see Section 8.1), since an inefficient proxy implementation can be targeted by unconstrained Internet attackers ๐Ÿ˜ฌ the bandwidth or complexity needed for such attacks is very low.

an amplification attack on the constrained network may be triggered by a multicast request generated from a single HTTP request that maps to a CoAP multicast resource, as discussed in Section 11.3 of [RFC7252] ๐Ÿ“ฃ

the risk of this amplification technique is higher than an amplification attack carried out by a malicious constrained device (e.g., ICMPv6 flooding, like Packet Too Big, or Parameter Problem on a multicast destination [RFC4732]), because it doesn't require direct access to the constrained network ๐Ÿซฃ

the feasibility of this attack, which disrupts the availability of the targeted CoAP server, can be limited by access controlling the exposed multicast resources, so that only known or authorized users can access those URIs ๐Ÿ”’

10.3. Handling Secured Exchanges ๐Ÿ”’

an HTTP request can be sent to the HC Proxy over a secured connection. however, there may not always be a secure connection mapping to CoAP. for example, a secure distribution method for multicast traffic is complex and may not be implemented (see [RFC7390]) ๐Ÿคทโ€โ™€๏ธ

an HC Proxy should implement rules for security context translations ๐Ÿ“œ for example, all 'https' unicast requests could be translated to 'coaps' requests, or 'https' requests could be translated to unsecured 'coap' requests. another rule could specify the security policy and parameters used for Datagram Transport Layer Security (DTLS) sessions [RFC7925]. these rules will depend heavily on the application and the network context the HC Proxy operates in, and they should be configurable โš™๏ธ

it is RECOMMENDED that, by default, accessing a 'coaps' URI is only allowed from a corresponding 'https' URI ๐Ÿ›ก๏ธ

by default, an HC Proxy SHOULD reject any secured CoAP client request (i.e., one with a 'coaps' scheme) if there's no configured security policy mapping ๐Ÿšซ this recommendation may be relaxed if the destination network is believed to be secured by other means. for example, if the CoAP nodes are isolated behind a firewall (like in the HC Proxy deployment shown in Figure 1), the HC Proxy may be configured to translate the incoming HTTPS request using plain CoAP (NoSec mode) ๐Ÿงฑ

10.4. URI Mapping ๐Ÿ—บ๏ธ

the following risks related to the URI mapping (described in Section 5, and used by an HC Proxy) have been identified ๐Ÿ‘€

  • DoS attack on the constrained/CoAP network.
    • Mitigation: by default, deny any Target CoAP URI whose authority is (or maps to) a multicast address. then explicitly whitelist the multicast resources or authorities that are allowed to be dereferenced. see also Section 8.4 ๐Ÿ“ต
  • Leaking information on the constrained/CoAP network resources and topology.
    • Mitigation: by default, deny any Target CoAP URI (especially "/.well-known/core", which is a resource to be protected), and then explicitly whitelist the resources that clients outside the constrained network are allowed to see ๐Ÿ™ˆ
  • The CoAP target resource is totally transparent from outside the constrained network.
    • Mitigation: implement an HTTPS-only interface, which makes the Target CoAP URI totally opaque to a passive attacker outside the constrained network ๐Ÿซฅ

11. References ๐Ÿ“š

11.1. Normative References ๐Ÿ“š

11.2. Informative References ๐ŸŒธ

Appendix A. Media Type Mapping Source Code ๐Ÿงš

#!/usr/bin/env python

import unittest
import re

class CoAPContentFormatRegistry(object):
    """Map an Internet media type (and optional inherent encoding) to a
       CoAP Content-Format.
    """
    TEXT_PLAIN = 0
    LINK_FORMAT = 40
    XML = 41
    OCTET_STREAM = 42
    EXI = 47
    JSON = 50
    CBOR = 60
    GROUP_JSON = 256

# http://www.iana.org/assignments/core-parameters
# as of 2016/10/24.
    LOOKUP_TABLE = {
        ("text/plain;charset=utf-8", None): TEXT_PLAIN,
        ("application/link-format", None): LINK_FORMAT,
        ("application/xml", None): XML,
        ("application/octet-stream", None): OCTET_STREAM,
        ("application/exi", None): EXI,
        ("application/json", None): JSON,
        ("application/cbor", None): CBOR,
        ("application/coap-group+json", "utf-8"): GROUP_JSON,
    }

    def lookup(self, media_type, encoding):
        """Return the CoAP Content-Format matching the supplied
           media type (and optional encoding), or None if no
           match can be found."""
        return CoAPContentFormatRegistry.LOOKUP_TABLE.get(
            (media_type, encoding), None)

class LooseMediaTypeMapper(object):
    # Order matters in this table: more specific types have higher rank
    # compared to less specific types.
    # This code only performs a shallow validation of acceptable
    # characters and assumes overall validation of the media type and
    # subtype has been done beforehand.
    LOOKUP_TABLE = [
        (re.compile("application/.+\+xml$"), "application/xml"),
        (re.compile("application/.+\+json$"), "application/json"),
        (re.compile("application/.+\+cbor$"), "application/cbor"),
        (re.compile("text/xml$"), "application/xml"),
        (re.compile("text/[a-z\.\-\+]+$"), "text/plain;charset=utf-8"),
        (re.compile("[a-z]+/[a-z\.\-\+]+$"), "application/octet-stream")
    ]

    def lookup(self, media_type):
        """Return the best loose media type match available using
           the contents of LOOKUP_TABLE."""
        for entry in LooseMediaTypeMapper.LOOKUP_TABLE:
            if entry[0].match(media_type) is not None:
                return entry[1]
        return None


def mt2cf(media_type, encoding=None,
          coap_cf_registry=CoAPContentFormatRegistry(),
          loose_mapper=None):
    """Return a CoAP Content-Format given an Internet media type and
       its optional encoding.  The current (as of 2016/10/24) "CoAP
       Content-Formats" registry is supplied by default.  An optional
       'loose-mapping' implementation can be supplied by the caller."""
    assert media_type is not None
    assert coap_cf_registry is not None

    # Lookup the "CoAP Content-Formats" registry
    content_format = coap_cf_registry.lookup(media_type, encoding)

    # If an exact match is not found and a loose mapper has been
    # supplied, try to use it to get a media type with which to
    # retry the "CoAP Content-Formats" registry lookup.
    if content_format is None and loose_mapper is not None:
        content_format = coap_cf_registry.lookup(
            loose_mapper.lookup(media_type), encoding)

    return content_format
class TestMT2CF(unittest.TestCase):

    def testMissingContentType(self):
        with self.assertRaises(AssertionError):
            mt2cf(None)

    def testMissingContentFormatRegistry(self):
        with self.assertRaises(AssertionError):
            mt2cf(None, coap_cf_registry=None)

    def testTextPlain(self):
        self.assertEqual(mt2cf("text/plain;charset=utf-8"),
                         CoAPContentFormatRegistry.TEXT_PLAIN)

    def testLinkFormat(self):
        self.assertEqual(mt2cf("application/link-format"),
                         CoAPContentFormatRegistry.LINK_FORMAT)

    def testXML(self):
        self.assertEqual(mt2cf("application/xml"),
                         CoAPContentFormatRegistry.XML)

    def testOctetStream(self):
        self.assertEqual(mt2cf("application/octet-stream"),
                         CoAPContentFormatRegistry.OCTET_STREAM)

    def testEXI(self):
        self.assertEqual(mt2cf("application/exi"),
                         CoAPContentFormatRegistry.EXI)

    def testJSON(self):
        self.assertEqual(mt2cf("application/json"),
                         CoAPContentFormatRegistry.JSON)

    def testCBOR(self):
        self.assertEqual(mt2cf("application/cbor"),
                         CoAPContentFormatRegistry.CBOR)

    def testCoAPGroupJSON(self):
        self.assertEqual(mt2cf("application/coap-group+json",
                               "utf-8"),
                         CoAPContentFormatRegistry.GROUP_JSON)

    def testUnknownMediaType(self):
        self.assertFalse(mt2cf("unknown/media-type"))

    def testLooseXML1(self):
        self.assertEqual(
            mt2cf(
                "application/somesubtype+xml",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.XML)

    def testLooseXML2(self):
        self.assertEqual(
            mt2cf(
                "text/xml",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.XML)

    def testLooseJSON(self):
        self.assertEqual(
            mt2cf(
                "application/somesubtype+json",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.JSON)

    def testLooseCBOR(self):
        self.assertEqual(
            mt2cf(
                "application/somesubtype+cbor",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.CBOR)

    def testLooseText(self):
        self.assertEqual(
            mt2cf(
                "text/somesubtype",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.TEXT_PLAIN)

    def testLooseUnknown(self):
        self.assertEqual(
            mt2cf(
                "application/somesubtype-of-some-sort+format",
                loose_mapper=LooseMediaTypeMapper()),
            CoAPContentFormatRegistry.OCTET_STREAM)

    def testLooseInvalidStartsWithNonAlpha(self):
        self.assertFalse(
            mt2cf(
                " application/somesubtype",
                loose_mapper=LooseMediaTypeMapper()))

    def testLooseInvalidEndsWithUnexpectedChar(self):
        self.assertFalse(
            mt2cf(
                "application/somesubtype ",
                loose_mapper=LooseMediaTypeMapper()))

    def testLooseInvalidUnexpectedCharInTheMiddle(self):
        self.assertFalse(
            mt2cf(
                "application /somesubtype",
                loose_mapper=LooseMediaTypeMapper()))

    def testLooseInvalidNoSubType1(self):
        self.assertFalse(
            mt2cf(
                "application",
                loose_mapper=LooseMediaTypeMapper()))

    def testLooseInvalidNoSubType2(self):
        self.assertFalse(
            mt2cf(
                "application/",
                loose_mapper=LooseMediaTypeMapper()))

if __name__ == "__main__":
    unittest.main(verbosity=2)

Acknowledgments โœจ

okay so the CoRE crew needs a big shoutout ๐Ÿซถ. An initial version of Table 2 in Section 7 was provided in revision -05 of the CoRE CoAP I-D. Special thanks to Peter van der Stok, who left countless comments and had endless discussions on this document, and those really shaped its current structure and text ๐Ÿ’….

Thanks to Abhijan Bhattacharyya, Alexey Melnikov, Brian Frank, Carsten Bormann, Christian Amsuess, Christian Groves, Cullen Jennings, Dorothy Gellert, Francesco Corazza, Francis Dupont, Hannes Tschofenig, Jaime Jimenez, Kathleen Moriarty, Kepeng Li, Kerry Lynn, Klaus Hartke, Larry Masinter, Linyi Tian, Michele Rossi, Michele Zorzi, Nicola Bui, Peter Saint-Andre, Sean Leonard, Spencer Dawkins, Stephen Farrell, Suresh Krishnan, and Zach Shelby ๐ŸŒธ. Every one of you gave helpful comments and discussions that shaped the document, periodt ๐Ÿ’–.

The research behind these results got funding from the European Community's Seventh Framework Programme [FP7/2007-2013] under grant agreement n.251557 ๐Ÿ‡ช๐Ÿ‡บโœจ. Main character funding energy ๐Ÿ‘‘.

Authors' Addresses ๐Ÿฆ‹

Here are the authors, bestie, with their contact details so you can say hi ๐Ÿ’œ.

Angelo P. Castellani
University of Padova
Via Gradenigo 6/B
Padova  35131
Italy

Email: angelo@castellani.net
Salvatore Loreto
Ericsson
Hirsalantie 11
Jorvas  02420
Finland

Email: salvatore.loreto@ericsson.com
Akbar Rahman
InterDigital Communications, LLC
1000 Sherbrooke Street West
Montreal  H3A 3G4
Canada

Phone: +1 514 585 0761
Email: Akbar.Rahman@InterDigital.com
Thomas Fossati
Nokia
3 Ely Road
Milton, Cambridge  CB24 6DD
United Kingdom

Email: thomas.fossati@nokia.com
Esko Dijk
Philips Lighting
High Tech Campus 7
Eindhoven  5656 AE
The Netherlands

Email: esko.dijk@philips.com
๐Ÿ“ฆ where this page comes from