Search code examples
http-headerscontent-typeresteasy

Content-Type case sensitivity in RESTEasy 3


I am developing a RestEasy client to connect to a 3rd party REST service which has defined its own custom media types. A made up example is

application/vnd.abc.thirdPartyThing-v1+json

Note the uppercase P in thirdParty.

I am using RESTEasy 3.0.11 for my client implementation. At the point where I make a POST call to the service my code looks like

Response response = target.request()
        .post(Entity.<ThirdPartyThing>entity(
                thing,
                "application/vnd.abc.thirdPartyThing-v1+json"));

but RESTEasy sends to the server

Content-Type: application/vnd.abc.thirdpartything-v1+json

This is due to RESTEasy's MediaTypeHeaderDelegate class's toString() method, which lowercases the type and subtype MediaTypeHeaderDelegate. This should be correct, or at least unimportant, as RFC-1341 states that Content-Type values are case-insensitive - RFC-1341

Unfortunately the 3rd party service is checking the Content-Type in a case sensitive manner and so returning a 415 UNSUPPORTED MEDIA TYPE error. I've tested using curl which doesn't alter the content-type value and confirmed that it's a case issue. application/vnd.abc.thirdPartyThing-v1+json works, application/vnd.abc.thirdpartything-v1+json does not.

I'm in the process of raising a ticket, but in the meantime is there any way to override RESTEasy's default behaviour and send Content-Type headers without lowercasing the value?

Thanks for reading.


Solution

  • I could reproduce this behavior with RESTeasy 3.0.6.Final and would not expect it. Maybe you could check their JIRA if this has already been discussed or open an issue. I once had problems on the server side because a 2.x version of RESTeasy was checking the charset attribute of the Content-Type header case-sensitive. This was also changed.

    You could solve this problem by a really ugly workaround: Overwrite the header again in a ClientRequestFilter.

    public class ContentTypeFilter implements ClientRequestFilter {
    
        private Map<String, String> contentTypes;
    
        public ContentTypeFilter() {
            contentTypes = new HashMap<>();
            contentTypes.put("text/foo", "text/Foo");
        }
    
        @Override
        public void filter(ClientRequestContext requestContext) throws IOException {
            String contentType = requestContext.getHeaderString("Content-Type");
            if (contentTypes.containsKey(contentType)) {
                requestContext.getHeaders().putSingle("Content-Type", contentTypes.get(contentType));
            }
        }
    
    }
    

    Don't forget to register this Filter:

    Client client = ClientBuilder.newClient().register(ContentTypeFilter.class);