@@ -919,7 +919,7 @@ private HeaderParseStatus parseHeader() throws IOException {
919
919
headerData .lastSignificantChar = pos ;
920
920
byteBuffer .position (byteBuffer .position () - 1 );
921
921
// skipLine() will handle the error
922
- return skipLine ();
922
+ return skipLine (false );
923
923
}
924
924
925
925
// chr is next byte of header name. Convert to lowercase.
@@ -930,7 +930,7 @@ private HeaderParseStatus parseHeader() throws IOException {
930
930
931
931
// Skip the line and ignore the header
932
932
if (headerParsePos == HeaderParsePosition .HEADER_SKIPLINE ) {
933
- return skipLine ();
933
+ return skipLine (false );
934
934
}
935
935
936
936
//
@@ -987,15 +987,11 @@ private HeaderParseStatus parseHeader() throws IOException {
987
987
// CRLF or LF is an acceptable line terminator
988
988
eol = true ;
989
989
} else if (prevChr == Constants .CR ) {
990
- // Invalid value
991
- // Delete the header (it will be the most recent one)
992
- headers .removeHeader (headers .size () - 1 );
993
- return skipLine ();
990
+ // Invalid value - also need to delete header
991
+ return skipLine (true );
994
992
} else if (chr != Constants .HT && HttpParser .isControl (chr )) {
995
- // Invalid value
996
- // Delete the header (it will be the most recent one)
997
- headers .removeHeader (headers .size () - 1 );
998
- return skipLine ();
993
+ // Invalid value - also need to delete header
994
+ return skipLine (true );
999
995
} else if (chr == Constants .SP || chr == Constants .HT ) {
1000
996
byteBuffer .put (headerData .realPos , chr );
1001
997
headerData .realPos ++;
@@ -1043,7 +1039,27 @@ private HeaderParseStatus parseHeader() throws IOException {
1043
1039
}
1044
1040
1045
1041
1046
- private HeaderParseStatus skipLine () throws IOException {
1042
+ private HeaderParseStatus skipLine (boolean deleteHeader ) throws IOException {
1043
+ boolean rejectThisHeader = rejectIllegalHeader ;
1044
+ // Check if rejectIllegalHeader is disabled and needs to be overridden
1045
+ // for this header. The header name is required to determine if this
1046
+ // override is required. The header name is only available once the
1047
+ // header has been created. If the header has been created then
1048
+ // deleteHeader will be true.
1049
+ if (!rejectThisHeader && deleteHeader ) {
1050
+ if (headers .getName (headers .size () - 1 ).equalsIgnoreCase ("content-length" )) {
1051
+ // Malformed content-length headers must always be rejected
1052
+ // RFC 9112, section 6.3, bullet 5.
1053
+ rejectThisHeader = true ;
1054
+ } else {
1055
+ // Only need to delete the header if the request isn't going to
1056
+ // be rejected (it will be the most recent one)
1057
+ headers .removeHeader (headers .size () - 1 );
1058
+ }
1059
+ }
1060
+
1061
+ // Parse the rest of the invalid header so we can construct a useful
1062
+ // exception and/or debug message.
1047
1063
headerParsePos = HeaderParsePosition .HEADER_SKIPLINE ;
1048
1064
boolean eol = false ;
1049
1065
@@ -1069,11 +1085,11 @@ private HeaderParseStatus skipLine() throws IOException {
1069
1085
headerData .lastSignificantChar = pos ;
1070
1086
}
1071
1087
}
1072
- if (rejectIllegalHeader || log .isDebugEnabled ()) {
1088
+ if (rejectThisHeader || log .isDebugEnabled ()) {
1073
1089
String message = sm .getString ("iib.invalidheader" ,
1074
1090
HeaderUtil .toPrintableString (byteBuffer .array (), headerData .lineStart ,
1075
1091
headerData .lastSignificantChar - headerData .lineStart + 1 ));
1076
- if (rejectIllegalHeader ) {
1092
+ if (rejectThisHeader ) {
1077
1093
throw new IllegalArgumentException (message );
1078
1094
}
1079
1095
log .debug (message );
0 commit comments