diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-11-16 11:19:22 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-11-17 13:28:07 +0100 |
commit | cdbf498c9182ac06bb21ce8ae7b745dd8c8f3c83 (patch) | |
tree | 21a21f94ef0d888d74597b6142956c1b41901b13 /container-disc | |
parent | e4c14623ad4ecbe6337a49d2176621c528bf7c22 (diff) |
Support default request/response filters per connector
Filter requests using default request/response filter if no other filters matches the request uri.
Diffstat (limited to 'container-disc')
-rw-r--r-- | container-disc/src/main/java/com/yahoo/container/jdisc/FilterBindingsProvider.java | 98 | ||||
-rw-r--r-- | container-disc/src/main/java/com/yahoo/container/jdisc/FilterUtil.java | 99 |
2 files changed, 84 insertions, 113 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/FilterBindingsProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/FilterBindingsProvider.java index 195aee93246..6527a368113 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/FilterBindingsProvider.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/FilterBindingsProvider.java @@ -1,16 +1,21 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc; +import com.google.inject.Inject; import com.yahoo.component.ComponentId; +import com.yahoo.component.ComponentSpecification; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.di.componentgraph.Provider; import com.yahoo.container.http.filter.FilterChainRepository; import com.yahoo.jdisc.http.ServerConfig; +import com.yahoo.jdisc.http.filter.RequestFilter; +import com.yahoo.jdisc.http.filter.ResponseFilter; import com.yahoo.jdisc.http.filter.SecurityRequestFilter; +import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; import com.yahoo.jdisc.http.server.jetty.FilterBindings; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; +import java.util.Set; /** * Provides filter bindings based on vespa config. @@ -20,35 +25,100 @@ import java.util.List; */ public class FilterBindingsProvider implements Provider<FilterBindings> { + private static final ComponentId SEARCH_SERVER_COMPONENT_ID = ComponentId.fromString("SearchServer"); + private final FilterBindings filterBindings; + @Inject public FilterBindingsProvider(ComponentId componentId, ServerConfig config, FilterChainRepository filterChainRepository, ComponentRegistry<SecurityRequestFilter> legacyRequestFilters) { try { - this.filterBindings = FilterUtil.setupFilters( - componentId, - legacyRequestFilters, - toFilterSpecs(config.filter()), - filterChainRepository); + FilterBindings.Builder builder = new FilterBindings.Builder(); + configureLegacyFilters(builder, componentId, legacyRequestFilters); + configureFilters(builder, config, filterChainRepository); + this.filterBindings = builder.build(); } catch (Exception e) { throw new RuntimeException( "Invalid config for http server '" + componentId.getNamespace() + "': " + e.getMessage(), e); } } - private List<FilterUtil.FilterSpec> toFilterSpecs(List<ServerConfig.Filter> inFilters) { - List<FilterUtil.FilterSpec> outFilters = new ArrayList<>(); - for (ServerConfig.Filter inFilter : inFilters) { - outFilters.add(new FilterUtil.FilterSpec(inFilter.id(), inFilter.binding())); + // TODO(gjoranv): remove + private static void configureLegacyFilters( + FilterBindings.Builder builder, + ComponentId id, + ComponentRegistry<SecurityRequestFilter> legacyRequestFilters) { + ComponentId serverName = id.getNamespace(); + if (SEARCH_SERVER_COMPONENT_ID.equals(serverName) && !legacyRequestFilters.allComponents().isEmpty()) { + String filterId = "legacy-filters"; + builder.addRequestFilter(filterId, SecurityRequestFilterChain.newInstance(legacyRequestFilters.allComponents())); + builder.addRequestFilterBinding(filterId, "http://*/*"); + } + } + + private static void configureFilters( + FilterBindings.Builder builder, ServerConfig config, FilterChainRepository filterRepository) { + addFilterInstances(builder, config, filterRepository); + addFilterBindings(builder, config, filterRepository); + addPortDefaultFilters(builder, config, filterRepository); + } + + private static void addFilterInstances( + FilterBindings.Builder builder, ServerConfig config, FilterChainRepository filterRepository) { + Set<String> filterIds = new HashSet<>(); + config.filter().forEach(filterBinding -> filterIds.add(filterBinding.id())); + config.defaultFilters().forEach(defaultFilter -> filterIds.add(defaultFilter.filterId())); + for (String filterId : filterIds) { + Object filterInstance = getFilterInstance(filterRepository, filterId); + if (filterInstance instanceof RequestFilter && filterInstance instanceof ResponseFilter) { + throw new IllegalArgumentException("The filter " + filterInstance.getClass().getName() + + " is unsupported since it's both a RequestFilter and a ResponseFilter."); + } else if (filterInstance instanceof RequestFilter) { + builder.addRequestFilter(filterId, (RequestFilter)filterInstance); + } else if (filterInstance instanceof ResponseFilter) { + builder.addResponseFilter(filterId, (ResponseFilter)filterInstance); + } else if (filterInstance == null) { + throw new IllegalArgumentException("No http filter with id " + filterId); + } else { + throw new IllegalArgumentException("Unknown filter type: " + filterInstance.getClass().getName()); + } + } + } + + private static void addFilterBindings( + FilterBindings.Builder builder, ServerConfig config, FilterChainRepository filterRepository) { + for (ServerConfig.Filter filterBinding : config.filter()) { + if (isRequestFilter(filterRepository, filterBinding.id())) { + builder.addRequestFilterBinding(filterBinding.id(), filterBinding.binding()); + } else { + builder.addResponseFilterBinding(filterBinding.id(), filterBinding.binding()); + } + } + } + + private static void addPortDefaultFilters( + FilterBindings.Builder builder, ServerConfig config, FilterChainRepository filterRepository) { + for (ServerConfig.DefaultFilters defaultFilter : config.defaultFilters()) { + if (isRequestFilter(filterRepository, defaultFilter.filterId())) { + builder.setRequestFilterDefaultForPort(defaultFilter.filterId(), defaultFilter.localPort()); + } else { + builder.setResponseFilterDefaultForPort(defaultFilter.filterId(), defaultFilter.localPort()); + } } - return outFilters; + } + + private static boolean isRequestFilter(FilterChainRepository filterRepository, String filterId) { + return getFilterInstance(filterRepository, filterId) instanceof RequestFilter; + } + + private static Object getFilterInstance(FilterChainRepository filterRepository, String filterId) { + return filterRepository.getFilter(ComponentSpecification.fromString(filterId)); } @Override public FilterBindings get() { return filterBindings; } - @Override - public void deconstruct() {} + @Override public void deconstruct() {} } diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/FilterUtil.java b/container-disc/src/main/java/com/yahoo/container/jdisc/FilterUtil.java deleted file mode 100644 index 52829d6710e..00000000000 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/FilterUtil.java +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.container.jdisc; - -import com.yahoo.component.ComponentId; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.component.provider.ComponentRegistry; -import com.yahoo.container.http.filter.FilterChainRepository; -import com.yahoo.jdisc.http.filter.RequestFilter; -import com.yahoo.jdisc.http.filter.ResponseFilter; -import com.yahoo.jdisc.http.filter.SecurityRequestFilter; -import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; -import com.yahoo.jdisc.http.server.jetty.FilterBindings; - -import java.util.List; - -/** - * Helper class to set up filter binding repositories based on config. - * - * @author Øyvind Bakksjø - * @author bjorncs - */ -class FilterUtil { - - private static final ComponentId SEARCH_SERVER_COMPONENT_ID = ComponentId.fromString("SearchServer"); - - private final FilterBindings.Builder builder = new FilterBindings.Builder(); - - private FilterUtil() {} - - private void configureFilters(List<FilterSpec> filtersConfig, FilterChainRepository filterChainRepository) { - for (FilterSpec filterConfig : filtersConfig) { - Object filter = filterChainRepository.getFilter(ComponentSpecification.fromString(filterConfig.getId())); - if (filter == null) { - throw new RuntimeException("No http filter with id " + filterConfig.getId()); - } - addFilter(filter, filterConfig.getBinding(), filterConfig.getId()); - } - } - - private void addFilter(Object filter, String binding, String filterId) { - if (filter instanceof RequestFilter && filter instanceof ResponseFilter) { - throw new RuntimeException("The filter " + filter.getClass().getName() + - " is unsupported since it's both a RequestFilter and a ResponseFilter."); - } else if (filter instanceof RequestFilter) { - builder.addRequestFilter(filterId, binding, (RequestFilter) filter); - } else if (filter instanceof ResponseFilter) { - builder.addResponseFilter(filterId, binding, (ResponseFilter) filter); - } else { - throw new RuntimeException("Unknown filter type " + filter.getClass().getName()); - } - } - - // TODO(gjoranv): remove - private void configureLegacyFilters(ComponentId id, ComponentRegistry<SecurityRequestFilter> legacyRequestFilters) { - ComponentId serverName = id.getNamespace(); - if (SEARCH_SERVER_COMPONENT_ID.equals(serverName) && !legacyRequestFilters.allComponents().isEmpty()) { - builder.addRequestFilter( - "legacy-filters", "http://*/*", SecurityRequestFilterChain.newInstance(legacyRequestFilters.allComponents())); - } - } - - /** - * Populates binding repositories with filters based on config. - */ - public static FilterBindings setupFilters( - ComponentId componentId, - ComponentRegistry<SecurityRequestFilter> legacyRequestFilters, - List<FilterSpec> filtersConfig, - FilterChainRepository filterChainRepository) { - FilterUtil filterUtil = new FilterUtil(); - - // TODO(gjoranv): remove - filterUtil.configureLegacyFilters(componentId, legacyRequestFilters); - - filterUtil.configureFilters(filtersConfig, filterChainRepository); - - return filterUtil.builder.build(); - } - - public static class FilterSpec { - - private final String id; - private final String binding; - - public FilterSpec(String id, String binding) { - this.id = id; - this.binding = binding; - } - - public String getId() { - return id; - } - - public String getBinding() { - return binding; - } - } - -} |