1212import java .util .regex .*;
1313
1414public class ContentDispositionHeader {
15-
16- // Regular expressions as static final strings
17- private static final String HEX_ESCAPE_REPLACE_REGEXP = "%([0-9A-Fa-f]{2})" ;
18- private static final String NON_LATIN1_REGEXP = "[^\\ x20-\\ x7e\\ xa0-\\ xff]" ;
19- private static final String QESC_REGEXP = "\\ \\ \\ ([\\ u0000-\\ u007f])" ;
20- private static final String PARAM_REGEXP = ";[\\ x09\\ x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ x09\\ x20]*=(?:[\\ x09\\ x20]*\" (?:[\\ x20!\\ x23-\\ x5b\\ x5d-\\ x7e\\ x80-\\ xff]|\\ \\ [\\ x20-\\ x7e])*\" |[\\ x09\\ x20]*[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ x09\\ x20]*)" ;
21- private static final String EXT_VALUE_REGEXP = "^([A-Za-z0-9!#$%&+\\ -^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$" ;
22- private static final String DISPOSITION_TYPE_REGEXP = "^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ x09\\ x20]*(?:$|;)" ;
15+ private static final Pattern HEX_ESCAPE_REPLACE_REGEXP = Pattern .compile ("%([0-9A-Fa-f]{2})" );
16+
17+ /**
18+ * RegExp to match non-latin1 characters.
19+ * @private
20+ */
21+ private static final Pattern NON_LATIN1_REGEXP = Pattern .compile ("[^\\ x20-\\ x7e\\ xa0-\\ xff]" );
22+
23+ /**
24+ * RegExp to match quoted-pair in RFC 2616
25+ *
26+ * quoted-pair = "\" CHAR
27+ * CHAR = <any US-ASCII character (octets 0 - 127)>
28+ */
29+ private static final Pattern QESC_REGEXP = Pattern .compile ("\\ \\ ([\\ u0000-\\ u007f])" );
30+
31+ /**
32+ * RegExp for various RFC 2616 grammar
33+ *
34+ * parameter = token "=" ( token | quoted-string )
35+ * token = 1*<any CHAR except CTLs or separators>
36+ * separators = "(" | ")" | "<" | ">" | "@"
37+ * | "," | ";" | ":" | "\" | <">
38+ * | "/" | "[" | "]" | "?" | "="
39+ * | "{" | "}" | SP | HT
40+ * quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
41+ * qdtext = <any TEXT except <">>
42+ * quoted-pair = "\" CHAR
43+ * CHAR = <any US-ASCII character (octets 0 - 127)>
44+ * TEXT = <any OCTET except CTLs, but including LWS>
45+ * LWS = [CRLF] 1*( SP | HT )
46+ * CRLF = CR LF
47+ * CR = <US-ASCII CR, carriage return (13)>
48+ * LF = <US-ASCII LF, linefeed (10)>
49+ * SP = <US-ASCII SP, space (32)>
50+ * HT = <US-ASCII HT, horizontal-tab (9)>
51+ * CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
52+ * OCTET = <any 8-bit sequence of data>
53+ */
54+ private static final Pattern PARAM_REGEXP = Pattern .compile (";[\\ t ]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ t ]*=[\\ t ]*(\" (?:[\\ x20!\\ x23-\\ x5b\\ x5d-\\ x7e\\ x80-\\ xff]|\\ \\ [\\ x20-\\ x7e])*\" |[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ t ]*" );
55+
56+ /**
57+ * RegExp for various RFC 5987 grammar
58+ *
59+ * ext-value = charset "'" [ language ] "'" value-chars
60+ * charset = "UTF-8" / "ISO-8859-1" / mime-charset
61+ * mime-charset = 1*mime-charsetc
62+ * mime-charsetc = ALPHA / DIGIT
63+ * / "!" / "#" / "$" / "%" / "&"
64+ * / "+" / "-" / "^" / "_" / "`"
65+ * / "{" / "}" / "~"
66+ * language = ( 2*3ALPHA [ extlang ] )
67+ * / 4ALPHA
68+ * / 5*8ALPHA
69+ * extlang = *3( "-" 3ALPHA )
70+ * value-chars = *( pct-encoded / attr-char )
71+ * pct-encoded = "%" HEXDIG HEXDIG
72+ * attr-char = ALPHA / DIGIT
73+ * / "!" / "#" / "$" / "&" / "+" / "-" / "."
74+ * / "^" / "_" / "`" / "|" / "~"
75+ */
76+ private static final Pattern EXT_VALUE_REGEXP = Pattern .compile ("^([A-Za-z0-9!#$%&+\\ -^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$" );
77+
78+ /**
79+ * RegExp for various RFC 6266 grammar
80+ *
81+ * disposition-type = "inline" | "attachment" | disp-ext-type
82+ * disp-ext-type = token
83+ * disposition-parm = filename-parm | disp-ext-parm
84+ * filename-parm = "filename" "=" value
85+ * | "filename*" "=" ext-value
86+ * disp-ext-parm = token "=" value
87+ * | ext-token "=" ext-value
88+ * ext-token = <the characters in token, followed by "*">
89+ */
90+ private static final Pattern DISPOSITION_TYPE_REGEXP = Pattern .compile ("^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\ t ]*(?:$|;)" );
2391
2492 private static String decodeField (String str ) {
25- Pattern pattern = Pattern .compile (EXT_VALUE_REGEXP );
26- Matcher matcher = pattern .matcher (str );
93+ Matcher matcher = EXT_VALUE_REGEXP .matcher (str );
2794
2895 if (!matcher .find ()) {
2996 throw new IllegalArgumentException ("invalid extended field value" );
@@ -47,7 +114,7 @@ private static String decodeField(String str) {
47114
48115 private static String getLatin1 (String val ) {
49116 // simple Unicode -> ISO-8859-1 transformation
50- return val .replaceAll (NON_LATIN1_REGEXP , "?" );
117+ return val .replaceAll (NON_LATIN1_REGEXP . pattern () , "?" );
51118 }
52119
53120 public record ParseResult (String type , Map <String , String > params ) {}
@@ -57,8 +124,7 @@ public static ParseResult parse(String string) {
57124 throw new IllegalArgumentException ("argument string is required" );
58125 }
59126
60- Pattern pattern = Pattern .compile (DISPOSITION_TYPE_REGEXP );
61- Matcher matcher = pattern .matcher (string );
127+ Matcher matcher = DISPOSITION_TYPE_REGEXP .matcher (string );
62128
63129 if (!matcher .find ()) {
64130 throw new IllegalArgumentException ("invalid type format" );
@@ -74,8 +140,7 @@ public static ParseResult parse(String string) {
74140 String value ;
75141
76142 // calculate index to start at
77- pattern = Pattern .compile (PARAM_REGEXP );
78- matcher = pattern .matcher (string );
143+ matcher = PARAM_REGEXP .matcher (string );
79144 matcher .region (index , string .length ());
80145
81146 // match parameters
@@ -112,7 +177,7 @@ public static ParseResult parse(String string) {
112177 // remove quotes and escapes
113178 value = value
114179 .substring (1 , value .length () - 1 )
115- .replaceAll (QESC_REGEXP , "$1" );
180+ .replaceAll (QESC_REGEXP . pattern () , "$1" );
116181 }
117182
118183 params .put (key , value );
@@ -130,8 +195,7 @@ private static String pDecode(String hex) {
130195 }
131196
132197 private static String replaceAll (String input , Replacer replacer ) {
133- Pattern pattern = Pattern .compile (ContentDispositionHeader .HEX_ESCAPE_REPLACE_REGEXP );
134- Matcher matcher = pattern .matcher (input );
198+ Matcher matcher = HEX_ESCAPE_REPLACE_REGEXP .matcher (input );
135199 StringBuilder sb = new StringBuilder ();
136200
137201 while (matcher .find ()) {
0 commit comments