Skip to content

Commit 818cee8

Browse files
committed
Further improvement
1 parent 2c450ca commit 818cee8

File tree

1 file changed

+65
-102
lines changed

1 file changed

+65
-102
lines changed

src/main/java/io/vertx/core/http/impl/HttpUtils.java

Lines changed: 65 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -873,46 +873,63 @@ public static void validateHeaderValue(CharSequence value) {
873873
}
874874
}
875875

876-
private static void validateAsciiHeaderValue(AsciiString asciiString) {
877-
final int length = asciiString.length();
876+
private static void validateAsciiHeaderValue(AsciiString value) {
877+
final int length = value.length();
878878
if (length == 0) {
879879
return;
880880
}
881-
byte[] asciiChars = asciiString.array();
882-
int off = asciiString.arrayOffset();
881+
byte[] asciiChars = value.array();
882+
int off = value.arrayOffset();
883883
int end = off + length;
884-
int state = NO_CR_LF_STATE;
885-
// Start looping through each of the character
884+
886885
for (int index = off; index < end; index++) {
887-
state = validateLatinValue(asciiString, state, asciiChars[index]);
888-
}
889-
if (state != 0) {
890-
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + asciiString);
886+
int latinChar = asciiChars[index] & 0xFF;
887+
if (latinChar == 0x7F) {
888+
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + value);
889+
}
890+
// non-printable chars are rare so let's make it a fall-back method, whilst still accepting HTAB
891+
if (latinChar < 32 && latinChar != 0x09) {
892+
validateSequenceHeaderValue(value, index - off);
893+
break;
894+
}
891895
}
892896
}
893897

894-
private static void validateStringHeaderValue(String seq) {
895-
896-
int state = NO_CR_LF_STATE;
897-
// Start looping through each of the character
898-
for (int index = 0; index < seq.length(); index++) {
899-
state = validateValueChar(seq, state, seq.charAt(index));
898+
private static void validateStringHeaderValue(String value) {
899+
final int length = value.length();
900+
if (length == 0) {
901+
return;
900902
}
901903

902-
if (state != 0) {
903-
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
904+
for (int index = 0; index < length; index++) {
905+
char latinChar = value.charAt(index);
906+
if (latinChar == 0x7F) {
907+
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + value);
908+
}
909+
// non-printable chars are rare so let's make it a fall-back method, whilst still accepting HTAB
910+
if (latinChar < 32 && latinChar != 0x09) {
911+
validateSequenceHeaderValue(value, index);
912+
break;
913+
}
904914
}
905915
}
906916

907-
private static void validateSequenceHeaderValue(CharSequence seq) {
908-
int state = 0;
909-
// Start looping through each of the character
910-
for (int index = 0; index < seq.length(); index++) {
911-
state = validateValueChar(seq, state, seq.charAt(index));
917+
private static void validateSequenceHeaderValue(CharSequence value) {
918+
final int length = value.length();
919+
if (length == 0) {
920+
return;
912921
}
913922

914-
if (state != 0) {
915-
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
923+
for (int index = 0; index < length; index++) {
924+
char latinChar = value.charAt(index);
925+
if (latinChar == 0x7F) {
926+
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + value);
927+
}
928+
// non-printable chars are rare so let's make it a fall-back method, whilst still accepting HTAB
929+
if (latinChar < 32 && latinChar != 0x09) {
930+
validateSequenceHeaderValue(value, index);
931+
break;
932+
}
916933
}
917934
}
918935

@@ -921,91 +938,37 @@ private static void validateSequenceHeaderValue(CharSequence seq) {
921938
private static final int CR_STATE = 1;
922939
private static final int LF_STATE = 2;
923940

924-
private static int validateLatinValue(CharSequence seq, int state, byte latinChar) {
925-
/*
926-
* State:
927-
* 0: Previous character was neither CR nor LF
928-
* 1: The previous character was CR
929-
* 2: The previous character was LF
930-
*/
931-
if (latinChar == 0x7F) {
932-
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + seq);
933-
}
934-
if ((latinChar & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
935-
// this is a rare scenario
936-
validateNonPrintableCtrlLatin(seq, latinChar);
937-
// this can include LF and CR as they are non-printable characters
938-
if (state == NO_CR_LF_STATE) {
939-
// Check the CRLF (HT | SP) pattern
940-
switch (latinChar) {
941-
case '\r':
942-
return CR_STATE;
943-
case '\n':
944-
return LF_STATE;
945-
}
946-
return NO_CR_LF_STATE;
941+
/**
942+
* This method is taken as we need to validate the header value for the non-printable characters.
943+
*/
944+
private static void validateSequenceHeaderValue(CharSequence seq, int index) {
945+
// we already expect the very-first character to be non-printable
946+
int state = validateValueChar(seq, NO_CR_LF_STATE, seq.charAt(index));
947+
for (int i = index + 1; i < seq.length(); i++) {
948+
state = validateValueChar(seq, state, seq.charAt(i));
949+
}
950+
if (state != NO_CR_LF_STATE) {
951+
throw new IllegalArgumentException("a header value must not end with '\\r' or '\\n':" + seq);
947952
}
948-
}
949-
if (state != NO_CR_LF_STATE) {
950-
// this is a rare scenario
951-
return validateCrLfLatin(seq, state, latinChar);
952-
} else {
953-
return NO_CR_LF_STATE;
954-
}
955-
}
956-
957-
private static void validateNonPrintableCtrlLatin(CharSequence seq, byte latinChar) {
958-
// The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
959-
switch (latinChar) {
960-
case 0x09: // Horizontal tab - HTAB
961-
case 0x0a: // Line feed - LF
962-
case 0x0d: // Carriage return - CR
963-
break;
964-
default:
965-
throw new IllegalArgumentException("a header value contains a prohibited character '" + Byte.toUnsignedInt(latinChar) + "': " + seq);
966-
}
967-
}
968-
969-
970-
private static int validateCrLfLatin(CharSequence seq, int state, byte latinChar) {
971-
switch (state) {
972-
case CR_STATE:
973-
if (latinChar == '\n') {
974-
return LF_STATE;
975-
}
976-
throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
977-
case LF_STATE:
978-
switch (latinChar) {
979-
case '\t':
980-
case ' ':
981-
// return to the normal state
982-
return NO_CR_LF_STATE;
983-
default:
984-
throw new IllegalArgumentException("only ' ' and '\\t' are allowed after '\\n': " + seq);
985-
}
986-
default:
987-
// this should never happen
988-
throw new AssertionError();
989-
}
990953
}
991954

992-
private static int validateValueChar(CharSequence seq, int state, char character) {
955+
private static int validateValueChar(CharSequence seq, int state, char ch) {
993956
/*
994957
* State:
995958
* 0: Previous character was neither CR nor LF
996959
* 1: The previous character was CR
997960
* 2: The previous character was LF
998961
*/
999-
if (character == 0x7F) {
962+
if (ch == 0x7F) {
1000963
throw new IllegalArgumentException("a header value contains a prohibited character '127': " + seq);
1001964
}
1002-
if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
965+
if ((ch & HIGHEST_INVALID_VALUE_CHAR_MASK) == 0) {
1003966
// this is a rare scenario
1004-
validateNonPrintableCtrlChar(seq, character);
967+
validateNonPrintableCtrlChar(seq, ch);
1005968
// this can include LF and CR as they are non-printable characters
1006969
if (state == NO_CR_LF_STATE) {
1007970
// Check the CRLF (HT | SP) pattern
1008-
switch (character) {
971+
switch (ch) {
1009972
case '\r':
1010973
return CR_STATE;
1011974
case '\n':
@@ -1016,21 +979,21 @@ private static int validateValueChar(CharSequence seq, int state, char character
1016979
}
1017980
if (state != NO_CR_LF_STATE) {
1018981
// this is a rare scenario
1019-
return validateCrLfChar(seq, state, character);
982+
return validateCrLfChar(seq, state, ch);
1020983
} else {
1021984
return NO_CR_LF_STATE;
1022985
}
1023986
}
1024987

1025-
private static int validateCrLfChar(CharSequence seq, int state, char character) {
988+
private static int validateCrLfChar(CharSequence seq, int state, char ch) {
1026989
switch (state) {
1027990
case CR_STATE:
1028-
if (character == '\n') {
991+
if (ch == '\n') {
1029992
return LF_STATE;
1030993
}
1031994
throw new IllegalArgumentException("only '\\n' is allowed after '\\r': " + seq);
1032995
case LF_STATE:
1033-
switch (character) {
996+
switch (ch) {
1034997
case '\t':
1035998
case ' ':
1036999
// return to the normal state
@@ -1044,15 +1007,15 @@ private static int validateCrLfChar(CharSequence seq, int state, char character)
10441007
}
10451008
}
10461009

1047-
private static void validateNonPrintableCtrlChar(CharSequence seq, int character) {
1010+
private static void validateNonPrintableCtrlChar(CharSequence seq, int ch) {
10481011
// The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
1049-
switch (character) {
1012+
switch (ch) {
10501013
case 0x09: // Horizontal tab - HTAB
10511014
case 0x0a: // Line feed - LF
10521015
case 0x0d: // Carriage return - CR
10531016
break;
10541017
default:
1055-
throw new IllegalArgumentException("a header value contains a prohibited character '" + (int) character + "': " + seq);
1018+
throw new IllegalArgumentException("a header value contains a prohibited character '" + (int) ch + "': " + seq);
10561019
}
10571020
}
10581021

0 commit comments

Comments
 (0)