Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support custom request headers from java client and migrations tool #8787

Merged
merged 6 commits into from
Feb 22, 2022

Conversation

vcrfxia
Copy link
Contributor

@vcrfxia vcrfxia commented Feb 17, 2022

Description

This PR adds support for specifying custom request headers for requests issued to the ksqlDB server via the Java client, and also when applying migrations with the ksql migrations tool.

When creating a Java client instance, the new ClientOptions#setRequestHeaders(Map<String,String>) method can be used to set custom request headers:

/**
   * Sets custom request headers to be sent with requests to the ksqlDB server.
   * These headers are in addition to any automatic headers such as the
   * authorization header.
   *
   * <p>If this method is called more than once, only the headers passed on
   * the last invocation will be used. To update existing custom headers,
   * use this method in combination with {@link ClientOptions#getRequestHeaders()}.
   *
   * <p>In case of overlap between these custom headers and automatic headers such
   * as the authorization header, these custom headers take precedence.
   *
   * @param requestHeaders custom request headers
   * @return a reference to this
   */
  ClientOptions setRequestHeaders(Map<String, String> requestHeaders);

This PR also introduces a corresponding ClientOptions#getRequestHeaders() method as mentioned in the javadoc.

When using the ksql-migrations tool, you can now pass an optional --headers flag to the apply command in order to specify custom request headers to be sent with all requests to the ksqlDB server (related to applying the migration(s)):

ksql-migrations ... apply ... --headers /path/to/custom/headers/file.txt

The headers file should be formatted as a properties file. Either of the following is acceptable:

X-My-Custom-Header: abcdefg
X-My-Other-Custom-Header: asdfgh

or

X-My-Custom-Header=abcdefg
X-My-Other-Custom-Header=asdfgh

Testing done

Unit + manual.

Reviewer checklist

  • Ensure docs are updated if necessary. (eg. if a user visible feature is being added or changed).
  • Ensure relevant issues are linked (description should include text like "Fixes #")

@vcrfxia vcrfxia requested a review from a team as a code owner February 17, 2022 18:47
@@ -307,6 +309,26 @@ containing multiple ksqlDB statements fails during the migration, it's possible
some of the statements will have been run on the ksqlDB server while later statements
have not.

You can optionally pass custom request headers to be sent with all ksqlDB requests
made as part of the `apply` command. In order to do so, pass the location of a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
made as part of the `apply` command. In order to do so, pass the location of a
made as part of the `apply` command by passing the location of a

Copy link
Member

@JimGalasyn JimGalasyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, with one suggestion.

@@ -238,6 +249,11 @@ public int getHttp2MultiplexingLimit() {
return http2MultiplexingLimit;
}

@Override
public Map<String, String> getRequestHeaders() {
return requestHeaders == null ? null : new HashMap<>(requestHeaders);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to return an empty map?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly, though it is a public API so we should decide now. (The javadoc I added says it returns null if it was never set but that can easily be changed.) Would you expect an empty map? I can make that change in order to be consistent with the String fields returning the empty string if not set, rather than null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I tried to look for other similar API instances briefly.

I did this: https://github.com/confluentinc/ksql/blob/master/ksqldb-api-client/src/main/java/io/confluent/ksql/api/client/impl/HttpRequestImpl.java#L29-L30 where empty maps are used rather than null values. I think that's a slight node to changing to empty maps.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, updated.

+ ", http2MultiplexingLimit=" + http2MultiplexingLimit
+ ", requestHeaders='" + requestHeaders + '\''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random question, have you seen this output? (Asking in case it'd look goofy or not print things.)

Separately, are any of the headers potentially sensitive / something that should not be printed / logged?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The headers are whatever users set (they're completely custom), so in theory they could be sensitive but there's no way for them to specify that as such. Do you think it's better to not log the headers then (or at least the values)? I'm not sure when/if this would actually ever get printed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's not already some strong guidance or precedent here, we are probably fine.


private static Map<String, String> loadRequestHeaders(final String headersFile) {
if (headersFile == null || headersFile.trim().isEmpty()) {
return null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return an empty map here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly about this one. It's an internal helper method and the rest of the code keeps null checks to be defensive anyway.

@@ -46,14 +49,16 @@ public void shouldCreateNonTlsClientOptions() {
assertThat(clientOptions.getKeyAlias(), is(""));
assertThat(clientOptions.isUseAlpn(), is(false));
assertThat(clientOptions.isVerifyHost(), is(true));
assertThat(clientOptions.getRequestHeaders(), nullValue());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be an emptyMap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good catch.

@@ -158,6 +164,12 @@ public ClientOptions setHttp2MultiplexingLimit(final int http2MultiplexingLimit)
return this;
}

@Override
public ClientOptions setRequestHeaders(final Map<String, String> requestHeaders) {
this.requestHeaders = ImmutableMap.copyOf(requestHeaders);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to catch for null input or is the NPE that'd come out of copyOf what we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, fixed.

Copy link
Member

@jnh5y jnh5y left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for changing to empty maps!

The comments are non-blocking, nice-to-haves.

@vcrfxia vcrfxia merged commit ffe57f5 into confluentinc:master Feb 22, 2022
@vcrfxia vcrfxia deleted the java-client-headers branch February 22, 2022 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants