@@ -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