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 * Determines the server's base using the incoming request
028 */
029public class IncomingRequestAddressStrategy implements IServerAddressStrategy {
030
031        private String myServletPath;
032
033        @Override
034        public String determineServerBase(ServletContext theServletContext, HttpServletRequest theRequest) {
035                if (theRequest == null) {
036                        return null;
037                }
038                String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
039
040                String servletPath;
041                if (myServletPath != null) {
042                        servletPath = myServletPath;
043                } else {
044                        servletPath = StringUtils.defaultString(theRequest.getServletPath());
045                }
046
047                StringBuffer requestUrl = theRequest.getRequestURL();
048                String servletContextPath = StringUtils.defaultString(theRequest.getContextPath());
049
050                String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length());
051                if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
052                        requestPath = requestPath.substring(1);
053                }
054
055                int startOfPath = requestUrl.indexOf("//");
056                int requestUrlLength = requestUrl.length();
057
058                if (startOfPath != -1 && (startOfPath + 2) < requestUrlLength) {
059                        startOfPath = requestUrl.indexOf("/", startOfPath + 2);
060                }
061                if (startOfPath == -1) {
062                        startOfPath = 0;
063                }
064
065                int contextIndex;
066                if (servletPath.length() == 0 || servletPath.equals("/")) {
067                        if (requestPath.length() == 0) {
068                                contextIndex = requestUrlLength;
069                        } else {
070                                contextIndex = requestUrl.indexOf(requestPath, startOfPath);
071                        }
072                } else {
073                        // servletContextPath can start with servletPath
074                        contextIndex = requestUrl.indexOf(servletPath + "/", startOfPath);
075                        if (contextIndex == -1) {
076                                contextIndex = requestUrl.indexOf(servletPath, startOfPath);
077                        }
078                }
079
080                String fhirServerBase;
081                int length = contextIndex + servletPath.length();
082                if (length > requestUrlLength) {
083                        length = requestUrlLength;
084                }
085                fhirServerBase = requestUrl.substring(0, length);
086                return fhirServerBase;
087        }
088
089        /**
090         * 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
091         * deployments where it isn't obvious to the servlet which part of the path is actually the root path to reach the servlet.
092         * <p>
093         * Example values could be:
094         * <ul>
095         * <li>null</li>
096         * <li>/</li>
097         * <li>/base</li>
098         * </ul>
099         * </p>
100         * <p>
101         * <b>Wildcards are not supported!</b>
102         * </p>
103         */
104        public void setServletPath(String theServletPath) {
105                myServletPath = theServletPath;
106        }
107}