Skip to content
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

refactor(http/upgrade): Http11Upgrade is Clone #3540

Merged
merged 9 commits into from
Jan 22, 2025

Conversation

cratelyn
Copy link
Collaborator

@cratelyn cratelyn commented Jan 17, 2025

see linkerd/linkerd2#8733.

in the 1.0 interface of the http crate, request and response extensions must
now satisfy a Clone bound. Http11Upgrade was written before this was the
case, and is very intentionally designed around the idea that it not be
cloneable.

insert_half() in particular could cause the proxy to panic if it were
to clone a request or response's extensions. it might call
insert_half() a second time, and discover that the TryLock<T> had
already been set.

moreover, holding on to a copy of the extensions would prevent the
Drop method for Inner from being called. This would cause
connections that negotiate an HTTP/1.1 upgrade to deadlock due to the
OnUpgrade futures never being polled, and failing to create a Duplex
that acts as the connection's I/O transport.

this commit makes use of the alterations to Http11Upgrade made in
previous commits, and adds a safe implementation of Clone. by
only shallowly copying the extension, we tie the upgrade glue to a
specific request/response.

the extension can be cloned, but any generated copies will be inert.

@cratelyn cratelyn marked this pull request as ready for review January 17, 2025 15:31
@cratelyn cratelyn requested a review from a team as a code owner January 17, 2025 15:31
@olix0r olix0r self-assigned this Jan 20, 2025
this is a noöp change, to set the stage for subsequent changes to the
internal model of `Http11Upgrade`.

this `inner` field will shortly be an option, and this will make it
easier to only follow these panicking branches when the inner lock is
`Some(_)`.

Signed-off-by: katelyn martin <[email protected]>
this commit hinges on this change to the upgrade middleware's `inner`
field.

we still retain a reference-counted copy of the `Inner` state, but now
we may store `None` here.

```
 pub struct Http11Upgrade {
     half: Half,
-    inner: Arc<Inner>,
+    inner: Option<Arc<Inner>>,
 }
```

a new branch is added to the `insert_half` method that consumes the
"sender" and inserts an upgrade future; when this is `None` it will do
nothing, rather than panicking.

Signed-off-by: katelyn martin <[email protected]>
this type is an empty flag to indicate whether an `Http11Upgrade`
extension corresponds to the server or client half of the upgrade
future channel.

this type is made copy, to facilitate making the `Http11Upgrade`
extension safely cloneable.

Signed-off-by: katelyn martin <[email protected]>
this commit makes `Http11Upgrade` a cloneable type.

see <linkerd/linkerd2#8733>.

in the 1.0 interface of the `http` crate, request and response
extensions must now satisfy a `Clone` bound.

`Http11Upgrade` was written before this was the case, and is very
intentionally designed around the idea that it *not* be cloneable.

`insert_half()` in particular could cause the proxy to panic if it were
to clone a request or response's extensions. it might call
`insert_half()` a second time, and discover that the `TryLock<T>` had
already been set.

moreover, holding on to a copy of the extensions would prevent the
`Drop` method for `Inner` from being called. This would cause
connections that negotiate an HTTP/1.1 upgrade to deadlock due to the
`OnUpgrade` futures never being polled, and failing to create a `Duplex`
that acts as the connection's I/O transport.

this commit makes use of the alterations to `Http11Upgrade` made in
previous commits, and adds a *safe* implementation of `Clone`. by
only shallowly copying the extension, we tie the upgrade glue to a
*specific* request/response.

the extension can be cloned, but any generated copies will be inert.

Signed-off-by: katelyn martin <[email protected]>
@cratelyn cratelyn force-pushed the kate/http-1.1-upgrade-middleware-is-clone branch from 2231b8b to 476aa04 Compare January 21, 2025 01:46
Copy link
Member

@olix0r olix0r left a comment

Choose a reason for hiding this comment

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

and doc lints, as you noted...

linkerd/http/upgrade/src/upgrade.rs Outdated Show resolved Hide resolved
cratelyn and others added 5 commits January 22, 2025 09:49
`FutureExt::map_ok()` won't work if we try to return an error from this
block. the `and_then()` adaptor is used to chain futures, and also won't
work given a synchronous closure.

this can be done with the equivalent `.await` syntax, and leaves a nicer
hole for us to propagate other errors here, shortly.

Signed-off-by: katelyn martin <[email protected]>
@cratelyn cratelyn merged commit 76b5f10 into main Jan 22, 2025
15 checks passed
@cratelyn cratelyn deleted the kate/http-1.1-upgrade-middleware-is-clone branch January 22, 2025 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants