Buggy code:
public class DecodeInterceptor extends BaseInterceptor { private String defaultEncoding = null ; private boolean useSessionEncoding = true ; private String charsetAttribute = "charset" ; private String charsetURIAttribute = ";charset=" ; private int encodingInfoNote ; private int decodedNote ; private int encodingSourceNote ; private int sessionEncodingNote ; private boolean normalize = true ; private boolean safe = true ; private boolean saveOriginal = false ; public DecodeInterceptor ( ) { } public void setDefaultEncoding ( String s ) { } public void setUseSessionEncoding ( boolean b ) { } public void setCharsetAttribute ( String s ) { } public void setNormalize ( boolean b ) { } public void setSaveOriginal ( boolean b ) { } public void setSafe ( boolean b ) { } public void engineInit ( ContextManager cm ) throws TomcatException { } private void normalizePath ( MessageBytes pathMB ) { } private boolean normalize ( ByteChunk bc ) { } private String normalize ( String str ) { } private boolean isSafeURI ( MessageBytes pathMB ) { } public int postReadRequest ( Request req ) { MessageBytes pathMB = req . requestURI ( ) ; if ( pathMB . isNull ( ) ) throw new RuntimeException ( "ASSERT:<seq2seq4repair_space>null<seq2seq4repair_space>path<seq2seq4repair_space>in<seq2seq4repair_space>request<seq2seq4repair_space>URI" ) ; if ( ( safe ) && ( ! ( isSafeURI ( pathMB ) ) ) ) { req . setAttribute ( "javax.servlet.error.message" , "Unsafe<seq2seq4repair_space>URL" ) ; return 403 ; } if ( ( normalize ) && ( ( ( pathMB . indexOf ( "////" ) ) >= 0 ) || ( ( pathMB . indexOf ( "//." ) ) >= 0 ) ) ) { normalizePath ( pathMB ) ; if ( ( debug ) > 0 ) log ( ( "Normalized<seq2seq4repair_space>url<seq2seq4repair_space>" + pathMB ) ) ; } String charEncoding = null ; MimeHeaders headers = req . getMimeHeaders ( ) ; MessageBytes contentType = req . contentType ( ) ; if ( contentType != null ) { String contentTypeString = contentType . toString ( ) ; charEncoding = ContentType . getCharsetFromContentType ( contentTypeString ) ; if ( ( debug ) > 0 ) log ( ( ( ( "Got<seq2seq4repair_space>encoding<seq2seq4repair_space>from<seq2seq4repair_space>content-type<seq2seq4repair_space>" + charEncoding ) + "<seq2seq4repair_space>" ) + contentTypeString ) ) ; req . setNote ( encodingSourceNote , "Content-Type" ) ; } if ( ( debug ) > 99 ) dumpHeaders ( headers ) ; if ( ( charEncoding == null ) && ( ( charsetURIAttribute ) != null ) ) { int idxCharset = req . requestURI ( ) . indexOf ( charsetURIAttribute ) ; if ( idxCharset >= 0 ) { String uri = req . requestURI ( ) . toString ( ) ; int nextAtt = uri . indexOf ( ';' , ( idxCharset + 1 ) ) ; String next = null ; if ( nextAtt > 0 ) { next = uri . substring ( nextAtt ) ; charEncoding = uri . substring ( ( idxCharset + ( charsetURIAttribute . length ( ) ) ) , nextAtt ) ; req . requestURI ( ) . setString ( ( ( uri . substring ( 0 , idxCharset ) ) + next ) ) ; req . setNote ( encodingSourceNote , "Request-Attribute" ) ; } else { charEncoding = uri . substring ( ( idxCharset + ( charsetURIAttribute . length ( ) ) ) ) ; req . requestURI ( ) . setString ( uri . substring ( 0 , idxCharset ) ) ; req . setNote ( encodingSourceNote , "Request-Attribute" ) ; } if ( ( debug ) > 0 ) log ( ( ( ( "ReqAtt=<seq2seq4repair_space>" + charEncoding ) + "<seq2seq4repair_space>" ) + ( req . requestURI ( ) ) ) ) ; } } if ( charEncoding == null ) { if ( ( debug ) > 0 ) log ( ( "Default<seq2seq4repair_space>encoding<seq2seq4repair_space>" + ( defaultEncoding ) ) ) ; if ( ( defaultEncoding ) != null ) charEncoding = defaultEncoding ; } if ( charEncoding != null ) req . setCharEncoding ( charEncoding ) ; if ( ( req . getNote ( decodedNote ) ) != null ) { if ( ( debug ) > 5 ) log ( ( "Already<seq2seq4repair_space>decoded<seq2seq4repair_space>" + ( req . getNote ( decodedNote ) ) ) ) ; return 0 ; } if ( saveOriginal ) { try { req . unparsedURI ( ) . duplicate ( pathMB ) ; } catch ( IOException ex ) { log ( "Error<seq2seq4repair_space>copying<seq2seq4repair_space>request<seq2seq4repair_space>" , ex ) ; } } if ( ( ( pathMB . indexOf ( '%' ) ) >= 0 ) || ( ( pathMB . indexOf ( '+' ) ) >= 0 ) ) { try { if ( ( debug ) > 1 ) log ( ( "Before<seq2seq4repair_space>" + ( pathMB . toString ( ) ) ) ) ; <START_BUG> req . getURLDecoder ( ) . convert ( pathMB ) ; <END_BUG> pathMB . resetStringValue ( ) ; if ( ( debug ) > 1 ) log ( ( "After<seq2seq4repair_space>" + ( pathMB . toString ( ) ) ) ) ; if ( ( pathMB . indexOf ( '' ) ) >= 0 ) { return 404 ; } req . setNote ( decodedNote , this ) ; } catch ( IOException ex ) { log ( "Error<seq2seq4repair_space>decoding<seq2seq4repair_space>request<seq2seq4repair_space>" , ex ) ; return 400 ; } } return 0 ; } public int beforeBody ( Request req , Response res ) { } public Object getInfo ( Context ctx , Request req , int info , String k ) { } public int setInfo ( Context ctx , Request req , int info , String k , Object v ) { } private void dumpHeaders ( MimeHeaders mh ) { } }

Fix:
req . getURLDecoder ( ) . convert ( pathMB , false ) ;