Skip to content

Commit

Permalink
Merge pull request #3518 from froque/fix_case_sensitive_headermap_v2
Browse files Browse the repository at this point in the history
Fixes case insensitive headerMap and header toMultimap
  • Loading branch information
jknack authored Sep 7, 2024
2 parents ef8aa61 + 5542d7d commit f632652
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 13 deletions.
2 changes: 1 addition & 1 deletion jooby/src/main/java/io/jooby/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ public interface Context extends Registry {
/**
* Header as single-value map.
*
* @return Header as single-value map.
* @return Header as single-value map, with case insensitive keys.
*/
@NonNull Map<String, String> headerMap();

Expand Down
4 changes: 2 additions & 2 deletions jooby/src/main/java/io/jooby/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;

import edu.umd.cs.findbugs.annotations.NonNull;
Expand All @@ -25,6 +24,7 @@
import io.jooby.exception.TypeMismatchException;
import io.jooby.internal.ArrayValue;
import io.jooby.internal.HashValue;
import io.jooby.internal.HeadersValue;
import io.jooby.internal.MissingValue;
import io.jooby.internal.MultipartNode;
import io.jooby.internal.SingleValue;
Expand Down Expand Up @@ -545,7 +545,7 @@ default boolean isObject() {
* @return A hash/object value.
*/
static @NonNull ValueNode headers(Context ctx, @NonNull Map<String, Collection<String>> values) {
HashValue node = new HashValue(ctx, null, () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER));
HeadersValue node = new HeadersValue(ctx);
node.put(values);
return node;
}
Expand Down
13 changes: 3 additions & 10 deletions jooby/src/main/java/io/jooby/internal/HashValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.StringJoiner;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.function.Supplier;

import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
Expand All @@ -29,18 +28,12 @@
import io.jooby.ValueNode;

public class HashValue implements ValueNode {
private static final Map<String, ValueNode> EMPTY = Collections.emptyMap();
protected static final Map<String, ValueNode> EMPTY = Collections.emptyMap();
private Context ctx;
private Map<String, ValueNode> hash = EMPTY;
protected Map<String, ValueNode> hash = EMPTY;
private final String name;
private boolean arrayLike;

public HashValue(Context ctx, String name, Supplier<Map<String, ValueNode>> mapSupplier) {
this.ctx = ctx;
this.name = name;
this.hash = mapSupplier.get();
}

public HashValue(Context ctx, String name) {
this.ctx = ctx;
this.name = name;
Expand Down Expand Up @@ -164,7 +157,7 @@ private boolean isNumber(String value) {
return true;
}

private Map<String, ValueNode> hash() {
protected Map<String, ValueNode> hash() {
if (hash == EMPTY) {
hash = new LinkedHashMap<>();
}
Expand Down
44 changes: 44 additions & 0 deletions jooby/src/main/java/io/jooby/internal/HeadersValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.jooby.internal;

import edu.umd.cs.findbugs.annotations.NonNull;
import io.jooby.Context;
import io.jooby.ValueNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class HeadersValue extends HashValue implements ValueNode {

public HeadersValue(final Context ctx) {
super(ctx);
}

@Override
protected Map<String, ValueNode> hash() {
if (hash == EMPTY) {
hash = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
}
return hash;
}

@NonNull
@Override
public Map<String, String> toMap() {
Map<String, String> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
toMultimap().forEach((k, v) -> map.put(k, v.get(0)));
return map;
}

@NonNull
@Override
public Map<String, List<String>> toMultimap() {
Map<String, List<String>> result = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Set<Map.Entry<String, ValueNode>> entries = hash.entrySet();
for (Map.Entry<String, ValueNode> entry : entries) {
ValueNode value = entry.getValue();
result.putAll(value.toMultimap());
}
return result;
}
}
6 changes: 6 additions & 0 deletions tests/src/test/java/io/jooby/test/Issue2357.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public void headersShouldBeCaseInsensitive(ServerTestRunner runner) {
Assertions.assertEquals("value1", ctx.header("x-header1").value());
Assertions.assertEquals("value1", ctx.header("X-HEADER1").value());
Assertions.assertEquals("value1", ctx.header("X-hEaDeR1").value());
Assertions.assertEquals("value1", ctx.headerMap().get("x-header1"));
Assertions.assertEquals("value1", ctx.headerMap().get("X-HEADER1"));
Assertions.assertEquals("value1", ctx.headerMap().get("X-hEaDeR1"));
Assertions.assertEquals("value1", ctx.header().toMultimap().get("x-header1").get(0));
Assertions.assertEquals("value1", ctx.header().toMultimap().get("X-HEADER1").get(0));
Assertions.assertEquals("value1", ctx.header().toMultimap().get("X-hEaDeR1").get(0));
return "OK";
}))
.ready(
Expand Down

0 comments on commit f632652

Please sign in to comment.