mirror of
https://github.com/apple/pkl.git
synced 2026-07-01 02:31:45 +02:00
Add support for HTTP proxying (#506)
* Add `--proxy` and `--no-proxy` CLI flags * Add property `http` to `pkl:settings` * Move `EvaluatorSettings` from `pkl:Project` to its own module and add property `http` * Add support for proxying in server mode, and through Gradle * Add `setProxy()` to `HttpClient` * Add documentation
This commit is contained in:
committed by
GitHub
parent
a520ae7d04
commit
b03530ed1f
+1
@@ -10,6 +10,7 @@ pkl:base
|
||||
pkl:Benchmark
|
||||
pkl:DocPackageInfo
|
||||
pkl:DocsiteInfo
|
||||
pkl:EvaluatorSettings
|
||||
pkl:json
|
||||
pkl:jsonnet
|
||||
pkl:math
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package org.pkl.core.http
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.net.URI
|
||||
|
||||
@Suppress("HttpUrlsUsage")
|
||||
class NoProxyRuleTest {
|
||||
@Test
|
||||
fun wildcard() {
|
||||
val noProxyRule = NoProxyRule("*")
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com")))
|
||||
assertTrue(noProxyRule.matches(URI("https://bar.com")))
|
||||
assertTrue(noProxyRule.matches(URI("https://foo:5000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hostname matching`() {
|
||||
val noProxyRule = NoProxyRule("foo.com")
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com")))
|
||||
assertTrue(noProxyRule.matches(URI("http://foo.com")))
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("https://FOO.COM")))
|
||||
assertTrue(noProxyRule.matches(URI("https://bar.foo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("https://bar.foo.com.bar")))
|
||||
assertFalse(noProxyRule.matches(URI("https://bar.foocom")))
|
||||
assertFalse(noProxyRule.matches(URI("https://fooo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("https://ooofoo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("pkl:foo.com")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hostname matching, leading dot`() {
|
||||
val noProxyRule = NoProxyRule(".foo.com")
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com")))
|
||||
assertTrue(noProxyRule.matches(URI("http://foo.com")))
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("https://FOO.COM")))
|
||||
assertTrue(noProxyRule.matches(URI("https://bar.foo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("https://bar.foo.com.bar")))
|
||||
assertFalse(noProxyRule.matches(URI("https://bar.foocom")))
|
||||
assertFalse(noProxyRule.matches(URI("https://fooo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("https://ooofoo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("pkl:foo.com")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `hostname matching, with port`() {
|
||||
val noProxyRule = NoProxyRule("foo.com:5000")
|
||||
assertTrue(noProxyRule.matches(URI("https://foo.com:5000")))
|
||||
assertFalse(noProxyRule.matches(URI("https://foo.com")))
|
||||
assertFalse(noProxyRule.matches(URI("https://foo.com:3000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv4 address literal matching`() {
|
||||
val noProxyRule = NoProxyRule("192.168.1.1")
|
||||
assertTrue(noProxyRule.matches(URI("http://192.168.1.1:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("http://192.168.1.1")))
|
||||
assertTrue(noProxyRule.matches(URI("https://192.168.1.1")))
|
||||
assertFalse(noProxyRule.matches(URI("https://192.168.1.0")))
|
||||
assertFalse(noProxyRule.matches(URI("https://192.168.1.0:5000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv4 address literal matching, with port`() {
|
||||
val noProxyRule = NoProxyRule("192.168.1.1:5000")
|
||||
assertTrue(noProxyRule.matches(URI("http://192.168.1.1:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("https://192.168.1.1:5000")))
|
||||
assertFalse(noProxyRule.matches(URI("http://192.168.1.1")))
|
||||
assertFalse(noProxyRule.matches(URI("https://192.168.1.1")))
|
||||
assertFalse(noProxyRule.matches(URI("http://192.168.1.1:3000")))
|
||||
assertFalse(noProxyRule.matches(URI("https://192.168.1.1:3000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv6 address literal matching`() {
|
||||
val noProxyRule = NoProxyRule("::1")
|
||||
assertTrue(noProxyRule.matches(URI("http://[::1]")))
|
||||
assertTrue(noProxyRule.matches(URI("http://[::1]:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("https://[::1]")))
|
||||
assertTrue(noProxyRule.matches(URI("https://[0000:0000:0000:0000:0000:0000:0000:0001]")))
|
||||
assertFalse(noProxyRule.matches(URI("https://[::2]")))
|
||||
assertFalse(noProxyRule.matches(URI("https://[::2]:5000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv6 address literal matching, with port`() {
|
||||
val noProxyRule = NoProxyRule("[::1]:5000")
|
||||
assertTrue(noProxyRule.matches(URI("http://[::1]:5000")))
|
||||
assertTrue(noProxyRule.matches(URI("https://[0000:0000:0000:0000:0000:0000:0000:0001]:5000")))
|
||||
assertFalse(noProxyRule.matches(URI("http://[::1]")))
|
||||
assertFalse(noProxyRule.matches(URI("https://[::1]")))
|
||||
assertFalse(noProxyRule.matches(URI("https://[::2]")))
|
||||
assertFalse(noProxyRule.matches(URI("https://[::2]:5000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv4 port from protocol`() {
|
||||
val noProxyRuleHttp = NoProxyRule("192.168.1.1:80")
|
||||
assertTrue(noProxyRuleHttp.matches(URI("http://192.168.1.1")))
|
||||
assertTrue(noProxyRuleHttp.matches(URI("http://192.168.1.1:80")))
|
||||
assertTrue(noProxyRuleHttp.matches(URI("https://192.168.1.1:80")))
|
||||
assertFalse(noProxyRuleHttp.matches(URI("https://192.168.1.1")))
|
||||
assertFalse(noProxyRuleHttp.matches(URI("https://192.168.1.1:5000")))
|
||||
|
||||
val noProxyRuleHttps = NoProxyRule("192.168.1.1:443")
|
||||
assertTrue(noProxyRuleHttps.matches(URI("https://192.168.1.1")))
|
||||
assertTrue(noProxyRuleHttps.matches(URI("http://192.168.1.1:443")))
|
||||
assertFalse(noProxyRuleHttps.matches(URI("http://192.168.1.1")))
|
||||
assertFalse(noProxyRuleHttps.matches(URI("https://192.168.1.1:80")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv4 cidr block matching`() {
|
||||
val noProxyRule1 = NoProxyRule("10.0.0.0/16")
|
||||
assertTrue(noProxyRule1.matches(URI("https://10.0.0.0")))
|
||||
assertTrue(noProxyRule1.matches(URI("https://10.0.255.255")))
|
||||
assertTrue(noProxyRule1.matches(URI("https://10.0.255.255:5000")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://10.1.0.0")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://11.0.0.0")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://9.255.255.255")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://9.255.255.255:5000")))
|
||||
|
||||
val noProxyRule2 = NoProxyRule("10.0.0.0/32")
|
||||
assertTrue(noProxyRule2.matches(URI("https://10.0.0.0")))
|
||||
assertTrue(noProxyRule2.matches(URI("https://10.0.0.0:5000")))
|
||||
assertFalse(noProxyRule2.matches(URI("https://10.0.0.1")))
|
||||
assertFalse(noProxyRule2.matches(URI("https://9.255.255.55:5000")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ipv6 cidr block matching`() {
|
||||
val noProxyRule1 = NoProxyRule("1000::ff/32")
|
||||
assertTrue(noProxyRule1.matches(URI("https://[1000::]")))
|
||||
assertTrue(noProxyRule1.matches(URI("https://[1000:0:ffff:ffff:ffff:ffff:ffff:ffff]")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://[999::]")))
|
||||
assertFalse(noProxyRule1.matches(URI("https://[1000:1::]")))
|
||||
|
||||
val noProxyRule2 = NoProxyRule("1000::ff/128")
|
||||
assertTrue(noProxyRule2.matches(URI("https://[1000::ff]")))
|
||||
assertFalse(noProxyRule2.matches(URI("https://[999::]")))
|
||||
assertFalse(noProxyRule2.matches(URI("https://[1001::]")))
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import java.net.http.HttpResponse
|
||||
|
||||
class RequestCapturingClient : HttpClient {
|
||||
lateinit var request: HttpRequest
|
||||
|
||||
|
||||
override fun <T : Any> send(
|
||||
request: HttpRequest,
|
||||
responseBodyHandler: HttpResponse.BodyHandler<T>
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.pkl.commons.writeString
|
||||
import org.pkl.core.*
|
||||
import org.pkl.core.http.HttpClient
|
||||
import org.pkl.core.packages.PackageUri
|
||||
import org.pkl.core.project.Project.EvaluatorSettings
|
||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import java.util.regex.Pattern
|
||||
@@ -40,7 +40,7 @@ class ProjectTest {
|
||||
listOf(Path.of("apiTest1.pkl"), Path.of("apiTest2.pkl")),
|
||||
listOf("PklProject", "PklProject.deps.json", ".**", "*.exe")
|
||||
)
|
||||
val expectedSettings = EvaluatorSettings(
|
||||
val expectedSettings = PklEvaluatorSettings(
|
||||
mapOf("two" to "2"),
|
||||
mapOf("one" to "1"),
|
||||
listOf("foo:", "bar:").map(Pattern::compile),
|
||||
@@ -52,7 +52,8 @@ class ProjectTest {
|
||||
path.resolve("modulepath2/")
|
||||
),
|
||||
Duration.ofMinutes(5.0),
|
||||
path
|
||||
path,
|
||||
null
|
||||
)
|
||||
projectPath.writeString("""
|
||||
amends "pkl:Project"
|
||||
@@ -116,7 +117,7 @@ class ProjectTest {
|
||||
""".trimIndent())
|
||||
val project = Project.loadFromPath(projectPath)
|
||||
assertThat(project.`package`).isEqualTo(expectedPackage)
|
||||
assertThat(project.settings).isEqualTo(expectedSettings)
|
||||
assertThat(project.evaluatorSettings).isEqualTo(expectedSettings)
|
||||
assertThat(project.tests).isEqualTo(listOf(path.resolve("test1.pkl"), path.resolve("test2.pkl")))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,18 @@ import java.nio.file.Path
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatCode
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.pkl.commons.createParentDirectories
|
||||
import org.pkl.commons.writeString
|
||||
import org.pkl.core.Evaluator
|
||||
import org.pkl.core.ModuleSource
|
||||
import org.pkl.core.PObject
|
||||
import org.pkl.core.StackFrameTransformers
|
||||
import org.pkl.core.evaluatorSettings.PklEvaluatorSettings
|
||||
import org.pkl.core.runtime.VmException
|
||||
import org.pkl.core.settings.PklSettings.Editor
|
||||
import java.net.URI
|
||||
|
||||
class PklSettingsTest {
|
||||
@Test
|
||||
@@ -25,7 +30,61 @@ class PklSettingsTest {
|
||||
)
|
||||
|
||||
val settings = PklSettings.loadFromPklHomeDir(tempDir)
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.SUBLIME))
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.SUBLIME, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `load user settings with http`(@TempDir tempDir: Path) {
|
||||
val settingsPath = tempDir.resolve("settings.pkl")
|
||||
settingsPath.createParentDirectories()
|
||||
settingsPath.writeString(
|
||||
"""
|
||||
amends "pkl:settings"
|
||||
http {
|
||||
proxy {
|
||||
address = "http://localhost:8080"
|
||||
noProxy {
|
||||
"example.com"
|
||||
"pkg.pkl-lang.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val settings = PklSettings.loadFromPklHomeDir(tempDir)
|
||||
val expectedHttp = PklEvaluatorSettings.Http(
|
||||
PklEvaluatorSettings.Proxy(
|
||||
URI("http://localhost:8080"),
|
||||
listOf("example.com", "pkg.pkl-lang.org")
|
||||
)
|
||||
)
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.SYSTEM, expectedHttp))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `load user settings with http, but no noProxy`(@TempDir tempDir: Path) {
|
||||
val settingsPath = tempDir.resolve("settings.pkl")
|
||||
settingsPath.createParentDirectories()
|
||||
settingsPath.writeString(
|
||||
"""
|
||||
amends "pkl:settings"
|
||||
http {
|
||||
proxy {
|
||||
address = "http://localhost:8080"
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
val settings = PklSettings.loadFromPklHomeDir(tempDir)
|
||||
val expectedHttp = PklEvaluatorSettings.Http(
|
||||
PklEvaluatorSettings.Proxy(
|
||||
URI("http://localhost:8080"),
|
||||
listOf(),
|
||||
)
|
||||
)
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.SYSTEM, expectedHttp))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -39,7 +98,7 @@ class PklSettingsTest {
|
||||
)
|
||||
|
||||
val settings = PklSettings.load(ModuleSource.path(settingsPath))
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.IDEA))
|
||||
assertThat(settings).isEqualTo(PklSettings(Editor.IDEA, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -76,6 +135,6 @@ class PklSettingsTest {
|
||||
}
|
||||
|
||||
private fun checkEquals(expected: Editor, actual: PObject) {
|
||||
assertThat(actual.getProperty("urlScheme") as String).isEqualTo(expected.urlScheme)
|
||||
assertThat(actual.getProperty("urlScheme") as String).isEqualTo(expected.urlScheme())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user