Git Product home page Git Product logo

Comments (11)

talios avatar talios commented on June 15, 2024

I hit something similar to this the other day and worked around it with:

var query = req.query();
if (!query.isEmpty() && query.get("period") instanceof String period) {

Having to check the isEmpty is kind-of a pain. Tho the out-of-bounds you got seems worse.

from helidon.

hrstoyanov avatar hrstoyanov commented on June 15, 2024

@talios have you tried:

var period = req.query().first("period").asString().orElse("whatever);

//or

req
    .query()
    .first("period")
    .asString()
    .ifPresent(period->{....});

from helidon.

talios avatar talios commented on June 15, 2024

@hrstoyanov That works nicely - even better using .as(Period::parse) to map to the desired type. Much cleaner - cheers!

from helidon.

tomas-langer avatar tomas-langer commented on June 15, 2024

Reason for this bug is that the implementation did not expect an empty list as a value in the map used to create it.
The place we introduced this (I think the only one) is in URI Query, where we handle the case of a parameter without a follow-up = as a name without a value - so contains returns true, but there is no value.
So we were missing a validation of the map for the assumption of the implementation, and a change once we decided to support it.
The only sloppiness I see here is the lack of test for a query parameter without a value...

from helidon.

hrstoyanov avatar hrstoyanov commented on June 15, 2024

@tomas-langer apologies, the code is actaully very nicely designed maybe needs unit test, I updated the initial report. Sorry!

from helidon.

jbescos avatar jbescos commented on June 15, 2024

Merged, thank you for reporting it

from helidon.

hrstoyanov avatar hrstoyanov commented on June 15, 2024

@jbescos @tomas-langer

I have not looked at the fix details, but can you , please, confirm that this code:

ServerRequest req = ...;
var params = eq.content().as(Parameters.class);

will not fail with:

io.helidon.http.RequestException: No entity
	at [email protected]/io.helidon.http.RequestException$Builder.build(RequestException.java:139)
	at [email protected]/io.helidon.webserver.http.ErrorHandlers.unhandledError(ErrorHandlers.java:203)
	at [email protected]/io.helidon.webserver.http.ErrorHandlers.lambda$handleError$1(ErrorHandlers.java:182)

but rather - return an empty Parameters object? That way developers need not do noise checks, as it is the case in 4.0.8:

var content = req.content();
if(content.hasEntity()) {
 var params = content.as(Parameters.class)
}

from helidon.

jbescos avatar jbescos commented on June 15, 2024

I think this is another issue. I was working in the:
Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0

That was happening when you were expecting an optional.

But in the example you wrote, .as(Parameters.class); does not return an optional. I think it is fine to throw an exception because otherwise we need to return null. We would need to change the API to return an Optional.

@tomas-langer is on vacations but he can review it when he comes back.

from helidon.

hrstoyanov avatar hrstoyanov commented on June 15, 2024

Thanks @jbescos , I see. My suggestion is to return Parameters object always, but perhaps with empty parameters, if possible.

Also, take a look at issue #8652:

The test case example shown uses exactly the kind of code from above that can fail:

req.content().as(Parameters.class);

from helidon.

jbescos avatar jbescos commented on June 15, 2024

I am running one test I have created:

// Client
    @Test
    public void testFormNoEntity() {
        try (Http1ClientResponse res = client.post("/form/content").request()) {
            Parameters received = res.as(Parameters.class);
            assertThat(received.first(NO_VALUE).isEmpty(), is(true));
        }
    }
// Server
    private void formContent(ServerRequest req, ServerResponse res) {
        Parameters form = req.content().as(Parameters.class);
        res.send(form);
    }

And I am hitting the exception with the next stacktrace:

System Thread [[0x7ee4364d 0x4afac8ea] WebServer socket] (Suspended)	
	io.helidon.http.media.ReadableEntityBase$EmptyReadableEntity.as(java.lang.Class<T>) line: 255	
	io.helidon.webclient.tests.GreetService.formContent(io.helidon.webserver.http.ServerRequest, io.helidon.webserver.http.ServerResponse) line: 193	
	io.helidon.webclient.tests.GreetService$$Lambda.0x00007f02fc228250.handle(io.helidon.webserver.http.ServerRequest, io.helidon.webserver.http.ServerResponse) line: not available	
	io.helidon.webserver.http.HttpRoutingImpl$RoutingExecutor.doRoute(io.helidon.webserver.ConnectionContext, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: 165	
	io.helidon.webserver.http.HttpRoutingImpl$RoutingExecutor.call() line: 124	
	io.helidon.webserver.http.HttpRoutingImpl$RoutingExecutor.call() line: 102	
	io.helidon.webserver.http.ErrorHandlers.runWithErrorHandling(io.helidon.webserver.ConnectionContext, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse, java.util.concurrent.Callable<java.lang.Void>) line: 75	
	io.helidon.webserver.http.Filters$FilterChainImpl.proceed() line: 121	
	io.helidon.webserver.security.SecurityContextFilter.filter(io.helidon.webserver.http.FilterChain, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: 88	
	io.helidon.webserver.http.Filters$FilterChainImpl.proceed() line: 119	
	io.helidon.webserver.observe.tracing.TracingObserver$TracingFilter$$Lambda.0x00007f02fc2c8f10.run() line: not available	
	io.helidon.common.context.Contexts.runInContext(io.helidon.common.context.Context, java.lang.Runnable) line: 117	
	io.helidon.webserver.observe.tracing.TracingObserver$TracingFilter.filter(io.helidon.webserver.http.FilterChain, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: 247	
	io.helidon.webserver.http.Filters$FilterChainImpl.proceed() line: 119	
	io.helidon.webserver.context.ContextRoutingFeature$$Lambda.0x00007f02fc2c1918.run() line: not available	
	io.helidon.common.context.Contexts.runInContext(io.helidon.common.context.Context, java.lang.Runnable) line: 117	
	io.helidon.webserver.context.ContextRoutingFeature.filter(io.helidon.webserver.http.FilterChain, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: 50	
	io.helidon.webserver.context.ContextRoutingFeature$$Lambda.0x00007f02fc222ee0.filter(io.helidon.webserver.http.FilterChain, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: not available	
	io.helidon.webserver.http.Filters$FilterChainImpl.proceed() line: 119	
	io.helidon.webserver.http.Filters.executeFilters(io.helidon.webserver.http.FilterChain) line: 87	
	io.helidon.webserver.http.Filters.lambda$filter$0(io.helidon.webserver.http.FilterChain) line: 83	
	io.helidon.webserver.http.Filters$$Lambda.0x00007f02fc2c14d8.call() line: not available	
	io.helidon.webserver.http.ErrorHandlers.runWithErrorHandling(io.helidon.webserver.ConnectionContext, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse, java.util.concurrent.Callable<java.lang.Void>) line: 75	
	io.helidon.webserver.http.Filters.filter(io.helidon.webserver.ConnectionContext, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse, java.util.concurrent.Callable<java.lang.Void>) line: 83	
	io.helidon.webserver.http.HttpRoutingImpl.route(io.helidon.webserver.ConnectionContext, io.helidon.webserver.http.RoutingRequest, io.helidon.webserver.http.RoutingResponse) line: 73	
	io.helidon.webserver.http1.Http1Connection.route(io.helidon.http.HttpPrologue, io.helidon.http.WritableHeaders<?>) line: 357	
	io.helidon.webserver.http1.Http1Connection.handle(java.util.concurrent.Semaphore) line: 194	
	io.helidon.webserver.ConnectionHandler.run() line: 165	
	io.helidon.webserver.ConnectionHandler(io.helidon.common.task.InterruptableTask<T>).call() line: 47	
	io.helidon.webserver.ThreadPerTaskExecutor$ThreadBoundFuture<T>.run() line: 239	
	java.lang.VirtualThread.runWith(java.lang.Object, java.lang.Runnable) line: 341	
	java.lang.VirtualThread.run(java.lang.Runnable) line: 311	
	java.lang.VirtualThread$VThreadContinuation$1.run() line: 192	
	java.lang.VirtualThread$VThreadContinuation(jdk.internal.vm.Continuation).enter0() line: 320	
	jdk.internal.vm.Continuation.enter(jdk.internal.vm.Continuation, boolean) line: 312	

The exception is explicitly thrown in this line:

throw new IllegalStateException("No entity");

The question is whether we can return an empty value instead of failing. Lets wait for @tomas-langer to review it.

from helidon.

hrstoyanov avatar hrstoyanov commented on June 15, 2024

@tomas-langer ^^^

from helidon.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.