001package ca.uhn.fhir.rest.server; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2016 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import javax.servlet.ServletContext; 024import javax.servlet.http.HttpServletRequest; 025 026import org.apache.commons.lang3.StringUtils; 027 028/** 029 * Determines the server's base using the incoming request 030 */ 031public class IncomingRequestAddressStrategy implements IServerAddressStrategy { 032 033 private String myServletPath; 034 035 @Override 036 public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) { 037 String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI()); 038 039 String servletPath; 040 if (myServletPath != null) { 041 servletPath = myServletPath; 042 } else { 043 servletPath = StringUtils.defaultString(theRequest.getServletPath()); 044 } 045 046 StringBuffer requestUrl = theRequest.getRequestURL(); 047 String servletContextPath = StringUtils.defaultString(theRequest.getContextPath()); 048 049 String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length()); 050 if (requestPath.length() > 0 && requestPath.charAt(0) == '/') { 051 requestPath = requestPath.substring(1); 052 } 053 054 int startOfPath = requestUrl.indexOf("//"); 055 int requestUrlLength = requestUrl.length(); 056 057 if (startOfPath != -1 && (startOfPath + 2) < requestUrlLength) { 058 startOfPath = requestUrl.indexOf("/", startOfPath + 2); 059 } 060 if (startOfPath == -1) { 061 startOfPath = 0; 062 } 063 064 int contextIndex; 065 if (servletPath.length() == 0 || servletPath.equals("/")) { 066 if (requestPath.length() == 0) { 067 contextIndex = requestUrlLength; 068 } else { 069 contextIndex = requestUrl.indexOf(requestPath, startOfPath); 070 } 071 } else { 072 //servletContextPath can start with servletPath 073 contextIndex = requestUrl.indexOf(servletPath + "/", startOfPath); 074 if (contextIndex == -1) { 075 contextIndex = requestUrl.indexOf(servletPath, startOfPath); 076 } 077 } 078 079 String fhirServerBase; 080 int length = contextIndex + servletPath.length(); 081 if (length > requestUrlLength) { 082 length = requestUrlLength; 083 } 084 fhirServerBase = requestUrl.substring(0, length); 085 return fhirServerBase; 086 } 087 088 /** 089 * If set to a non-null value (default is <code>null</code>), this address strategy assumes that the FHIR endpoint is deployed to the given servlet path within the context. This is useful in some 090 * deployments where it isn't obvious to the servlet which part of the path is actually the root path to reach the servlet. 091 * <p> 092 * Example values could be: 093 * <ul> 094 * <li>null</li> 095 * <li>/</li> 096 * <li>/base</li> 097 * </ul> 098 * </p> 099 * <p> 100 * <b>Wildcards are not supported!</b> 101 * </p> 102 */ 103 public void setServletPath(String theServletPath) { 104 myServletPath = theServletPath; 105 } 106 107 /** 108 * Determines the servlet's context path. 109 * 110 * This is here to try and deal with the wide variation in servers and what they return. 111 * 112 * 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 113 * 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. 114 * 115 * 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 116 * 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 117 * behavour across a wide variety of platforms. 118 * 119 * 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. 120 */ 121 public static String determineServletContextPath(HttpServletRequest theRequest, RestfulServer server) { 122 String retVal; 123 if (server.getServletContext() != null) { 124 if (server.getServletContext().getMajorVersion() >= 3 || (server.getServletContext().getMajorVersion() > 2 && server.getServletContext().getMinorVersion() >= 5)) { 125 retVal = server.getServletContext().getContextPath(); 126 } else { 127 retVal = theRequest.getContextPath(); 128 } 129 } else { 130 retVal = theRequest.getContextPath(); 131 } 132 retVal = StringUtils.defaultString(retVal); 133 return retVal; 134 } 135 136}