Skip to content

WebClient: Explicit Content-Type application/octet-stream is overwritten #33303

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

Closed
othi opened this issue Aug 2, 2024 · 4 comments
Closed

WebClient: Explicit Content-Type application/octet-stream is overwritten #33303

othi opened this issue Aug 2, 2024 · 4 comments
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply

Comments

@othi
Copy link

othi commented Aug 2, 2024

Affected version: 6.1.11

The API I'm consuming requires the Content-Type header to be application/octet-stream for certain binary payloads.

The Content-Type is set explicitly using RequestBodySpec.contentType() but it is later overwritten in this method:

private static MediaType getResourceMediaType(
@Nullable MediaType mediaType, Resource resource, Map<String, Object> hints) {
if (mediaType != null && mediaType.isConcrete() && !mediaType.equals(MediaType.APPLICATION_OCTET_STREAM)) {
return mediaType;
}
mediaType = MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Resource associated with '" + mediaType + "'");
}
return mediaType;
}

This is unintuitive behaviour and not configurable. To circumvent this, I have to rename the file to an extension not present in spring-web/src/main/resources/org/springframework/http/mime.types so my explicitly set header is respected.

To reproduce, here is a function that sets the content type of the request:

    public void test() throws IOException {
        File f = File.createTempFile("test", ".pdf");

        WebClient webClient = WebClient.create();
        RequestBodySpec builder = webClient.method(HttpMethod.POST).uri("http://localhost:12458");
        builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
        builder.body(BodyInserters.fromValue(new FileSystemResource(f)));
        builder.retrieve().toBodilessEntity().block();
    }

Resulting request using netcat:

me@dev:~$ nc -l 12458
POST / HTTP/1.1
accept-encoding: gzip
user-agent: ReactorNetty/1.1.9
host: localhost:12458
accept: */*
Content-Type: application/pdf   <---------
content-length: 0

Expected result:

Content-Type: application/octet-stream

Thanks

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 2, 2024
@bclozel bclozel added in: web Issues in web modules (web, webmvc, webflux, websocket) status: waiting-for-triage An issue we've not yet triaged or decided on and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Aug 2, 2024
@imvtsl
Copy link
Contributor

imvtsl commented Aug 7, 2024

@bclozel
Is it okay if I work on this issue?

@bclozel
Copy link
Member

bclozel commented Sep 10, 2024

Sorry for the delayed feedback.

I'm not sure we can support this specific use case without undoing the mime type detection, which is widely used. I think application/octet-stream is assumed as the default for many client libraries, hence our check.

Have you considered using a custom media type like application/octet-stream;force=true or something equivalent? An additional parameter would skip this check.

@bclozel bclozel added the status: waiting-for-feedback We need additional information before we can continue label Sep 10, 2024
@othi
Copy link
Author

othi commented Sep 13, 2024

That does work in my case but it still seems unfortunate to have to do that.

Would it not be acceptable to you to have the setter set a flag to indicate that it was called, making the choice of the content-type explicit? I understand that mime type detection is a helpful feature, but if the setter is called on the builder, surely the user did not want that choice to be overridden?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 13, 2024
@bclozel
Copy link
Member

bclozel commented Sep 13, 2024

Thanks for the proposal, but I think we're going to stick with the current behavior.

The ResourceHttpMessageWriter is trying to detect a more precise media type, and here it does. I'm not sure what the requirement is here, maybe because the remote server doesn't support anything but application/octet-stream? In this case, if the filename is not meant to be used at all as source of truth, I would suggest using a Resource implementation that does not expose the filename information. This would also work and probably better reflect the use case you're facing: the file information is not relevant, only the content bytes.

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Sep 13, 2024
@bclozel bclozel added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Sep 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

4 participants