spring-cloud / spring-cloud-openfeign

Support for using OpenFeign in Spring Cloud apps
Apache License 2.0
1.2k stars 779 forks source link

NPE in FeignResponseAdapter in case Content-Length header is not provided and response status is not 1XX, NO_CONTENT and NOT_MODIFIED #972

Closed martinsefcik closed 7 months ago

martinsefcik commented 8 months ago

Describe the bug If HTTP response has no Content-Legnth header defined and response status code is not 1XX, NO_CONTENT and NOT_MODIFIED (implemented in org.springframework.web.client.IntrospectingClientHttpResponse#hasMessageBody) and response has no body then we are getting the following NPE in org.springframework.cloud.openfeign.support.SpringDecoder.FeignResponseAdapter#getBody.

java.lang.NullPointerException: Cannot invoke "feign.Response$Body.asInputStream()" because the return value of "feign.Response.body()" is null
    at org.springframework.cloud.openfeign.support.SpringDecoder$FeignResponseAdapter.getBody(SpringDecoder.java:116)
    at org.springframework.web.client.IntrospectingClientHttpResponse.hasEmptyMessageBody(IntrospectingClientHttpResponse.java:83)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:90)
    at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:75)
    at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:53)
    at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:36)
    at feign.InvocationContext.proceed(InvocationContext.java:36)
    at feign.ResponseHandler.decode(ResponseHandler.java:122)
    at feign.ResponseHandler.handleResponse(ResponseHandler.java:73)
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:114)
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:70)
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:96)

It's happening because org.springframework.web.client.HttpMessageConverterExtractor used in SpringDecoder in extractData method calls org.springframework.web.client.IntrospectingClientHttpResponse#hasMessageBody method which identifies that response has message and because of that also org.springframework.web.client.IntrospectingClientHttpResponse#hasEmptyMessageBody is executed which tries to get response body input stream by executing org.springframework.cloud.openfeign.support.SpringDecoder.FeignResponseAdapter#getBody but this method does not check if body is null and tries to get input stream from it.

So changing this in org.springframework.cloud.openfeign.support.SpringDecoder.FeignResponseAdapter#getBody:

return response.body().asInputStream();

to this:

return response.body() != null ? response.body().asInputStream() : null;

helped in our case.

Sample Just call any endpoint which is not returning Content-Length header and body and response status is not 1XX, NO_CONTENT and NOT_MODIFIED. I our case it is simple HEAD call with no body and 200 response status code which is doing that.

Versions used: spring-cloud-openfeign-core = 4.0.4 spring-boot = 3.1.5

igorbljahhin commented 8 months ago

Same issue for spring-cloud-openfeign-core = 3.0.1.

OlgaMaciaszek commented 7 months ago

Hello @martinsefcik, thanks for pointing this out. Makes sense. Will fix it.