davsclaus commented on code in PR #27099:
URL: https://github.com/apache/camel/pull/27099#discussion_r4136334761


##########
components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java:
##########
@@ -104,7 +107,21 @@ public ValidationError validate(Exchange exchange, 
ValidationContext validationC
             boolean customHeader
                     = !startsWithIgnoreCase(key, "Camel") && 
!filter.applyFilterToCamelHeaders(key, value, exchange);
             if (customHeader) {
-                builder.withHeader(key, exchange.getMessage().getHeader(key, 
String.class));
+                if (value instanceof Collection<?> values) {
+                    // A header sent more than once arrives as a Collection 
(CollectionHelper.appendEntry).
+                    // Converting that to a single String would hand the 
validator the collection's
+                    // toString(), such as "[a, b]" - a value the client never 
sent - so the schema would
+                    // be checked against fabricated data, and a repeated 
scalar parameter would never be
+                    // reported. Pass the values on instead, as the query 
parameters below already do.
+                    List<String> headerValues = new ArrayList<>(values.size());
+                    for (Object headerValue : values) {
+                        
headerValues.add(exchange.getContext().getTypeConverter()
+                                .convertTo(String.class, exchange, 
headerValue));
+                    }
+                    builder.withHeader(key, headerValues);

Review Comment:
   Per RFC 9110 ยง5.3, repeating a list-valued header is equivalent to one 
header with the values joined by commas. So `tags: dog` + `tags: cat` means the 
same as `tags: dog,cat`, which the contract accepts. With this change the 
repeated form is rejected: the `[explode=false]` in that message is hardcoded 
in swagger-request-validator's `ParameterValidator`, and the petstore contract 
declares `explode: true`. Could we join the values with `,` when the header 
parameter is an array schema, and keep the list for scalars (where >1 value 
really is invalid)? Also, `convertTo` can return null for a null element; worth 
skipping those.



##########
components/camel-openapi-validator/src/test/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidatorTest.java:
##########
@@ -123,4 +124,104 @@ public void testValidateHeader() {
                 "application/json", "application/json", true, null, null, 
null, null));
         Assertions.assertNull(error);
     }
+
+    @Test
+    public void testValidateRepeatedScalarHeader() {
+        exchange.setProperty(Exchange.REST_OPENAPI, openAPI);
+        exchange.setProperty(Exchange.CONTENT_TYPE, "application/json");
+        exchange.getMessage().setHeader(Exchange.HTTP_METHOD, "DELETE");
+        exchange.getMessage().setHeader(Exchange.HTTP_PATH, "pet/123");
+        exchange.getMessage().setHeader("Accept", "application/json");
+        exchange.getMessage().setBody("");
+
+        // A header sent more than once arrives as a List, exactly as 
CollectionHelper.appendEntry
+        // leaves it. api_key is declared "type": "string", so two values 
violate the contract.
+        exchange.getMessage().setHeader("api_key", List.of("key-one", 
"key-two"));
+
+        RestClientRequestValidator.ValidationError error
+                = validator.validate(exchange, new 
RestClientRequestValidator.ValidationContext(
+                        "application/json", "application/json", false, null, 
null, null, null));
+
+        Assertions.assertNotNull(error, "a repeated scalar header parameter 
must be reported");
+        Assertions.assertEquals(400, error.statusCode());
+        Assertions.assertFalse(error.body().contains("[key-one, key-two]"),
+                "the collection must not be stringified into the validated 
value");
+    }
+
+    @Test
+    public void testValidateSingleScalarHeaderStillPasses() {
+        exchange.setProperty(Exchange.REST_OPENAPI, openAPI);
+        exchange.setProperty(Exchange.CONTENT_TYPE, "application/json");
+        exchange.getMessage().setHeader(Exchange.HTTP_METHOD, "DELETE");
+        exchange.getMessage().setHeader(Exchange.HTTP_PATH, "pet/123");
+        exchange.getMessage().setHeader("Accept", "application/json");
+        exchange.getMessage().setHeader("api_key", "key-one");
+        exchange.getMessage().setBody("");
+
+        RestClientRequestValidator.ValidationError error
+                = validator.validate(exchange, new 
RestClientRequestValidator.ValidationContext(
+                        "application/json", "application/json", false, null, 
null, null, null));
+
+        Assertions.assertNull(error);
+    }
+
+    @Test
+    public void testValidateRepeatedArrayHeaderIsReported() {

Review Comment:
   This locks in rejecting a request that is valid HTTP (see the comment on the 
validator). I'd drop it or flip it, depending on the outcome there.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to