...
There is no any changes on public interfaces. We just add define a new configuration property "response.http.headers"prefix "filter.name.<name>.", then followed by a set of properties which define rules for header. The following section has detailed description on this new propertydescription.
Proposed Changes
Adding New PropertyProperties
We will add a new property "response.http.headers" set of new properties in org.apache.kafka.connect.runtime.WorkerConfig class. It will allow REST server administrator to configure headers based on their security policies. We borrow and take advantage of Jetty HeaderFilter class and use same format of headerConfig, includedPaths, excludedPaths, includedMimeTypes, excludedMimeTypes, includedHttpMethods, excludedHttpMethods init parameters.
Description of Properties
header.config
init param. The format for response.http.headers will be "[[action] [header]:[header value],..." which is a list of [action] [header]:[value] separated by comma ",". So it is a CSV of actions to perform on headers with the following syntax:
[action] [header name]: [header value],
[action] can be one of "set, add, setDate, or addDate" which specify an action will perform on header.
...
[header name] specify name of header.
[header value] specify value for the header. We need put double quotes around the value if the value contains commas due to we use comma as separator for different headers.
Example:
header.config=set X-Frame-Options: DENY, "add Cache-Control: no-cache, no-store, must-revalidate", setDate Expires: 31540000000, addDate Last-Modified: 0
header.includedpaths
It is optional. it is a comma separated values of included path specs applied to headers.config. See path spec rules section.
Example:
header.includedpaths=^/test/0$
header.excludedaths
It is optional. it is a comma separated values of excluded path specs applied to headers.config. See path spec rules section.
Example:
header.excludedpaths=^/test/0$
header.includedmimetypes
It is optional. it is a comma separated values of included mime types applied to headers.config.
Example:
header.includedmimetypes=application/json
header.excludedmimetypes
It is optional. it is a comma separated values of excluded mime types applied to headers.config.
Example:
header.excludedmimetypes=application/xml
header.includedhttpmethods
It is optional. it is a comma separated values of included http methods applied to headers.config.
Example:
header.includedhttpmethods=POST,PUT
header.excludedhttpmethods
It is optional. it is a comma separated values of excluded http methods applied to headers.config.
Example:
header.excludedhttpmethods=GET
Path Spec Rules:
- If the spec starts with
^
, the spec is assumed to be a regex based path spec and will match with normal Java regex rules. - If the spec starts with
/
, the spec is assumed to be a Servlet url-pattern rules path spec for either an exact match or prefix based match. - If the spec starts with
*.
, the spec is assumed to be a Servlet url-pattern rules path spec for a suffix based match. - All other syntaxes are unsupported.
Multiple Headers Configuration
We use Jetty HeaderFilter to implement HTTP response header configuration. We need support multiple rules applied to multiple different response headers.
We define a prefix filter.name.<name>. to allow multiple configurations, so that different paths have different headers.
Example:
filter.name.header1.header.config of configuration for response.http.headersresponse.http.headers=set X-Frame-Options: DENY, "add Cache-Control: no-cache, no-store, must-revalidate", setDate Expires: 31540000000, addDate Last-Modified: 0
filter.name.header1.header.includedpaths=^/test/0$
filter.name.header1.header.excludedpaths=^/test1/0$
filter.name.header1.header.includedmimetypes=application/jsonheader
filter.name.header1.header.excludedmimetypes=application/xml
filter.name.header1.header.includedhttpmethods=POST,PUT
filter.name.header1.header.excludedhttpmethods=GET
Implementation
Implementation will use Jetty HeaderFilter class. We need update org.apache.kafka.connect.runtime.rest.RestServer class. During initializing process Connect REST server will read all header configuration configurations from the property responsewith prefix filter.httpname.headers, then create a list of FilterHoder with HeaderFilter class and add the list of filter holder holders to Servlet context handler based on name of filter. Implementation is similar as we handle header access.control.allow.origin in Connect REST server.
...
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
Map<String, String> headerFilterConfigs = extractHeaderFilterConfig(workerConfig);
for (String name : headerFilterConfigs.getkeySet()) {
String filterName = extract
String responseHeaders = config.getString("response.http.headers");
FilterHolder headersFilterHolder = new FilterHolder(HeaderFilter.class);
headersFilterHolder.setName("headerConfig");
headersFilterHolder.setInitParameter("headerConfig", responseHeaders);
context.addFilter(headersFilterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
References
...