4040import java .util .ArrayList ;
4141import java .util .Collections ;
4242import java .util .HashMap ;
43+ import java .util .Iterator ;
4344import java .util .List ;
4445import java .util .Map ;
46+ import java .util .Map .Entry ;
4547
4648import org .restlet .Context ;
4749import org .restlet .Request ;
@@ -86,64 +88,100 @@ public class TunnelFilter extends Filter {
8688 *
8789 * @author Thierry Boileau
8890 */
89- private static class AcceptReplacer {
91+ private static class HeaderReplacer {
9092
9193 static class Builder {
92- String acceptOld ;
93-
94- String acceptNew ;
95-
9694 Map <String , String > agentAttributes = new HashMap <String , String >();
9795
98- void setAcceptOld (String acceptOld ) {
99- this .acceptOld = acceptOld ;
100- }
96+ String newValue ;
10197
102- void setAcceptNew (String acceptNew ) {
103- this .acceptNew = acceptNew ;
98+ String oldValue ;
99+
100+ HeaderReplacer build () {
101+ return new HeaderReplacer (oldValue , newValue , agentAttributes );
104102 }
105103
106104 void putAgentAttribute (String key , String value ) {
107105 agentAttributes .put (key , value );
108106 }
109107
110- AcceptReplacer build ( ) {
111- return new AcceptReplacer ( acceptOld , acceptNew , agentAttributes ) ;
108+ void setNewValue ( String newValue ) {
109+ this . newValue = newValue ;
112110 }
113- }
114111
115- AcceptReplacer (String acceptOld , String acceptNew ,
116- Map <String , String > agentAttributes ) {
117- this .acceptOld = acceptOld ;
118- this .acceptNew = acceptNew ;
119- this .agentAttributes = Collections .unmodifiableMap (agentAttributes );
112+ void setOldValue (String oldValue ) {
113+ this .oldValue = oldValue ;
114+ }
120115 }
121116
122- /** New accept header value. */
123- private final String acceptNew ;
124-
125- /** Old accept header value. */
126- private final String acceptOld ;
127-
128117 /** Agent attributes that must be checked. */
129118 private final Map <String , String > agentAttributes ;
130119
131- public String getAcceptNew () {
132- return acceptNew ;
133- }
120+ /** New header value. */
121+ private final String headerNew ;
134122
135- public String getAcceptOld () {
136- return acceptOld ;
123+ /** Old header value. */
124+ private final String headerOld ;
125+
126+ HeaderReplacer (String headerOld , String headerNew ,
127+ Map <String , String > agentAttributes ) {
128+ this .headerOld = headerOld ;
129+ this .headerNew = headerNew ;
130+ this .agentAttributes = Collections .unmodifiableMap (agentAttributes );
137131 }
138132
139133 public Map <String , String > getAgentAttributes () {
140134 return agentAttributes ;
141135 }
142136
137+ public String getHeaderNew () {
138+ return headerNew ;
139+ }
140+
141+ public String getHeaderOld () {
142+ return headerOld ;
143+ }
144+
145+ /**
146+ * Indicates if the current header replacer matches the request
147+ * attributes.
148+ *
149+ * @param agentAttributes
150+ * The user agent attributes to match.
151+ * @param headerOld
152+ * The facultative value of the current's request header to
153+ * match.
154+ * @return true if the given request's attibutes match the current
155+ * header replacer.
156+ */
157+ public boolean matchesConditions (Map <String , String > agentAttributes ,
158+ String headerOld ) {
159+ // Check the conditions
160+ boolean checked = true ;
161+ // Check that the agent properties match the properties
162+ // set by the rule.
163+ for (Iterator <Entry <String , String >> iterator = getAgentAttributes ()
164+ .entrySet ().iterator (); checked && iterator .hasNext ();) {
165+ Entry <String , String > entry = iterator .next ();
166+ String attribute = agentAttributes .get (entry .getKey ());
167+ checked = (attribute != null && attribute
168+ .equalsIgnoreCase (entry .getValue ()));
169+ }
170+ if (checked && getHeaderOld () != null ) {
171+ // If the rule defines an old header value, check that it is the
172+ // same than the user agent's header value.
173+ checked = getHeaderOld ().equals (headerOld );
174+ }
175+ return checked ;
176+ }
177+
143178 }
144179
180+ /** Used to replace accept-encoding header values. */
181+ private final List <HeaderReplacer > acceptEncodingReplacers = getAcceptEncodingReplacers ();
182+
145183 /** Used to replace accept header values. */
146- private final List <AcceptReplacer > acceptReplacers = getAcceptReplacers ();
184+ private final List <HeaderReplacer > acceptReplacers = getAcceptReplacers ();
147185
148186 /**
149187 * Constructor.
@@ -176,26 +214,63 @@ public int beforeHandle(Request request, Response response) {
176214 return CONTINUE ;
177215 }
178216
217+ /**
218+ * Returns the list of new accept-encoding header values. Each of them
219+ * describe also a set of conditions required to set the new value. This
220+ * method is used only to initialize the headerReplacers field.
221+ *
222+ * @return The list of new accept-encoding header values.
223+ */
224+ private List <HeaderReplacer > getAcceptEncodingReplacers () {
225+ // Load the accept.properties file.
226+ return getheaderReplacers (
227+ Engine .getResource ("org/restlet/service/accept-encoding.properties" ),
228+ "acceptEncodingOld" , "acceptEncodingNew" );
229+ }
230+
179231 /**
180232 * Returns the list of new accept header values. Each of them describe also
181233 * a set of conditions required to set the new value. This method is used
182- * only to initialize the acceptReplacers field.
234+ * only to initialize the headerReplacers field.
183235 *
184236 * @return The list of new accept header values.
185237 */
186- private List <AcceptReplacer > getAcceptReplacers () {
187- List <AcceptReplacer > acceptReplacers = new ArrayList <AcceptReplacer >();
238+ private List <HeaderReplacer > getAcceptReplacers () {
188239 // Load the accept.properties file.
189- final URL userAgentPropertiesUrl = Engine
190- .getResource ("org/restlet/service/accept.properties" );
240+ return getheaderReplacers (
241+ Engine .getResource ("org/restlet/service/accept.properties" ),
242+ "acceptOld" , "acceptNew" );
243+ }
244+
245+ /**
246+ * Returns the list of new header values. Each of them describe also a set
247+ * of conditions required to set the new value. This method is used only to
248+ * initialize the headerReplacers field.
249+ *
250+ * @param userAgentPropertiesUrl
251+ * The URL of the properties file that describe replacement
252+ * values based on the user agent string.
253+ * @param oldHeaderName
254+ * The name of the property that gives the value of the header to
255+ * be replaced (could be null - in that case, the new value is
256+ * unconditionnaly set.
257+ * @param newHeaderName
258+ * The name of the property that gives the replacement value.
259+ * @return
260+ */
261+ private List <HeaderReplacer > getheaderReplacers (
262+ final URL userAgentPropertiesUrl , String oldHeaderName ,
263+ String newHeaderName ) {
264+ List <HeaderReplacer > headerReplacers = new ArrayList <HeaderReplacer >();
265+
191266 if (userAgentPropertiesUrl != null ) {
192267 BufferedReader reader ;
193268 try {
194269 reader = new BufferedReader (new InputStreamReader (
195270 userAgentPropertiesUrl .openStream (),
196271 CharacterSet .UTF_8 .getName ()), IoUtils .BUFFER_SIZE );
197272
198- AcceptReplacer .Builder acceptReplacerBuilder = new AcceptReplacer .Builder ();
273+ HeaderReplacer .Builder headerReplacerBuilder = new HeaderReplacer .Builder ();
199274
200275 try {
201276 // Read the entire file, excluding comment lines starting
@@ -207,17 +282,17 @@ private List<AcceptReplacer> getAcceptReplacers() {
207282 if (keyValue .length == 2 ) {
208283 final String key = keyValue [0 ].trim ();
209284 final String value = keyValue [1 ].trim ();
210- if ("acceptOld" .equalsIgnoreCase (key )) {
211- acceptReplacerBuilder . setAcceptOld ((""
285+ if (oldHeaderName .equalsIgnoreCase (key )) {
286+ headerReplacerBuilder . setOldValue ((""
212287 .equals (value )) ? null : value );
213- } else if ("acceptNew" .equalsIgnoreCase (key )) {
214- acceptReplacerBuilder . setAcceptNew (value );
215- acceptReplacers .add (acceptReplacerBuilder
288+ } else if (newHeaderName .equalsIgnoreCase (key )) {
289+ headerReplacerBuilder . setNewValue (value );
290+ headerReplacers .add (headerReplacerBuilder
216291 .build ());
217292
218- acceptReplacerBuilder = new AcceptReplacer .Builder ();
293+ headerReplacerBuilder = new HeaderReplacer .Builder ();
219294 } else {
220- acceptReplacerBuilder .putAgentAttribute (
295+ headerReplacerBuilder .putAgentAttribute (
221296 key , value );
222297 }
223298 }
@@ -233,8 +308,7 @@ private List<AcceptReplacer> getAcceptReplacers() {
233308 }
234309 }
235310
236- return acceptReplacers ;
237-
311+ return headerReplacers ;
238312 }
239313
240314 /**
@@ -521,45 +595,40 @@ private void processUserAgent(Request request) {
521595 final Map <String , String > agentAttributes = request .getClientInfo ()
522596 .getAgentAttributes ();
523597 if (agentAttributes != null ) {
524- if (!this .acceptReplacers .isEmpty ()) {
598+ if (!this .acceptReplacers .isEmpty ()
599+ || !this .acceptEncodingReplacers .isEmpty ()) {
525600 // Get the old Accept header value
526601 @ SuppressWarnings ("unchecked" )
527602 Series <Header > headers = (Series <Header >) request
528603 .getAttributes ().get (HeaderConstants .ATTRIBUTE_HEADERS );
604+
529605 String acceptOld = (headers != null ) ? headers .getFirstValue (
530606 HeaderConstants .HEADER_ACCEPT , true ) : null ;
531-
532607 // Check each replacer
533- for (AcceptReplacer acceptReplacer : this .acceptReplacers ) {
534- // Check the conditions
535- boolean checked = true ;
536-
537- for (String key : acceptReplacer .getAgentAttributes ()
538- .keySet ()) {
539- String attribute = agentAttributes .get (key );
540- // Check that the agent properties match the properties
541- // set by the rule.
542- checked = checked
543- && (attribute != null && attribute
544- .equalsIgnoreCase (acceptReplacer
545- .getAgentAttributes ().get (key )));
608+ for (HeaderReplacer headerReplacer : this .acceptReplacers ) {
609+ if (headerReplacer .matchesConditions (agentAttributes ,
610+ acceptOld )) {
611+ ClientInfo clientInfo = new ClientInfo ();
612+ PreferenceReader .addMediaTypes (
613+ headerReplacer .getHeaderNew (), clientInfo );
614+ request .getClientInfo ().setAcceptedMediaTypes (
615+ clientInfo .getAcceptedMediaTypes ());
616+ break ;
546617 }
547- if (checked ) {
548- // If the rule defines an acceptOld value, check that it
549- // is the same than the user agent's "accept" header
550- // value.
551- if (acceptReplacer .getAcceptOld () != null ) {
552- checked = acceptReplacer .getAcceptOld ().equals (
553- acceptOld );
554- }
555- if (checked ) {
556- ClientInfo clientInfo = new ClientInfo ();
557- PreferenceReader .addMediaTypes (
558- acceptReplacer .getAcceptNew (), clientInfo );
559- request .getClientInfo ().setAcceptedMediaTypes (
560- clientInfo .getAcceptedMediaTypes ());
561- break ;
562- }
618+ }
619+ String acceptEncodingOld = (headers != null ) ? headers
620+ .getFirstValue (HeaderConstants .HEADER_ACCEPT_ENCODING ,
621+ true ) : null ;
622+ // Check each replacer
623+ for (HeaderReplacer headerReplacer : this .acceptEncodingReplacers ) {
624+ if (headerReplacer .matchesConditions (agentAttributes ,
625+ acceptEncodingOld )) {
626+ ClientInfo clientInfo = new ClientInfo ();
627+ PreferenceReader .addEncodings (
628+ headerReplacer .getHeaderNew (), clientInfo );
629+ request .getClientInfo ().setAcceptedEncodings (
630+ clientInfo .getAcceptedEncodings ());
631+ break ;
563632 }
564633 }
565634 }
0 commit comments