mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
ENT-11003: Upgraded Jetty and Jersey. (#7715)
* ENT-11003: Upgraded jetty and jersey. Fixed up simm valuation demo.
This commit is contained in:
parent
5b6248de35
commit
0f713aaa44
@ -49,15 +49,15 @@ artemisVersion=2.32.0
|
|||||||
# TODO Upgrade Jackson only when corda is using kotlin 1.3.10
|
# TODO Upgrade Jackson only when corda is using kotlin 1.3.10
|
||||||
jacksonVersion=2.17.0
|
jacksonVersion=2.17.0
|
||||||
jacksonKotlinVersion=2.17.0
|
jacksonKotlinVersion=2.17.0
|
||||||
jettyVersion=9.4.54.v20240208
|
jettyVersion=12.0.7
|
||||||
jerseyVersion=2.25
|
jerseyVersion=3.1.6
|
||||||
servletVersion=4.0.1
|
servletVersion=4.0.1
|
||||||
assertjVersion=3.12.2
|
assertjVersion=3.12.2
|
||||||
slf4JVersion=2.0.12
|
slf4JVersion=2.0.12
|
||||||
log4JVersion=2.23.1
|
log4JVersion=2.23.1
|
||||||
okhttpVersion=4.11.0
|
okhttpVersion=4.11.0
|
||||||
nettyVersion=4.1.77.Final
|
nettyVersion=4.1.77.Final
|
||||||
fileuploadVersion=1.4
|
fileuploadVersion=2.0.0-M1
|
||||||
kryoVersion=5.5.0
|
kryoVersion=5.5.0
|
||||||
kryoSerializerVersion=0.43
|
kryoSerializerVersion=0.43
|
||||||
# Legacy JUnit 4 version
|
# Legacy JUnit 4 version
|
||||||
|
@ -87,7 +87,7 @@ dependencies {
|
|||||||
}
|
}
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation "commons-fileupload:commons-fileupload:$fileupload_version"
|
testImplementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version"
|
||||||
// Guava: Google test library (collections test suite)
|
// Guava: Google test library (collections test suite)
|
||||||
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||||
testImplementation "com.google.jimfs:jimfs:1.1"
|
testImplementation "com.google.jimfs:jimfs:1.1"
|
||||||
|
@ -47,7 +47,7 @@ dependencies {
|
|||||||
testImplementation sourceSets.obfuscator.output
|
testImplementation sourceSets.obfuscator.output
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
||||||
testImplementation "junit:junit:$junit_version"
|
testImplementation "junit:junit:$junit_version"
|
||||||
testImplementation "commons-fileupload:commons-fileupload:$fileupload_version"
|
testImplementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version"
|
||||||
// Guava: Google test library (collections test suite)
|
// Guava: Google test library (collections test suite)
|
||||||
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
testImplementation "com.google.guava:guava-testlib:$guava_version"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
|
||||||
|
@ -200,8 +200,8 @@ dependencies {
|
|||||||
// Jetty dependencies for NetworkMapClient test.
|
// Jetty dependencies for NetworkMapClient test.
|
||||||
// Web stuff: for HTTP[S] servlets
|
// Web stuff: for HTTP[S] servlets
|
||||||
testImplementation "org.hamcrest:hamcrest-library:2.1"
|
testImplementation "org.hamcrest:hamcrest-library:2.1"
|
||||||
testImplementation "org.eclipse.jetty:jetty-servlet:${jetty_version}"
|
testImplementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:${jetty_version}"
|
||||||
testImplementation "org.eclipse.jetty:jetty-webapp:${jetty_version}"
|
testImplementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:${jetty_version}"
|
||||||
testImplementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
testImplementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
||||||
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
|
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
|
||||||
testImplementation "com.google.jimfs:jimfs:1.1"
|
testImplementation "com.google.jimfs:jimfs:1.1"
|
||||||
@ -211,6 +211,7 @@ dependencies {
|
|||||||
testImplementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
testImplementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
||||||
testImplementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}"
|
testImplementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}"
|
||||||
testImplementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}"
|
testImplementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}"
|
||||||
|
testImplementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
|
||||||
|
|
||||||
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit_vintage_version}"
|
||||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_jupiter_version}"
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
package net.corda.node.utilities.registration
|
package net.corda.node.utilities.registration
|
||||||
|
|
||||||
|
import jakarta.ws.rs.Consumes
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.POST
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.PathParam
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.logElapsedTime
|
import net.corda.core.internal.logElapsedTime
|
||||||
import net.corda.core.internal.readFully
|
import net.corda.core.internal.readFully
|
||||||
@ -40,9 +48,6 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
import java.util.concurrent.ConcurrentSkipListSet
|
import java.util.concurrent.ConcurrentSkipListSet
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipOutputStream
|
import java.util.zip.ZipOutputStream
|
||||||
import javax.ws.rs.*
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
|
|
||||||
class NodeRegistrationTest {
|
class NodeRegistrationTest {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -43,6 +43,7 @@ dependencies {
|
|||||||
|
|
||||||
// Javax is required for webapis
|
// Javax is required for webapis
|
||||||
implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
||||||
|
implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
|
||||||
implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
|
implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
|
||||||
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
|
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
|
||||||
|
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package net.corda.bank.api
|
package net.corda.bank.api
|
||||||
|
|
||||||
|
import jakarta.ws.rs.Consumes
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.POST
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.contracts.Amount
|
import net.corda.core.contracts.Amount
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -10,9 +17,6 @@ import net.corda.core.utilities.getOrThrow
|
|||||||
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.ws.rs.*
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
|
|
||||||
// API is accessible from /api/bank. All paths specified below are relative to it.
|
// API is accessible from /api/bank. All paths specified below are relative to it.
|
||||||
@Path("bank")
|
@Path("bank")
|
||||||
|
@ -54,6 +54,7 @@ dependencies {
|
|||||||
|
|
||||||
// Javax is required for webapis
|
// Javax is required for webapis
|
||||||
implementation "org.glassfish.jersey.core:jersey-server:$jersey_version"
|
implementation "org.glassfish.jersey.core:jersey-server:$jersey_version"
|
||||||
|
implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
|
||||||
|
|
||||||
// Cordapp dependencies
|
// Cordapp dependencies
|
||||||
// Specify your cordapp's dependencies below, including dependent cordapps
|
// Specify your cordapp's dependencies below, including dependent cordapps
|
||||||
|
@ -80,7 +80,8 @@ tasks.register('generateDependencies') {
|
|||||||
processResources.finalizedBy generateDependencies
|
processResources.finalizedBy generateDependencies
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
archiveClassifier = 'fat'
|
// Test CorDapp filters out *-tests.jar. We only want the shrinked jar not this one.
|
||||||
|
archiveClassifier = 'tests'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('shrink', ProGuardTask) {
|
tasks.register('shrink', ProGuardTask) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import net.corda.plugins.SignJar
|
||||||
|
|
||||||
apply plugin: 'org.jetbrains.kotlin.jvm'
|
apply plugin: 'org.jetbrains.kotlin.jvm'
|
||||||
apply plugin: 'net.corda.plugins.quasar-utils'
|
apply plugin: 'net.corda.plugins.quasar-utils'
|
||||||
apply plugin: 'net.corda.plugins.cordapp'
|
apply plugin: 'net.corda.plugins.cordapp'
|
||||||
@ -15,6 +17,9 @@ cordapp {
|
|||||||
vendor "R3"
|
vendor "R3"
|
||||||
licence "Open Source (Apache 2)"
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
|
signing {
|
||||||
|
enabled false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -43,3 +48,9 @@ dependencies {
|
|||||||
jar {
|
jar {
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('sign', SignJar) {
|
||||||
|
inputJars jar
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.finalizedBy sign
|
@ -15,7 +15,6 @@ import net.corda.vega.api.PortfolioApiUtils
|
|||||||
import net.corda.vega.api.SwapDataModel
|
import net.corda.vega.api.SwapDataModel
|
||||||
import net.corda.vega.api.SwapDataView
|
import net.corda.vega.api.SwapDataView
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -30,7 +29,6 @@ class SimmValuationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(timeout=300_000)
|
@Test(timeout=300_000)
|
||||||
@Ignore("TODO JDK17: Fixme - Stage 2")
|
|
||||||
fun `runs SIMM valuation demo`() {
|
fun `runs SIMM valuation demo`() {
|
||||||
driver(DriverParameters(isDebug = true,
|
driver(DriverParameters(isDebug = true,
|
||||||
startNodesInProcess = false, // starting nodes in separate processes to ensure system class path does not contain 3rd party libraries (masking serialization issues)
|
startNodesInProcess = false, // starting nodes in separate processes to ensure system class path does not contain 3rd party libraries (masking serialization issues)
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
package net.corda.vega.api
|
package net.corda.vega.api
|
||||||
|
|
||||||
import com.opengamma.strata.basics.currency.MultiCurrencyAmount
|
import com.opengamma.strata.basics.currency.MultiCurrencyAmount
|
||||||
|
import jakarta.ws.rs.Consumes
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.POST
|
||||||
|
import jakarta.ws.rs.PUT
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.PathParam
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.utilities.parsePublicKeyBase58
|
import net.corda.core.utilities.parsePublicKeyBase58
|
||||||
import net.corda.core.utilities.toBase58String
|
import net.corda.core.utilities.toBase58String
|
||||||
@ -24,9 +33,6 @@ import net.corda.vega.portfolio.toStateAndRef
|
|||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import javax.ws.rs.*
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
|
|
||||||
//TODO: Change import namespaces vega -> ....
|
//TODO: Change import namespaces vega -> ....
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ dependencies {
|
|||||||
|
|
||||||
// Jetty dependencies for NetworkMapClient test.
|
// Jetty dependencies for NetworkMapClient test.
|
||||||
// Web stuff: for HTTP[S] servlets
|
// Web stuff: for HTTP[S] servlets
|
||||||
implementation "org.eclipse.jetty:jetty-servlet:${jetty_version}"
|
implementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:${jetty_version}"
|
||||||
implementation "org.eclipse.jetty:jetty-webapp:${jetty_version}"
|
implementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:${jetty_version}"
|
||||||
implementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
implementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
||||||
|
|
||||||
implementation "org.gradle:gradle-tooling-api:7.1"
|
implementation "org.gradle:gradle-tooling-api:7.1"
|
||||||
@ -68,6 +68,7 @@ dependencies {
|
|||||||
implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
implementation "org.glassfish.jersey.core:jersey-server:${jersey_version}"
|
||||||
implementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}"
|
implementation "org.glassfish.jersey.containers:jersey-container-servlet-core:${jersey_version}"
|
||||||
implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}"
|
implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:${jersey_version}"
|
||||||
|
implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
|
||||||
|
|
||||||
implementation "io.reactivex:rxjava:$rxjava_version"
|
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||||
implementation("org.apache.activemq:artemis-core-client:${artemis_version}") {
|
implementation("org.apache.activemq:artemis-core-client:${artemis_version}") {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.testing.driver.internal
|
package net.corda.testing.driver.internal
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
@ -14,7 +15,6 @@ import net.corda.testing.driver.OutOfProcess
|
|||||||
import net.corda.testing.node.User
|
import net.corda.testing.node.User
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import javax.validation.constraints.NotNull
|
|
||||||
|
|
||||||
interface NodeHandleInternal : NodeHandle {
|
interface NodeHandleInternal : NodeHandle {
|
||||||
val configuration: NodeConfiguration
|
val configuration: NodeConfiguration
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
package net.corda.testing.node.internal.network
|
package net.corda.testing.node.internal.network
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
import net.corda.core.internal.toX500Name
|
import net.corda.core.internal.toX500Name
|
||||||
@ -24,11 +28,11 @@ import org.bouncycastle.asn1.x509.DistributionPointName
|
|||||||
import org.bouncycastle.asn1.x509.Extension
|
import org.bouncycastle.asn1.x509.Extension
|
||||||
import org.bouncycastle.asn1.x509.GeneralName
|
import org.bouncycastle.asn1.x509.GeneralName
|
||||||
import org.bouncycastle.asn1.x509.GeneralNames
|
import org.bouncycastle.asn1.x509.GeneralNames
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletHolder
|
||||||
import org.eclipse.jetty.server.Server
|
import org.eclipse.jetty.server.Server
|
||||||
import org.eclipse.jetty.server.ServerConnector
|
import org.eclipse.jetty.server.ServerConnector
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
|
||||||
import org.eclipse.jetty.servlet.ServletHolder
|
|
||||||
import org.glassfish.jersey.server.ResourceConfig
|
import org.glassfish.jersey.server.ResourceConfig
|
||||||
import org.glassfish.jersey.servlet.ServletContainer
|
import org.glassfish.jersey.servlet.ServletContainer
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
@ -40,10 +44,6 @@ import java.security.cert.X509Certificate
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.security.auth.x500.X500Principal
|
import javax.security.auth.x500.X500Principal
|
||||||
import javax.ws.rs.GET
|
|
||||||
import javax.ws.rs.Path
|
|
||||||
import javax.ws.rs.Produces
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable {
|
class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable {
|
||||||
@ -79,7 +79,7 @@ class CrlServer(hostAndPort: NetworkHostAndPort) : Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val server: Server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
|
private val server: Server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
|
||||||
handler = HandlerCollection().apply {
|
handler = ContextHandlerCollection().apply {
|
||||||
addHandler(buildServletContextHandler())
|
addHandler(buildServletContextHandler())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
package net.corda.testing.node.internal.network
|
package net.corda.testing.node.internal.network
|
||||||
|
|
||||||
|
import jakarta.ws.rs.Consumes
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.POST
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.PathParam
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
|
import jakarta.ws.rs.core.Response.ok
|
||||||
|
import jakarta.ws.rs.core.Response.status
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -14,11 +24,11 @@ import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
|||||||
import net.corda.nodeapi.internal.network.NetworkMap
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.ParametersUpdate
|
import net.corda.nodeapi.internal.network.ParametersUpdate
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletHolder
|
||||||
import org.eclipse.jetty.server.Server
|
import org.eclipse.jetty.server.Server
|
||||||
import org.eclipse.jetty.server.ServerConnector
|
import org.eclipse.jetty.server.ServerConnector
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
|
||||||
import org.eclipse.jetty.servlet.ServletHolder
|
|
||||||
import org.glassfish.jersey.server.ResourceConfig
|
import org.glassfish.jersey.server.ResourceConfig
|
||||||
import org.glassfish.jersey.servlet.ServletContainer
|
import org.glassfish.jersey.servlet.ServletContainer
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
@ -29,11 +39,6 @@ import java.security.SignatureException
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.ws.rs.*
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
import javax.ws.rs.core.Response.ok
|
|
||||||
import javax.ws.rs.core.Response.status
|
|
||||||
|
|
||||||
class NetworkMapServer(private val pollInterval: Duration,
|
class NetworkMapServer(private val pollInterval: Duration,
|
||||||
hostAndPort: NetworkHostAndPort = NetworkHostAndPort("localhost", 0),
|
hostAndPort: NetworkHostAndPort = NetworkHostAndPort("localhost", 0),
|
||||||
@ -54,7 +59,7 @@ class NetworkMapServer(private val pollInterval: Duration,
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
|
server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
|
||||||
handler = HandlerCollection().apply {
|
handler = ContextHandlerCollection().apply {
|
||||||
addHandler(ServletContextHandler().apply {
|
addHandler(ServletContextHandler().apply {
|
||||||
contextPath = "/"
|
contextPath = "/"
|
||||||
val resourceConfig = ResourceConfig().apply {
|
val resourceConfig = ResourceConfig().apply {
|
||||||
|
@ -31,10 +31,10 @@ dependencies {
|
|||||||
implementation project(":common-logging")
|
implementation project(":common-logging")
|
||||||
|
|
||||||
// Web stuff: for HTTP[S] servlets
|
// Web stuff: for HTTP[S] servlets
|
||||||
implementation "org.eclipse.jetty:jetty-servlet:$jetty_version"
|
implementation "org.eclipse.jetty.ee10:jetty-ee10-servlet:$jetty_version"
|
||||||
implementation "org.eclipse.jetty:jetty-webapp:$jetty_version"
|
implementation "org.eclipse.jetty.ee10:jetty-ee10-webapp:$jetty_version"
|
||||||
implementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
//implementation "javax.servlet:javax.servlet-api:${servlet_version}"
|
||||||
implementation "commons-fileupload:commons-fileupload:$fileupload_version"
|
implementation "org.apache.commons:commons-fileupload2-jakarta:$fileupload_version"
|
||||||
|
|
||||||
// Log4J: logging framework (with SLF4J bindings)
|
// Log4J: logging framework (with SLF4J bindings)
|
||||||
implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version"
|
implementation "org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version"
|
||||||
@ -43,14 +43,11 @@ dependencies {
|
|||||||
// JOpt: for command line flags.
|
// JOpt: for command line flags.
|
||||||
implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
|
implementation "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
|
||||||
|
|
||||||
// Jersey for JAX-RS implementation for use in Jetty
|
|
||||||
// TODO: remove force upgrade when jersey catches up
|
|
||||||
implementation "org.eclipse.jetty:jetty-continuation:${jetty_version}"
|
|
||||||
|
|
||||||
implementation "org.glassfish.jersey.core:jersey-server:$jersey_version"
|
implementation "org.glassfish.jersey.core:jersey-server:$jersey_version"
|
||||||
implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jersey_version"
|
implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jersey_version"
|
||||||
implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:$jersey_version"
|
implementation "org.glassfish.jersey.containers:jersey-container-jetty-http:$jersey_version"
|
||||||
implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version"
|
implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jersey_version"
|
||||||
|
implementation "org.glassfish.jersey.inject:jersey-hk2:$jersey_version"
|
||||||
|
|
||||||
// For rendering the index page.
|
// For rendering the index page.
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.12"
|
implementation "org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.12"
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package net.corda.webserver.api
|
package net.corda.webserver.api
|
||||||
|
|
||||||
|
import jakarta.ws.rs.GET
|
||||||
|
import jakarta.ws.rs.Path
|
||||||
|
import jakarta.ws.rs.Produces
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import javax.ws.rs.GET
|
|
||||||
import javax.ws.rs.Path
|
|
||||||
import javax.ws.rs.Produces
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top level interface to external interaction with the distributed ledger.
|
* Top level interface to external interaction with the distributed ledger.
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.webserver.converters
|
package net.corda.webserver.converters
|
||||||
|
|
||||||
|
import jakarta.ws.rs.ext.ParamConverter
|
||||||
|
import jakarta.ws.rs.ext.ParamConverterProvider
|
||||||
|
import jakarta.ws.rs.ext.Provider
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
import javax.ws.rs.ext.ParamConverter
|
|
||||||
import javax.ws.rs.ext.ParamConverterProvider
|
|
||||||
import javax.ws.rs.ext.Provider
|
|
||||||
|
|
||||||
object CordaX500NameConverter : ParamConverter<CordaX500Name> {
|
object CordaX500NameConverter : ParamConverter<CordaX500Name> {
|
||||||
override fun toString(value: CordaX500Name) = value.toString()
|
override fun toString(value: CordaX500Name) = value.toString()
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package net.corda.webserver.internal
|
package net.corda.webserver.internal
|
||||||
|
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.messaging.vaultQueryBy
|
import net.corda.core.messaging.vaultQueryBy
|
||||||
import net.corda.webserver.api.APIServer
|
import net.corda.webserver.api.APIServer
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
|
|
||||||
class APIServerImpl(val rpcOps: CordaRPCOps) : APIServer {
|
class APIServerImpl(val rpcOps: CordaRPCOps) : APIServer {
|
||||||
override fun serverTime(): LocalDateTime {
|
override fun serverTime(): LocalDateTime {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package net.corda.webserver.internal
|
package net.corda.webserver.internal
|
||||||
|
|
||||||
|
import jakarta.ws.rs.core.Response
|
||||||
|
import jakarta.ws.rs.ext.ExceptionMapper
|
||||||
|
import jakarta.ws.rs.ext.Provider
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import javax.ws.rs.core.Response
|
|
||||||
import javax.ws.rs.ext.ExceptionMapper
|
|
||||||
import javax.ws.rs.ext.Provider
|
|
||||||
|
|
||||||
// Provides basic exception logging to all APIs
|
// Provides basic exception logging to all APIs
|
||||||
@Provider
|
@Provider
|
||||||
|
@ -14,12 +14,12 @@ import net.corda.webserver.WebServerConfig
|
|||||||
import net.corda.webserver.converters.CordaConverterProvider
|
import net.corda.webserver.converters.CordaConverterProvider
|
||||||
import net.corda.webserver.services.WebServerPluginRegistry
|
import net.corda.webserver.services.WebServerPluginRegistry
|
||||||
import net.corda.webserver.servlets.*
|
import net.corda.webserver.servlets.*
|
||||||
|
import org.eclipse.jetty.ee10.servlet.DefaultServlet
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletContextHandler
|
||||||
|
import org.eclipse.jetty.ee10.servlet.ServletHolder
|
||||||
import org.eclipse.jetty.server.*
|
import org.eclipse.jetty.server.*
|
||||||
|
import org.eclipse.jetty.server.handler.ContextHandlerCollection
|
||||||
import org.eclipse.jetty.server.handler.ErrorHandler
|
import org.eclipse.jetty.server.handler.ErrorHandler
|
||||||
import org.eclipse.jetty.server.handler.HandlerCollection
|
|
||||||
import org.eclipse.jetty.servlet.DefaultServlet
|
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler
|
|
||||||
import org.eclipse.jetty.servlet.ServletHolder
|
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory
|
import org.eclipse.jetty.util.ssl.SslContextFactory
|
||||||
import org.glassfish.jersey.server.ResourceConfig
|
import org.glassfish.jersey.server.ResourceConfig
|
||||||
import org.glassfish.jersey.server.ServerProperties
|
import org.glassfish.jersey.server.ServerProperties
|
||||||
@ -30,7 +30,6 @@ import java.io.Writer
|
|||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
import java.net.BindException
|
import java.net.BindException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
|
|
||||||
class NodeWebServer(val config: WebServerConfig) {
|
class NodeWebServer(val config: WebServerConfig) {
|
||||||
private companion object {
|
private companion object {
|
||||||
@ -60,7 +59,7 @@ class NodeWebServer(val config: WebServerConfig) {
|
|||||||
|
|
||||||
private fun initWebServer(localRpc: CordaRPCOps): Server {
|
private fun initWebServer(localRpc: CordaRPCOps): Server {
|
||||||
// Note that the web server handlers will all run concurrently, and not on the node thread.
|
// Note that the web server handlers will all run concurrently, and not on the node thread.
|
||||||
val handlerCollection = HandlerCollection()
|
val handlerCollection = ContextHandlerCollection()
|
||||||
|
|
||||||
// API, data upload and download to services (attachments, rates oracles etc)
|
// API, data upload and download to services (attachments, rates oracles etc)
|
||||||
handlerCollection.addHandler(buildServletContextHandler(localRpc))
|
handlerCollection.addHandler(buildServletContextHandler(localRpc))
|
||||||
@ -72,7 +71,7 @@ class NodeWebServer(val config: WebServerConfig) {
|
|||||||
httpsConfiguration.outputBufferSize = 32768
|
httpsConfiguration.outputBufferSize = 32768
|
||||||
httpsConfiguration.addCustomizer(SecureRequestCustomizer())
|
httpsConfiguration.addCustomizer(SecureRequestCustomizer())
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
val sslContextFactory = SslContextFactory()
|
val sslContextFactory = SslContextFactory.Server()
|
||||||
sslContextFactory.keyStorePath = config.keyStorePath
|
sslContextFactory.keyStorePath = config.keyStorePath
|
||||||
sslContextFactory.setKeyStorePassword(config.keyStorePassword)
|
sslContextFactory.setKeyStorePassword(config.keyStorePassword)
|
||||||
sslContextFactory.setKeyManagerPassword(config.keyStorePassword)
|
sslContextFactory.setKeyManagerPassword(config.keyStorePassword)
|
||||||
@ -118,15 +117,15 @@ class NodeWebServer(val config: WebServerConfig) {
|
|||||||
contextPath = "/"
|
contextPath = "/"
|
||||||
errorHandler = object : ErrorHandler() {
|
errorHandler = object : ErrorHandler() {
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun writeErrorPageHead(request: HttpServletRequest, writer: Writer, code: Int, message: String) {
|
override fun writeErrorHtmlHead(request: Request?, writer: Writer?, code: Int, message: String?) {
|
||||||
writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n")
|
writer?.write("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n")
|
||||||
writer.write("<title>Corda $safeLegalName : Error $code</title>\n")
|
writer?.write("<title>Corda $safeLegalName : Error $code</title>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun writeErrorPageMessage(request: HttpServletRequest, writer: Writer, code: Int, message: String, uri: String) {
|
override fun writeErrorHtmlMessage(request: Request?, writer: Writer?, code: Int, message: String?, cause: Throwable?, uri: String?) {
|
||||||
writer.write("<h1>Corda $safeLegalName</h1>\n")
|
writer?.write("<h1>Corda $safeLegalName</h1>\n")
|
||||||
super.writeErrorPageMessage(request, writer, code, message, uri)
|
super.writeErrorHtmlMessage(request, writer, code, message, cause, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setAttribute("rpc", localRpc)
|
setAttribute("rpc", localRpc)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package net.corda.webserver.servlets
|
package net.corda.webserver.servlets
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServlet
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
|
import jakarta.ws.rs.core.HttpHeaders
|
||||||
|
import jakarta.ws.rs.core.MediaType
|
||||||
import net.corda.core.internal.extractFile
|
import net.corda.core.internal.extractFile
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -8,11 +13,6 @@ import java.io.FileNotFoundException
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
import javax.servlet.http.HttpServlet
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
import javax.servlet.http.HttpServletResponse
|
|
||||||
import javax.ws.rs.core.HttpHeaders
|
|
||||||
import javax.ws.rs.core.MediaType
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows the node administrator to either download full attachment zips, or individual files within those zips.
|
* Allows the node administrator to either download full attachment zips, or individual files within those zips.
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package net.corda.webserver.servlets
|
package net.corda.webserver.servlets
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServlet
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.stream.appendHTML
|
import kotlinx.html.stream.appendHTML
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
@ -7,9 +10,6 @@ import net.corda.webserver.services.WebServerPluginRegistry
|
|||||||
import org.glassfish.jersey.server.model.Resource
|
import org.glassfish.jersey.server.model.Resource
|
||||||
import org.glassfish.jersey.server.model.ResourceMethod
|
import org.glassfish.jersey.server.model.ResourceMethod
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import javax.servlet.http.HttpServlet
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
import javax.servlet.http.HttpServletResponse
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dumps some data about the installed CorDapps.
|
* Dumps some data about the installed CorDapps.
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package net.corda.webserver.servlets
|
package net.corda.webserver.servlets
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServlet
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import net.corda.core.messaging.CordaRPCOps
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload
|
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.servlet.http.HttpServlet
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
import javax.servlet.http.HttpServletResponse
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uploads to the node via the [CordaRPCOps] uploadFile interface.
|
* Uploads to the node via the [CordaRPCOps] uploadFile interface.
|
||||||
@ -19,7 +19,7 @@ class DataUploadServlet : HttpServlet() {
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
|
override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
|
||||||
val isMultipart = ServletFileUpload.isMultipartContent(req)
|
val isMultipart = JakartaServletFileUpload.isMultipartContent(req)
|
||||||
val rpc = servletContext.getAttribute("rpc") as CordaRPCOps
|
val rpc = servletContext.getAttribute("rpc") as CordaRPCOps
|
||||||
|
|
||||||
if (!isMultipart) {
|
if (!isMultipart) {
|
||||||
@ -27,7 +27,7 @@ class DataUploadServlet : HttpServlet() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val upload = ServletFileUpload()
|
val upload = JakartaServletFileUpload()
|
||||||
val iterator = upload.getItemIterator(req)
|
val iterator = upload.getItemIterator(req)
|
||||||
val messages = ArrayList<String>()
|
val messages = ArrayList<String>()
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class DataUploadServlet : HttpServlet() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
messages += rpc.uploadAttachment(item.openStream()).toString()
|
messages += rpc.uploadAttachment(item.inputStream).toString()
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
reportError(e.toString())
|
reportError(e.toString())
|
||||||
continue
|
continue
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.webserver.servlets
|
package net.corda.webserver.servlets
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import javax.ws.rs.ext.ContextResolver
|
import jakarta.ws.rs.ext.ContextResolver
|
||||||
import javax.ws.rs.ext.Provider
|
import jakarta.ws.rs.ext.Provider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Primary purpose is to install Kotlin extensions for Jackson ObjectMapper so data classes work
|
* Primary purpose is to install Kotlin extensions for Jackson ObjectMapper so data classes work
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.corda.webserver.servlets
|
package net.corda.webserver.servlets
|
||||||
|
|
||||||
|
import jakarta.ws.rs.container.ContainerRequestContext
|
||||||
|
import jakarta.ws.rs.container.ContainerResponseContext
|
||||||
|
import jakarta.ws.rs.container.ContainerResponseFilter
|
||||||
|
import jakarta.ws.rs.ext.Provider
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import javax.ws.rs.container.ContainerRequestContext
|
|
||||||
import javax.ws.rs.container.ContainerResponseContext
|
|
||||||
import javax.ws.rs.container.ContainerResponseFilter
|
|
||||||
import javax.ws.rs.ext.Provider
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This adds headers needed for cross site scripting on API clients.
|
* This adds headers needed for cross site scripting on API clients.
|
||||||
|
Loading…
Reference in New Issue
Block a user