
001package ca.uhn.fhir.rest.server; 002 003/* 004 * #%L 005 * HAPI FHIR - Server Framework 006 * %% 007 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 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 if (theRequest == null) { 038 return null; 039 } 040 String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI()); 041 042 String servletPath; 043 if (myServletPath != null) { 044 servletPath = myServletPath; 045 } else { 046 servletPath = StringUtils.defaultString(theRequest.getServletPath()); 047 } 048 049 StringBuffer requestUrl = theRequest.getRequestURL(); 050 String servletContextPath = StringUtils.defaultString(theRequest.getContextPath()); 051 052 String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length()); 053 if (requestPath.length() > 0 && requestPath.charAt(0) == '/') { 054 requestPath = requestPath.substring(1); 055 } 056 057 int startOfPath = requestUrl.indexOf("//"); 058 int requestUrlLength = requestUrl.length(); 059 060 if (startOfPath != -1 && (startOfPath + 2) < requestUrlLength) { 061 startOfPath = requestUrl.indexOf("/", startOfPath + 2); 062 } 063 if (startOfPath == -1) { 064 startOfPath = 0; 065 } 066 067 int contextIndex; 068 if (servletPath.length() == 0 || servletPath.equals("/")) { 069 if (requestPath.length() == 0) { 070 contextIndex = requestUrlLength; 071 } else { 072 contextIndex = requestUrl.indexOf(requestPath, startOfPath); 073 } 074 } else { 075 //servletContextPath can start with servletPath 076 contextIndex = requestUrl.indexOf(servletPath + "/", startOfPath); 077 if (contextIndex == -1) { 078 contextIndex = requestUrl.indexOf(servletPath, startOfPath); 079 } 080 } 081 082 String fhirServerBase; 083 int length = contextIndex + servletPath.length(); 084 if (length > requestUrlLength) { 085 length = requestUrlLength; 086 } 087 fhirServerBase = requestUrl.substring(0, length); 088 return fhirServerBase; 089 } 090 091 /** 092 * 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 093 * deployments where it isn't obvious to the servlet which part of the path is actually the root path to reach the servlet. 094 * <p> 095 * Example values could be: 096 * <ul> 097 * <li>null</li> 098 * <li>/</li> 099 * <li>/base</li> 100 * </ul> 101 * </p> 102 * <p> 103 * <b>Wildcards are not supported!</b> 104 * </p> 105 */ 106 public void setServletPath(String theServletPath) { 107 myServletPath = theServletPath; 108 } 109 110 /** 111 * Determines the servlet's context path. 112 * 113 * This is here to try and deal with the wide variation in servers and what they return. 114 * 115 * 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 116 * 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. 117 * 118 * 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 119 * 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 120 * behavour across a wide variety of platforms. 121 * 122 * 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. 123 */ 124 public static String determineServletContextPath(HttpServletRequest theRequest, RestfulServer server) { 125 String retVal; 126 if (server.getServletContext() != null) { 127 if (server.getServletContext().getMajorVersion() >= 3 || (server.getServletContext().getMajorVersion() > 2 && server.getServletContext().getMinorVersion() >= 5)) { 128 retVal = server.getServletContext().getContextPath(); 129 } else { 130 retVal = theRequest.getContextPath(); 131 } 132 } else { 133 retVal = theRequest.getContextPath(); 134 } 135 retVal = StringUtils.defaultString(retVal); 136 return retVal; 137 } 138 139}