vert-x3 / vertx-web

HTTP web applications for Vert.x
Apache License 2.0
1.11k stars 535 forks source link

Add `Accept` header to 415 responses #2663

Closed komape closed 1 day ago

komape commented 1 month ago

Describe the feature

If the content type of a request is not matching the accepted content types, a 415 Unsupported Media Type status is returned. According to the mdn web docs for the HTTP status 415 and the RFC 9110 for HTTP semantics, an Accept header with the accepted content types should be returned as well. This is currently missing and should be added.

For example, this endpoint accepts JSON and CSV:

router.route()
  .consumes("application/json")
  .consumes("text/csv")
  .handler(ctx -> {
    // handle request
  });

In case, the client does not provide any content type or a wrong one, for example text/plain, the response should be as follows:

HTTP/1.1 415 Unsupported Media Type
# other fields
Accept: application/json, text/csv
Content-Length: 0

This is a follow up from #2656.

Use cases

This feature fulfills the offical semantics for a 415 status.

Additionally, the client gets to know what type of content is accepted without looking for documentation.

Contribution

I would like to do it but I cannot say until when.

When is v5.0.0 supposed to be released?

tsegismont commented 3 weeks ago

@komape thank you for reporting this and for proposing to send a PR.

The Vert.x 5 release is expected before the end of this year. The sooner the better :-)

komape commented 3 weeks ago

@tsegismont I took a look but unfortunately I cannot execute the RouterTest due to the error further below.

I guess this issue is not the right place to ask for help but I'm not sure where else I should ask. I couldn't find anything in the community/user group. I requested to join in order to ask for help. I also couldn't find anything in the commiters group and I cannot ask to join the group. Can you add me? The link to the development group is not working at all anymore. The gitter channel is full with spam and also not usable. I also thought about Stack Overflow but it states at multiple places that the other channels are preferred.

Which is the right place to ask for help regarding this issue? I cannot test my added code at the moment which I would like to do before I open a PR. Thanks for your help in advance!

Starting test: RouterTest#testConsumes 
Unhandled exception 
java.lang.NoClassDefFoundError: io/vertx/ext/auth/audit/SecurityAudit
    at java.base/java.lang.Class.getDeclaredFields0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3473)
    at java.base/java.lang.Class.getDeclaredField(Class.java:2780)
    at java.base/java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl$1.run(AtomicIntegerFieldUpdater.java:398)
    at java.base/java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl$1.run(AtomicIntegerFieldUpdater.java:396)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
    at java.base/java.util.concurrent.atomic.AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl.<init>(AtomicIntegerFieldUpdater.java:395)
    at java.base/java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdater.java:93)
    at io.vertx.web@5.0.0-SNAPSHOT/io.vertx.ext.web.impl.RoutingContextImplBase.<clinit>(RoutingContextImplBase.java:43)
    at io.vertx.web@5.0.0-SNAPSHOT/io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:68)
    at io.vertx.web@5.0.0-SNAPSHOT/io.vertx.ext.web.impl.RouterImpl.handle(RouterImpl.java:37)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xServerRequestHandler.handle(Http1xServerRequestHandler.java:72)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xServerRequestHandler.handle(Http1xServerRequestHandler.java:31)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.impl.ContextBase.emit(ContextBase.java:83)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xServerConnection.handleMessage(Http1xServerConnection.java:164)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.net.impl.VertxConnection.read(VertxConnection.java:240)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:147)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
    at io.netty.codec.http@4.2.0.Alpha5/io.netty.handler.codec.http.websocketx.extensions.WebSocketServerExtensionHandler.onHttpRequestChannelRead(WebSocketServerExtensionHandler.java:158)
    at io.netty.codec.http@4.2.0.Alpha5/io.netty.handler.codec.http.websocketx.extensions.WebSocketServerExtensionHandler.channelRead(WebSocketServerExtensionHandler.java:82)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xUpgradeToH2CHandler.channelRead(Http1xUpgradeToH2CHandler.java:120)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.codec@4.2.0.Alpha5/io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
    at io.netty.codec@4.2.0.Alpha5/io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xOrH2CHandler.end(Http1xOrH2CHandler.java:61)
    at io.vertx.core@5.0.0-SNAPSHOT/io.vertx.core.http.impl.Http1xOrH2CHandler.channelRead(Http1xOrH2CHandler.java:38)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1357)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:868)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:444)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:386)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:585)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:560)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:501)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:478)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:184)
    at io.netty.transport@4.2.0.Alpha5/io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:156)
    at io.netty.common@4.2.0.Alpha5/io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1123)
    at io.netty.common@4.2.0.Alpha5/io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.common@4.2.0.Alpha5/io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ClassNotFoundException: io.vertx.ext.auth.audit.SecurityAudit
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
    ... 57 more
tsegismont commented 3 weeks ago

It's surprising, the Vert.x user and dev groups are supposed to be open to any email sender. Are you aware of any restriction @vietj ?

@komape please create a draft PR to share your code and I'll give it a try. Thanks

komape commented 3 weeks ago

@tsegismont Thanks, see PR #2672 for the draft.