@@ -863,7 +863,32 @@ public static void validateHeader(CharSequence name, Iterable<? extends CharSequ
863863 });
864864 }
865865
866- public static void validateHeaderValue (CharSequence seq ) {
866+ public static void validateHeaderValue (CharSequence value ) {
867+ if (value instanceof AsciiString ) {
868+ validateAsciiHeaderValue ((AsciiString ) value );
869+ } else if (value instanceof String ) {
870+ validateStringHeaderValue ((String ) value );
871+ } else {
872+ validateSequenceHeaderValue (value );
873+ }
874+ }
875+
876+ private static void validateAsciiHeaderValue (AsciiString asciiString ) {
877+ byte [] asciiChars = asciiString .array ();
878+ int off = asciiString .arrayOffset ();
879+ int len = asciiString .length ();
880+ int state = 0 ;
881+ // Start looping through each of the character
882+ for (int index = 0 ; index < len ; index ++) {
883+ state = validateValueChar (asciiString , state , (char ) Byte .toUnsignedInt (asciiChars [off + index ]));
884+ }
885+
886+ if (state != 0 ) {
887+ throw new IllegalArgumentException ("a header value must not end with '\\ r' or '\\ n':" + asciiString );
888+ }
889+ }
890+
891+ private static void validateStringHeaderValue (String seq ) {
867892
868893 int state = 0 ;
869894 // Start looping through each of the character
@@ -876,7 +901,23 @@ public static void validateHeaderValue(CharSequence seq) {
876901 }
877902 }
878903
904+ private static void validateSequenceHeaderValue (CharSequence seq ) {
905+ int state = 0 ;
906+ // Start looping through each of the character
907+ for (int index = 0 ; index < seq .length (); index ++) {
908+ state = validateValueChar (seq , state , seq .charAt (index ));
909+ }
910+
911+ if (state != 0 ) {
912+ throw new IllegalArgumentException ("a header value must not end with '\\ r' or '\\ n':" + seq );
913+ }
914+ }
915+
879916 private static final int HIGHEST_INVALID_VALUE_CHAR_MASK = ~0x1F ;
917+ private static final int NO_CR_LF_STATE = 0 ;
918+ private static final int CR_STATE = 1 ;
919+ private static final int LF_STATE = 2 ;
920+
880921
881922 private static int validateValueChar (CharSequence seq , int state , char character ) {
882923 /*
@@ -885,45 +926,56 @@ private static int validateValueChar(CharSequence seq, int state, char character
885926 * 1: The previous character was CR
886927 * 2: The previous character was LF
887928 */
888- if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK ) == 0 || character == 0x7F ) { // 0x7F is "DEL".
889- // The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
929+ if ((character & HIGHEST_INVALID_VALUE_CHAR_MASK ) == 0 || character == 0x7F ) {
930+ validateNonPrintableCtrlChar (seq , character );
931+ }
932+
933+ // Check the CRLF (HT | SP) pattern
934+ if (state == NO_CR_LF_STATE ) {
890935 switch (character ) {
891- case 0x09 : // Horizontal tab - HTAB
892- case 0x0a : // Line feed - LF
893- case 0x0d : // Carriage return - CR
894- break ;
895- default :
896- throw new IllegalArgumentException ("a header value contains a prohibited character '" + (int ) character + "': " + seq );
936+ case '\r' :
937+ return CR_STATE ;
938+ case '\n' :
939+ return LF_STATE ;
897940 }
941+ return NO_CR_LF_STATE ;
942+ } else {
943+ return validateCrLf (seq , state , character );
898944 }
945+ }
899946
900- // Check the CRLF (HT | SP) pattern
947+ private static int validateCrLf ( CharSequence seq , int state , char character ) {
901948 switch (state ) {
902- case 0 :
903- switch (character ) {
904- case '\r' :
905- return 1 ;
906- case '\n' :
907- return 2 ;
908- }
909- break ;
910- case 1 :
911- switch (character ) {
912- case '\n' :
913- return 2 ;
914- default :
915- throw new IllegalArgumentException ("only '\\ n' is allowed after '\\ r': " + seq );
949+ case CR_STATE :
950+ if (character == '\n' ) {
951+ return LF_STATE ;
916952 }
917- case 2 :
953+ throw new IllegalArgumentException ("only '\\ n' is allowed after '\\ r': " + seq );
954+ case LF_STATE :
918955 switch (character ) {
919956 case '\t' :
920957 case ' ' :
921- return 0 ;
958+ // return to the normal state
959+ return NO_CR_LF_STATE ;
922960 default :
923961 throw new IllegalArgumentException ("only ' ' and '\\ t' are allowed after '\\ n': " + seq );
924962 }
963+ default :
964+ // this should never happen
965+ throw new AssertionError ();
966+ }
967+ }
968+
969+ private static void validateNonPrintableCtrlChar (CharSequence seq , char character ) {
970+ // The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR
971+ switch (character ) {
972+ case 0x09 : // Horizontal tab - HTAB
973+ case 0x0a : // Line feed - LF
974+ case 0x0d : // Carriage return - CR
975+ break ;
976+ default :
977+ throw new IllegalArgumentException ("a header value contains a prohibited character '" + (int ) character + "': " + seq );
925978 }
926- return state ;
927979 }
928980
929981 private static final boolean [] VALID_H_NAME_ASCII_CHARS ;
@@ -959,13 +1011,15 @@ private static int validateValueChar(CharSequence seq, int state, char character
9591011 public static void validateHeaderName (CharSequence value ) {
9601012 if (value instanceof AsciiString ) {
9611013 // no need to check for ASCII-ness anymore
962- validateHeaderName ((AsciiString ) value );
1014+ validateAsciiHeaderName ((AsciiString ) value );
1015+ } else if (value instanceof String ) {
1016+ validateStringHeaderName ((String ) value );
9631017 } else {
964- validateHeaderName0 (value );
1018+ validateSequenceHeaderName (value );
9651019 }
9661020 }
9671021
968- private static void validateHeaderName (AsciiString value ) {
1022+ private static void validateAsciiHeaderName (AsciiString value ) {
9691023 final int len = value .length ();
9701024 final int off = value .arrayOffset ();
9711025 final byte [] asciiChars = value .array ();
@@ -981,7 +1035,20 @@ private static void validateHeaderName(AsciiString value) {
9811035 }
9821036 }
9831037
984- private static void validateHeaderName0 (CharSequence value ) {
1038+ private static void validateStringHeaderName (String value ) {
1039+ for (int i = 0 ; i < value .length (); i ++) {
1040+ final char c = value .charAt (i );
1041+ // Check to see if the character is not an ASCII character, or invalid
1042+ if (c > 0x7f ) {
1043+ throw new IllegalArgumentException ("a header name cannot contain non-ASCII character: " + value );
1044+ }
1045+ if (!VALID_H_NAME_ASCII_CHARS [c & 0x7F ]) {
1046+ throw new IllegalArgumentException ("a header name cannot contain some prohibited characters, such as : " + value );
1047+ }
1048+ }
1049+ }
1050+
1051+ private static void validateSequenceHeaderName (CharSequence value ) {
9851052 for (int i = 0 ; i < value .length (); i ++) {
9861053 final char c = value .charAt (i );
9871054 // Check to see if the character is not an ASCII character, or invalid
0 commit comments