membrane / api-gateway

API gateway for REST, OpenAPI, GraphQL and SOAP written in Java.
https://membrane-api.io
Apache License 2.0
464 stars 138 forks source link

ReusableJsonGenerator causes NPE on the second call for invalid calls. #1346

Open precoder opened 4 days ago

precoder commented 4 days ago

Hello everyone,

We have the oauth2authserver endpoints under: https://localhost:8843/auth/

If we call this endpoint on browser with GET call without any parameters, we land into DefaultEndpointProcessor and get {"error":"invalid_request"} as expected.

However on a second call with the same invalid request causes a NPE (stack trace enabled by <transport printStackTrace="true"/>):

java.lang.NullPointerException
    at java.base/java.lang.System.arraycopy(Native Method)
    at com.fasterxml.jackson.core.json.UTF8JsonGenerator._writeBytes(UTF8JsonGenerator.java:1304)
    at com.fasterxml.jackson.core.json.UTF8JsonGenerator._verifyValueWrite(UTF8JsonGenerator.java:1181)
    at com.fasterxml.jackson.core.json.UTF8JsonGenerator.writeStartObject(UTF8JsonGenerator.java:380)
    at com.predic8.membrane.core.interceptor.oauth2.OAuth2Util.createParameterizedJsonErrorResponse(OAuth2Util.java:55)
    at com.predic8.membrane.core.interceptor.oauth2.processors.DefaultEndpointProcessor.process(DefaultEndpointProcessor.java:34)
    at com.predic8.membrane.core.interceptor.oauth2.processors.OAuth2Processors.runProcessors(OAuth2Processors.java:35)
    at com.predic8.membrane.core.interceptor.oauth2.OAuth2AuthorizationServerInterceptor.handleRequest(OAuth2AuthorizationServerInterceptor.java:138)
    at com.predic8.membrane.core.interceptor.InterceptorFlowController.invokeRequestHandlers(InterceptorFlowController.java:111)
    at com.predic8.membrane.core.interceptor.UserFeatureInterceptor.handleRequest(UserFeatureInterceptor.java:44)
    at com.predic8.membrane.core.interceptor.InterceptorFlowController.invokeRequestHandlers(InterceptorFlowController.java:111)
    at com.predic8.membrane.core.interceptor.InterceptorFlowController.invokeHandlers(InterceptorFlowController.java:76)
    at com.predic8.membrane.core.transport.http.AbstractHttpHandler.invokeHandlers(AbstractHttpHandler.java:61)
    at com.predic8.membrane.core.transport.http.HttpServerHandler.process(HttpServerHandler.java:227)
    at com.predic8.membrane.core.transport.http.HttpServerHandler.run(HttpServerHandler.java:128)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
    at java.base/java.lang.Thread.run(Thread.java:840)

Reason behind this is UTF8JsonGenerator uses a "_outputBuffer" array internally. This array is initialized in the Constructor. https://github.com/FasterXML/jackson-core/blob/jackson-core-2.17.2/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java#L131 or https://github.com/FasterXML/jackson-core/blob/jackson-core-2.17.2/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java#L164

This array is set to null by UTF8JsonGenerator ._releaseBuffers method after execution of the request. https://github.com/FasterXML/jackson-core/blob/jackson-core-2.17.2/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java#L1277

on the next call for writeStartObject we get a NPE since the internal buffer is not re-initialized.

precoder commented 4 days ago

I created a Unit Test to reproduce the issue (generation of json2 causes NPE). I made a quick fix by re-creating the JsonGenerator on resetAndGet call. If you can find a more fine granular solution without re-creating the JsonGenerator then you can get a better performance for JSON generation.