Compare commits
2 Commits
3d1847c408
...
fc9900d821
Author | SHA1 | Date | |
---|---|---|---|
fc9900d821
|
|||
1a78c8092b
|
@@ -66,6 +66,15 @@ allprojects { subproject ->
|
||||
}
|
||||
}
|
||||
|
||||
pluginManager.withPlugin('jacoco') {
|
||||
test {
|
||||
finalizedBy jacocoTestReport
|
||||
}
|
||||
jacocoTestReport {
|
||||
dependsOn test
|
||||
}
|
||||
}
|
||||
|
||||
pluginManager.withPlugin(catalog.plugins.kotlin.jvm.get().pluginId) {
|
||||
tasks.withType(KotlinCompile.class) {
|
||||
compilerOptions.jvmTarget = JvmTarget.JVM_21
|
||||
|
@@ -46,7 +46,8 @@ class BenchmarkCommand : GbcsCommand() {
|
||||
val random = Random(SecureRandom.getInstance("NativePRNGNonBlocking").nextLong())
|
||||
while (true) {
|
||||
val key = Base64.getUrlEncoder().encode(random.nextBytes(16)).toString(Charsets.UTF_8)
|
||||
val value = random.nextBytes(0x1000)
|
||||
val content = random.nextInt().toByte()
|
||||
val value = ByteArray(0x1000, { _ -> content })
|
||||
yield(key to value)
|
||||
}
|
||||
}
|
||||
|
@@ -30,16 +30,18 @@ import io.netty.handler.ssl.SslContextBuilder
|
||||
import io.netty.handler.stream.ChunkedWriteHandler
|
||||
import io.netty.util.concurrent.Future
|
||||
import io.netty.util.concurrent.GenericFutureListener
|
||||
import net.woggioni.gbcs.client.impl.Parser
|
||||
import net.woggioni.gbcs.common.Xml
|
||||
import net.woggioni.gbcs.common.contextLogger
|
||||
import net.woggioni.gbcs.common.debug
|
||||
import net.woggioni.gbcs.client.impl.Parser
|
||||
import net.woggioni.gbcs.common.trace
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.URI
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
import java.util.Base64
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
@@ -67,6 +69,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
data class Profile(
|
||||
val serverURI: URI,
|
||||
val authentication: Authentication?,
|
||||
val connectionTimeout : Duration?,
|
||||
val maxConnections : Int
|
||||
)
|
||||
|
||||
@@ -104,6 +107,9 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
option(ChannelOption.TCP_NODELAY, true)
|
||||
option(ChannelOption.SO_KEEPALIVE, true)
|
||||
remoteAddress(InetSocketAddress(host, port))
|
||||
profile.connectionTimeout?.let {
|
||||
option(ChannelOption.CONNECT_TIMEOUT_MILLIS, it.toMillis().toInt())
|
||||
}
|
||||
}
|
||||
val channelPoolHandler = object : AbstractChannelPoolHandler() {
|
||||
|
||||
@@ -114,20 +120,29 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
private var leaseCount = AtomicInteger()
|
||||
|
||||
override fun channelReleased(ch: Channel) {
|
||||
log.debug {
|
||||
"Released lease ${leaseCount.decrementAndGet()}"
|
||||
val activeLeases = leaseCount.decrementAndGet()
|
||||
log.trace {
|
||||
"Released channel ${ch.id().asShortText()}, number of active leases: $activeLeases"
|
||||
}
|
||||
}
|
||||
|
||||
override fun channelAcquired(ch: Channel?) {
|
||||
log.debug {
|
||||
"Acquired lease ${leaseCount.getAndIncrement()}"
|
||||
override fun channelAcquired(ch: Channel) {
|
||||
val activeLeases = leaseCount.getAndIncrement()
|
||||
log.trace {
|
||||
"Acquired channel ${ch.id().asShortText()}, number of active leases: $activeLeases"
|
||||
}
|
||||
}
|
||||
|
||||
override fun channelCreated(ch: Channel) {
|
||||
val connectionId = connectionCount.getAndIncrement()
|
||||
log.debug {
|
||||
"Created connection ${connectionCount.getAndIncrement()}"
|
||||
"Created connection $connectionId, total number of active connections: $connectionId"
|
||||
}
|
||||
ch.closeFuture().addListener {
|
||||
val activeConnections = connectionCount.decrementAndGet()
|
||||
log.debug {
|
||||
"Closed connection $connectionId, total number of active connections: $activeConnections"
|
||||
}
|
||||
}
|
||||
val pipeline: ChannelPipeline = ch.pipeline()
|
||||
|
||||
@@ -202,6 +217,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
ctx.close()
|
||||
pipeline.removeLast()
|
||||
pool.release(channel)
|
||||
super.exceptionCaught(ctx, cause)
|
||||
}
|
||||
})
|
||||
// Prepare the HTTP request
|
||||
@@ -219,7 +235,7 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes())
|
||||
}
|
||||
set(HttpHeaderNames.HOST, profile.serverURI.host)
|
||||
set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
|
||||
set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE)
|
||||
set(
|
||||
HttpHeaderNames.ACCEPT_ENCODING,
|
||||
HttpHeaderValues.GZIP.toString() + "," + HttpHeaderValues.DEFLATE.toString()
|
||||
@@ -237,6 +253,8 @@ class GbcsClient(private val profile: Configuration.Profile) : AutoCloseable {
|
||||
// Set headers
|
||||
// Send the request
|
||||
channel.writeAndFlush(request)
|
||||
} else {
|
||||
responseFuture.completeExceptionally(channelFuture.cause())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -11,6 +11,7 @@ import java.nio.file.Path
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.time.Duration
|
||||
|
||||
object Parser {
|
||||
|
||||
@@ -60,7 +61,9 @@ object Parser {
|
||||
val maxConnections = child.renderAttribute("max-connections")
|
||||
?.let(String::toInt)
|
||||
?: 50
|
||||
profiles[name] = GbcsClient.Configuration.Profile(uri, authentication, maxConnections)
|
||||
val connectionTimeout = child.renderAttribute("connection-timeout")
|
||||
?.let(Duration::parse)
|
||||
profiles[name] = GbcsClient.Configuration.Profile(uri, authentication, connectionTimeout, maxConnections)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
<xs:attribute name="name" type="xs:token" use="required"/>
|
||||
<xs:attribute name="base-url" type="xs:anyURI" use="required"/>
|
||||
<xs:attribute name="max-connections" type="xs:positiveInteger" default="50"/>
|
||||
<xs:attribute name="connection-timeout" type="xs:duration"/>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="noAuthType"/>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
alias catalog.plugins.kotlin.jvm
|
||||
id 'jacoco'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,8 @@ import javax.net.ssl.X509TrustManager
|
||||
|
||||
class ClientCertificateValidator private constructor(
|
||||
private val sslHandler: SslHandler,
|
||||
private val x509TrustManager: X509TrustManager) : ChannelInboundHandlerAdapter() {
|
||||
private val x509TrustManager: X509TrustManager
|
||||
) : ChannelInboundHandlerAdapter() {
|
||||
override fun userEventTriggered(ctx: ChannelHandlerContext, evt: Any) {
|
||||
if (evt is SslHandshakeCompletionEvent) {
|
||||
if (evt.isSuccess) {
|
||||
@@ -42,7 +43,8 @@ class ClientCertificateValidator private constructor(
|
||||
val validator = CertPathValidator.getInstance("PKIX").apply {
|
||||
val rc = revocationChecker as PKIXRevocationChecker
|
||||
rc.options = EnumSet.of(
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK)
|
||||
PKIXRevocationChecker.Option.NO_FALLBACK
|
||||
)
|
||||
}
|
||||
val params = PKIXParameters(trustStore).apply {
|
||||
isRevocationEnabled = certificateRevocationEnabled
|
||||
@@ -72,11 +74,16 @@ class ClientCertificateValidator private constructor(
|
||||
}
|
||||
} else {
|
||||
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||
trustManagerFactory.trustManagers.asSequence().filter { it is X509TrustManager }.single() as X509TrustManager
|
||||
trustManagerFactory.trustManagers.asSequence().filter { it is X509TrustManager }
|
||||
.single() as X509TrustManager
|
||||
}
|
||||
}
|
||||
|
||||
fun of(sslHandler : SslHandler, trustStore : KeyStore?, certificateRevocationEnabled : Boolean) : ClientCertificateValidator {
|
||||
fun of(
|
||||
sslHandler: SslHandler,
|
||||
trustStore: KeyStore?,
|
||||
certificateRevocationEnabled: Boolean
|
||||
): ClientCertificateValidator {
|
||||
return ClientCertificateValidator(sslHandler, getTrustManager(trustStore, certificateRevocationEnabled))
|
||||
}
|
||||
}
|
||||
|
@@ -21,14 +21,20 @@ import org.w3c.dom.TypeInfo
|
||||
import java.nio.file.Paths
|
||||
import java.time.Duration
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object Parser {
|
||||
fun parse(document: Document): Configuration {
|
||||
val root = document.documentElement
|
||||
val anonymousUser = User("", null, emptySet())
|
||||
var connection: Configuration.Connection? = null
|
||||
var eventExecutor: Configuration.EventExecutor? = null
|
||||
var connection: Configuration.Connection = Configuration.Connection(
|
||||
Duration.of(10, ChronoUnit.SECONDS),
|
||||
Duration.of(10, ChronoUnit.SECONDS),
|
||||
Duration.of(60, ChronoUnit.SECONDS),
|
||||
Duration.of(30, ChronoUnit.SECONDS),
|
||||
Duration.of(30, ChronoUnit.SECONDS),
|
||||
67108864
|
||||
)
|
||||
var eventExecutor: Configuration.EventExecutor = Configuration.EventExecutor(true)
|
||||
var cache: Cache? = null
|
||||
var host = "127.0.0.1"
|
||||
var port = 11080
|
||||
@@ -194,8 +200,12 @@ object Parser {
|
||||
}.toSet()
|
||||
|
||||
private fun parseUserRefs(root: Element) = root.asIterable().asSequence().map {
|
||||
it.renderAttribute("ref")
|
||||
}.toSet()
|
||||
when(it.localName) {
|
||||
"user" -> it.renderAttribute("ref")
|
||||
"anonymous" -> ""
|
||||
else -> ConfigurationException("Unrecognized tag '${it.localName}'")
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseUsers(root: Element): Sequence<User> {
|
||||
return root.asIterable().asSequence().filter {
|
||||
|
@@ -1,11 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<gbcs:server use-virtual-threads="false"
|
||||
max-request-size="67108864"
|
||||
incoming-connections-backlog-size="1024"
|
||||
<gbcs:server
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:gbcs="urn:net.woggioni.gbcs.server"
|
||||
xs:schemaLocation="urn:net.woggioni.gbcs.server jpms://net.woggioni.gbcs.server/net/woggioni/gbcs/server/schema/gbcs.xsd">
|
||||
<bind host="127.0.0.1" port="8080"/>
|
||||
<bind host="127.0.0.1" port="8080" incoming-connections-backlog-size="1024"/>
|
||||
<connection
|
||||
max-request-size="67108864"
|
||||
idle-timeout="PT30S"
|
||||
read-timeout="PT10S"
|
||||
write-timeout="PT10S"
|
||||
read-idle-timeout="PT60S"
|
||||
write-idle-timeout="PT60S"/>
|
||||
<event-executor use-virtual-threads="true"/>
|
||||
<cache xs:type="gbcs:fileSystemCacheType" path="/tmp/gbcs" max-age="P7D"/>
|
||||
<authentication>
|
||||
<none/>
|
||||
|
Reference in New Issue
Block a user