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

Rest client 307 redirect doesn't keep original request headers #35126

Closed
jdussouillez opened this issue Aug 1, 2023 · 17 comments · Fixed by #41485
Closed

Rest client 307 redirect doesn't keep original request headers #35126

jdussouillez opened this issue Aug 1, 2023 · 17 comments · Fixed by #41485
Labels
area/rest-client kind/bug Something isn't working
Milestone

Comments

@jdussouillez
Copy link

jdussouillez commented Aug 1, 2023

Describe the bug

The bug is following issue #34644

With Quarkus v3.2.1+, a POST request done on an endpoint responding HTTP 307 now sends a POST request on the new URL. The problem now is that the original request headers are lost and not sent to the new URL.

It works fine with curl and Postman. Unfortunately I couldn't find any documentation about headers after redirect in the RFCs.

Expected behavior

When sending the new request after a redirect, the HTTP method and the headers must be kept from the original request (method is OK since #34644 but headers are lost).

-> POST /token, headers=[H1, H2]
<- HTTP 307, Location=/token2
-> POST /token2, headers=[H1, H2]

Actual behavior

The headers are not sent in the request after the redirect.

-> POST /token, headers=[H1, H2]
<- HTTP 307, Location=/token2
-> POST /token2, headers=[]

How to Reproduce?

Reproducer: https://github.com/jdussouillez/quarkus-rest-client-post-redirect-post/tree/missing-headers

Same as #34644 but use missing-headers branch.

The server requires "X-Api-Version" header or will fail with "Bad request". Using curl it works fine:

curl

Using Quarkus Rest client it fails with 400 because the "X-Api-Version" header wasn't sent in the second request.

quarkus-rest-client

Output of uname -a or ver

No response

Output of java -version

openjdk version "17.0.7"

GraalVM version (if different from Java)

No response

Quarkus version or git rev

3.2.2.Final

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

@jdussouillez jdussouillez added the kind/bug Something isn't working label Aug 1, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Aug 1, 2023

/cc @Sgitario (rest-client), @cescoffier (rest-client), @geoand (rest-client)

@geoand
Copy link
Contributor

geoand commented Aug 1, 2023

I wonder what the spec says about this... I don't recall ever hearing about header handling although it does sound reasonable

@jdussouillez
Copy link
Author

Yeah I looked in both RFCs mentioned here but nothing says if the headers must be sent again or not.

@cescoffier
Copy link
Member

I don't think we can forward all headers blindly. Some may contain sensible content which should not be forwarded. So, it would require a list of the headers to not forward (or a more prescriptive approach where we list the headers to forward, but that could be annoying)

@jdussouillez
Copy link
Author

jdussouillez commented Aug 1, 2023

So, it would require a list of the headers to not forward (or a more prescriptive approach where we list the headers to forward, but that could be annoying)

@geoand imagined a more flexible solution (but a bit heavy) here by using an AdvancedRedirectHandler to customize the request sent after the redirect, using the original request and redirect response informations. I guess headers could also be overridden with this solution.

Something like:

// ...
RedirectRequest of(ResteasyReactiveClientRequestContext reqContext, Response redirectResponse) {
    return new RedirectResponse() {
        @Override
        public URI uri() {
            return null; // null means the default value (redirectResponse's "Location" header value)
        }

        @Override
        public String httpMethod() {
            return null; // null means the original HTTP method (reqContext.getMethod())
        }

        @Override
        public MultivaluedMap<String, Object> headers() {
            return null; // null means the request headers (reqContext.getHeaders()) but you can remove/add stuff here
        }
    };
}
// ...

@geoand
Copy link
Contributor

geoand commented Aug 1, 2023

Right, that design would allow for such a use case.

I'll leave it to @Sgitario and @cescoffier to decide if it's complexity is warranted.

@cescoffier
Copy link
Member

I think it's a good approach. I'm fearing we start introducing dozens of parameters to capture everything, while a single programmatic approach would work.

@Sgitario
Copy link
Contributor

Sgitario commented Aug 1, 2023

why would we need the AdvancedRedirectHandler implementation? We could provide default methods in the existing RedirectHandler like:

public interface RedirectHandler {
    int DEFAULT_PRIORITY = 5000;

    URI handle(Response response);

    default int getPriority() {
        return Optional.ofNullable(this.getClass().getAnnotation(Priority.class)).map(Priority::value).orElse(DEFAULT_PRIORITY);
    }

    default Set<String> propagateHeaders() {
        return Set.of();
    }

    default MultivaluedMap<String, Object> addHeaders(MultivaluedMap<String, Object> requestHeaders) {
        return new MultivaluedHashMap<>();
    }
}

I've added two new methods:

  • propagateHeaders to explicitly set the header names to propagate from the header
  • addHeaders to add headers (we could also provide here the request headers)

@geoand
Copy link
Contributor

geoand commented Aug 1, 2023

That could certainly be an option, I would personally not prefer it since it is almost certainly not what we would do if we were designing the API from scratch.

@jdussouillez
Copy link
Author

Any updates?

@geoand
Copy link
Contributor

geoand commented Oct 3, 2023 via email

@jdussouillez
Copy link
Author

Bumping. It would be nice to have this (to remove manual HTTP requests and use REST client instead)

@geoand
Copy link
Contributor

geoand commented Jun 26, 2024

I'll try and check this soon

geoand added a commit to geoand/quarkus that referenced this issue Jun 26, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
@geoand
Copy link
Contributor

geoand commented Jun 26, 2024

Can you try #41485?

It introduces the new AdvancedRedirectHandler which you can be used as shown in the new AdvancedRedirectTest

geoand added a commit to geoand/quarkus that referenced this issue Jun 27, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
geoand added a commit to geoand/quarkus that referenced this issue Jun 27, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
geoand added a commit to geoand/quarkus that referenced this issue Jun 28, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
geoand added a commit to geoand/quarkus that referenced this issue Jun 28, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
@quarkus-bot quarkus-bot bot added this to the 3.13 - main milestone Jun 30, 2024
@jdussouillez
Copy link
Author

jdussouillez commented Jul 8, 2024

@geoand Thanks, the AdvancedRedirectHandler works fine!

See my reproducer's "quarkus-v3.13" branch


But now I see another issue: the POST body is not sent to the redirect request. Note that it is also an issue with RedirectHandler's URI handle(Response response) method.

Is there a way to do this using the new AdvancedRedirectHandler? I guess it's not that easy because Vert.x RequestOptions does not handle body, only method, headers, URL, etc.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307

The method and the body of the original request are reused to perform the redirected request.
[...]
The only difference between 307 and 302 is that 307 guarantees that the method and the body will not be changed when the redirected request is made.

Reproducer: https://github.com/jdussouillez/quarkus-rest-client-post-redirect-post/tree/quarkus-v3.13 (client gets a 400 instead of 200 because body is null)

@geoand
Copy link
Contributor

geoand commented Jul 8, 2024

If Vert'x is not handling doing this, there is not much we can do in Quarkus - see that AdvancedRedirectHandler is just used to setup a Vert.x object which is set to io.vertx.core.http.HttpClientBuilder#withRedirectHandler

@jdussouillez
Copy link
Author

I created #41751 as this issue is closed and the new feature works fine.

holly-cummins pushed a commit to holly-cummins/quarkus that referenced this issue Jul 31, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
danielsoro pushed a commit to danielsoro/quarkus that referenced this issue Sep 20, 2024
This handler allows users to set all options of the
new request.
It should not be needed in all but the most weird scenarios.

Closes: quarkusio#35126
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/rest-client kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants