Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error handling of invalid content-type #7053

Closed
janotav opened this issue Jun 22, 2023 · 5 comments
Closed

Error handling of invalid content-type #7053

janotav opened this issue Jun 22, 2023 · 5 comments
Assignees
Labels
2.x Issues for 2.x version branch question Further information is requested SE webserver

Comments

@janotav
Copy link

janotav commented Jun 22, 2023

Environment Details

  • Helidon Version: 2.6.0
  • Helidon SE
  • JDK version: 17
  • OS: Linux
  • Docker version (if applicable):

Problem Description

Sending POST request with invalid content-type %{bad actor}

Leads to java.lang.IllegalArgumentException in the server log and on the client side the observed behaviour is:

  • 400 Bad Request
  • content: Could not parse '%{bad actor}'

Expected behaviour

We would like to:

  • be able to control response status & content
  • avoid Unexpected error occurred during routing! exception in our server log

Is that currently possible? If not, can this be added?

@tomas-langer
Copy link
Member

To create a custom response for "pre-routing" errors, such as bad request, you can add a DirectHandler.
See WebServer.Builder.directHandler(DirectHandler handler, DirectHandler.EvenType... types)

You direct hanlder will get as much information as could be retrieved from the request, and you can create a customized response to be sent back.

@tomas-langer
Copy link
Member

For the part about not seeing the error in your logs, could you share the stacktrace of that exception please (I plan to split it into a new issue, so if you are OK with creating a new issue specifically for the error in the logs, it would be nice).

Thanks

@janotav
Copy link
Author

janotav commented Jun 27, 2023

Here is full stack:

java.lang.IllegalArgumentException: Could not parse '%{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Tenable','rtgKIzqK')}.multipart/form-data'
at io.helidon.common.http.MediaType.parse(MediaType.java:360)
at java.base/java.util.Optional.map(Optional.java:260)
at io.helidon.webserver.HashRequestHeaders.contentType(HashRequestHeaders.java:82)
at io.helidon.webserver.Request.<init>(Request.java:90)
at io.helidon.webserver.RequestRouting$RoutedRequest.<init>(RequestRouting.java:255)
at io.helidon.webserver.RequestRouting.route(RequestRouting.java:86)
at io.helidon.webserver.ForwardingHandler.lambda$channelReadHttpRequest$17(ForwardingHandler.java:470)
at io.helidon.webserver.RequestContext.lambda$runInScope$4(RequestContext.java:77)
at io.helidon.common.context.Contexts.runInContext(Contexts.java:117)
at io.helidon.webserver.RequestContext.runInScope(RequestContext.java:75)
at io.helidon.webserver.ForwardingHandler.channelReadHttpRequest(ForwardingHandler.java:470)
at io.helidon.webserver.ForwardingHandler.lambda$channelRead0$3(ForwardingHandler.java:166)
at io.helidon.common.context.Contexts.runInContext(Contexts.java:137)
at io.helidon.webserver.ForwardingHandler.channelRead0(ForwardingHandler.java:165)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1373)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1236)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1285)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833) Caused by: java.lang.IllegalStateException: Unexpected character: /
at io.helidon.common.http.Tokenizer.checkState(Tokenizer.java:173)
at io.helidon.common.http.Tokenizer.consumeCharacter(Tokenizer.java:109)
at io.helidon.common.http.MediaType.parse(MediaType.java:326) ... 44 more

@tomas-langer
Copy link
Member

Example of a direct handler that maps bad requests to not found:

DirectHandler badRequestHandler = (transportRequest, eventType, responseStatus, message) -> DirectHandler.TransportResponse.builder()
                .status(Http.Status.NOT_FOUND_404)
                .entity("Endpoint not found")
                .build();

The exception is still written to the log, As that error is handled elsewhere, the message should not be printed. I will create an issue for it.

@tomas-langer
Copy link
Member

Submitted an issue for the logging problem. I will close this one as I have answered how to customize the response for bad requests.

@tomas-langer tomas-langer added the question Further information is requested label Jun 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.x Issues for 2.x version branch question Further information is requested SE webserver
Projects
Archived in project
Development

No branches or pull requests

3 participants