mirror of
https://github.com/apple/pkl.git
synced 2026-05-25 16:19:20 +02:00
Add support for customizing HTTP headers (#1196)
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: https://github.com/apple/pkl-evolution/pull/24 --------- Co-authored-by: Jen Basch <jbasch94@gmail.com> Co-authored-by: Islon Scherer <islonscherer@gmail.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import java.util.regex.Pattern
|
||||
import org.pkl.core.Pair
|
||||
import org.pkl.core.evaluatorSettings.Color
|
||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
||||
import org.pkl.core.evaluatorSettings.TraceMode
|
||||
@@ -144,6 +145,9 @@ data class CliBaseOptions(
|
||||
/** URL prefixes to rewrite. */
|
||||
val httpRewrites: Map<URI, URI>? = null,
|
||||
|
||||
/** HTTP headers to add to the request. */
|
||||
val httpHeaders: List<Pair<Pattern, List<Pair<String, String>>>>? = null,
|
||||
|
||||
/** External module reader process specs */
|
||||
val externalModuleReaders: Map<String, ExternalReader> = mapOf(),
|
||||
|
||||
|
||||
@@ -218,6 +218,10 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
||||
cliOptions.httpRewrites ?: evaluatorSettings?.http?.rewrites ?: settings.http?.rewrites()
|
||||
}
|
||||
|
||||
private val httpHeaders: List<Pair<Pattern, List<Pair<String, String>>>>? by lazy {
|
||||
cliOptions.httpHeaders ?: project?.evaluatorSettings?.http?.headers ?: settings.http?.headers
|
||||
}
|
||||
|
||||
protected val externalModuleReaders: Map<String, PklEvaluatorSettings.ExternalReader> by lazy {
|
||||
(evaluatorSettings?.externalModuleReaders ?: emptyMap()) + cliOptions.externalModuleReaders
|
||||
}
|
||||
@@ -277,6 +281,7 @@ abstract class CliCommand(protected val cliOptions: CliBaseOptions) {
|
||||
setProxy(proxyAddress, noProxy ?: listOf())
|
||||
}
|
||||
httpRewrites?.let(::setRewrites)
|
||||
httpHeaders?.let(::setHeaders)
|
||||
// Lazy building significantly reduces execution time of commands that do minimal work.
|
||||
// However, it means that HTTP client initialization errors won't surface until an HTTP
|
||||
// request is made.
|
||||
|
||||
@@ -31,10 +31,12 @@ import java.util.regex.Pattern
|
||||
import org.pkl.commons.cli.CliBaseOptions
|
||||
import org.pkl.commons.cli.CliException
|
||||
import org.pkl.commons.shlex
|
||||
import org.pkl.core.Pair as PPair
|
||||
import org.pkl.core.evaluatorSettings.Color
|
||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings.ExternalReader
|
||||
import org.pkl.core.evaluatorSettings.TraceMode
|
||||
import org.pkl.core.runtime.VmUtils
|
||||
import org.pkl.core.util.GlobResolver
|
||||
import org.pkl.core.util.IoUtils
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@@ -285,6 +287,37 @@ class BaseOptions : OptionGroup() {
|
||||
.multiple()
|
||||
.toMap()
|
||||
|
||||
val httpHeaders: List<PPair<Pattern, List<PPair<String, String>>>> by
|
||||
option(
|
||||
names = arrayOf("--http-headers"),
|
||||
metavar = "<url-pattern>=<header name>:<header value>",
|
||||
help = "HTTP header to add to the request.",
|
||||
)
|
||||
.splitPair()
|
||||
.transformAll { it ->
|
||||
val headersMap = mutableMapOf<String, MutableList<PPair<String, String>>>()
|
||||
|
||||
try {
|
||||
val headerRegex = Regex("""^(.+?):[ \t]*(.+)$""")
|
||||
for ((stringPattern, header) in it) {
|
||||
val (headerName, headerValue) =
|
||||
headerRegex.find(header)?.destructured
|
||||
?: fail("Header '$header' is not in 'name:value' format.")
|
||||
IoUtils.validateHeaderName(headerName)
|
||||
IoUtils.validateHeaderValue(headerValue)
|
||||
headersMap
|
||||
.computeIfAbsent(stringPattern) { mutableListOf() }
|
||||
.add(PPair(headerName, headerValue))
|
||||
}
|
||||
|
||||
headersMap.entries.map { PPair(GlobResolver.toRegexPattern(it.key), it.value) }
|
||||
} catch (e: IllegalArgumentException) {
|
||||
fail(e.message!!)
|
||||
} catch (e: GlobResolver.InvalidGlobPatternException) {
|
||||
fail(e.message!!)
|
||||
}
|
||||
}
|
||||
|
||||
val externalModuleReaders: Map<String, ExternalReader> by
|
||||
option(
|
||||
names = arrayOf("--external-module-reader"),
|
||||
@@ -351,6 +384,7 @@ class BaseOptions : OptionGroup() {
|
||||
httpProxy = proxy,
|
||||
httpNoProxy = noProxy,
|
||||
httpRewrites = httpRewrites.ifEmpty { null },
|
||||
httpHeaders = httpHeaders.ifEmpty { null },
|
||||
externalModuleReaders = externalModuleReaders,
|
||||
externalResourceReaders = externalResourceReaders,
|
||||
traceMode = traceMode,
|
||||
|
||||
Reference in New Issue
Block a user