...
Property Name | Type | Default | Importance | Description | Example for Value |
---|---|---|---|---|---|
response.http.headers | stringLIST | "" | medium | Defines names of headers which will be separated by comma. The name could be any string which uniquely identify header. | default, header1connector1, header2connector2 |
response.http.headers.{name}.header.config | stringSTRING | "" | low | Define a set of HTTP headers for header defined by {name} which will be one of names defined in property response.http.headers. Detailed explanation see See Detailed Explanation section for this property due to the format is more complex. | set X-Frame-Options: DENY, "add Cache-Control: no-cache, no-store, must-revalidate", setDate Expires: 31540000000, addDate Last-Modified: 0 |
response.http.headers.{name}. included.paths | stringSTRING | "" | low | It is a comma separated values of included path specs applied to HTTP headers. See path spec rules section. | /connectors/connector1/topics/* |
response.http.headers.{name}.excluded.paths | stringSTRING | "" | low | It is a comma separated values of excluded path specs applied to HTTP headers. See path spec rules section. | /connectors/connector1/status |
response.http.headers.{name}.included.mime.types | stringSTRING | "" | low | It is a comma separated values of included mime types applied to HTTP headers | application/json |
response.http.headers.{name}.excluded.mime.types | stringSTRING | "" | low | It is a comma separated values of excluded mime types applied to HTTP headers. | application/xml |
response.http.headers.{name}.included.http.methods | stringSTRING | "" | low | It is a comma separated values of included http methods applied to HTTP headers | POST,PUT |
response.http.headers.{name}.excluded.http.methods | stringSTRING | "" | low | It is a comma separated values of excluded http methods applied to HTTP headers | GET |
...
We use Jetty HeaderFilter to implement HTTP response header configuration. We need support multiple different rules applied to multiple different response headers based on different resources. For most usage cases, one header should be sufficient. But we do provide flexible configuration for multiple headers usages.
We define a prefix response.http.headers.<name>{name}. to allow configure multiple configurations , so that different paths have different headersfor different resources. The "<name>" will be the name of header and that will be used to uniquely identify the header config which could only apply to different Servlet path or HTTP methods. "{name}", for instance "connector1" in following example, will be used to uniquely identify a set of HTTP response headers applied to one resource under /connectors/connector1
Example:
Code Block |
---|
response.http.headers.defaultconnetor1.header.config=set X-Frame-Options: DENY, "add Cache-Control: no-cache, no-store, must-revalidate", setDate Expires: 31540000000, addDate Last-Modified: 0 response.http.headers.defaultconnetor1.header.included.paths=/connectors/connector1/topics/* response.http.headers.defaultconnetor1.excluded.paths=/connectors/connector1/status response.http.headers.defaultconnetor1.included.mime.types=application/json response.http.headers.defaultconnetor1.excluded.mime.types=application/xml response.http.headers.defaultconnetor1.included.http.methods=POST,PUT response.http.headers.defaultconnetor1.excluded.http.methods=GET response.http.headers.header1connetor2.header.config=set X-Frame-Options: DENY, "add Cache-Control: no-cache, no-store, must-revalidate", setDate Expires: 31540000000, addDate Last-Modified: 0 response.http.headers.header1connetor2.header.included.paths=^/connectors/test2connector2/0$* response.http.headers.header1connetor2.excluded.paths=^/connectors/test3connector2/0$ status response.http.headers.header1connetor2.included.mime.types=application/json response.http.headers.header1connetor2.excluded.mime.types=application/xml response.http.headers.header1connetor2.included.http.methods=POST,PUT response.http.headers.header1connetor2.excluded.http.methods=GET |
Implementation
Implementation will use the Jetty HeaderFilter
Jetty HeaderFilter class. We need to update orgupdate org.apache.kafka.connect.runtime.rest.RestServer class. During initialization the Connect REST server will read all header configurations from the property with During initialization process, the Connect REST server will check property response.http.headers. If the value of response.http.headers is not empty, then REST server will read all headers configurations from the property with prefix response.http.headers.{name}, then and create a list of FilterHolder with HeaderFilter
with HeaderFilter class and add the list of filter holders to the Servlet context handler based on the name of the filterthe header. Implementation is similar to how we handle the header accessheader access.control.allow.origin in the Connect REST server.
Pseudocode
public void configureHttpResponsHeaderFilters(ServletContextHandler context) {
Map<String, Map<String, String>> headersConfigs = extractHttpResponseHeaderConfig();
FilterHolder headerFilterHolder = null;
for (Map.Entry<String, Map<String, String>> entry : headersConfigs.entrySet()) {
headerFilterHolder = new FilterHolder(HeaderFilter.class);
headerFilterHolder.setName(entry.getKey());
Map<String, String> oneHeaderConfig = entry.getValue();
for (Map.Entry<String, String> oneHeader : oneHeaderConfig.entrySet()) {
switch (oneHeader.getKey().toUpperCase()) {
case "HEADER.CONFIG":
headerFilterHolder.setInitParameter("headerConfig", oneHeader.getValue());
break;
case "INCLUDED.PATHS":
headerFilterHolder.setInitParameter("includedPaths", oneHeader.getValue());
break;
case "EXCLUDED.PATHS":
headerFilterHolder.setInitParameter("excludedPaths", oneHeader.getValue());
break;
case "INCLUDED.MIME.TYPES":
headerFilterHolder.setInitParameter("includedMimeTypes", oneHeader.getValue());
break;
case "ENCLUDED.MIME.TYPES":
headerFilterHolder.setInitParameter("excludedMimeTypes", oneHeader.getValue());
break;
case "INCLUDED.HTTP.METHODS":
headerFilterHolder.setInitParameter("includedHttpMethods", oneHeader.getValue());
break;
case "ENCLUDED.HTTP.METHODS":
headerFilterHolder.setInitParameter("excludedHttpMethods", oneHeader.getValue());
break;
default:
}
}
context.addFilter(headerFilterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
}
}
...