From 10802c8f39ae3177bdd03beb8c5910d7bfe5cf77 Mon Sep 17 00:00:00 2001 From: Michael Dowling Date: Tue, 19 May 2026 17:19:26 -0500 Subject: [PATCH] Optimize normalizeValue for headers --- .../smithy/java/http/api/HeaderUtils.java | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/http/http-api/src/main/java/software/amazon/smithy/java/http/api/HeaderUtils.java b/http/http-api/src/main/java/software/amazon/smithy/java/http/api/HeaderUtils.java index eb93cf224..8f3153512 100644 --- a/http/http-api/src/main/java/software/amazon/smithy/java/http/api/HeaderUtils.java +++ b/http/http-api/src/main/java/software/amazon/smithy/java/http/api/HeaderUtils.java @@ -12,9 +12,6 @@ public final class HeaderUtils { // Header name lookup table: 0=invalid, 1=valid lower, 2=valid upper. private static final byte[] HEADER_NAME_TABLE = new byte[128]; - // Header value lookup table: true = allowed character - private static final boolean[] VALID_VALUE_CHAR = new boolean[256]; - static { for (char c = 'a'; c <= 'z'; c++) { HEADER_NAME_TABLE[c] = 1; @@ -26,16 +23,6 @@ public final class HeaderUtils { for (int i = 0; i < validChars.length(); i++) { HEADER_NAME_TABLE[validChars.charAt(i)] = 1; } - - // Valid value chars per RFC 7230 field-content: SP, HTAB, VCHAR, obs-text - VALID_VALUE_CHAR[' '] = true; - VALID_VALUE_CHAR['\t'] = true; - for (int c = 0x21; c <= 0x7E; c++) { - VALID_VALUE_CHAR[c] = true; - } - for (int c = 0x80; c <= 0xFF; c++) { - VALID_VALUE_CHAR[c] = true; - } } private HeaderUtils() {} @@ -102,25 +89,36 @@ static String normalizeName(String name) { * @throws IllegalArgumentException if the value contains invalid characters */ public static String normalizeValue(String value) { - // Simulate String.trim(), but we only want to trim leading and trailing ' ' and '\t'. int len = value.length(); - int end = len - 1; - int start = trimStart(value, end); - end = trimEnd(value, start); - if (start > end) { - return ""; + if (len == 0) { + return value; } - for (int i = start; i <= end; i++) { + // Peek at the boundaries to detect whether trimming is needed. + char first = value.charAt(0); + char last = value.charAt(len - 1); + boolean trimNeeded = first == ' ' || first == '\t' || last == ' ' || last == '\t'; + + // Ensure valid chars match obs-text + for (int i = 0; i < len; i++) { char c = value.charAt(i); - if (c > 255 || !VALID_VALUE_CHAR[c]) { + if (c > 0xFF || (c < 0x20 && c != '\t') || c == 0x7F) { throw invalidHeaderValueChar(value); } } - return (start == 0 && end == len - 1) - ? value - : value.substring(start, end + 1); + if (!trimNeeded) { + return value; + } + + int end = len - 1; + int start = trimStart(value, end); + end = trimEnd(value, start); + if (start > end) { + return ""; + } + + return value.substring(start, end + 1); } private static int trimStart(String s, int end) {