Use HttpServletRequest.getContextPath to get the context path
This commit is contained in:
parent
e9061ef975
commit
75798cf9fe
|
@ -23,7 +23,7 @@
|
|||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<artifactId>jetty</artifactId>
|
||||
<version>6.1.26</version>
|
||||
<version>6.1.26</version> <!-- 6.1.26 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
@ -35,21 +35,16 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
|
|||
@Override
|
||||
public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
|
||||
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
|
||||
|
||||
|
||||
String servletPath;
|
||||
if (myServletPath != null) {
|
||||
servletPath = myServletPath;
|
||||
} else {
|
||||
servletPath = StringUtils.defaultString(theRequest.getServletPath());
|
||||
}
|
||||
|
||||
|
||||
StringBuffer requestUrl = theRequest.getRequestURL();
|
||||
String servletContextPath = "";
|
||||
if (theServletContext != null) {
|
||||
servletContextPath = StringUtils.defaultString(theServletContext.getContextPath());
|
||||
// } else {
|
||||
// servletContextPath = servletPath;
|
||||
}
|
||||
String servletContextPath = StringUtils.defaultString(theRequest.getContextPath());
|
||||
|
||||
String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length());
|
||||
if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
|
||||
|
@ -105,4 +100,33 @@ public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
|
|||
myServletPath = theServletPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the servlet's context path.
|
||||
*
|
||||
* This is here to try and deal with the wide variation in servers and what they return.
|
||||
*
|
||||
* getServletContext().getContextPath() is supposed to return the path to the specific servlet we are deployed as but it's not available everywhere. On some servers getServletContext() can return
|
||||
* null (old Jetty seems to suffer from this, see hapi-fhir-base-test-mindeps-server) and on other old servers (Servlet 2.4) getServletContext().getContextPath() doesn't even exist.
|
||||
*
|
||||
* theRequest.getContextPath() returns the context for the specific incoming request. It should be available everywhere, but it's likely to be less predicable if there are multiple servlet mappings
|
||||
* pointing to the same servlet, so we don't favour it. This is possibly not the best strategy (maybe we should just always use theRequest.getContextPath()?) but so far people seem happy with this
|
||||
* behavour across a wide variety of platforms.
|
||||
*
|
||||
* If you are having troubles on a given platform/configuration and want to suggest a change or even report incompatibility here, we'd love to hear about it.
|
||||
*/
|
||||
public static String determineServletContextPath(HttpServletRequest theRequest, RestfulServer server) {
|
||||
String retVal;
|
||||
if (server.getServletContext() != null) {
|
||||
if (server.getServletContext().getMajorVersion() >= 3 || (server.getServletContext().getMajorVersion() > 2 && server.getServletContext().getMinorVersion() >= 5)) {
|
||||
retVal = server.getServletContext().getContextPath();
|
||||
} else {
|
||||
retVal = theRequest.getContextPath();
|
||||
}
|
||||
} else {
|
||||
retVal = theRequest.getContextPath();
|
||||
}
|
||||
retVal = StringUtils.defaultString(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -525,15 +525,11 @@ public class RestfulServer extends HttpServlet {
|
|||
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
|
||||
String servletPath = StringUtils.defaultString(theRequest.getServletPath());
|
||||
StringBuffer requestUrl = theRequest.getRequestURL();
|
||||
String servletContextPath = "";
|
||||
|
||||
// if (getServletContext().getMajorVersion() >= 3) {
|
||||
// // getServletContext is only supported in version 3+ of servlet-api
|
||||
if (getServletContext() != null) {
|
||||
servletContextPath = StringUtils.defaultString(getServletContext().getContextPath());
|
||||
}
|
||||
// }
|
||||
String servletContextPath = IncomingRequestAddressStrategy.determineServletContextPath(theRequest, this);
|
||||
|
||||
/*
|
||||
* Just for debugging..
|
||||
*/
|
||||
if (ourLog.isTraceEnabled()) {
|
||||
ourLog.trace("Request FullPath: {}", requestFullPath);
|
||||
ourLog.trace("Servlet Path: {}", servletPath);
|
||||
|
@ -752,6 +748,7 @@ public class RestfulServer extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations,
|
||||
* but subclasses may put initialization code in {@link #initialize()}, which is called immediately before beginning
|
||||
|
@ -842,6 +839,7 @@ public class RestfulServer extends HttpServlet {
|
|||
* (which extends {@link ServletException}), as this is a flag to the servlet container that the servlet
|
||||
* is not usable.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected void initialize() throws ServletException {
|
||||
// nothing by default
|
||||
}
|
||||
|
|
|
@ -220,6 +220,8 @@ public class IncomingRequestAddressStrategyTest {
|
|||
|
||||
private static class MyServlet extends HttpServlet {
|
||||
|
||||
private static final long serialVersionUID = -8903322104434705422L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException {
|
||||
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.util.RandomServerPortProvider;
|
||||
|
||||
public class ServletContextParsingTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static IdDt ourLastId;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServletContextParsingTest.class);
|
||||
|
||||
private Server myServer;
|
||||
|
||||
public void after() throws Exception {
|
||||
if (myServer != null) {
|
||||
myServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastId = null;
|
||||
}
|
||||
|
||||
private void httpGet(String url) throws IOException, ClientProtocolException {
|
||||
ourLastId = null;
|
||||
|
||||
HttpGet httpget = new HttpGet(url);
|
||||
HttpResponse status = ourClient.execute(httpget);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
}
|
||||
|
||||
private void startServer(int port, String contextPath, String servletPath) throws Exception {
|
||||
myServer = new Server(port);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath(contextPath);
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setServlet(new MyServlet());
|
||||
proxyHandler.addServlet(handler, servletPath);
|
||||
|
||||
myServer.setHandler(proxyHandler);
|
||||
myServer.start();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnderJettyWithContextPathServletRoot() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
|
||||
String contextPath = "/ctx";
|
||||
String servletPath = "/*";
|
||||
|
||||
startServer(port, contextPath, servletPath);
|
||||
|
||||
httpGet("http://localhost:" + port + "/ctx/Patient/123/_history/234?_pretty=true");
|
||||
assertEquals("Patient/123/_history/234", ourLastId.getValue());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUnderJettyWithContextPathServletRoot2() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
|
||||
String contextPath = "/ctx";
|
||||
String servletPath = "/foo/bar/*"; // not /* but still this should work
|
||||
|
||||
startServer(port, contextPath, servletPath);
|
||||
|
||||
httpGet("http://localhost:" + port + "/ctx/foo/bar/Patient/123/_history/222");
|
||||
assertEquals("Patient/123/_history/222", ourLastId.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnderJettyWithContextPathServletPath() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
|
||||
String contextPath = "/ctx";
|
||||
String servletPath = "/servlet/*";
|
||||
|
||||
startServer(port, contextPath, servletPath);
|
||||
|
||||
httpGet("http://localhost:" + port + "/ctx/servlet/Patient/123/_history/222");
|
||||
assertEquals("Patient/123/_history/222", ourLastId.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnderJettyWithMultiplePaths() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
|
||||
myServer = new Server(port);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath("/ctx");
|
||||
|
||||
proxyHandler.addServlet(new ServletHolder(new MyServlet()), "/servlet/*");
|
||||
proxyHandler.addServlet(new ServletHolder(new MyServlet()), "/foo/bar/*");
|
||||
|
||||
myServer.setHandler(proxyHandler);
|
||||
myServer.start();
|
||||
|
||||
httpGet("http://localhost:" + port + "/ctx/servlet/Patient/123/_history/222");
|
||||
assertEquals("Patient/123/_history/222", ourLastId.getValue());
|
||||
|
||||
httpGet("http://localhost:" + port + "/ctx/foo/bar/Patient/123/_history/222");
|
||||
assertEquals("Patient/123/_history/222", ourLastId.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnderJettyWithContextRootServletRoot() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
|
||||
String contextPath = "/";
|
||||
String servletPath = "/*";
|
||||
|
||||
startServer(port, contextPath, servletPath);
|
||||
|
||||
httpGet("http://localhost:" + port + "/Patient/123/_history/222");
|
||||
assertEquals("Patient/123/_history/222", ourLastId.getValue());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
}
|
||||
|
||||
private static class MyServlet extends RestfulServer {
|
||||
|
||||
private static final long serialVersionUID = -8903322104434705422L;
|
||||
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
setResourceProviders(new MyPatientProvider());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MyPatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read(version=true)
|
||||
public Patient read(@IdParam IdDt theId) {
|
||||
ourLastId = theId;
|
||||
Patient retVal = new Patient();
|
||||
retVal.setId(theId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>restful-server-example</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -53,6 +53,12 @@
|
|||
Resources and datatypes are now serializable. This is an
|
||||
experimental feature which hasn't yet been extensively tested. Please test and give us your feedback!
|
||||
</action>
|
||||
<action type="add">
|
||||
Switch REST server to using HttpServletRequest#getContextPath() to get
|
||||
the servlet's context path. This means that the server should behave more
|
||||
predictably, and should work in servlet 2.4 environments. Thanks to
|
||||
Ken Zeisset for the suggestion!
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.1" date="2015-07-13">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue