001/*-
002 * #%L
003 * HAPI FHIR - Client 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.client.interceptor;
021
022import ca.uhn.fhir.interceptor.api.Hook;
023import ca.uhn.fhir.interceptor.api.Pointcut;
024import ca.uhn.fhir.rest.client.api.IHttpRequest;
025
026import java.util.ArrayList;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030import java.util.Objects;
031
032/**
033 * This interceptor adds arbitrary header values to requests made by the client.
034 *
035 * This is now also possible directly on the Fluent Client API by calling
036 * {@link ca.uhn.fhir.rest.gclient.IClientExecutable#withAdditionalHeader(String, String)}
037 */
038public class AdditionalRequestHeadersInterceptor {
039        private final Map<String, List<String>> myAdditionalHttpHeaders;
040
041        /**
042         * Constructor
043         */
044        public AdditionalRequestHeadersInterceptor() {
045                myAdditionalHttpHeaders = new HashMap<>();
046        }
047
048        /**
049         * Constructor
050         *
051         * @param theHeaders The additional headers to add to every request
052         */
053        public AdditionalRequestHeadersInterceptor(Map<String, List<String>> theHeaders) {
054                this();
055                if (theHeaders != null) {
056                        myAdditionalHttpHeaders.putAll(theHeaders);
057                }
058        }
059
060        /**
061         * Adds the given header value.
062         * Note that {@code headerName} and {@code headerValue} cannot be null.
063         * @param headerName the name of the header
064         * @param headerValue the value to add for the header
065         * @throws NullPointerException if either parameter is {@code null}
066         */
067        public void addHeaderValue(String headerName, String headerValue) {
068                Objects.requireNonNull(headerName, "headerName cannot be null");
069                Objects.requireNonNull(headerValue, "headerValue cannot be null");
070
071                getHeaderValues(headerName).add(headerValue);
072        }
073
074        /**
075         * Adds the list of header values for the given header.
076         * Note that {@code headerName} and {@code headerValues} cannot be null.
077         * @param headerName the name of the header
078         * @param headerValues the list of values to add for the header
079         * @throws NullPointerException if either parameter is {@code null}
080         */
081        public void addAllHeaderValues(String headerName, List<String> headerValues) {
082                Objects.requireNonNull(headerName, "headerName cannot be null");
083                Objects.requireNonNull(headerValues, "headerValues cannot be null");
084
085                getHeaderValues(headerName).addAll(headerValues);
086        }
087
088        /**
089         * Gets the header values list for a given header.
090         * If the header doesn't have any values, an empty list will be returned.
091         * @param headerName the name of the header
092         * @return the list of values for the header
093         */
094        private List<String> getHeaderValues(String headerName) {
095                if (myAdditionalHttpHeaders.get(headerName) == null) {
096                        myAdditionalHttpHeaders.put(headerName, new ArrayList<>());
097                }
098                return myAdditionalHttpHeaders.get(headerName);
099        }
100
101        /**
102         * Adds the additional header values to the HTTP request.
103         * @param theRequest the HTTP request
104         */
105        @Hook(Pointcut.CLIENT_REQUEST)
106        public void interceptRequest(IHttpRequest theRequest) {
107                for (Map.Entry<String, List<String>> header : myAdditionalHttpHeaders.entrySet()) {
108                        for (String headerValue : header.getValue()) {
109                                if (headerValue != null) {
110                                        theRequest.addHeader(header.getKey(), headerValue);
111                                }
112                        }
113                }
114        }
115}