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

ResourceHttpMessageConverter always returns "application/octet-stream" Content-Type [SPR-12894] #17493

Closed
spring-issuemaster opened this issue Apr 7, 2015 · 5 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Apr 7, 2015

Konstantinos Filios opened SPR-12894 and commented

I have the following controller:

@RestController
public class TestController
{
    @RequestMapping(value = "/image", method = RequestMethod.GET)
    public Resource getImage()
    {
        return new FileSystemResource("/path/to/image.png");
    }
}

I have configured web mvc to only add a ResourceHttpMessageConverter so I rule out interference from other converters. I have also made sure JAF is included in the classpath.

When I test the method with an HTTP client (always with Accept: **/**), I do get the contents of the image back, but the Content-Type is wrong. It's always application/octet-stream;charset=UTF-8

While debugging the code, I noticed that the ResourceHttpMessageConverter.getDefaultContentType method never gets called.

This seems to happen because in AbstractMessageConverterMethodProcessor.writeWithMessageConverters, the following block yields a selectedMediaType equal to MediaType.APPLICATION_OCTET_STREAM

MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
     if (mediaType.isConcrete()) {
          selectedMediaType = mediaType;
          break;
     }
     else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
          selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
          break;
     }
}

This is actually expected if you consider that the only constructor of ResourceHttpMessageConverter defines MediaType.ALL as the supported media type:

public ResourceHttpMessageConverter() {
     super(MediaType.ALL);
}

Consequently, when AbstractHttpMessageConverter.write is called a few instructions later, it reaches the code block below, in which the if condition evaluates to false since the passed contentType equals MediaType.APPLICATION_OCTET_STREAM:

if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
     contentTypeToUse = getDefaultContentType(t);
}

I tried changing the controller method's @RequestMapping with a produces="image/*" but obviously nothing changed.


Affects: 4.1.6

Referenced from: commits 8ff7cc7

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 8, 2015

Rossen Stoyanchev commented

I see so basically ResourceHttpMessageConverter needs a Resource to make an accurate MediaType choice. However AbstractMessageConverterMethodProcessor only takes into consideration the converter's list of supportedMediaTypes which in this case is MediaType.ALL.

Given that AbstractMessageConverterMethodProcessor falls back on application/octet-stream by default when nothing more specific is chosen, perhaps AbstractHttpMessageConverter should check if getDefaultContentType(t) can yield something more specific. Something like:

if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
	contentTypeToUse = getDefaultContentType(t);
}
else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
	// can getDefaultContentType(t) return a more concrete media type?
}

Arjen Poutsma what do you think?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 9, 2015

Arjen Poutsma commented

That sounds like a good idea.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 9, 2015

Rossen Stoyanchev commented

Konstantinos Filios unrelated to the fix, I'm just curious about the use of an @RequestMapping method vs the resource handling mechanism base don ResourceHttpRequestHandler?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 9, 2015

Konstantinos Filios commented

Rossen Stoyanchev I considered ResourceHttpRequestHandler but I have some non-trivial authorization checks which determine whether I finally serve the resource or not. The actual url is of the form /users/[id]/image and unfortunately the HttpSecurity configuration does not seem to allow exchange of data between the antMatchers() and the subsequent access() calls.

Something like the scenario described in this SO question

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Apr 9, 2015

Rossen Stoyanchev commented

Thanks for the comment.

/cc Rob Winch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.