Extract path info from requests without decoding

The fix for Guice issue #745[1] causes getPathInfo() within the
GuiceFilter to return decoded values, eliminating the difference
between "foo/bar" and "foo%2Fbar". This is in spec with the servlet
standard, whose javadoc for getPathInfo[2] states that the return
value be "decoded by the web container".

Work around this by extracting the path part directly from the request
URI, which is unmodified by the container. This is copying the Guice
behavior prior to the bugfix. We do this with a static method rather
than using our own HttpServletRequestWrapper as we don't want to
produce a request wrapper that is not in spec.

[1] https://github.com/google/guice/issues/745
[2] http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#getPathInfo()

Change-Id: I48fb32710d45f573fb167c6344ad76541672858c
This commit is contained in:
Dave Borowitz
2014-10-16 14:51:22 -07:00
parent 835c3f9510
commit c5e42048d3
4 changed files with 144 additions and 3 deletions

View File

@@ -0,0 +1,91 @@
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.httpd;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
public class RequestUtilTest {
private List<Object> mocks;
@Before
public void setUp() {
mocks = Collections.synchronizedList(new ArrayList<>());
}
@After
public void tearDown() {
for (Object mock : mocks) {
verify(mock);
}
}
@Test
public void emptyContextPath() {
assertEquals("/foo/bar", RequestUtil.getEncodedPathInfo(
mockRequest("/s/foo/bar", "", "/s")));
assertEquals("/foo%2Fbar", RequestUtil.getEncodedPathInfo(
mockRequest("/s/foo%2Fbar", "", "/s")));
}
@Test
public void emptyServletPath() {
assertEquals("/foo/bar", RequestUtil.getEncodedPathInfo(
mockRequest("/c/foo/bar", "/c", "")));
assertEquals("/foo%2Fbar", RequestUtil.getEncodedPathInfo(
mockRequest("/c/foo%2Fbar", "/c", "")));
}
@Test
public void trailingSlashes() {
assertEquals("/foo/bar/", RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo/bar/", "/c", "/s")));
assertEquals("/foo/bar/", RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo/bar///", "/c", "/s")));
assertEquals("/foo%2Fbar/", RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo%2Fbar/", "/c", "/s")));
assertEquals("/foo%2Fbar/", RequestUtil.getEncodedPathInfo(
mockRequest("/c/s/foo%2Fbar///", "/c", "/s")));
}
@Test
public void servletPathMatchesRequestPath() {
assertEquals(null, RequestUtil.getEncodedPathInfo(
mockRequest("/c/s", "/c", "/s")));
}
private HttpServletRequest mockRequest(String uri, String contextPath, String servletPath) {
HttpServletRequest req = createMock(HttpServletRequest.class);
expect(req.getRequestURI()).andStubReturn(uri);
expect(req.getContextPath()).andStubReturn(contextPath);
expect(req.getServletPath()).andStubReturn(servletPath);
replay(req);
mocks.add(req);
return req;
}
}