Repository: vert-x3/vertx-web
Issue: */* produces does not limit AcceptableContentType based on Accept header

### Version

* vert.x core: 3.6.0-SNAPSHOT
* vert.x web: 3.6.0-SNAPSHOT

### Context

When a route can produce `*/*` and the client specifies a specific content type via the Accept header, AcceptableContentType returns `*/*` instead of the client specified content type. To figure out what the client is requesting, you have to examine the parsed Accept header yourself.

### Steps to reproduce

Sample code:

```
public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    HttpServer server = vertx.createHttpServer();
    Router router = Router.router(vertx);

    router.route().produces("*/*").handler(routingContext -> {
      HttpServerResponse response = routingContext.response();

      response.end("Accept headers are:" +
        routingContext.parsedHeaders().accept().stream().map(ParsedHeaderValue::rawValue).collect(Collectors.toList()) +
        "\\nAcceptable Content Type is " +
        routingContext.getAcceptableContentType());
    });

    server.requestHandler(router).listen(8080);
  }
```

Start up above server.
```
curl -H "Accept: application/json" localhost:8080
Accept headers are:[application/json]
Acceptable Content Type is */*
```

I would expect Acceptable Content Type to be `application/json`

Changed files:
vertx-web/src/main/java/io/vertx/ext/web/ParsedHeaderValues.java, vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java, vertx-web/src/main/java/io/vertx/ext/web/impl/ParsableHeaderValuesContainer.java

diff --git a/vertx-web/src/main/java/io/vertx/ext/web/ParsedHeaderValues.java b/vertx-web/src/main/java/io/vertx/ext/web/ParsedHeaderValues.java
index 54e1a1777..b54d8171b 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/ParsedHeaderValues.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/ParsedHeaderValues.java
@@ -1,11 +1,11 @@
 package io.vertx.ext.web;
 
-import java.util.Collection;
-import java.util.List;
-
 import io.vertx.codegen.annotations.GenIgnore;
 import io.vertx.codegen.annotations.VertxGen;
 
+import java.util.Collection;
+import java.util.List;
+
 /**
  * A container with the request's headers that are meaningful enough to be parsed
  * Contains:
@@ -54,5 +54,5 @@ public interface ParsedHeaderValues {
    * @return The first header that matched, otherwise empty if none matched
    */
   @GenIgnore
-  <T extends ParsedHeaderValue> T findBestUserAcceptedIn(List<T> accepted, Collection<T> in);
+  MIMEHeader findBestUserAcceptedIn(List<MIMEHeader> accepted, Collection<MIMEHeader> in);
 }
diff --git a/vertx-web/src/main/java/io/vertx/ext/web/impl/ParsableHeaderValuesContainer.java b/vertx-web/src/main/java/io/vertx/ext/web/impl/ParsableHeaderValuesContainer.java
index a9c528c06..1ae8bf71a 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/impl/ParsableHeaderValuesContainer.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/impl/ParsableHeaderValuesContainer.java
@@ -1,13 +1,13 @@
 package io.vertx.ext.web.impl;
 
-import java.util.Collection;
-import java.util.List;
-
 import io.vertx.ext.web.LanguageHeader;
 import io.vertx.ext.web.MIMEHeader;
 import io.vertx.ext.web.ParsedHeaderValue;
 import io.vertx.ext.web.ParsedHeaderValues;
 
+import java.util.Collection;
+import java.util.List;
+
 public class ParsableHeaderValuesContainer implements ParsedHeaderValues {
 
   private List<MIMEHeader> accept;
@@ -48,11 +48,14 @@ public class ParsableHeaderValuesContainer implements ParsedHeaderValues {
   }
 
   @Override
-  public <T extends ParsedHeaderValue> T findBestUserAcceptedIn(List<T> userAccepted, Collection<T> in) {
-    for (T acceptableType: userAccepted) {
-      T acceptedType = acceptableType.findMatchedBy(in);
-      if(acceptedType != null){
-        return acceptedType;
+  public MIMEHeader findBestUserAcceptedIn(List<MIMEHeader> userAccepted, Collection<MIMEHeader> in) {
+    for (MIMEHeader acceptableType: userAccepted) {
+      MIMEHeader acceptedType = acceptableType.findMatchedBy(in);
+      if (acceptedType != null) {
+        if ("*".equals(acceptedType.subComponent()) || "*".equals(acceptedType.component()))
+          return acceptableType;
+        else
+          return acceptedType;
       }
     }
     return null;
diff --git a/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java b/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
index 9019767d1..b469388ae 100644
--- a/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
+++ b/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
@@ -1088,6 +1088,33 @@ public class RouterTest extends WebTestBase {
     testRequestWithAccepts(HttpMethod.GET, "/foo", "application/*", 404, "Not Found");
   }
 
+  @Test
+  public void testProducesSubtypeWildcardAcceptTextPlain() throws Exception {
+    router.route().produces("text/*").handler(rc -> {
+      rc.response().setStatusMessage(rc.getAcceptableContentType());
+      rc.response().end();
+    });
+    testRequestWithAccepts(HttpMethod.GET, "/foo", "text/plain", 200, "text/plain");
+  }
+
+  @Test
+  public void testProducesComponentWildcardAcceptTextPlain() throws Exception {
+    router.route().produces("*/plain").handler(rc -> {
+      rc.response().setStatusMessage(rc.getAcceptableContentType());
+      rc.response().end();
+    });
+    testRequestWithAccepts(HttpMethod.GET, "/foo", "text/plain", 200, "text/plain");
+  }
+
+  @Test
+  public void testProducesAllWildcard() throws Exception {
+    router.route().produces("*/*").handler(rc -> {
+      rc.response().setStatusMessage(rc.getAcceptableContentType());
+      rc.response().end();
+    });
+    testRequestWithAccepts(HttpMethod.GET, "/foo", "text/plain", 200, "text/plain");
+  }
+
   @Test
   public void testProducesTopLevelTypeWildcard() throws Exception {
     router.route().produces("application/json").handler(rc -> {