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

[Factors] Change how incoming-request.authority is set. #2723

Merged
merged 3 commits into from
Aug 19, 2024

Conversation

rylev
Copy link
Collaborator

@rylev rylev commented Aug 19, 2024

The moral equivalent of #2684 for factors.

The second commit fixes a remaining issue: incoming-request.authority won't otherwise be set in service chained requests. This is because authority was set a layer above where service chained requests hook into the http trigger stack. The setting of authority has been moved into HttpServer::handle_trigger_route from the HttpServer::handle method. I believe this will work fine as the only thing the handle function does in addition to calling handle_trigger_route is handling the well known routes, 404s, and extract_trace_context all of which shouldn't need the scheme and authority.

Always rely on the `Host` header for authority incoming-reques.authority. To
determine where `self` requests should be routed, explicitly pass a
the listening address.

Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
@rylev rylev requested a review from lann August 19, 2024 09:21
@@ -67,7 +67,8 @@ pub(crate) type InstanceState = ();

/// The Spin HTTP trigger.
pub struct HttpTrigger {
listen_addr: SocketAddr,
/// The address the server will listen on.
addr_to_bind: SocketAddr,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wouldn't change this; the CLI flag is --listen...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I hear ya. I wanted to draw attention to the fact that this might not be the actual SocketAddr the socket is listening on (in the case of a 0 port), but perhaps that's not worth the potential confusion in the other direction.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

By the way, the CLI arg is actually --address... But I'll still change it back.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Unfortunately it is a trick:

#[clap(long = "listen", ...)]
pub address: SocketAddr,

crates/trigger-http2/src/server.rs Outdated Show resolved Hide resolved
fn set_req_uri(req: &mut Request<Body>, scheme: Scheme, addr: SocketAddr) -> anyhow::Result<()> {
/// The incoming request's URI is relative to the server, so we need to set the scheme and authority.
/// The `Host` header is used to set the authority. This function will error if no `Host` header is
/// present or if it is not parsable as an `Authority`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Based on hyperium/hyper#1612 I believe this should also consider the req.uri().authority(), verifying that they are identical if both are present.

client_addr: SocketAddr,
) -> anyhow::Result<Response<Body>> {
set_req_uri(&mut req, scheme, self.listen_addr)?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this be done at the top of instrumented_service_fn? The http_span! there emits the scheme for o11y. As a bonus it would avoid needing to thread the server_scheme param through here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Putting it in instrumented_service_fn moves the logic up the call stack where we need to move it down the call stack.

The call graph is: instrumented_service_fn -> handle -> handle_trigger_route. The handler for service chained calls calls handle_trigger_route which is why we moved set_req_uri to that function - the service chained request also needs its uri manipulated. If we were to move that logic up to instrumented_service_fn, the issue this change is trying to address would persist.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah gotcha. Perhaps it would make sense to split the scheme and host updates? 🤔

Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
Comment on lines 43 to 49
let server = self.server.clone();
let resp_fut = async move {
match server
.handle_trigger_route(req, route_match, CHAINED_CLIENT_ADDR)
.handle_trigger_route(req, route_match, Scheme::HTTP, CHAINED_CLIENT_ADDR)
.await
{
Ok(resp) => Ok(Ok(IncomingResponse {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if we should be setting the SelfRequestOrigin unconditionally in this interceptor. It seems like self requests ought to work in service-chained handlers? 🤔

Comment on lines +355 to +361
if let Some(a) = parts.authority.as_ref() {
if a != &authority {
return Err(anyhow::anyhow!(
"authority in 'Host' header does not match authority in URI"
));
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, I wasn't very clear. I believe it is valid to have just the host header, just the uri authority, or both set, where in the "both" case they must match.

Egads this seems complicated: https://www.rfc-editor.org/rfc/rfc9113.html#section-8.3.1-2.3.3

Copy link
Collaborator

@lann lann left a comment

Choose a reason for hiding this comment

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

Given that the HTTP trigger doesn't currently support http/2 I think the current impl is OK to merge.

@lann lann merged commit 3cd28a8 into factors Aug 19, 2024
2 checks passed
@lann lann deleted the factors-authority branch August 19, 2024 18:35
@lann lann mentioned this pull request Aug 27, 2024
48 tasks
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