Skip to content

POST with empty Content-Type generates an error #444

@mdesharnais

Description

@mdesharnais

Hello,
Given the following minimal setup:

import java.nio.*;
import java.nio.file.*;
import org.jooby.*;

public class Main extends Jooby {
  {
    parser((type, ctxt) -> {
      if (type.getRawType() == ByteBuffer.class) {
        return ctxt.body(body -> {
          return ByteBuffer.wrap(body.bytes());
        });
      }
      return ctxt.next();
    });

    post("/upload", req -> {
      ByteBuffer buffer = req.body().to(ByteBuffer.class);
      Files.write(Paths.get("upload"), buffer.array());
      return "";
    });
  }

  public static void main(final String[] args) throws Throwable {
    new Main().start(args);
  }
}

The following works correctly:

$ curl -i --request POST --header 'Content-Type: text/plain' --data 'abc' localhost:8080/upload
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 0
connection: keep-alive

While the following generates an error:

$ curl -i --request POST --data 'abc' localhost:8080/upload
HTTP/1.1 400 Bad Request
Cache-Control: must-revalidate,no-cache,no-store
Content-Type: text/html;charset=UTF-8
Content-Length: 2834
connection: keep-alive

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {font-family: "open sans",sans-serif; margin-left: 20px;}
h1 {font-weight: 300; line-height: 44px; margin: 25px 0 0 0;}
h2 {font-size: 16px;font-weight: 300; line-height: 44px; margin: 0;}
footer {font-weight: 300; line-height: 44px; margin-top: 10px;}
hr {background-color: #f7f7f9;}
div.trace {border:1px solid #e1e1e8; background-color: #f7f7f9;}
p {padding-left: 20px;}
p.tab {padding-left: 40px;}
</style>
<title>
400 Bad Request
</title>
<body>
<h1>Bad Request</h1>
<hr><h2>message: Bad Request(400): Failed to parse parameters to 'java.nio.ByteBuffer'</h2>
<h2>status: 400</h2>
<h2>stack:</h2>
<div class="trace">
<p class="line"><code>org.jooby.Err: Bad Request(400): Failed to parse parameters to 'java.nio.ByteBuffer'</code></p>
<p class="line tab"><code>  at org.jooby.internal.MutantImpl.to(MutantImpl.java:87)</code></p>
<p class="line tab"><code>  at org.jooby.internal.MutantImpl.to(MutantImpl.java:75)</code></p>
<p class="line tab"><code>  at org.jooby.Mutant.to(Mutant.java:307)</code></p>
<p class="line tab"><code>  at com.gfaga.portail.Main.lambda$new$2(Main.java:27)</code></p>
<p class="line tab"><code>  at org.jooby.Route$OneArgHandler.handle(Route.java:1727)</code></p>
<p class="line tab"><code>  at org.jooby.internal.RouteImpl.handle(RouteImpl.java:108)</code></p>
<p class="line tab"><code>  at org.jooby.internal.RouteChain.next(RouteChain.java:70)</code></p>
<p class="line tab"><code>  at org.jooby.Route$Chain.next(Route.java:2074)</code></p>
<p class="line tab"><code>  at org.jooby.internal.HttpHandlerImpl.handle(HttpHandlerImpl.java:293)</code></p>
<p class="line tab"><code>  at org.jooby.internal.netty.NettyHandler.channelRead0(NettyHandler.java:85)</code></p>
<p class="line tab"><code>  at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)</code></p>
<p class="line tab"><code>  at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372)</code></p>
<p class="line tab"><code>  at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:38)</code></p>
<p class="line tab"><code>  at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:363)</code></p>
<p class="line tab"><code>  at io.netty.util.concurrent.DefaultEventExecutor.run(DefaultEventExecutor.java:66)</code></p>
<p class="line tab"><code>  at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:877)</code></p>
<p class="line tab"><code>  at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)</code></p>
<p class="line tab"><code>  at java.lang.Thread.run(Thread.java:745)</code></p>
</div>
</body>
</html>

According to §3.1.1.5 Content-Type of RFC 7231:

A sender that generates a message containing a payload body SHOULD
generate a Content-Type header field in that message unless the
intended media type of the enclosed representation is unknown to the
sender.  If a Content-Type header field is not present, the recipient
MAY either assume a media type of "application/octet-stream"
([RFC2046], Section 4.5.1) or examine the data to determine its type.

I tried a little bit to track down the origin of this behaviour and could only confirm, that the parser is successfully added to the context, but for some reason it is not being used.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions