Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Property NameTypeDefaultImportanceDescriptionExample for Value
response.http.headersstringLIST""mediumDefines 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.configstringSTRING""lowDefine 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.pathsstringSTRING""lowIt is comma separated values of included path specs applied to HTTP headers. See path spec rules section.
/connectors/connector1/topics/*
response.http.headers.{name}.excluded.pathsstringSTRING""lowIt is 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.typesstringSTRING""lowIt is comma separated values of included mime types applied to HTTP headersapplication/json
response.http.headers.{name}.excluded.mime.typesstringSTRING""low

It is comma separated values of excluded mime types applied to HTTP headers.

application/xml
response.http.headers.{name}.included.http.methodsstringSTRING""lowIt is comma separated values of included http methods applied to HTTP headersPOST,PUT
response.http.headers.{name}.excluded.http.methodsstringSTRING""lowIt is comma separated values of excluded http methods applied to HTTP headersGET

...

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));
}
}

...