Skip to content

Commit 120eba1

Browse files
committed
Added ability to override Accept-encoding header values restlet#654. Proposed by Tal Liron.
1 parent 1e24da7 commit 120eba1

3 files changed

Lines changed: 151 additions & 76 deletions

File tree

build/tmpl/text/changes.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Changes log
1010
- Enhancements
1111
- Added support of nowrap "deflater" (support of GZIP compatible compression), issue #786.
1212
Reported and contributed by Tal Liron.
13+
- Added ability to override Accept-encoding header values #654.
14+
Proposed by Tal Liron.
1315

1416
- 2.1.4 (09/07/2013)
1517
- Bug fixed

modules/org.restlet/src/org/restlet/engine/application/TunnelFilter.java

Lines changed: 145 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
import java.util.ArrayList;
4141
import java.util.Collections;
4242
import java.util.HashMap;
43+
import java.util.Iterator;
4344
import java.util.List;
4445
import java.util.Map;
46+
import java.util.Map.Entry;
4547

4648
import org.restlet.Context;
4749
import 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
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#Internet explorer
2+
agentName: msie
3+
acceptEncodingOld: deflate
4+
acceptEncodingNew: deflate-no-wrap

0 commit comments

Comments
 (0)