Ultimately, I have this in my rule:
<set name="urlrewrite.originalRequestUri">%{request-uri}</set>
<set name="urlrewrite.originalQueryString">%{query-string}</set>
Works like a charm. I can grab those values as request attributes
later.
However... if my request query string contains a dollar ($), I get a
StringIndexOutOfBoundsException. Now I realize that isn't a valid
character in a query string (it should be escaped) but a user can
easily type it into their address bar.
For example:
/whatver?x=$
results in:
java.lang.StringIndexOutOfBoundsException: String index out of range:
3
at java.lang.String.charAt(String.java:687)
at java.util.regex.Matcher.appendReplacement(Matcher.java:711)
at
org.tuckey.web.filters.urlrewrite.VariableReplacer.replace(VariableReplacer.java:
88)
It works just fine if there is no "$" there. I narrowed it down to a
unit test (using junit 4 and jMock to stub the request):
import static org.junit.Assert.assertEquals;
import javax.servlet.http.HttpServletRequest;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Before;
import org.junit.Test;
import org.tuckey.web.filters.urlrewrite.VariableReplacer;
public class UrlRewriteVariableReplacerTest {
private Mockery context;
private HttpServletRequest request;
@Before
public void setUp() throws Exception {
context = new Mockery();
request = context.mock(HttpServletRequest.class);
}
@Test
public final void testVariableReplace() {
final String queryString = "x=$";
context.checking(new Expectations() {
{
allowing(request).getQueryString();
will(returnValue(queryString));
}
});
final String result = VariableReplacer.replace("%{query-
string}", request);
assertEquals(queryString, result);
}
}
java.lang.StringIndexOutOfBoundsException: String index out of range:
3
at java.lang.String.charAt(String.java:687)
at java.util.regex.Matcher.appendReplacement(Matcher.java:711)
at
org.tuckey.web.filters.urlrewrite.VariableReplacer.replace(VariableReplacer.java:
88)
at
urlrewritefilter.UrlRewriteVariableReplacerTest.testVariableReplace(UrlRewriteVariableReplacerTest.java:
38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:
99)
at
org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:
81)
at
org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:
34)
at
org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:
75)
at
org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:
45)
at
org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:
66)
at
org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:
35)
at org.junit.internal.runners.TestClassRunner
$1.runUnprotected(TestClassRunner.java:42)
at
org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:
34)
at
org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:
52)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:
38)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:
38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
460)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
673)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:
386)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:
196)
Am I going about this the wrong way?
Thanks,
Tim
The javadoc for that states:
http://java.sun.com/javase/6/docs/api/java/util/regex/Matcher.html#appendReplacement(java.lang.StringBuffer,%20java.lang.String)
Note that backslashes (\) and dollar signs ($) in the replacement
string may cause the results to be different than if it were being
treated as a literal replacement string. Dollar signs may be treated
as references to captured subsequences as described above, and
backslashes are used to escape literal characters in the replacement
string.
It can be fixed by manually tracking the lastAppendPosition and using
substring() to splice together the result.
Instead of
varMatcher.appendReplacement(sb, varValue);
do
sb.append(subjectOfReplacement.substring(lastAppendPosition,
varMatcher.start()));
sb.append(varValue);
lastAppendPosition = varMatcher.end();
and instead of
varMatcher.appendTail(sb);
do
sb.append(subjectOfReplacement.substring(lastAppendPosition,
subjectOfReplacement.length()));
where "lastAppendPosition" was declared outside of the matcher.find()
while loop.
Tim