Internet-Draft M. Toomim
Expires: 6 May 2027 Invisible College
Intended status: Informational G. Little
Invisible College
R. Walker
Bard College
B. Bellomy
Invisible College
J. Gentle
Invisible College
2 November 2026
Braid-HTTP: State Synchronization for HTTP
draft-toomim-httpbis-braid-http-05
Abstract
HTTP transfers the state of a resource once, and leaves programmers
to keep it up to date as it changes. Braid-HTTP extends HTTP from
*transferring* state to *synchronizing* it, with a set of independent
extensions, each of which addresses a limitation of HTTP on its own.
When used together, a website can synchronize with any other
website's state by its URL, just as a page on today's web can link to
any other page. This document introduces the extensions, shows how
they work alone and together, and points to the documents that define
them.
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. HTTP needs state synchronization, not just transfer ..........4
1.2. We extend HTTP with versions, updates, and subscriptions .....4
2. The extensions are modular and composable ......................6
3. The extensions combine to support replay, resume, and merge ....7
4. The same extensions serve CDNs, feeds, chats, and editors ......8
5. The extensions support many existing systems ...................9
5.1. Subscriptions express both push and pull .....................9
5.2. Versions express both linear and branching histories .........9
6. Related work ...................................................9
6.1. SSE and WebSocket ............................................9
6.2. Transfer-Encoding: chunked ..................................10
6.3. IETF work in progress .......................................10
6.4. Other IETF protocols ........................................10
6.5. Web frameworks ..............................................11
7. Where to start reading ........................................12
8. How this work is developed ....................................12
9. Security Considerations .......................................12
10. IANA Considerations ..........................................12
11. References ...................................................13
11.1. Normative References .......................................13
11.2. Informative References .....................................13
1. Introduction
1.1. HTTP needs state synchronization, not just transfer
HTTP [RFC9110] transfers a snapshot of state within a single request
and response. If the state changes, HTTP does not automatically
update clients with the new versions. This design satisficed when
webpages were mostly static and written by hand; however today's
websites are dynamic, generated from layers of state in databases,
and provide realtime updates across multiple clients and servers.
Programmers today need to *synchronize*, not just *transfer* state,
and to do this, they must work around HTTP.
The web has a long history of such workarounds. The original web
required users to click reload when a page changed. Javascript and
XMLHTTPRequest [XHR] made it possible to update just part of a page,
running a GET request behind the scenes. However, a GET request
still could not push server-initiated updates. To work around this,
web programmers would poll the resource with repeated GETs, which was
inefficient. Long-polling was invented to reduce redundant requests,
but still requires the client to initiate a round-trip for each
update. Server-Sent Events [SSE] finally created a standard for the
server to push events, but SSE provides semantics of an event-stream,
not an update-stream, and SSE programmers must encode the semantics
of updating a resource within the event stream. Today there is still
no standard to push updates to a resource's state.
In practice, web programmers today often give up on using standards
for "data that changes", and instead send custom messages over a
WebSocket: a hand-rolled synchronization protocol. Unfortunately,
this forfeits the benefits of HTTP and ReST, such as caching and a
uniform interface [REST]. As the web becomes increasingly dynamic,
web applications are forced to implement additional layers of
non-standard Javascript frameworks to synchronize changes to state.
1.2. We extend HTTP with versions, updates, and subscriptions
Each of these workarounds exists because HTTP is missing a piece.
HTTP has no way to name a point in a resource's history, to express a
change the same way from client to server and from server to client,
to send several 200 responses per request, or to keep responding to a
GET as its resource changes. Braid-HTTP adds each missing piece as a
separate extension, which is useful by itself. Together, they
generalize HTTP into a synchronization protocol, and ReST into a
synchronization architecture:
HTTP: HyperText *Transfer* Protocol
becomes: HyperState *Synchronization* Protocol
ReST: Representational State *Transfer*
becomes: Representational State *Synchronization*
For example, a client can subscribe to a chat, and get its current
state, and then each new message as it is posted:
Request:
GET /chat
Subscribe: stream
Response:
HTTP/1.1 209 Multiresponse
Subscribe: stream
Content-Type: application/http-history
Cache-Control: no-store
Incremental: ?1
HTTP/1.1 200 OK | The state at version 1
Version: ("1") |
Content-Type: text/plain |
Content-Length: 6 |
|
Hello! |
HTTP/1.1 200 OK | The change to version 2
Version: ("2") |
Parents: ("1") |
Content-Type: text/plain |
Content-Length: 14 |
|
Hello! Hi you. |
Each extension adds one piece of this exchange. The Subscribe header
asks the server to keep the response open, and to send each change
[SUBSCRIPTIONS]. The 209 Multiresponse holds several responses in
one [MULTIRESPONSE], and the Incremental header [RFC10036] asks
intermediaries to forward each one as it arrives. The Version header
says which point in time each response is at, and Parents says which
points came just before it [VERSIONS]. And Updates [UPDATES] defines
how to send each change as a patch, which every client, server, and
intermediary replays the same way.
A cache can serve this subscription to many clients at once. It
holds one subscription to the origin, and passes each change on to
every client that subscribes through it [SUBSCRIPTIONS-CACHING]:
+--------+
| origin |
+--------+
|
one subscription
|
+----------+
| CDN edge |
+----------+
/ | \
/ | \
client client client
While that subscription is open, the origin pushes each change into
the cache in half a round trip, so the cache serves the new state
even to plain GETs of /chat.
Just as a page can link to a page on any other website by its URL
alone, a website with these extensions can synchronize with the state
of any other website by its URL alone, with no API or socket protocol
between the two.
2. The extensions are modular and composable
Each extension addresses an independent limitation of HTTP:
Versions [VERSIONS]: HTTP has no way to name a point in a resource's
history. Versions gives HTTP a sense of time. Each message can
name the version that it creates, and the version just before it,
as events in a DAG, so a client can GET the state at a version,
and say which version its PUT builds on.
Updates [UPDATES]: HTTP has no way to express a change that means
the same in a request and in a response. PATCH has no matching
response, and a 206 does not say that the rest of the
representation is unchanged. Updates makes each change mean the
same thing in both directions. It defines snapshots, patches, and
deletions that a client can send in a request, and a server in a
response, and every peer replays each one the same way.
Multiresponse [MULTIRESPONSE]: Each HTTP request has one response.
Multiresponse fits many responses into one. It defines the 209
Multiresponse status code, whose content holds several responses,
and application/http-history, a format for a resource's responses
over time.
Subscriptions [SUBSCRIPTIONS]: An ordinary GET gets one response,
and the client does not hear when its resource changes later.
Subscriptions turn a GET into a stream of changes. The server
sends the current state, and then each change as it happens, in a
multiresponse. Two documents extend Subscriptions. Subscriptions
Caching [SUBSCRIPTIONS-CACHING] defines how a cache serves one
upstream subscription to many subscribers, and Poll and Push
[POLL-AND-PUSH] defines modes for origins, and paths, that cannot
hold a response open.
Merge Types [MERGE-TYPES]: HTTP does not say how to merge changes
that peers make in parallel. With Merge Types, many peers can
edit one resource at once, and still agree. Every peer merges
parallel edits with the same algorithm, OT or CRDT, so every peer
reaches the same state. Merge Types builds on Versions, to tell
which edits were parallel, and on Updates, to know what each one
changed.
The new header fields of these extensions share one syntax, Simpler
Fields [SIMPLER-FIELDS], a profile of Structured Fields that a light
client can parse with a regular expression.
3. The extensions combine to support replay, resume, and merge
Various combinations of these extensions produce useful emergent
properties. Here are some interesting combinations:
Updates and Versions: Each update applies to the state at its
Parents, even when updates arrive out of order.
Versions and Multiresponse: A client can request a span of history,
and get each update in it.
Subscriptions and Versions: A client resumes a subscription where it
left off, from the origin or from a cache.
Subscriptions and Updates: A server can send each change in a
subscription as a patch, and every peer replays it the same way.
Updates, Versions, and Merge Types: When peers edit a resource in
parallel, they merge their edits consistently.
Subscriptions, Updates, Versions, and Merge Types: Peers reach
strong eventual consistency [CRDT]. Each subscriber receives
every update, and once two peers have received the same updates,
they merge them by their Merge Type into the same state. A future
document will define reliable delivery for the updates that
clients send to servers.
4. The same extensions serve CDNs, feeds, chats, and editors
CDN performance: With a subscription, the origin updates the CDN's
cache in half a round trip, where a purge and a refetch take 1.5
round trips. Pages that change with their data bypass the CDN
today, over a WebSocket or SSE. With a subscription, they can
load and update through it: they load about as fast as cached
pages, and update as fast as over a WebSocket. Each edge serves
all its subscribers from one subscription to the origin
[SUBSCRIPTIONS] [SUBSCRIPTIONS-CACHING]. We demonstrated this
with a prototype on Cloudflare's network, using only its public
APIs [MEETING-144].
Simple updates over time: Most applications just need their pages to
update as their data changes. With subscriptions, this is easy,
and these applications can stay on HTTP, where caches can serve
them [SUBSCRIPTIONS].
News and feeds: A news site, or an RSS feed, can push each new item
to its readers, with no polling [SUBSCRIPTIONS], and a reader can
resume where it left off ([VERSIONS], Section 4.1).
AI sessions: A conversation with an AI model is an append-only log,
and with a subscription, it becomes cacheable and resumable
[SUBSCRIPTIONS] [VERSIONS] [UPDATES].
Resumable uploads: An upload is the same append-only log, going the
other way, from client to server ([UPDATES], and the bytestream
Version Type of [VERSIONS], Section 4.3).
Collaborative editing: Collaborative editors, and local-first
applications, can merge parallel edits with any OT or CRDT
algorithm [VERSIONS] [UPDATES] [MERGE-TYPES]. Time Machines
[TIME-MACHINES] gives the theory.
5. The extensions support many existing systems
The extensions are general HTTP machinery. They can express the ways
that existing systems deliver changes, and the ways that they name
points in time.
5.1. Subscriptions express both push and pull
A server can stream a subscription's updates in one response, deliver
them one at a time to a client that polls, or push them to another
server as requests [SUBSCRIPTIONS] [POLL-AND-PUSH]. These are the
ways that existing systems deliver changes. Server-Sent Events [SSE]
streams them. HTTP Events Query [EVENTS-QUERY] streams them, or
long-polls for them. Webhooks and WebSub [WEBSUB] push them to a
server. And Mercure's hub [MERCURE] and Pushpin's proxy [GRIP] relay
them from a publisher to its subscribers.
5.2. Versions express both linear and branching histories
A version is a set of events in a DAG [VERSIONS], and a Version Type
can say how to read the events. So versions can express:
- hash histories, as in git, and Merkle DAGs, as in the AT Protocol
[ATPROTO];
- vector clocks;
- branches and tags, which can simulate opening and committing a
transaction; and
- bytestreams, as for resumable uploads.
6. Related work
6.1. SSE and WebSocket
Server-Sent Events [SSE] streams events from a server to a client, in
one HTTP response. But its events are text only, with no headers of
their own, and SSE numbers them in one linear sequence, which a
distributed history can't follow. Nor does SSE say how an event
changes the state of a resource, so each application defines that
itself, inside its events.
WebSocket gives a page a two-way channel, with no semantics of state
at all, so each application defines its own protocol over it.
6.2. Transfer-Encoding: chunked
A server could send each response of a subscription as a chunk, in
chunked transfer coding. But chunks are only an encoding of the
transfer, with no meaning of their own, and any intermediary can
re-chunk a response as it forwards it. And HTTP/2 has no chunked
transfer coding at all, so the chunk boundaries disappear over any
HTTP/2 hop.
6.3. IETF work in progress
Four drafts in progress overlap with this work:
- HTTP Events Query [EVENTS-QUERY] also subscribes a client to the
resource itself, with a QUERY request. Each notification
represents an event, and Events Query leaves versions,
resumption, and merging to other specifications, which Versions,
Updates, and Merge Types could provide. It follows Per Resource
Events [PREP], by the same author.
- The Mercure Protocol [MERCURE] relays updates from a publisher to
its subscribers through a hub, at the hub's own URL. Each update
is a Server-Sent Event with no headers of its own, so it has no
version, and the caches on the path to the resource gain nothing
from it. Poll and Push [POLL-AND-PUSH] defines a subscription
gateway, which works like a Mercure hub, for origins that cannot
hold a response open.
- Resumable Uploads [RESUMABLE-UPLOAD] defines headers and a status
code for one task, uploading a file in pieces. Updates and
Versions express the same task in general terms, as patches with
a bytestream Version Type ([VERSIONS], Section 4.3).
- Byte-Range PATCH [BYTE-RANGE-PATCH] sends patches with
Content-Range, as Updates does, so the two can share one patch
format. It also has useful mechanisms to avoid Partial PUTs on
legacy servers.
6.4. Other IETF protocols
A number of IETF specifications already standardize aspects of
synchronization for specific domains. IMAP [RFC9051] provides
synchronization of email. WebDAV provides the synchronization of
"collections" [RFC6578], and has been extended specifically for
calendar data in CalDAV [RFC4791], and for vCards in CardDAV
[RFC6352]. More recently, JMAP [RFC8620] provides an updated method
of synchronization, supporting mail, calendars, and contacts.
6.5. Web frameworks
Web applications typically synchronize the state of a client and
server with layers of models, views, and controllers in web
frameworks. When HTTP synchronizes state itself, programmers write
fewer layers of code on top of it.
====== Legacy Websites ====== ====== Braid Websites ======
Today's webpages are Braid-HTTP generalizes HTTP
generated from multiple into a standard for
layers of state. Each layer synchronizing state within
has a different API. and between websites.
x Non-standard state API o Standard state API
_Client__
/ \
: o o o o : Webpage DOM o o o o State
: \| \| : \| \|
: x x : HTML Templates o o State
: /| /| : /| /|
: x x x x : JS Models o o o o State
\ | | | | / | | | |
| | | | | | | |
o o o o - http:// - o o o o - http:// -
/ | | | | \ | | | |
: x x x x : Views o o o o State
: | \| | : | \| |
: x x x : Controllers o o o State
: \ / \| : \ / \|
: x x : Models o o State
: \ / : \ /
\.... x ../ Database o State
Server
Today's programmers have to Each piece of state (o) has a
learn each API, and wire them URI; whether public or
together, making sure that internal. State can be a
changes to shared state function of other state, and
synchronize across all automatically recompute when
layers and computers. its dependencies change.
Braid-HTTP guarantees network
synchronization.
7. Where to start reading
Application developers can start with Subscriptions [SUBSCRIPTIONS],
which shows how a page subscribes to a resource with a GET, and then
read Updates [UPDATES], to send changes as patches.
CDN and cache implementers can start with Subscriptions Caching
[SUBSCRIPTIONS-CACHING], which shows how one subscription to the
origin serves every subscriber at an edge, and how the edge answers
plain GETs from its validated copy.
Origins on serverless or shared hosting, which cannot hold a response
open, can start with Poll and Push [POLL-AND-PUSH].
8. How this work is developed
braid.org is an open group working on interoperable state
synchronization: with HTTP, where most of the world's state lives,
and with the state of operating systems and applications. Its aim is
for any state, anywhere, to be as easy to read and write as a local
variable: as if already downloaded and always up to date, within its
access control.
These documents are contributions to the IETF, developed in the open
at braid.org. Anyone can propose changes to them, and once the HTTP
Working Group adopts them, it holds change control.
9. Security Considerations
Each extension's document has its own security considerations. This
document adds none.
10. IANA Considerations
This document has no IANA actions.
11. References
11.1. Normative References
[RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP Semantics", STD 97, RFC 9110, June 2022.
11.2. Informative References
[ATPROTO] "AT Protocol", .
[BYTE-RANGE-PATCH]
Wright, A., "Byte Range PATCH",
draft-wright-http-patch-byterange, work in progress.
[CRDT] Shapiro, M., Preguica, N., Baquero, C., and M. Zawirski,
"Conflict-free replicated data types", in SSS'11
Proceedings of the 13th international conference on
Stabilization, safety, and security of distributed
systems, October 2011.
[EVENTS-QUERY]
Gupta, R., "HTTP Events Query",
draft-gupta-httpapi-events-query-04, work in progress,
November 2026.
[GRIP] Fanout, "Generic Realtime Intermediary Protocol",
.
[MEETING-144]
Toomim, M., "Braided CDN Polyfills", Braid Meeting 144,
September 2026, .
[MERCURE] Dunglas, K., "The Mercure Protocol",
draft-dunglas-mercure-08, work in progress, August 2026.
[MERGE-TYPES]
Toomim, M., Milutinovic, M., and B. Bellomy, "Consistent
Merge Types for HTTP",
draft-toomim-httpbis-braid-merge-types-00, work in
progress, November 2026.
[MULTIRESPONSE]
Toomim, M., "Multiresponses for HTTP",
draft-toomim-httpbis-braid-multiresponse-00, work in
progress, November 2026.
[POLL-AND-PUSH]
Toomim, M., "Poll and Push Modes for HTTP Subscriptions",
draft-toomim-httpbis-braid-poll-and-push-00, work in
progress, November 2026.
[PREP] Gupta, R., "Per Resource Events",
draft-gupta-httpbis-per-resource-events-03, work in
progress.
[REST] Fielding, R., "Architectural Styles and the Design of
Network-based Software Architectures", Doctoral
dissertation, University of California, Irvine, 2000.
[RESUMABLE-UPLOAD]
Kleidl, M., Zhang, G., and L. Pardue, "Resumable Uploads
for HTTP", draft-ietf-httpbis-resumable-upload, work in
progress.
[RFC4791] Daboo, C., Desruisseaux, B., and L. Dusseault,
"Calendaring Extensions to WebDAV (CalDAV)", RFC 4791,
March 2007.
[RFC6352] Daboo, C., "CardDAV: vCard Extensions to Web Distributed
Authoring and Versioning (WebDAV)", RFC 6352, August 2011.
[RFC6578] Daboo, C. and A. Quillaud, "Collection Synchronization for
Web Distributed Authoring and Versioning (WebDAV)", RFC
6578, March 2012.
[RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application
Protocol (JMAP)", RFC 8620, July 2019.
[RFC9051] Melnikov, A., Ed. and B. Leiba, Ed., "Internet Message
Access Protocol (IMAP) - Version 4rev2", RFC 9051, August
2021.
[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.
[SSE] Hickson, I., "Server-Sent Events", W3C Recommendation,
February 2015,
.
[SUBSCRIPTIONS]
Toomim, M., "Subscriptions for HTTP",
draft-toomim-httpbis-braid-subscriptions-00, work in
progress, November 2026.
[SUBSCRIPTIONS-CACHING]
Toomim, M., "Caching for HTTP Subscriptions",
draft-toomim-httpbis-braid-subscriptions-caching-00, work
in progress, November 2026.
[TIME-MACHINES]
Toomim, M., "Time Machines",
.
[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.
[WEBSUB] Genestoux, J., Ed. and A. Parecki, Ed., "WebSub", W3C
Recommendation, January 2018,
.
[XHR] van Kesteren, A., "XMLHttpRequest", WHATWG Living
Standard, .
Acknowledgements
In addition to the authors, this spec contains intellectual
contributions from the following people:
- Mitar Milutinovic
- Sarah Allen
- Duane Johnson
- Travis Kriplean
- Marius Nita
- Paul Pham
- Morgan Dixon
- Karthik Palaniappan
We thank the following people for key feedback on previous drafts:
- Austin Wright
- Martin Thomson
- Eric Kinnear
- Olli Vanhoja
- Julian Reschke
- Chris Lemmons
- Rahul Gupta
We also thank Mark Nottingham, Fred Baker, Adam Roach, and Barry
Leiba for facilitating a productive environment within the IETF.
Authors' Addresses
Michael Toomim
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
EMail: toomim@gmail.com
Web: https://invisible.college/@toomim
Greg Little
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
EMail: glittle@gmail.com
Web: https://glittle.org/
Rafie Walker
Bard College
EMail: slickytail.mc@gmail.com
Bryn Bellomy
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
EMail: bryn@signals.io
Web: https://invisible.college/@bryn
Joseph Gentle
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
EMail: me@josephg.com
Web: https://josephg.com/