Skip to content

Add support for customizing HTTP headers#1196

Open
kyokuping wants to merge 13 commits intoapple:mainfrom
kyokuping:feat/headers
Open

Add support for customizing HTTP headers#1196
kyokuping wants to merge 13 commits intoapple:mainfrom
kyokuping:feat/headers

Conversation

@kyokuping
Copy link
Copy Markdown

@kyokuping kyokuping commented Aug 31, 2025

This PR adds support for custom HTTP headers, introducing a --http-header CLI flag to accept key=value pairs. These headers can also be specified within the setting.pkl file.

Closes #633

SPICE: apple/pkl-evolution#24

Copy link
Copy Markdown
Contributor

@HT154 HT154 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 the contribution! 🎉

I have a few primary concerns here:

  • Although rare, it is valid to send a specific header more than once in a request. When there are headers with the same name their order may also matter.
  • How does your implementation handle "reserved" headers that users should not override like Origin or User-Agent?
  • It seems less than ideal to send the same headers to all hosts, eg. if host A requires auth but host B does not, Pkl should not send a configured Authorization header to both hosts. I think a prefix matching scheme like the one used for rewrites is necessary here to ensure the proper security controls are in place.

To this end, I think the Pkl API for this needs to be something along these lines:

headers: Mapping<HttpRewrite, Listing<Pair<String, String>>>

This complicates the CLI a bit, of course, but maybe something like this is reasonable?

--http-header <prefix>='<header name>: <header value>'

@kyokuping kyokuping requested a review from HT154 September 6, 2025 14:45
@HT154
Copy link
Copy Markdown
Contributor

HT154 commented Sep 17, 2025

Just a heads up, we want reviews from the entire core team because this feature affects the core language and has security implications. One member of the team is currently out on leave so it's going to be a little bit before we can fully review this, but we haven't forgotten about it!

Comment on lines 168 to 170
/// HTTP headers to add to outbound requests targeting specified URLs.
headers: Mapping<HttpRewrite, Listing<Pair<String, String>>>?
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We need the @Since annotation here for documentation purposes. It would also be good to add specificity and examples to the doc comment, similar to rewrites above.

Suggested change
/// HTTP headers to add to outbound requests targeting specified URLs.
headers: Mapping<HttpRewrite, Listing<Pair<String, String>>>?
}
/// HTTP headers to add to outbound requests targeting specified URLs.
@Since { version = "0.30.0" }
headers: Mapping<HttpRewrite, Listing<Pair<String, String>>>?
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm also curious if it makes sense to rename HttpRewrite to HttpPrefix (with typealias marked @Deprecated for backwards compatibility) and refactoring the corresponding Java APIs. Interested in input from @bioball and @stackoverflow on this.

Comment on lines +298 to +300
val headerParts = header.split(":", limit = 2)
require(headerParts.size == 2) { "Header '$header' is not in 'name:value' format. " }
PPair(headerParts[0], headerParts[1])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

curl accepts this same syntax, but also accepts <name>:[ \t]+<value> and appears to strip the leading (but not trailing) whitespace from header values before sending the request. To avoid surprise for users of Pkl, it might be good to do the same. In theory, HTTP servers should be ignoring this leading (and trailing) whitespace when parsing headers so it shouldn't matter, but it might be best to avoid taking chances here.

I'm also wondering if it makes sense to do some validation of characters in headers here (and in the EvaluatorSettings API) to eagerly report invalid characters instead of lazily doing so when a matching request is made for the first time.

Copy link
Copy Markdown
Contributor

@stackoverflow stackoverflow left a comment

Choose a reason for hiding this comment

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

The design sounds sensible at first glance, but due to the complexity and security issues it may cause it may be a good idea to create a SPICE for it.
What do you think @bioball, @HT154?

Copy link
Copy Markdown
Member

@bioball bioball left a comment

Choose a reason for hiding this comment

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

Hey, thanks for the PR! I agree with @stackoverflow; it'd be good to have this discussed in a SPICE.

If you'd like to drive this feature, can you write one up? It should be submitted as PR to pkl-evolution.

Your SPICE should start by copy/pasting the template. Your SPICE number would be the next number after the latest proposed SPICE see (https://github.com/apple/pkl-evolution/pulls)

}
}
}
return underlying.send(wrappedRequestBuilder.build(), responseBodyHandler);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The logic of adding headers should be handled in RequestRewritingClient

@kyokuping
Copy link
Copy Markdown
Author

I will resume working on this PR after getting the SPICE merged!

@kyokuping kyokuping marked this pull request as draft September 25, 2025 04:30
@stackoverflow
Copy link
Copy Markdown
Contributor

As a heads up: the SPICE can only be merged once this pr is merged and released on a new version. So you only need the SPICE to be approved.

@bioball
Copy link
Copy Markdown
Member

bioball commented Nov 13, 2025

@kyokuping was the close intentional?

@kyokuping
Copy link
Copy Markdown
Author

Sorry, accidentally closed the PR. 😢

@bioball
Copy link
Copy Markdown
Member

bioball commented Nov 13, 2025

Gotcha, feel free to re-open a new PR!

@kyokuping kyokuping reopened this Nov 14, 2025
@discount-elf
Copy link
Copy Markdown

Happy to see this, just went looking for http(s) auth support :D

@kyokuping kyokuping marked this pull request as ready for review March 3, 2026 13:36
@kyokuping kyokuping requested a review from HT154 March 3, 2026 13:36
@danievanzyl
Copy link
Copy Markdown

When will this be merged? Really looking forward to access private repos 🙏🏻

Copy link
Copy Markdown
Contributor

@HT154 HT154 left a comment

Choose a reason for hiding this comment

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

Hey @kyokuping would you mind rebasing this to resolve the conflict(s)?

I have some pretty minor feedback, but from a technical standpoint this looks pretty good. I'd like to try and ship this in 0.32 in a few months, so it'd be great if this was ready for another set of eyes by the time the core team's all back together in a few weeks!

- Introduce pattern-based URL matches
- Both accept a single and multiple values for header values
- Move header append logic to RequestRewritingClient
@kyokuping kyokuping requested a review from HT154 March 16, 2026 15:10
Comment on lines +897 to +900
if (!headerName.equals(headerName.toLowerCase())) {
throw new IllegalArgumentException(
"HTTP header '%s' should be all lowercase".formatted(headerName));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this validation actually necessary? Why would this be preferable to normalizing header names during CLI parsing?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Based on the previous review on the SPICE, I updated the settings to enforce lowercase values and therefore expected the CLI to match this behavior. If we want to change this in the CLI, we should probably align the EvaluatorSettings implementation too. Which way do you prefer to go with?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the evaluator settings, "pre"-normalization is required to ensure the Mapping has unique keys. On the CLI, each instance of the option is parsed linearly, so the CLI could perform its own normalization without issue.

In general, I think it's best that we accept the broadest input possible for each input method (even if those are not consistent). It's very possible the other core folks could disagree, so I'm happy to put a pin in this until they're back over the next few weeks.

Co-authored-by: Jen Basch <jbasch94@gmail.com>
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.

Pkl package using private repo (using authentication)

6 participants