eclipse-ee4j / eclipse-ee4j/jersey

JsonProcessingFeature fails on single byte POST

Open
#3,750 2 comments 1 reaction 0 assignees View on GitHub
Dominant language
Java
Stars
730
Forks
382
PR merge metrics
No merged PRs in 30d

Description

When attempting to POST a single digit JsonNumber as the contents of the body using the JsonProcessingFeature, the parse fails with an exception from javax.json of not enough characters to detect the input encoding.

While this is probably a bug with `org.glassfish.json.UnicodeDetectingInputStream` from the JSON-P project, trying to avoid this with using `application/json; charset=utf-8` as the Content-Type doesn't skip the encoding detection.

Eg:
```
curl -X POST -H "Content-Type: application/json" -d "1" http://localhost:9998/Eg
```
and
```
curl -X POST -H "Content-Type: application/json; charset=utf-8" -d "1" http://localhost:9998/Eg
```
both fail.

```java
package eg;

import java.net.URI;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.json.JsonValue;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.UriBuilder;

import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.jsonp.JsonProcessingFeature;
import org.glassfish.jersey.server.ResourceConfig;

@Path("Eg")
public class Eg {

@POST
@Consumes("application/json")
public void getHello(JsonValue val) {
System.out.println(val);
}

public static void main(String[] args) throws Exception {
makeGrizzlyLog();

URI baseUri = UriBuilder.fromUri("http://localhost/").port(9998).build();
ResourceConfig cfg = new ResourceConfig().register(Eg.class)
.register(JsonProcessingFeature.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(baseUri, cfg);

Runtime.getRuntime()
.addShutdownHook(new Thread(() -> {
server.shutdownNow();
}));

server.start();
Thread.currentThread().join();
}

private static void makeGrizzlyLog() {
Logger log = Logger.getLogger("org.glassfish.grizzly.http.server.HttpHandler");
log.setLevel(Level.FINE);
log.setUseParentHandlers(false);
ConsoleHandler ch = new ConsoleHandler();
ch.setLevel(Level.ALL);
log.addHandler(ch);
}

}
```
Stack trace the same with both `curl` invocations.
```
FINE: service exception
javax.json.JsonException: Cannot auto-detect encoding, not enough chars
at org.glassfish.json.UnicodeDetectingInputStream.detectEncoding(UnicodeDetectingInputStream.java:130)
at org.glassfish.json.UnicodeDetectingInputStream.(UnicodeDetectingInputStream.java:75)
at org.glassfish.json.JsonParserImpl.(JsonParserImpl.java:95)
at org.glassfish.json.JsonReaderImpl.(JsonReaderImpl.java:73)
at org.glassfish.json.JsonReaderFactoryImpl.createReader(JsonReaderFactoryImpl.java:71)
at org.glassfish.json.jaxrs.JsonValueBodyReader.readFrom(JsonValueBodyReader.java:93)
at org.glassfish.json.jaxrs.JsonValueBodyReader.readFrom(JsonValueBodyReader.java:66)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:257)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:236)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:73)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:156)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1091)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:271)
at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:97)
at org.glassfish.jersey.server.internal.inject.EntityParamValueParamProvider$EntityValueSupplier.apply(EntityParamValueParamProvider.java:80)
at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.apply(ParamValueFactoryWithSource.java:74)
at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:92)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:133)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:183)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
at org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpContainer.service(GrizzlyHttpContainer.java:377)
at org.glassfish.grizzly.http.server.HttpHandler$1.run(HttpHandler.java:224)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
at java.lang.Thread.run(Thread.java:748)
```

Using:
* Oracle JDK 1.8.0_144
* Jersey 2.26
* org.glassfish.jersey.containers:jersey-container-grizzly2-http
* org.glassfish.jersey.inject:jersey-hk2
* org.glassfish.jersey.media:jersey-media-json-processing

Contributor guide

Open the contributing guide

Research direction

Start at org.glassfish.jersey.jsonp.JsonValueBodyReader.readFrom, following the stack trace into JsonReaderImpl and the failing UnicodeDetectingInputStream path. Reproduce the issue with the two curl commands using a single-digit JSON body and compare behavior with the charset parameter. Done means JsonProcessingFeature accepts the request and delivers the JSON value without the encoding exception.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.