Add https support
This commit is contained in:
parent
f8e0cc44f9
commit
0727ced422
17 changed files with 383 additions and 83 deletions
|
@ -10,15 +10,15 @@ import java.util.concurrent.CopyOnWriteArrayList
|
|||
@Slf4j
|
||||
@PackageScope
|
||||
class ContextExecutor {
|
||||
private final HttpServerWraper httpServerWraper
|
||||
private final HttpServerWrapper httpServerWrapper
|
||||
final String path
|
||||
private final List<Mock> mocks
|
||||
|
||||
ContextExecutor(HttpServerWraper httpServerWraper, Mock initialMock) {
|
||||
this.httpServerWraper = httpServerWraper
|
||||
ContextExecutor(HttpServerWrapper httpServerWrapper, Mock initialMock) {
|
||||
this.httpServerWrapper = httpServerWrapper
|
||||
this.path = "/${initialMock.path}"
|
||||
this.mocks = new CopyOnWriteArrayList<>([initialMock])
|
||||
httpServerWraper.createContext(path) {
|
||||
httpServerWrapper.createContext(path) {
|
||||
HttpExchange ex ->
|
||||
try {
|
||||
applyMocks(ex)
|
||||
|
|
|
@ -2,6 +2,7 @@ package pl.touk.mockserver.server
|
|||
|
||||
import com.sun.net.httpserver.HttpExchange
|
||||
import groovy.util.logging.Slf4j
|
||||
import pl.touk.mockserver.api.common.Https
|
||||
import pl.touk.mockserver.api.common.ImportAlias
|
||||
import pl.touk.mockserver.api.common.Method
|
||||
import pl.touk.mockserver.api.request.AddMock
|
||||
|
@ -30,8 +31,8 @@ import static pl.touk.mockserver.server.Util.createResponse
|
|||
@Slf4j
|
||||
class HttpMockServer {
|
||||
|
||||
private final HttpServerWraper httpServerWraper
|
||||
private final Map<Integer, HttpServerWraper> childServers = new ConcurrentHashMap<>()
|
||||
private final HttpServerWrapper httpServerWrapper
|
||||
private final Map<Integer, HttpServerWrapper> childServers = new ConcurrentHashMap<>()
|
||||
private final Set<String> mockNames = new CopyOnWriteArraySet<>()
|
||||
private final ConfigObject configuration = new ConfigObject()
|
||||
private final Executor executor
|
||||
|
@ -41,13 +42,13 @@ class HttpMockServer {
|
|||
|
||||
HttpMockServer(int port = 9999, ConfigObject initialConfiguration = new ConfigObject(), int threads = 10) {
|
||||
executor = Executors.newFixedThreadPool(threads)
|
||||
httpServerWraper = new HttpServerWraper(port, executor)
|
||||
httpServerWrapper = new HttpServerWrapper(port, executor)
|
||||
|
||||
initialConfiguration.values()?.each { ConfigObject co ->
|
||||
addMock(co)
|
||||
}
|
||||
|
||||
httpServerWraper.createContext('/serverControl', {
|
||||
httpServerWrapper.createContext('/serverControl', {
|
||||
HttpExchange ex ->
|
||||
try {
|
||||
if (ex.requestMethod == 'GET') {
|
||||
|
@ -108,7 +109,7 @@ class HttpMockServer {
|
|||
throw new RuntimeException('mock already registered')
|
||||
}
|
||||
Mock mock = mockFromRequest(request)
|
||||
HttpServerWraper child = getOrCreateChildServer(mock.port)
|
||||
HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
|
||||
child.addMock(mock)
|
||||
saveConfiguration(request)
|
||||
mockNames << name
|
||||
|
@ -121,7 +122,7 @@ class HttpMockServer {
|
|||
throw new RuntimeException('mock already registered')
|
||||
}
|
||||
Mock mock = mockFromConfig(co)
|
||||
HttpServerWraper child = getOrCreateChildServer(mock.port)
|
||||
HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
|
||||
child.addMock(mock)
|
||||
configuration.put(name, co)
|
||||
mockNames << name
|
||||
|
@ -156,6 +157,7 @@ class HttpMockServer {
|
|||
mock.responseHeaders = request.responseHeaders
|
||||
mock.schema = request.schema
|
||||
mock.preserveHistory = request.preserveHistory != false
|
||||
mock.https = request.https
|
||||
return mock
|
||||
}
|
||||
|
||||
|
@ -170,13 +172,23 @@ class HttpMockServer {
|
|||
mock.responseHeaders = co.responseHeaders ?: null
|
||||
mock.schema = co.schema ?: null
|
||||
mock.preserveHistory = co.preserveHistory != false
|
||||
if (co.https) {
|
||||
mock.https = new Https(
|
||||
keystorePath: co.https.keystorePath ?: null,
|
||||
keystorePassword: co.https.keystorePassword,
|
||||
keyPassword: co.https.keyPassword,
|
||||
truststorePath: co.https.truststorePath,
|
||||
truststorePassword: co.https.truststorePassword,
|
||||
requireClientAuth: co.https?.requireClientAuth?.asBoolean() ?: false
|
||||
)
|
||||
}
|
||||
return mock
|
||||
}
|
||||
|
||||
private HttpServerWraper getOrCreateChildServer(int mockPort) {
|
||||
HttpServerWraper child = childServers[mockPort]
|
||||
private HttpServerWrapper getOrCreateChildServer(int mockPort, Https https) {
|
||||
HttpServerWrapper child = childServers[mockPort]
|
||||
if (!child) {
|
||||
child = new HttpServerWraper(mockPort, executor)
|
||||
child = new HttpServerWrapper(mockPort, executor, https)
|
||||
childServers.put(mockPort, child)
|
||||
}
|
||||
return child
|
||||
|
@ -244,6 +256,6 @@ class HttpMockServer {
|
|||
|
||||
void stop() {
|
||||
childServers.values().each { it.stop() }
|
||||
httpServerWraper.stop()
|
||||
httpServerWrapper.stop()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler
|
||||
import com.sun.net.httpserver.HttpServer
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class HttpServerWraper {
|
||||
private final HttpServer httpServer
|
||||
final int port
|
||||
|
||||
private List<ContextExecutor> executors = []
|
||||
|
||||
HttpServerWraper(int port, Executor executor) {
|
||||
this.port = port
|
||||
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
|
||||
httpServer = HttpServer.create(addr, 0)
|
||||
httpServer.executor = executor
|
||||
log.info("Http server starting on port $port...")
|
||||
httpServer.start()
|
||||
log.info('Http server is started')
|
||||
}
|
||||
|
||||
void createContext(String context, HttpHandler handler) {
|
||||
httpServer.createContext(context, handler)
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
ContextExecutor executor = executors.find { it.path == mock.path }
|
||||
if (executor) {
|
||||
executor.addMock(mock)
|
||||
} else {
|
||||
executors << new ContextExecutor(this, mock)
|
||||
}
|
||||
log.info("Added mock ${mock.name}")
|
||||
}
|
||||
|
||||
void stop() {
|
||||
executors.each { httpServer.removeContext(it.contextPath) }
|
||||
httpServer.stop(0)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
return executors.collect { it.removeMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
return executors.collect { it.peekMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return executors.collect { it.mocks }.flatten() as List<Mock>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpHandler
|
||||
import com.sun.net.httpserver.HttpServer
|
||||
import com.sun.net.httpserver.HttpsServer
|
||||
import groovy.transform.PackageScope
|
||||
import groovy.util.logging.Slf4j
|
||||
import pl.touk.mockserver.api.common.Https
|
||||
|
||||
import javax.net.ssl.KeyManager
|
||||
import javax.net.ssl.KeyManagerFactory
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManager
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
import java.security.KeyStore
|
||||
import java.security.SecureRandom
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
@Slf4j
|
||||
@PackageScope
|
||||
class HttpServerWrapper {
|
||||
private final HttpServer httpServer
|
||||
final int port
|
||||
|
||||
private List<ContextExecutor> executors = []
|
||||
|
||||
HttpServerWrapper(int port, Executor executor, Https https = null) {
|
||||
this.port = port
|
||||
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
|
||||
httpServer = buildServer(addr, https)
|
||||
httpServer.executor = executor
|
||||
log.info("Http server starting on port $port...")
|
||||
httpServer.start()
|
||||
log.info('Http server is started')
|
||||
}
|
||||
|
||||
private HttpServer buildServer(InetSocketAddress addr, Https https) {
|
||||
if (https) {
|
||||
HttpsServer httpsServer = HttpsServer.create(addr, 0)
|
||||
httpsServer.httpsConfigurator = new HttpsConfig(buildSslContext(https), https)
|
||||
return httpsServer
|
||||
} else {
|
||||
return HttpServer.create(addr, 0)
|
||||
}
|
||||
}
|
||||
|
||||
private SSLContext buildSslContext(Https https) {
|
||||
KeyManager[] keyManagers = buildKeyManager(https)
|
||||
TrustManager[] trustManagers = buildTrustManager(https)
|
||||
|
||||
SSLContext ssl = SSLContext.getInstance('TLSv1')
|
||||
ssl.init(keyManagers, trustManagers, new SecureRandom())
|
||||
return ssl
|
||||
}
|
||||
|
||||
private KeyManager[] buildKeyManager(Https https) {
|
||||
KeyStore keyStore = KeyStore.getInstance('jks')
|
||||
keyStore.load(new FileInputStream(https.keystorePath), https.keystorePassword.toCharArray())
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.defaultAlgorithm)
|
||||
kmf.init(keyStore, https.keyPassword.toCharArray())
|
||||
return kmf.keyManagers
|
||||
}
|
||||
|
||||
private TrustManager[] buildTrustManager(Https https) {
|
||||
if (https.requireClientAuth) {
|
||||
KeyStore trustStore = KeyStore.getInstance('jks')
|
||||
trustStore.load(new FileInputStream(https.truststorePath), https.truststorePassword.toCharArray())
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.defaultAlgorithm)
|
||||
tmf.init(trustStore)
|
||||
return tmf.trustManagers
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
void createContext(String context, HttpHandler handler) {
|
||||
httpServer.createContext(context, handler)
|
||||
}
|
||||
|
||||
void addMock(Mock mock) {
|
||||
ContextExecutor executor = executors.find { it.path == mock.path }
|
||||
if (executor) {
|
||||
executor.addMock(mock)
|
||||
} else {
|
||||
executors << new ContextExecutor(this, mock)
|
||||
}
|
||||
log.info("Added mock ${mock.name}")
|
||||
}
|
||||
|
||||
void stop() {
|
||||
executors.each { httpServer.removeContext(it.contextPath) }
|
||||
httpServer.stop(0)
|
||||
}
|
||||
|
||||
List<MockEvent> removeMock(String name) {
|
||||
return executors.collect { it.removeMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<MockEvent> peekMock(String name) {
|
||||
return executors.collect { it.peekMock(name) }.flatten() as List<MockEvent>
|
||||
}
|
||||
|
||||
List<Mock> getMocks() {
|
||||
return executors.collect { it.mocks }.flatten() as List<Mock>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package pl.touk.mockserver.server
|
||||
|
||||
import com.sun.net.httpserver.HttpsConfigurator
|
||||
import com.sun.net.httpserver.HttpsParameters
|
||||
import groovy.transform.CompileStatic
|
||||
import pl.touk.mockserver.api.common.Https
|
||||
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLParameters
|
||||
|
||||
@CompileStatic
|
||||
class HttpsConfig extends HttpsConfigurator {
|
||||
private final Https https
|
||||
|
||||
HttpsConfig(SSLContext sslContext, Https https) {
|
||||
super(sslContext)
|
||||
this.https = https
|
||||
}
|
||||
|
||||
@Override
|
||||
void configure(HttpsParameters httpsParameters) {
|
||||
SSLContext sslContext = getSSLContext()
|
||||
SSLParameters sslParameters = sslContext.defaultSSLParameters
|
||||
sslParameters.needClientAuth = https.requireClientAuth
|
||||
httpsParameters.needClientAuth = https.requireClientAuth
|
||||
httpsParameters.SSLParameters = sslParameters
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import groovy.transform.PackageScope
|
|||
import groovy.util.logging.Slf4j
|
||||
import org.codehaus.groovy.control.CompilerConfiguration
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer
|
||||
import pl.touk.mockserver.api.common.Https
|
||||
import pl.touk.mockserver.api.common.Method
|
||||
|
||||
import javax.xml.XMLConstants
|
||||
|
@ -35,6 +36,7 @@ class Mock implements Comparable<Mock> {
|
|||
private Validator validator
|
||||
Map<String, String> imports = [:]
|
||||
boolean preserveHistory = true
|
||||
Https https
|
||||
|
||||
Mock(String name, String path, int port) {
|
||||
if (!(name)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue