001/*
002 * #%L
003 * HAPI FHIR - Server Framework
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.rest.server;
021
022import jakarta.servlet.ServletContext;
023import jakarta.servlet.http.HttpServletRequest;
024import org.apache.commons.lang3.StringUtils;
025
026/**
027 * Provides the server base for a given incoming request. This can be used to account for
028 * multi-homed servers or other unusual network configurations.
029 */
030public interface IServerAddressStrategy {
031
032        /**
033         * Determine the server base for a given request
034         */
035        String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest);
036
037        /**
038         * Determines the servlet's context path.
039         *
040         * This is here to try and deal with the wide variation in servers and what they return.
041         *
042         * 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
043         * 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.
044         *
045         * 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
046         * 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
047         * behaviour across a wide variety of platforms.
048         *
049         * 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.
050         */
051        default String determineServletContextPath(HttpServletRequest theRequest, RestfulServer server) {
052                String retVal;
053                if (server.getServletContext() != null) {
054                        if (server.getServletContext().getMajorVersion() >= 3
055                                        || (server.getServletContext().getMajorVersion() > 2
056                                                        && server.getServletContext().getMinorVersion() >= 5)) {
057                                retVal = server.getServletContext().getContextPath();
058                        } else {
059                                retVal = theRequest.getContextPath();
060                        }
061                } else {
062                        retVal = theRequest.getContextPath();
063                }
064                retVal = StringUtils.defaultString(retVal);
065                return retVal;
066        }
067}