package org.mapfish.print.processor.http; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.mapfish.print.attribute.HttpRequestHeadersAttribute; import org.mapfish.print.config.Configuration; import org.mapfish.print.http.MfClientHttpRequestFactory; import org.mapfish.print.processor.AbstractProcessor; import org.mapfish.print.processor.http.matcher.URIMatcher; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.Nullable; /** * <p>This processor forwards all the headers from the print request (from the Mapfish Print client) to each http request made for * the particular print job. All headers can be forwarded (if forwardAll is set to true) or the specific headers to forward * can be specified.</p> * <p>Example 1: Forward all headers from print request</p> * <pre><code> * - !forwardHeaders * all: true * </code></pre> * <p>Example 2: Forward specific headers (header1 and header2 will be forwarded)</p> * <pre><code> * - !forwardHeaders * headers: [header1, header2] * </code></pre> * * <p>Can be applied conditionally using matchers, like in {@link RestrictUrisProcessor} * (<a href="processors.html#!restrictUris">!restrictUris</a>).</p> * [[examples=http_processors,osm_custom_params]] */ public final class ForwardHeadersProcessor extends AbstractProcessor<ForwardHeadersProcessor.Param, Void> implements HttpProcessor<ForwardHeadersProcessor.Param> { private final AddHeadersProcessor addHeadersProcessor = new AddHeadersProcessor(); private Set<String> headerNames = Sets.newHashSet(); private boolean forwardAll = false; /** * Constructor. */ public ForwardHeadersProcessor() { super(Void.class); } /** * Set the header names to forward from the request. Should not be defined if all is set to true * * @param names the header names. */ public void setHeaders(final Set<String> names) { // transform to lower-case because header names should be case-insensitive Set<String> lowerCaseNames = new HashSet<String>(); for (String name : names) { lowerCaseNames.add(name.toLowerCase()); } this.headerNames = lowerCaseNames; } /** * The matchers used to select the urls that are going to be modified by the processor. * For example: * <pre><code> * - !restrictUris * matchers: * - !localMatch * dummy: true * - !ipMatch * ip: www.camptocamp.org * - !dnsMatch * host: mapfish-geoportal.demo-camptocamp.com * port: 80 * - !dnsMatch * host: labs.metacarta.com * port: 80 * - !dnsMatch * host: terraservice.net * port: 80 * - !dnsMatch * host: tile.openstreetmap.org * port: 80 * - !dnsMatch * host: www.geocat.ch * port: 80 * </code></pre> * * @param matchers the list of matcher to use to check if a url is permitted */ public void setMatchers(final List<? extends URIMatcher> matchers) { this.addHeadersProcessor.setMatchers(matchers); } /** * If set to true then all headers are forwarded. If this is true headers should be empty (or undefined) * * @param all if true forward all headers */ public void setAll(final boolean all) { this.forwardAll = all; } @Override protected void extraValidation(final List<Throwable> validationErrors, final Configuration configuration) { if (!this.forwardAll && this.headerNames.isEmpty()) { validationErrors.add(new IllegalStateException("all is false and no headers are defined")); } if (this.forwardAll && !this.headerNames.isEmpty()) { validationErrors.add(new IllegalStateException("all is true but headers is defined. Either all is true " + "OR headers is specified")); } } @Override public MfClientHttpRequestFactory createFactoryWrapper( final Param param, final MfClientHttpRequestFactory requestFactory) { Map<String, Object> headers = Maps.newHashMap(); for (Map.Entry<String, List<String>> entry : param.requestHeaders.getHeaders().entrySet()) { if (ForwardHeadersProcessor.this.forwardAll || ForwardHeadersProcessor.this.headerNames.contains(entry.getKey().toLowerCase())) { headers.put(entry.getKey(), entry.getValue()); } } this.addHeadersProcessor.setHeaders(headers); return this.addHeadersProcessor.createFactoryWrapper(param, requestFactory); } @Nullable @Override public Param createInputParameter() { return new Param(); } @Nullable @Override public Void execute(final Param values, final ExecutionContext context) throws Exception { values.clientHttpRequestFactoryProvider.set( createFactoryWrapper(values, values.clientHttpRequestFactoryProvider.get())); return null; } /** * The parameters required by this processor. */ public static class Param extends ClientHttpFactoryProcessorParam { /** * The http headers from the print request. */ public HttpRequestHeadersAttribute.Value requestHeaders; } }