Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions draft-ietf-httpbis-connect-tcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,13 @@ When closing connections, endpoints are subject to the following requirements:
* When a TCP connection reaches the TIME-WAIT or CLOSED state, the associated endpoint MUST close its send stream.
- If the connection closed gracefully, the endpoint MUST close the send stream gracefully.
- Otherwise, the endpoint SHOULD close the send stream abruptly, using a mechanism appropriate to the HTTP version:
- HTTP/3: RESET_STREAM with H3_CONNECT_ERROR
- HTTP/2: RST_STREAM with CONNECT_ERROR
- HTTP/1.1 over TLS: a TLS Error Alert
- HTTP/1.1 (insecure): TCP RST.
- HTTP/3: reset the stream with H3_CONNECT_ERROR;
see {{!RFC9000, Section 19.4}} and {{?RFC9114, Section 8.1}}
- HTTP/2: reset the stream with CONNECT_ERROR;
see {{!RFC9113}}, Sections 6.4 and 7
- HTTP/1.1 over TLS: TCP shutdown without a TLS closure alert;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- HTTP/1.1 over TLS: TCP shutdown without a TLS closure alert;
- HTTP/1.1 over TLS: TCP shutdown, with or without a TLS closure alert;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Closure with a close_notify after receiving a FINAL_DATA capsule (representing FIN) would indicate graceful close. The purpose of this line is to provide a signal of ungraceful close (i.e. RST or timeout) that can be used after receiving the FIN (but before the connection is closed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, either works if you don't have FINAL_DATA, so why attempt to fix implementations.

see {{!RFC8446, Section 6.1}}.
- HTTP/1.1 without TLS: TCP RST
* When the receive stream is closed abruptly or without a FINAL_DATA capsule received, the endpoint SHOULD send a TCP RST if the TCP subsystem permits it.

The mandatory behaviors above enable endpoints to detect any truncation of incoming TCP data. The recommended behaviors propagate any TCP errors through the proxy connection.
Expand Down Expand Up @@ -204,7 +207,7 @@ The mandatory behaviors above enable endpoints to detect any truncation of incom
+-+-----+ +-+----------+ +----------+-+ +-----+-+
+---"abc"--->+-------DATA{"abc"}------->+---"abc"--->|
| | (... timeout @ A ...) | |
| +--------TLS Alert-------->+----RST---->|
| +--FIN (no close_notify)-->+----RST---->|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many implementation will treat this as a normal stream termination. That's because this is indistinguishable from a successful termination in the case that the TLS close_notify doesn't get sent (or doesn't make it through).

I would not show any message being exchanged here at all.

Suggested change
| +--FIN (no close_notify)-->+----RST---->|

Of course, this is based on you RECOMMENDING that no close_notify be sent. That's not something I would endorse.

The right way to deal with this in HTTP/1.1 is to use chunked encoding or Content-Length properly. If the connection ends before the request is terminated, then it's an abortive close.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many implementation will treat this as a normal stream termination.

Do you mean implementations of TLS, or of "connect-tcp"? I assume that the major implementations of TLS correctly surface an error when close_notify is omitted at shutdown; otherwise some uses would be vulnerable to truncation attacks. Implementations of "connect-tcp" do not yet exist, and can be asked to conform. My main concern would be about TLS-terminating load balancers that always send close_notify.

I would not show any message being exchanged here at all.

I don't understand. When A times out the TCP connection, what should it do with the HTTP connection?

Of course, this is based on you RECOMMENDING that no close_notify be sent. That's not something I would endorse.

Is there a reason why this recommendation is dangerous or problematic?

The right way to deal with this in HTTP/1.1 is to use chunked encoding or Content-Length properly.

In HTTP/1.1, "connect-tcp" uses HTTP Upgrade, so Content-Length and chunked encoding are not available. Instead, it uses the Capsule Protocol (similar to chunked encoding).

If the connection ends before the request is terminated, then it's an abortive close.

"connect-tcp" employs a FINAL_DATA capsule to represent the TCP FIN (end of incoming data), without any reliance on the HTTP transport/stream. However, according to RFC 9293 that's not the same as "closed":

"a user who expects no data in return need only wait to hear the connection was CLOSED successfully to know that all their data was received at the destination TCP endpoint."

To get to the CLOSED state, you need a signal for "received ACK of FIN". In H2/H3, the draft uses graceful stream closure for that. In H1 over TLS, close_notify seems to be the equivalent signal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many implementation will treat this as a normal stream termination.

Do you mean implementations of TLS, or of "connect-tcp"? I assume that the major implementations of TLS correctly surface an error when close_notify is omitted at shutdown; otherwise some uses would be vulnerable to truncation attacks. Implementations of "connect-tcp" do not yet exist, and can be asked to conform. My main concern would be about TLS-terminating load balancers that always send close_notify.
[...]
I don't understand. When A times out the TCP connection, what should it do with the HTTP connection?

I was talking about HTTP generally.

In the timeout case, you don't need to mandate any particular behaviour. Because a timeout can be many things, including a clean termination (FINAL_DATA included) or not. You are attempting to proscribe actions that don't need that.

Of course, this is based on you RECOMMENDING that no close_notify be sent. That's not something I would endorse.

Is there a reason why this recommendation is dangerous or problematic?

Because that's not how HTTP has worked so far and you are attempting to levy implementation requirements where they are most likely unwelcome. It might be appealing to have all implementations do the same thing here, but our experience is that they don't and they probably won't change just because it would be nicer if they would.

(ignore the stuff about message termination; that's what I get for not pulling in enough context)

Copy link
Contributor Author

@bemasc bemasc Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a timeout can be many things, including a clean termination

I'm referring to a TCP user timeout, which is an error in TCP terms. It cannot be a clean shutdown because the endpoint does not know if all data was successfully received in both directions.

My point in showing this example was partly to show that even with this level of detail, some information is still lost: all errors are collapsed into RST.

that's not how HTTP has worked so far and you are attempting to levy implementation requirements where they are most likely unwelcome

  1. It's not really "HTTP". This is Upgrade, so the HTTP session is over, and the connection is now owned by a new protocol named "connect-tcp".
  2. It's a recommendation, not a requirement. If you ignore it, everything will mostly be fine, but debugging failures will be a bit harder and you'll lose this signal in HTTP/3 (where abrupt closure is not as controversial) if you have version-translating intermediaries.
  3. In at least some implementations, it's extremely easy to implement. In my Go prototype it's one line: tlsConn.NetConn().Close(). If a behavior is helpful but not crucial, sometimes easy to implement and sometimes not worth the bother, that seems like a good case for RECOMMENDED. (Lowering this to OPTIONAL in HTTP/1.1, while it's still RECOMMENDED in HTTP/2 and HTTP/3, seems like extra text and complexity with no discernible benefit.)

| | | |
~~~
{: title="Timeout example (HTTP/1.1)"}
Expand Down Expand Up @@ -237,7 +240,7 @@ Servers that host a proxy under this specification MAY offer support for TLS ear

This specification supports the "Expect: 100-continue" request header ({{?RFC9110, Section 10.1.1}}) in any HTTP version. The "100 (Continue)" status code confirms receipt of a request at the proxy without waiting for the proxy-destination TCP handshake to succeed or fail. This might be particularly helpful when the destination host is not responding, as TCP handshakes can hang for several minutes before failing. Clients MAY send "Expect: 100-continue", and proxies MUST respect it by returning "100 (Continue)" if the request is not immediately rejected.

Proxies implementing this specification SHOULD include a "Proxy-Status" response header {{!RFC9209}} in any success or failure response (i.e., status codes 101, 2XX, 4XX, or 5XX) to support advanced client behaviors and diagnostics. In HTTP/2 or HTTP/3, proxies MAY additionally send a "Proxy-Status" trailer in the event of an unclean shutdown.
Proxies implementing this specification SHOULD include a "Proxy-Status" response header {{!RFC9209}} in any success or failure response (i.e., status codes 101, 2XX, 4XX, or 5XX) to support advanced client behaviors and diagnostics. In HTTP/2 or HTTP/3, proxies MAY additionally send a "Proxy-Status" trailer in the event of an abrupt stream closure.

# Applicability

Expand Down Expand Up @@ -291,7 +294,9 @@ A malicious client can achieve cause highly asymmetric resource usage at the pro
While this specification is fully functional under HTTP/1.1, performance-sensitive deployments SHOULD use HTTP/2 or HTTP/3 instead. When using HTTP/1.1:

* Each CONNECT request requires a new TCP and TLS connection, imposing a higher cost in setup latency, congestion control convergence, CPU time, and data transfer.
* It may be difficult to implement the recommended unclean shutdown signals ({{closing-connections}}), as many TLS libraries do not support injecting TLS Alerts.
* The graceful and abrupt closure signals ({{closing-connections}}) are more likely to be missing or corrupted:
- Some implementations may be unable to emit the recommended abrupt closure signals, due to limitations in their TCP and TLS subsystems.
- Faulty implementations may fail to send a TLS closure alert during graceful shutdown, or fail to report an error when the expected closure alert is not received. These misbehaviors are not compliant with {{RFC8446}}, but they are common nonetheless among HTTP/1.1 implementations today.
* The number of active connections through each client may be limited by the number of available TCP client ports, especially if:
- The client only has one IP address that can be used to reach the proxy.
- The client is shared between many parties, such as when acting as a gateway or concentrator.
Expand Down