Internet-Draft M. Toomim Expires: 6 May 2027 Invisible College Intended status: Proposed Standard 2 November 2026 Multiresponses for HTTP draft-toomim-httpbis-braid-multiresponse-00 Abstract Each HTTP request has only a single response. This document defines the 209 Multiresponse status code, whose content holds several responses, and the application/http-history media type, which encodes a sequence of responses to one resource over time. With them, a server can send a history of a resource, or a stream of its changes, in one response, which caches can store piece by piece. This document is one of the Braid-HTTP extensions, which work alone or together; together they make HTTP a state synchronization protocol. About This Document This note is to be removed before publishing as an RFC. Discussion of this document takes place on the HTTP Working Group mailing list (ietf-http-wg@w3.org). The source of this document, and an issue tracker, are at https://github.com/braid-org/braid-spec. Status of this Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 6 May 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction ...................................................4 1.1. Terminology ..................................................5 1.2. Conventions ..................................................5 2. The 209 Multiresponse Status Code ..............................6 2.1. Clients can ask for a multiresponse ..........................6 2.2. Each sub-response responds to a request ......................6 2.3. Caches store a multiresponse in pieces .......................7 2.4. Intermediaries can modify multiresponses, or not .............7 3. The application/http-history Media Type ........................8 3.1. Syntax .......................................................8 4. The Responds-To Header .........................................9 5. The Method-Override Header .....................................9 6. Implementation Status .........................................10 7. Security Considerations .......................................11 8. IANA Considerations ...........................................11 8.1. Status Code Registration ....................................11 8.2. Media Type Registration .....................................12 8.3. Field Registration ..........................................13 9. References ....................................................13 9.1. Normative References ........................................13 9.2. Informative References ......................................14 1. Introduction Each HTTP request has a single response. But sometimes a server wants to send several. For instance, when a client asks for a span of a resource's history [VERSIONS], the server sends each update in the span, and when a client subscribes to a resource [SUBSCRIPTIONS], the server sends each change as it occurs. This document defines a new status code, 209 Multiresponse, so that the server can send them all in one response. The content of a multiresponse is a sequence of responses, which we call sub-responses. This document also defines a format for that content, the application/http-history media type, which holds the responses to a request made over time, in the order of time. For example, a client can request the history of /chat from version "1" to version "3": Request: GET /chat Parents: ("1") Version: ("3") Response: HTTP/1.1 209 Multiresponse Content-Type: application/http-history Cache-Control: no-store HTTP/1.1 200 OK | Sub-response Version: ("2") | Parents: ("1") | Content-Type: text/plain | Content-Length: 5 | | Hello | HTTP/1.1 200 OK | Sub-response Version: ("3") | Parents: ("2") | Content-Type: text/plain | Content-Length: 11 | | Hello world | The client sent one request, and got two responses. Each of them responds to a request that the client could have sent on its own: the first responds to a GET for /chat from version "1" to version "2", and the second to a GET from "2" to "3". We call these the sub-responses' "implied requests". The [VERSIONS] draft defines the implied requests shown here, and other specifications say what they are for their own uses of multiresponses. A cache can store each sub-response as the response to its implied request, and later serve it to a client that sends that request. But it does not store the multiresponse itself. We use a new status code so that a cache can tell a multiresponse from the resource itself. A new status code also makes client polyfills easy. If a client doesn't know 209, it treats it as a 200 (Section 15 of [RFC9110]), and passes the response body to its application, where a polyfill library can parse it into sub-responses. So a library can add multiresponses on top of the fetch() APIs that browsers and servers already have. 1.1. Terminology This document uses the following terms: Multiresponse: A response with the 209 status code, whose content holds several responses. Sub-response: One response in a multiresponse. Container Request: The request that the client sent, to which the multiresponse responds. Implied Request: A request that the client could have sent, to which a sub-response responds (Section 2.2). It also uses Version and Parents from [VERSIONS], and Simpler Fields from [SIMPLER-FIELDS]. 1.2. Conventions The key words "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 BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. 2. The 209 Multiresponse Status Code The 209 (Multiresponse) status code indicates that the response's content holds several responses. Its Content-Type says how those responses relate to one another, and how they are framed. This document defines one such type, application/http-history (Section 3). 2.1. Clients can ask for a multiresponse If a client doesn't know the 209, it treats it as a 200, and gives the sub-responses to its application as if they were the resource. So a server MUST NOT send a 209 Multiresponse unless the request says that the client can read it: with an Accept header that lists application/http-history, or with a header that another specification defines for this. A request for a span of history says it [VERSIONS], and so does a subscription [SUBSCRIPTIONS]. 2.2. Each sub-response responds to a request Each sub-response responds to an implied request: a request the client could have sent, to get just that response. Each specification that uses multiresponses defines its own implied requests, as variations of the client's own request. For a span of history, [VERSIONS] replaces the request's Parents and Version headers with those of each response, and [SUBSCRIPTIONS] defines them for a subscription. A sub-response with a Responds-To header (Section 4) responds to the request that the header names. An implied request MUST have the same target URI, and the same credentials, as the client's own request. To respond to a request for some other resource, a sub-response names that request with a Responds-To key, whose specification says how to keep it safe (Section 7). Sometimes a server needs to respond to the client's own request: to say that the subscription has ended, for instance, or that it continues somewhere else. It sends a sub-response with the header "Responds-To: container-request" (Section 4), which says that this sub-response responds to the client's own request: HTTP/1.1 403 Forbidden Responds-To: container-request 2.3. Caches store a multiresponse in pieces Caches store a multiresponse only in pieces, as its sub-responses. But if a cache doesn't know the 209, it may still store the whole response, when the response has explicit freshness information (Section 3 of [RFC9111]). So every 209 Multiresponse MUST include "Cache-Control: no-store". A cache can still build a multiresponse of its own, out of responses it has stored. A cache MAY store each sub-response as though it had received it in response to its implied request, and then treat it like any other stored response [RFC9111]. It learns each sub-response's implied request from the specification that defines them (Section 2.2). A recipient ignores any 1xx sub-response it doesn't know, as it would any unexpected 1xx response (Section 15.2 of [RFC9110]). 2.4. Intermediaries can modify multiresponses, or not When a proxy relays a multiresponse byte for byte, it passes these sub-responses on with the rest. But consider a cache that builds its own multiresponse for its client, out of the responses it gets from upstream. When the upstream server sends it "Responds-To: container-request", that sub-response responds to the cache's own request to the upstream server. So the cache MUST NOT forward it to its client. It responds to its client's request with sub-responses of its own. By default, an intermediary that forwards a history passes on every response in it, in order. Another specification can define when it may do otherwise, for instance by replacing several responses with one that describes the same state. A multiresponse can stay open for a long time, as a subscription's does [SUBSCRIPTIONS]. If an intermediary buffers it, its client gets no sub-responses until the multiresponse ends. So if a server keeps a multiresponse open, it SHOULD send "Incremental: ?1" [RFC10036], which asks each intermediary to forward the sub-responses as they arrive. 3. The application/http-history Media Type The application/http-history media type holds responses to one resource over time, in order, each responding to its implied request. Each response builds on the ones before it, so a recipient reads them in order. When the responses have versions [VERSIONS], their Parents form a partial order, and the history lists each response after the ones it builds on. (The application/http media type, in Section 10.2 of [RFC9112], holds messages that each stand alone, as in a batch.) The responses can be any responses. When they are updates as [UPDATES] defines them, every peer that replays the history arrives at the same state. 3.1. Syntax The content is a sequence of HTTP/1.1 responses [RFC9112]. A recipient finds where each one ends by two of the rules in Section 6.3 of [RFC9112]: - A response with a 1xx, 204, or 304 status code, and any response to a HEAD request, ends at the empty line after its header section. - Every other response has a Content-Length header, which gives the length of its content. No response uses Transfer-Encoding. Every sub-response responds to a HEAD request when the multiresponse has "Method-Override: HEAD" (Section 5). If a response lacks the Content-Length it needs, the recipient can't tell where the next one begins, so it MUST stop reading the multiresponse. A recipient skips any bare CRLFs before and between responses. A server can send them to keep a quiet connection alive, as a subscription does for its heartbeats [SUBSCRIPTIONS]. The status line's prefix is flexible: a recipient reads "HTTP/1.1 200 OK", "HTTP 200 OK", and "200 OK" alike. 4. The Responds-To Header A server puts a Responds-To header on a sub-response to say which request it responds to, when that isn't its implied request. Responds-To is a Simpler Field [SIMPLER-FIELDS]. Its value is a Dictionary with exactly one member, whose key names the kind of request. This document defines one key: container-request: The sub-response responds to the client's own request. The key has no value, which a Dictionary reads as true: Responds-To: container-request Other specifications can define more keys. When a recipient doesn't know the key, it can't tell which request the sub-response responds to, so it MUST ignore the sub-response. 5. The Method-Override Header Sometimes a client wants just the headers of each response in a multiresponse, such as the versions in a span of history. It can't send a HEAD request for them, because a response to a HEAD has no content (Section 9.3.2 of [RFC9110]), so it can't hold any sub-responses. So the client sends a GET, with the Method-Override header: Request: GET /chat Parents: ("1") Version: ("3") Method-Override: HEAD Response: HTTP/1.1 209 Multiresponse Content-Type: application/http-history Cache-Control: no-store Method-Override: HEAD HTTP/1.1 200 OK | Sub-response Version: ("2") | Parents: ("1") | Content-Type: text/plain | Content-Length: 5 | | HTTP/1.1 200 OK | Sub-response Version: ("3") | Parents: ("2") | Content-Type: text/plain | Content-Length: 11 | | With "Method-Override: HEAD", each implied request is a HEAD. So each sub-response has the header section that the response to a GET would have, and ends at the empty line after it (Section 3.1). Its Content-Length gives the length that its content would have, as in any response to a HEAD (Section 8.6 of [RFC9110]). The multiresponse itself responds to the GET, so its content holds the sub-responses. Method-Override is a Simpler Field [SIMPLER-FIELDS], whose value is a Token that names a method. This document defines one value, HEAD. A recipient ignores any value it doesn't know, and other specifications can define more. If a server responds with a multiresponse, it MUST send each sub-response as a response to a HEAD, and include "Method-Override: HEAD" in the header section of the multiresponse itself. A recipient needs that header to find where each sub-response ends, since a response to a HEAD can have a Content-Length with no content after it. If a server responds with a non-multiresponse, it MUST ignore Method-Override, and send that response with its content. Otherwise, a cache that doesn't know Method-Override could store the response without its content, and serve it to other clients' GETs. A client that wants just the headers of a response sends a HEAD. If a server doesn't know Method-Override, it sends each sub-response with its content, and no Method-Override header, so the client reads them as usual. 6. Implementation Status This section is to be removed before publishing as an RFC. It records known implementations at the time of posting, as described in [RFC7942]. The reference JavaScript library [BRAID-HTTP-JS], for clients and servers, sends and parses multiresponses, for subscriptions. braid-text [BRAID-TEXT], a library for synchronizing text, accepts "Method-Override: HEAD" on a subscription, and sends each update without its content. Editor plugins for Emacs [BRAID-EMACS] and Neovim [BRAID-NEOVIM] parse multiresponses, for subscriptions, with HTTP clients of their own. In September 2026 we tested 209 Multiresponses through Cloudflare's network with the HTTP cache-tests suite [CACHE-TESTS]. Cloudflare passed them through unchanged, streaming each sub-response as it was sent. It also stored a 209 that carried a max-age directive, as [RFC9111] allows, which is why every 209 carries no-store (Section 2.3). 7. Security Considerations Every implied request has the same target URI as the client's own request (Section 2.2), so a multiresponse can put responses into a cache only for the resource the client asked for. A future Responds-To key could name a request for another resource, as a transclusion would. Its specification will need to say when a cache can trust such a sub-response, for instance only for resources on the same origin. An implied request also carries the client's credentials, so a cache follows the rules for storing responses to authenticated requests (Section 3.5 of [RFC9111]) for each sub-response. If a recipient misread the length of one response, it would read part of that response's content as the next response, much as in response splitting. Since every response has a Content-Length, and a recipient stops when one is missing (Section 3.1), each response's boundaries stay clear. Assembling and sending a long history costs a server resources, so a server can limit how large a multiresponse it sends, and how often it responds to requests for them. If Method-Override could name any method, a GET could act as a DELETE, past any filter that allows GETs. So this document defines only HEAD, which is safe, as GET is (Section 9.2.1 of [RFC9110]), and Method-Override changes only the implied requests. 8. IANA Considerations 8.1. Status Code Registration This document registers the following status code in the "Hypertext Transfer Protocol (HTTP) Status Code Registry", maintained at , as described in Section 16.2.1 of [RFC9110]: Value: 209 Description: Multiresponse Reference: Section 2 of this document 8.2. Media Type Registration This document registers the application/http-history media type, in the "Media Types" registry maintained at , following the procedures of [RFC6838], and the registration of application/http in Section 10.2 of [RFC9112]: Type name: application Subtype name: http-history Required parameters: N/A Optional parameters: N/A. The version and msgtype parameters of application/http do not apply, since every message is a response, and the status line's prefix is flexible. Encoding considerations: binary, as for application/http. Security considerations: see Section 7 of this document. Interoperability considerations: an HTTP/1.1 parser reads it, given the framing rules of Section 3.1. Published specification: this document. Applications that use this media type: subscriptions [SUBSCRIPTIONS], and requests for a span of history [VERSIONS]. Fragment identifier considerations: N/A Additional information: Deprecated alias names: 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: Michael Toomim Intended usage: COMMON Restrictions on usage: N/A Author: Michael Toomim Change controller: IETF 8.3. Field Registration This document registers the following fields in the "Hypertext Transfer Protocol (HTTP) Field Name Registry", maintained at , as described in Section 16.3.1 of [RFC9110]: Field Name: Responds-To Status: permanent Structured Type: Dictionary Reference: Section 4 of this document Field Name: Method-Override Status: permanent Structured Type: Item Reference: Section 5 of this document 9. References 9.1. Normative References [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997. [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, May 2017. [RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, June 2022. [RFC9111] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Caching", STD 98, RFC 9111, June 2022. [RFC9112] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP/1.1", STD 99, RFC 9112, June 2022. [RFC10036] Oku, K., Pauly, T., and M. Thomson, "Incremental Forwarding of HTTP Messages", RFC 10036, August 2026. [SIMPLER-FIELDS] Toomim, M., "Simpler Fields for HTTP", draft-toomim-httpbis-simpler-fields-00, work in progress, November 2026. 9.2. Informative References [BRAID-EMACS] braid.org, "braid-emacs", . [BRAID-HTTP-JS] braid.org, "braid-http", . [BRAID-NEOVIM] braid.org, "braid-neovim", . [BRAID-TEXT] braid.org, "braid-text", . [CACHE-TESTS] Nottingham, M., "HTTP Caching Tests", . [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, January 2013. [RFC7942] Sheffer, Y. and A. Farrel, "Improving Awareness of Running Code: The Implementation Status Section", BCP 205, RFC 7942, July 2016. [SUBSCRIPTIONS] Toomim, M., "Subscriptions for HTTP", draft-toomim-httpbis-braid-subscriptions-00, work in progress, November 2026. [UPDATES] Toomim, M., "Replayable Updates for HTTP", draft-toomim-httpbis-braid-updates-00, work in progress, November 2026. [VERSIONS] Toomim, M., "Resource Versioning for HTTP", draft-toomim-httpbis-braid-versions-00, work in progress, November 2026. Authors' Addresses Michael Toomim Invisible College, Berkeley 2053 Berkeley Way Berkeley, CA 94704 EMail: toomim@gmail.com Web: https://invisible.college/@toomim