-
Notifications
You must be signed in to change notification settings - Fork 291
add HTTP spec #508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add HTTP spec #508
Changes from 23 commits
bc1aa59
1f075f6
12f86b8
146c09a
5398f5d
b6c1bc2
8a57943
d506145
946f516
3681472
dd5d07c
46d1857
ebe612c
7e5a077
db2b3b5
6319458
c7c9c43
454e25c
a25267b
3014b22
f96359b
1e87960
d0f0d93
8fbd64a
71415b0
4a03bb0
877899d
dc71f2c
d8850aa
78e8ca1
d30efda
8628b5a
3c0ac40
75bc635
f95e4db
e3eb9dc
95ffe6d
8f44d00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,153 @@ | ||
| # HTTP | ||
|
|
||
| | Lifecycle Stage | Maturity | Status | Latest Revision | | ||
| | --------------- | ------------- | ------ | --------------- | | ||
| | 1A | Working Draft | Active | r0, 2023-01-23 | | ||
|
|
||
| Authors: [@marten-seemann], [@MarcoPolo] | ||
|
|
||
| Interest Group: [@lidel], [@thomaseizinger] | ||
|
|
||
| [@marten-seemann]: https://github.com/marten-seemann | ||
| [@MarcoPolo]: https://github.com/MarcoPolo | ||
| [@lidel]: https://github.com/lidel | ||
| [@thomaseizinger]: https://github.com/thomaseizinger | ||
|
|
||
| ## Introduction | ||
|
|
||
| This document defines how libp2p nodes can offer and use an HTTP transport alongside their other transports to support application protocols with HTTP semantics. This allows a wider variety of nodes to participate in the libp2p network, for example: | ||
MarcoPolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| - Browsers communicating with other libp2p nodes without needing a WebSocket, WebTransport, or WebRTC connection. | ||
| - HTTP only edge workers can run application protocols and respond to peers on the network. | ||
| - `curl` from the command line can make requests to other libp2p nodes. | ||
|
|
||
| The HTTP transport will also allow application protocols to make use of HTTP intermediaries such as HTTP caching, and layer 7 proxying and load balancing. This is all in addition to the existing features that libp2p provides such as: | ||
MarcoPolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| - Connectivity – Work on top of WebRTC, WebTransport, QUIC, TCP, or an HTTP transport. | ||
| - Hole punching – Work with peers behind NATs. | ||
| - Peer ID Authentication – Authenticate your peer by their libp2p peer id. | ||
| - Peer discovery – Learn about a peer given their peer id. | ||
|
|
||
| ## HTTP Semantics vs Encodings vs Transport | ||
|
|
||
| HTTP is a bit of an overloaded term. This section aims to clarify what we’re talking about when we say “HTTP”. | ||
|
|
||
|
|
||
| ```mermaid | ||
| graph TB | ||
| subgraph "HTTP Semantics" | ||
| HTTP | ||
| end | ||
| subgraph "Encoding" | ||
| HTTP1.1[HTTP/1.1] | ||
| HTTP2[HTTP/2] | ||
| HTTP3[HTTP/3] | ||
| end | ||
| subgraph "Transports" | ||
| Libp2p[libp2p streams] | ||
| HTTPTransport[HTTP transport] | ||
| end | ||
| HTTP --- HTTP1.1 | ||
| HTTP --- HTTP1.1 | ||
| HTTP1.1 --- Libp2p | ||
| HTTP --- HTTP2 | ||
| HTTP --- HTTP3 | ||
| HTTP1.1 --- HTTPTransport | ||
| HTTP2 --- HTTPTransport | ||
| HTTP3 --- HTTPTransport | ||
|
Comment on lines
+37
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. h2c to show how it can be multiplexed and negociated in many ways (header compression, binary based protocol, ...) ? |
||
| ``` | ||
|
|
||
| - *HTTP semantics* ([RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html)) is | ||
| the stateless application-level protocol that you work with when writing HTTP | ||
| apis (for example). | ||
|
|
||
| - *HTTP encoding* is the thing that takes your high level request/response | ||
| defined in terms of HTTP semantics and encodes it into a form that can be sent | ||
| over the wire. | ||
|
|
||
| - *HTTP transport* is the thing that takes your encoded reqeust/response and | ||
| sends it over the wire. For HTTP/1.1 and HTTP/2, this is a TCP+TLS connection. | ||
| For HTTP/3, this is a QUIC connection. | ||
|
|
||
| When this document says *HTTP* it is generally referring to *HTTP semantics*. | ||
|
|
||
| ## Interoperability with existing HTTP systems | ||
|
|
||
| A goal of this spec is to allow libp2p to be able to interoperate with existing HTTP servers and clients. Care is taken in this document to not introduce anything that would break interoperability with existing systems. | ||
|
Comment on lines
+72
to
+76
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this is a bit confusing to me. Above you are saying the you generally refer to HTTP semantics and the next sentence says that a goal is to interoperate with existing HTTP servers and clients which refers to the transport, correct?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refers to both actually |
||
|
|
||
| ## HTTP Transport | ||
|
|
||
| Nodes MUST use HTTPS (i.e., they MUST NOT use plaintext HTTP). It is RECOMMENDED to use HTTP/2 and HTTP/3. | ||
|
|
||
| Nodes signal support for their HTTP transport using the `/http` component in | ||
| their multiaddr. E.g., `/dns4/example.com/tls/http`. See the [HTTP multiaddr | ||
MarcoPolo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| component spec](https://github.com/libp2p/specs/pull/550) for more details. | ||
|
|
||
| ## Namespace | ||
|
|
||
| libp2p does not squat the global namespace. libp2p application protocols can be discovered by the [well-known resource](https://www.rfc-editor.org/rfc/rfc8615) `.well-known/libp2p`. This allows server operators to dynamically change the URLs of the application protocols offered, and not hard-code any assumptions how a certain resource is meant to be interpreted. | ||
|
|
||
| ```json | ||
|
|
||
| { | ||
| "protocols": { | ||
| "/kad/1.0.0": {"path": "/kademlia/"}, | ||
| "/ipfs-http/1.0.0": {"path": "/"}, | ||
marten-seemann marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The resource contains a mapping of application protocols to their respective URL. For example, this configuration file would tell a client | ||
|
|
||
| 1. That the Kademlia protocol is available at `/kademlia` and | ||
| 2. The [IPFS Trustless Gateway API](https://specs.ipfs.tech/http-gateways/trustless-gateway/) is mounted at `/`. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly, this only specifies the path but not the method (GET / POST) to use when accessing this protocol over HTTP and that's up to the specific protocol to define how to run it over HTTP?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm.. the methods will be specific to each protocol at each mount point, so not part of this spec?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That makes sense. As I see it there are two sections in this document:
So should we mention it in the specs that a libp2p protocol supporting http transport should specify the http method and headers to be used for the protocol. For the path they can expose it via the wellknown endpoint
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand. An application protocol would be built using HTTP semantics, and that protocol would then be able to run on libp2p streams or "standard" http transports like h2, h3. What do you mean by:
This spec does not define how you would take an existing libp2p protocol and map it to HTTP semantics. That is best done by the specific protocol itself. But maybe I'm misunderstanding your point? |
||
|
|
||
| It is valid to expose a service at `/`. It is RECOMMENDED that implementations facilitate the coexistence of different service endpoints by ensuring that more specific URLs are resolved before less specific ones. For example, when registering handlers, more specific paths like `/kademlia/foo` should take precedence over less specific handler, such as `/`. | ||
|
|
||
| ## Peer ID Authentication | ||
|
|
||
| When using the HTTP Transport, peer id authentication is optional. You only pay for it if you need it. This benefits use cases that don’t need peer authentication (e.g., fetching content addressed data) or authenticate some other way (not tied to libp2p peer ids). | ||
|
|
||
| Peer ID authentication in the HTTP Transport follows a similar to pattern to how | ||
| libp2p adds Peer ID authentication in WebTransport and WebRTC. We run the | ||
| standard libp2p Noise handshake, but using `IX` for client and server | ||
| authentication or `NX` for just server authentication. | ||
|
|
||
| Note: This is just one form of Peer ID authentication. Other forms may be added | ||
| in the future (with a different `WWW-Authenticate` value) or be added to the | ||
| application protocols themselves. | ||
|
|
||
| ### Authentication flow | ||
|
|
||
| 1. The client initiates a request that it knows must be authenticated OR the client responds to a `401` with the header `WWW-Authenticate: Libp2p-Noise` (The server MAY also include `Libp2p-Token` as an authentication scheme). | ||
| 2. The client sets the `Authorization` [header](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.6.2) to `Libp2p-Noise <multibase-encoded-noise-protobuf>` . This initiates the `IX` or `NX` handshake. | ||
|
||
| 1. The protobuf is multibase encoded, but clients MUST only use encodings that are HTTP header safe (refer to to the [token68 definition](https://www.rfc-editor.org/rfc/rfc9110.html#section-11.2)). To set the minimum bar for interoperability, clients and servers MUST support base32 encoding (”b” in the multibase table). | ||
| 2. When the server receives this request and `IX` was used, it can authenticate the client. | ||
| 3. The server responds with `Authentication-Info` field set to `Libp2p-Noise <multibase-encoding-noise-protobuf-response>`. | ||
| 1. The server MUST include the SNI used for the connection in the [Noise extensions](https://github.com/libp2p/specs/blob/master/noise/README.md#noise-extensions). | ||
| 2. The server MAY include a token in the Noise extensions that the client | ||
| can use to avoid doing another Noise handshake in the future. The client | ||
| would use this token by setting the `Authorization` header to `Libp2p-Token | ||
| <token>`. | ||
|
||
| 3. When the client receives this response, it can authenticate the server’s peer ID. | ||
| 4. The client verifies the SNI in the Noise extension matches the one used to initiate the connection. The client MUST close the connection if they differ. | ||
| 1. The client SHOULD remember this connection is authenticated. | ||
| 2. The client SHOULD use the `Libp2p-Token` if provided for future authorized requests. | ||
|
|
||
| This costs one round trip, but can piggy back on an appropriate request. | ||
|
|
||
| ### Authentication Endpoint | ||
|
|
||
| Because the client needs to make a request to authenticate the server, and the client may not want to make the real request before authenticating the server, the server MAY provide an authentication endpoint. This authentication endpoint is like any other application protocol, and it shows up in `.well-known/libp2p`, but it only does the authentication flow. It doesn’t send any other data besides what is defined in the above Authentication flow. The protocol id for the authentication endpoint is `/http-noise-auth/1.0.0`. | ||
|
|
||
| ## Using HTTP semantics over stream transports | ||
MarcoPolo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Application protocols using HTTP semantics can run over any libp2p stream transport. Clients open a new stream using `/http/1.1` as the protocol identifer. Clients encode their HTTP request as an HTTP/1.1 message and send it over the stream. Clients parse the response as an HTTP/1.1 message and then close the stream. | ||
Jorropo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
MarcoPolo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| HTTP/1.1 is chosen as the minimum bar for interoperability, but other encodings of HTTP semantics are possible as well and may be specified in a future update. | ||
Jorropo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Using other request-response semantics (not HTTP) | ||
|
|
||
| This document has focused on using HTTP semantics, but HTTP may not be the common divisor amongst all transports (current and future). It may be desirable to use some other request-response semantics for your application-level protocol, perhaps something like rust-libp2p’s [request-response](https://docs.rs/libp2p/0.52.1/libp2p/request_response/index.html) abstraction. Nothing specified in this document prohibits mapping other semantics onto HTTP semantics to keep the benefits of using an HTTP transport. | ||
|
|
||
| To support the simple request-response semantics, for example, the request MUST be encoded within a `POST` request to the proper URL (as defined in the Namespace section). The response is read from the body of the HTTP response. The client MUST authenticate the server and itself **before** making the request. | ||
MarcoPolo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
MarcoPolo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.