diff --git a/.gitignore b/.gitignore
index 2165313e71..bc8a1f650d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,4 @@ notes.txt
# MINE #
Guide.txt
docker
+src/main/resources/wiremock-gui-version.properties
diff --git a/.idea/icon.svg b/.idea/icon.svg
new file mode 100644
index 0000000000..20788b6866
--- /dev/null
+++ b/.idea/icon.svg
@@ -0,0 +1,87 @@
+
+
diff --git a/build.gradle b/build.gradle
index 3311a8ca6b..b77d97947c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,6 +12,7 @@ buildscript {
plugins {
id 'java-library'
+ id 'java-test-fixtures'
id 'scala'
id 'signing'
id 'maven-publish'
@@ -23,7 +24,8 @@ plugins {
id 'com.github.johnrengelman.shadow' version '8.1.1'
id "org.sonarqube" version "4.4.1.3373"
id 'jacoco'
- id 'com.github.node-gradle.node' version '7.0.1'
+ id "me.champeau.jmh" version "0.7.2"
+ id 'com.github.node-gradle.node' version '7.0.2'
}
group = 'org.wiremock'
@@ -32,8 +34,8 @@ project.ext {
versions = [
handlebars : '4.3.1',
jetty : '11.0.20',
- guava : '33.0.0-jre',
- jackson : '2.16.1',
+ guava : '33.1.0-jre',
+ jackson : '2.17.0',
xmlUnit : '2.9.1',
jsonUnit : '2.38.0',
junitJupiter: '5.10.2'
@@ -58,7 +60,7 @@ dependencies {
api "org.eclipse.jetty:jetty-alpn-java-client"
api "org.eclipse.jetty:jetty-alpn-client"
- api "org.eclipse.jetty.websocket:websocket-jakarta-server"
+ api "org.eclipse.jetty.websocket:websocket-jakarta-server:$versions.jetty"
api "io.jsonwebtoken:jjwt-api:0.11.5"
api "io.jsonwebtoken:jjwt-impl:0.11.5"
@@ -83,7 +85,6 @@ dependencies {
api "com.jayway.jsonpath:json-path:2.9.0", {
exclude group: 'org.ow2.asm', module: 'asm'
}
- api "org.ow2.asm:asm:9.6"
implementation "org.slf4j:slf4j-api:1.7.36"
standaloneOnly "org.slf4j:slf4j-nop:1.7.36"
@@ -96,60 +97,52 @@ dependencies {
compileOnly(platform("org.junit:junit-bom:$versions.junitJupiter"))
compileOnly("org.junit.jupiter:junit-jupiter")
- api 'org.apache.commons:commons-lang3:3.14.0'
api "com.github.jknack:handlebars:$versions.handlebars", {
exclude group: 'org.mozilla', module: 'rhino'
}
api("com.github.jknack:handlebars-helpers:$versions.handlebars") {
exclude group: 'org.mozilla', module: 'rhino'
+ exclude group: 'org.apache.commons', module: 'commons-lang3'
}
api 'commons-fileupload:commons-fileupload:1.5', {
exclude group: 'commons-io', module: 'commons-io'
}
- api "commons-io:commons-io:2.15.1"
-
- api 'com.networknt:json-schema-validator:1.3.3'
-
- testImplementation "junit:junit:4.13"
- testImplementation("org.junit.jupiter:junit-jupiter:$versions.junitJupiter")
- testImplementation("org.junit.platform:junit-platform-testkit")
+ api "commons-io:commons-io:2.16.0"
+
+ api 'com.networknt:json-schema-validator:1.4.0'
+
+ testFixturesApi("org.junit.jupiter:junit-jupiter:$versions.junitJupiter")
+ testFixturesApi("org.junit.platform:junit-platform-testkit")
+ testFixturesApi("org.junit.platform:junit-platform-launcher")
+ testFixturesApi("org.junit.jupiter:junit-jupiter-params")
+ testFixturesApi('org.junit-pioneer:junit-pioneer:2.2.0')
+ testFixturesApi "org.hamcrest:hamcrest-core:2.2"
+ testFixturesApi "org.hamcrest:hamcrest-library:2.2"
+ testFixturesApi 'org.mockito:mockito-core:5.11.0'
+ testFixturesApi 'org.mockito:mockito-junit-jupiter:5.11.0'
+ testFixturesApi "net.javacrumbs.json-unit:json-unit:$versions.jsonUnit"
+ testFixturesApi "org.skyscreamer:jsonassert:1.5.1"
+ testFixturesApi 'com.toomuchcoding.jsonassert:jsonassert:0.8.0'
+ testFixturesApi 'org.awaitility:awaitility:4.2.1'
+ testFixturesApi "commons-io:commons-io:2.16.0"
+
+ testImplementation "junit:junit:4.13.2"
testRuntimeOnly("org.junit.vintage:junit-vintage-engine")
- testImplementation("org.junit.platform:junit-platform-launcher")
- testImplementation("org.junit.jupiter:junit-jupiter-params")
- testImplementation('org.junit-pioneer:junit-pioneer:2.2.0')
-
- testImplementation "org.hamcrest:hamcrest-core:2.2"
- testImplementation "org.hamcrest:hamcrest-library:2.2"
- testImplementation 'org.mockito:mockito-core:5.10.0'
- testImplementation 'org.mockito:mockito-junit-jupiter:5.10.0'
- testImplementation "net.javacrumbs.json-unit:json-unit:$versions.jsonUnit"
- testImplementation "org.skyscreamer:jsonassert:1.2.3"
- testImplementation 'com.toomuchcoding.jsonassert:jsonassert:0.8.0'
- testImplementation 'org.awaitility:awaitility:4.2.0'
- testImplementation "com.googlecode.jarjar:jarjar:1.3"
- testImplementation "commons-io:commons-io:2.15.1"
testImplementation 'org.scala-lang:scala-library:2.13.13'
testImplementation 'com.tngtech.archunit:archunit-junit5:0.23.1'
testImplementation "org.eclipse.jetty:jetty-client"
testImplementation "org.eclipse.jetty.http2:http2-http-client-transport"
- testRuntimeOnly "org.slf4j:log4j-over-slf4j:2.0.12"
- testRuntimeOnly "ch.qos.logback:logback-classic:1.4.0"
testRuntimeOnly files('src/test/resources/classpath file source/classpathfiles.zip', 'src/test/resources/classpath-filesource.jar')
- testImplementation('net.jockx:littleproxy:1.1.3') {
- exclude group: 'com.google.guava', module: 'guava'
- exclude group: 'org.apache.commons', module: 'commons-lang3'
- exclude group: 'org.slf4j', module: 'slf4j-api'
- exclude group: 'io.netty', module: 'netty-all'
- }
- testImplementation "io.netty:netty-all:4.1.107.Final"
-
testImplementation files('test-extension/test-extension.jar')
+ testImplementation 'org.openjdk.jmh:jmh-core:1.37'
+ testImplementation 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
+
constraints {
- implementation "net.minidev:json-smart:2.5.0", {
+ implementation "net.minidev:json-smart:2.5.1", {
because 'Pinning this above the transitive version from json-path to get CVE fix'
}
}
@@ -226,10 +219,6 @@ allprojects {
version = '1.0.0-Snapshot'
}
-
- sourceCompatibility = 11
- targetCompatibility = 11
-
compileJava {
options.encoding = 'UTF-8'
@@ -244,6 +233,10 @@ allprojects {
options.compilerArgs += '--add-exports=java.base/sun.security.x509=ALL-UNNAMED'
}
+ compileTestFixturesJava {
+ options.encoding = 'UTF-8'
+ }
+
test {
// Set the timezone for testing somewhere other than my machine to increase the chances of catching timezone bugs
systemProperty 'user.timezone', 'Australia/Sydney'
@@ -277,7 +270,11 @@ allprojects {
shadowJar.dependsOn jar
}
+test.classpath += sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath
+
java {
+ sourceCompatibility = 11
+ targetCompatibility = 11
withSourcesJar()
withJavadocJar()
}
@@ -376,36 +373,55 @@ publishing {
}
}
+ components.java.withVariantsFromConfiguration(configurations.testFixturesApiElements) { skip() }
+ components.java.withVariantsFromConfiguration(configurations.testFixturesRuntimeElements) { skip() }
+
getComponents().withType(AdhocComponentWithVariants).each { c ->
c.withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
- publications {
- mavenJava(MavenPublication) { publication ->
- artifactId = "${jar.getArchiveBaseName().get()}"
- from components.java
- artifact testJar
+ if (JavaVersion.current().isJava11()) {
+ publications {
+ mavenJava(MavenPublication) { publication ->
+ artifactId = "${jar.getArchiveBaseName().get()}"
+ from components.java
+ artifact testJar
- pom.withXml {
- asNode().appendNode('description', 'A web service test double for all occasions')
- asNode().children().last() + pomInfo
+ pom.withXml {
+ asNode().appendNode('description', 'A web service test double for all occasions')
+ asNode().children().last() + pomInfo
+ }
}
- }
- standaloneJar(MavenPublication) { publication ->
- artifactId = "${jar.getArchiveBaseName().get()}-standalone"
- project.shadow.component(publication)
+ standaloneJar(MavenPublication) { publication ->
+ artifactId = "${jar.getArchiveBaseName().get()}-standalone"
+ project.shadow.component(publication)
- artifact sourcesJar
- artifact javadocJar
- artifact testJar
+ artifact sourcesJar
+ artifact javadocJar
+ artifact testJar
- pom.packaging 'jar'
- pom.withXml {
- asNode().appendNode('description', 'A web service test double for all occasions - standalone edition')
- asNode().children().last() + pomInfo
+ pom.packaging 'jar'
+ pom.withXml {
+ asNode().appendNode('description', 'A web service test double for all occasions - standalone edition')
+ asNode().children().last() + pomInfo
+ }
+ }
+ }
+ }
+
+ nexusPublishing {
+ // See https://github.com/wiremock/community/blob/main/infra/maven-central.md
+ repositories {
+ sonatype {
+ def envUsername = providers.environmentVariable("OSSRH_USERNAME").orElse("").get()
+ def envPassword = providers.environmentVariable("OSSRH_TOKEN").orElse("").get()
+ if (!envUsername.isEmpty() && !envPassword.isEmpty()) {
+ username.set(envUsername)
+ password.set(envPassword)
+ }
}
}
}
@@ -416,7 +432,6 @@ task checkReleasePreconditions {
def REQUIRED_GIT_BRANCH = 'master'
def currentGitBranch = 'git rev-parse --abbrev-ref HEAD'.execute().text.trim()
assert currentGitBranch == REQUIRED_GIT_BRANCH, "Must be on the $REQUIRED_GIT_BRANCH branch in order to release to Sonatype"
- assert JavaVersion.current().isJava11(), 'Must use Java 8 when releasing'
}
}
@@ -443,8 +458,21 @@ task generateWebapp(type: NpmTask) {
args = ['run', 'prod']
}
-task finalizeWebapp(type: Copy) {
+task versionTxt() {
dependsOn generateWebapp
+ doLast {
+ def wiremockVersionProps = new Properties()
+ wiremockVersionProps.load(new FileInputStream(projectDir.getAbsolutePath() + "/src/main/resources/version.properties"))
+ def wiremockVersion = wiremockVersionProps.getProperty("version")
+ new File(projectDir.getAbsolutePath() + "/src/main/resources", "wiremock-gui-version.properties").text = """# version file
+gui-version=$version
+version=$wiremockVersion
+"""
+ }
+}
+
+task finalizeWebapp(type: Copy) {
+ dependsOn versionTxt
// Because of: https://github.com/angular/angular-cli/issues/26304
// we need to copy some things around.
from 'webapp/wiremock/dist/browser'
@@ -593,3 +621,8 @@ wrapper {
gradleVersion = '8.6'
distributionType = Wrapper.DistributionType.BIN
}
+
+jmh {
+ includes = ['.*benchmarks.*']
+ threads = 50
+}
diff --git a/perf-test/src/main/java/wiremock/LoadTestConfiguration.java b/perf-test/src/main/java/wiremock/LoadTestConfiguration.java
index c3c5943e5d..50233ad017 100644
--- a/perf-test/src/main/java/wiremock/LoadTestConfiguration.java
+++ b/perf-test/src/main/java/wiremock/LoadTestConfiguration.java
@@ -20,7 +20,6 @@
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.apache.commons.lang3.RandomStringUtils.randomAscii;
public class LoadTestConfiguration {
diff --git a/sample-war/src/main/webappCustomMapping/WEB-INF/wiremock/__files/.gitignore b/sample-war/src/main/webappCustomMapping/WEB-INF/wiremock/__files/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/sample-war/src/main/webappLimitedRequestJournal/WEB-INF/wiremock/__files/.gitignore b/sample-war/src/main/webappLimitedRequestJournal/WEB-INF/wiremock/__files/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/settings.gradle b/settings.gradle
index 39952cb59f..9faf3ef478 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1,4 @@
rootProject.name = 'wiremock'
+if (JavaVersion.current() >= JavaVersion.VERSION_17) {
+ include 'wiremock-jetty12'
+}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/WireMockServer.java b/src/main/java/com/github/tomakehurst/wiremock/WireMockServer.java
index d0937a9e52..37c8f485f1 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/WireMockServer.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/WireMockServer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2023 Thomas Akehurst
+ * Copyright (C) 2011-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
import com.github.tomakehurst.wiremock.core.Container;
import com.github.tomakehurst.wiremock.core.Options;
import com.github.tomakehurst.wiremock.core.WireMockApp;
+import com.github.tomakehurst.wiremock.extension.Extension;
import com.github.tomakehurst.wiremock.global.GlobalSettings;
import com.github.tomakehurst.wiremock.http.HttpServer;
import com.github.tomakehurst.wiremock.http.HttpServerFactory;
@@ -49,8 +50,10 @@
import com.github.tomakehurst.wiremock.stubbing.StubMappingJsonRecorder;
import com.github.tomakehurst.wiremock.verification.*;
import java.util.List;
+import java.util.ServiceLoader;
import java.util.Set;
import java.util.UUID;
+import org.eclipse.jetty.util.Jetty;
public class WireMockServer implements Container, Stubbing, Admin {
@@ -72,10 +75,7 @@ public WireMockServer(Options options) {
this.stubRequestHandler = wireMockApp.buildStubRequestHandler();
- HttpServerFactory httpServerFactory =
- wireMockApp.getExtensions().ofType(HttpServerFactory.class).values().stream()
- .findFirst()
- .orElseGet(options::httpServerFactory);
+ HttpServerFactory httpServerFactory = getHttpServerFactory();
httpServer =
httpServerFactory.buildHttpServer(
@@ -84,6 +84,31 @@ public WireMockServer(Options options) {
client = new WireMock(wireMockApp);
}
+ private HttpServerFactory getHttpServerFactory() {
+ if (!options.isExtensionScanningEnabled() && !isJetty11()) {
+ return ServiceLoader.load(Extension.class).stream()
+ .filter(extension -> HttpServerFactory.class.isAssignableFrom(extension.type()))
+ .findFirst()
+ .map(e -> (HttpServerFactory) e.get())
+ .orElseThrow(
+ () ->
+ new FatalStartupException(
+ "Jetty 11 is not present and no suitable HttpServerFactory extension was found. Please ensure that the classpath includes a WireMock extension that provides an HttpServerFactory implementation. See http://wiremock.org/docs/extending-wiremock/ for more information."));
+ }
+
+ return wireMockApp.getExtensions().ofType(HttpServerFactory.class).values().stream()
+ .findFirst()
+ .orElseGet(options::httpServerFactory);
+ }
+
+ private static boolean isJetty11() {
+ try {
+ return Jetty.VERSION.startsWith("11");
+ } catch (Throwable e) {
+ return false;
+ }
+ }
+
public WireMockServer(
int port,
Integer httpsPort,
@@ -259,6 +284,11 @@ public void removeStub(StubMapping stubMapping) {
client.removeStubMapping(stubMapping);
}
+ @Override
+ public void removeStub(UUID id) {
+ client.removeStubMapping(id);
+ }
+
@Override
public List getStubMappings() {
return client.allStubMappings().getMappings();
diff --git a/src/main/java/com/github/tomakehurst/wiremock/admin/model/VersionResult.java b/src/main/java/com/github/tomakehurst/wiremock/admin/model/VersionResult.java
index ed3e2c75cd..e79a2fdb94 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/admin/model/VersionResult.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/admin/model/VersionResult.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,11 +18,18 @@
public class VersionResult {
private final String version;
- public VersionResult(String version) {
+ private final String guiVersion;
+
+ public VersionResult(String version, String guiVersion) {
this.version = version;
+ this.guiVersion = guiVersion;
}
public String getVersion() {
return version;
}
+
+ public String getGuiVersion() {
+ return guiVersion;
+ }
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/admin/tasks/GetVersionTask.java b/src/main/java/com/github/tomakehurst/wiremock/admin/tasks/GetVersionTask.java
index f9aaa4d55e..2066f24697 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/admin/tasks/GetVersionTask.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/admin/tasks/GetVersionTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ public ResponseDefinition execute(Admin admin, ServeEvent serveEvent, PathParams
.build();
}
- var versionResult = new VersionResult(Version.getCurrentVersion());
+ var versionResult = new VersionResult(Version.getCurrentVersion(), Version.getGuiVersion());
return jsonResponse(versionResult);
}
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/client/HttpAdminClient.java b/src/main/java/com/github/tomakehurst/wiremock/client/HttpAdminClient.java
index e4a7672e71..2f84211456 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/client/HttpAdminClient.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/client/HttpAdminClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2023 Thomas Akehurst
+ * Copyright (C) 2011-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
import static com.github.tomakehurst.wiremock.common.HttpClientUtils.getEntityAsStringAndCloseStream;
+import static com.github.tomakehurst.wiremock.common.Strings.isNotBlank;
import static com.github.tomakehurst.wiremock.security.NoClientAuthenticator.noClientAuthenticator;
import static java.util.Objects.requireNonNull;
import static org.apache.hc.core5.http.HttpHeaders.HOST;
@@ -49,7 +50,6 @@
import java.util.List;
import java.util.Optional;
import java.util.UUID;
-import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpPut;
@@ -454,7 +454,7 @@ public int port() {
}
private ProxySettings createProxySettings(String proxyHost, int proxyPort) {
- if (StringUtils.isNotBlank(proxyHost)) {
+ if (isNotBlank(proxyHost)) {
return new ProxySettings(proxyHost, proxyPort);
}
return ProxySettings.NO_PROXY;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/client/ResponseDefinitionBuilder.java b/src/main/java/com/github/tomakehurst/wiremock/client/ResponseDefinitionBuilder.java
index f687cce246..bcdd05f476 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/client/ResponseDefinitionBuilder.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/client/ResponseDefinitionBuilder.java
@@ -79,6 +79,10 @@ public static ResponseDefinitionBuilder like(ResponseDefinition responseDefiniti
responseDefinition.getAdditionalProxyRequestHeaders() != null
? (List) responseDefinition.getAdditionalProxyRequestHeaders().all()
: new ArrayList<>();
+ proxyResponseDefinitionBuilder.removeRequestHeaders =
+ responseDefinition.getRemoveProxyRequestHeaders() != null
+ ? responseDefinition.getRemoveProxyRequestHeaders()
+ : new ArrayList<>();
return proxyResponseDefinitionBuilder;
}
@@ -232,6 +236,7 @@ public ResponseDefinitionBuilder withStatusMessage(String message) {
public static class ProxyResponseDefinitionBuilder extends ResponseDefinitionBuilder {
private List additionalRequestHeaders = new ArrayList<>();
+ private List removeRequestHeaders = new ArrayList<>();
public ProxyResponseDefinitionBuilder(ResponseDefinitionBuilder from) {
this.status = from.status;
@@ -254,6 +259,11 @@ public ProxyResponseDefinitionBuilder withAdditionalRequestHeader(String key, St
return this;
}
+ public ProxyResponseDefinitionBuilder withRemoveRequestHeader(String key) {
+ removeRequestHeaders.add(key.toLowerCase());
+ return this;
+ }
+
public ProxyResponseDefinitionBuilder withProxyUrlPrefixToRemove(
String proxyUrlPrefixToRemove) {
this.proxyUrlPrefixToRemove = proxyUrlPrefixToRemove;
@@ -264,6 +274,7 @@ public ProxyResponseDefinitionBuilder withProxyUrlPrefixToRemove(
public ResponseDefinition build() {
return super.build(
!additionalRequestHeaders.isEmpty() ? new HttpHeaders(additionalRequestHeaders) : null,
+ !removeRequestHeaders.isEmpty() ? removeRequestHeaders : null,
proxyUrlPrefixToRemove);
}
}
@@ -274,11 +285,13 @@ public ResponseDefinitionBuilder withFault(Fault fault) {
}
public ResponseDefinition build() {
- return build(null, null);
+ return build(null, null, null);
}
protected ResponseDefinition build(
- HttpHeaders additionalProxyRequestHeaders, String proxyUrlPrefixToRemove) {
+ HttpHeaders additionalProxyRequestHeaders,
+ List removeProxyRequestHeaders,
+ String proxyUrlPrefixToRemove) {
HttpHeaders httpHeaders =
headers == null || headers.isEmpty() ? null : new HttpHeaders(headers);
Parameters transformerParameters =
@@ -292,6 +305,7 @@ protected ResponseDefinition build(
bodyFileName,
httpHeaders,
additionalProxyRequestHeaders,
+ removeProxyRequestHeaders,
fixedDelayMilliseconds,
delayDistribution,
chunkedDribbleDelay,
diff --git a/src/main/java/com/github/tomakehurst/wiremock/client/WireMock.java b/src/main/java/com/github/tomakehurst/wiremock/client/WireMock.java
index 9a3b28f227..6860f86d68 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/client/WireMock.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/client/WireMock.java
@@ -146,6 +146,10 @@ public static void removeStub(StubMapping stubMapping) {
defaultInstance.get().removeStubMapping(stubMapping);
}
+ public static void removeStub(UUID id) {
+ defaultInstance.get().removeStubMapping(id);
+ }
+
public static ListStubMappingsResult listAllStubMappings() {
return defaultInstance.get().allStubMappings();
}
@@ -458,6 +462,10 @@ public void removeStubMapping(StubMapping stubMapping) {
admin.removeStubMapping(stubMapping);
}
+ public void removeStubMapping(UUID id) {
+ admin.removeStubMapping(id);
+ }
+
public ListStubMappingsResult allStubMappings() {
return admin.listAllStubMappings();
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/ContentTypes.java b/src/main/java/com/github/tomakehurst/wiremock/common/ContentTypes.java
index 05a70e5e4c..3541e0a29f 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/ContentTypes.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/ContentTypes.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2023 Thomas Akehurst
+ * Copyright (C) 2016-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,9 @@
package com.github.tomakehurst.wiremock.common;
import static com.github.tomakehurst.wiremock.common.Strings.stringFromBytes;
+import static com.github.tomakehurst.wiremock.common.Strings.substringAfterLast;
import static com.github.tomakehurst.wiremock.common.TextType.JSON;
import static java.util.Arrays.asList;
-import static org.apache.commons.lang3.StringUtils.substringAfterLast;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.tomakehurst.wiremock.common.xml.Xml;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/FatalStartupException.java b/src/main/java/com/github/tomakehurst/wiremock/common/FatalStartupException.java
index 9a3f786b21..c64fa9ac41 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/FatalStartupException.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/FatalStartupException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2021 Thomas Akehurst
+ * Copyright (C) 2011-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,10 @@
public class FatalStartupException extends RuntimeException {
+ public FatalStartupException(String message) {
+ super(message);
+ }
+
public FatalStartupException(Throwable cause) {
super(cause);
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/Gzip.java b/src/main/java/com/github/tomakehurst/wiremock/common/Gzip.java
index 604fb85361..376f7e80f8 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/Gzip.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/Gzip.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2023 Thomas Akehurst
+ * Copyright (C) 2015-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package com.github.tomakehurst.wiremock.common;
import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
-import static com.github.tomakehurst.wiremock.common.Strings.DEFAULT_CHARSET;
import static com.github.tomakehurst.wiremock.common.Strings.bytesFromString;
+import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -49,7 +49,7 @@ public static String unGzipToString(byte[] gzippedContent) {
}
public static byte[] gzip(String plainContent) {
- return gzip(plainContent, DEFAULT_CHARSET);
+ return gzip(plainContent, UTF_8);
}
public static byte[] gzip(String plainContent, Charset charset) {
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/ListFunctions.java b/src/main/java/com/github/tomakehurst/wiremock/common/ListFunctions.java
index ff81c1b6ee..3f3a16b12d 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/ListFunctions.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/ListFunctions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020-2021 Thomas Akehurst
+ * Copyright (C) 2020-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public final class ListFunctions {
@@ -33,6 +35,11 @@ public static Pair, List> splitByType(A[] items, Cla
return new Pair<>(as, bs);
}
+ @SafeVarargs
+ public static List concatenate(List... lists) {
+ return Stream.of(lists).flatMap(List::stream).collect(Collectors.toList());
+ }
+
private ListFunctions() {
throw new UnsupportedOperationException("Not instantiable");
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/ParameterUtils.java b/src/main/java/com/github/tomakehurst/wiremock/common/ParameterUtils.java
index 478d958303..2b5e3ba3cf 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/ParameterUtils.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/ParameterUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,16 @@ public static T getFirstNonNull(T first, T second) {
throw new NullPointerException("Both parameters are null");
}
+ public static T getFirstNonNull(T first, T second, String etr) {
+ if (first != null) {
+ return first;
+ }
+ if (second != null) {
+ return second;
+ }
+ throw new NullPointerException(etr);
+ }
+
public static void checkParameter(boolean condition, String errorMessage) {
if (!condition) {
throw new IllegalArgumentException(errorMessage);
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/ProxySettings.java b/src/main/java/com/github/tomakehurst/wiremock/common/ProxySettings.java
index 9850336d54..7749f20bcb 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/ProxySettings.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/ProxySettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2023 Thomas Akehurst
+ * Copyright (C) 2013-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package com.github.tomakehurst.wiremock.common;
import static com.github.tomakehurst.wiremock.common.ParameterUtils.checkParameter;
-import static org.apache.commons.lang3.StringUtils.isEmpty;
+import static com.github.tomakehurst.wiremock.common.Strings.isNotEmpty;
import java.net.MalformedURLException;
import java.net.URL;
@@ -54,7 +54,7 @@ public static ProxySettings fromString(String config) {
ProxySettings proxySettings =
new ProxySettings(
proxyUrl.getHost(), proxyUrl.getPort() == -1 ? DEFAULT_PORT : proxyUrl.getPort());
- if (!isEmpty(proxyUrl.getUserInfo())) {
+ if (isNotEmpty(proxyUrl.getUserInfo())) {
String[] userInfoArray = proxyUrl.getUserInfo().split(":");
proxySettings.setUsername(userInfoArray[0]);
if (userInfoArray.length > 1) {
@@ -99,6 +99,6 @@ public String toString() {
}
return String.format(
- "%s:%s%s", host(), port(), (!isEmpty(this.username) ? " (with credentials)" : ""));
+ "%s:%s%s", host(), port(), (isNotEmpty(this.username) ? " (with credentials)" : ""));
}
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/RenderCache.java b/src/main/java/com/github/tomakehurst/wiremock/common/RequestCache.java
similarity index 63%
rename from src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/RenderCache.java
rename to src/main/java/com/github/tomakehurst/wiremock/common/RequestCache.java
index d868a0e367..8dc4131460 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/RenderCache.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/RequestCache.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020-2021 Thomas Akehurst
+ * Copyright (C) 2020-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.github.tomakehurst.wiremock.extension.responsetemplating;
+package com.github.tomakehurst.wiremock.common;
import static java.util.Arrays.asList;
@@ -21,8 +21,45 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Supplier;
-public class RenderCache {
+public class RequestCache {
+
+ private static RequestCache OFF =
+ new RequestCache() {
+ @Override
+ public void put(Key key, Object value) {}
+
+ @Override
+ public T get(Key key) {
+ return null;
+ }
+
+ @Override
+ public T get(Key key, Supplier supplier) {
+ return supplier.get();
+ }
+ };
+
+ private static final ThreadLocal current = new ThreadLocal<>();
+
+ public static RequestCache getCurrent() {
+ RequestCache requestCache = current.get();
+ if (requestCache == null) {
+ requestCache = new RequestCache();
+ current.set(requestCache);
+ }
+
+ return requestCache;
+ }
+
+ public static void onRequestEnd() {
+ current.remove();
+ }
+
+ public static void disable() {
+ current.set(OFF);
+ }
private final Map cache = new HashMap<>();
@@ -35,6 +72,11 @@ public T get(Key key) {
return (T) cache.get(key);
}
+ @SuppressWarnings("unchecked")
+ public T get(Key key, Supplier supplier) {
+ return (T) cache.computeIfAbsent(key, k -> supplier.get());
+ }
+
public static class Key {
private final Class> forClass;
private final List> elements;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/Strings.java b/src/main/java/com/github/tomakehurst/wiremock/common/Strings.java
index 35b0ebe45d..67ff208bae 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/Strings.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/Strings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2023 Thomas Akehurst
+ * Copyright (C) 2015-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,21 +15,273 @@
*/
package com.github.tomakehurst.wiremock.common;
+import static java.lang.Math.max;
import static java.lang.System.lineSeparator;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.lang3.StringUtils.getLevenshteinDistance;
import java.nio.charset.Charset;
-import org.apache.commons.lang3.text.WordUtils;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class Strings {
private Strings() {}
- public static final Charset DEFAULT_CHARSET = UTF_8;
+ private static ThreadLocalRandom random() {
+ return ThreadLocalRandom.current();
+ }
+
+ public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
+ if (s == null || t == null) {
+ throw new IllegalArgumentException("Strings must not be null");
+ }
+
+ int n = s.length();
+ int m = t.length();
+
+ if (n == 0) {
+ return m;
+ }
+ if (m == 0) {
+ return n;
+ }
+
+ if (n > m) {
+ // swap the input strings to consume less memory
+ final CharSequence tmp = s;
+ s = t;
+ t = tmp;
+ n = m;
+ m = t.length();
+ }
+
+ final int[] p = new int[n + 1];
+ // indexes into strings s and t
+ int i; // iterates through s
+ int j; // iterates through t
+ int upperleft;
+ int upper;
+
+ char jOfT; // jth character of t
+ int cost;
+
+ for (i = 0; i <= n; i++) {
+ p[i] = i;
+ }
+
+ for (j = 1; j <= m; j++) {
+ upperleft = p[0];
+ jOfT = t.charAt(j - 1);
+ p[0] = j;
+
+ for (i = 1; i <= n; i++) {
+ upper = p[i];
+ cost = s.charAt(i - 1) == jOfT ? 0 : 1;
+ // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
+ p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperleft + cost);
+ upperleft = upper;
+ }
+ }
+
+ return p[n];
+ }
+
+ public static String randomAlphanumeric(final int count) {
+ return random(count, true, true);
+ }
+
+ public static String random(final int count, final boolean letters, final boolean numbers) {
+ return random(count, 0, 0, letters, numbers);
+ }
+
+ public static String randomAlphabetic(final int count) {
+ return random(count, true, false);
+ }
+
+ public static String randomNumeric(final int count) {
+ return random(count, false, true);
+ }
+
+ public static String random(final int count, final String chars) {
+ if (chars == null) {
+ return random(count, 0, 0, false, false, null, random());
+ }
+ return random(count, chars.toCharArray());
+ }
+
+ public static String random(final int count, final char... chars) {
+ if (chars == null) {
+ return random(count, 0, 0, false, false, null, random());
+ }
+ return random(count, 0, chars.length, false, false, chars, random());
+ }
+
+ public static String randomAscii(final int count) {
+ return random(count, 32, 127, false, false);
+ }
+
+ public static String random(
+ final int count,
+ final int start,
+ final int end,
+ final boolean letters,
+ final boolean numbers) {
+ return random(count, start, end, letters, numbers, null, random());
+ }
+
+ public static String random(
+ int count,
+ int start,
+ int end,
+ final boolean letters,
+ final boolean numbers,
+ final char[] chars,
+ final Random random) {
+ if (count == 0) {
+ return "";
+ }
+ if (count < 0) {
+ throw new IllegalArgumentException(
+ "Requested random string length " + count + " is less than 0.");
+ }
+ if (chars != null && chars.length == 0) {
+ throw new IllegalArgumentException("The chars array must not be empty");
+ }
+
+ if (start == 0 && end == 0) {
+ if (chars != null) {
+ end = chars.length;
+ } else if (!letters && !numbers) {
+ end = Character.MAX_CODE_POINT;
+ } else {
+ end = 'z' + 1;
+ start = ' ';
+ }
+ } else if (end <= start) {
+ throw new IllegalArgumentException(
+ "Parameter end (" + end + ") must be greater than start (" + start + ")");
+ }
+
+ final int zeroDigitAscii = 48;
+ final int firstLetterAscii = 65;
+
+ if (chars == null && (numbers && end <= zeroDigitAscii || letters && end <= firstLetterAscii)) {
+ throw new IllegalArgumentException(
+ "Parameter end ("
+ + end
+ + ") must be greater then ("
+ + zeroDigitAscii
+ + ") for generating digits "
+ + "or greater then ("
+ + firstLetterAscii
+ + ") for generating letters.");
+ }
+
+ final StringBuilder builder = new StringBuilder(count);
+ final int gap = end - start;
+
+ while (count-- != 0) {
+ final int codePoint;
+ if (chars == null) {
+ codePoint = random.nextInt(gap) + start;
+
+ switch (Character.getType(codePoint)) {
+ case Character.UNASSIGNED:
+ case Character.PRIVATE_USE:
+ case Character.SURROGATE:
+ count++;
+ continue;
+ }
+
+ } else {
+ codePoint = chars[random.nextInt(gap) + start];
+ }
+
+ final int numberOfChars = Character.charCount(codePoint);
+ if (count == 0 && numberOfChars > 1) {
+ count++;
+ continue;
+ }
+
+ if (letters && Character.isLetter(codePoint)
+ || numbers && Character.isDigit(codePoint)
+ || !letters && !numbers) {
+ builder.appendCodePoint(codePoint);
+
+ if (numberOfChars == 2) {
+ count--;
+ }
+
+ } else {
+ count++;
+ }
+ }
+ return builder.toString();
+ }
+
+ public static String rightPad(final String str, final int size) {
+ return rightPad(str, size, ' ');
+ }
+
+ public static String rightPad(final String str, final int size, final char padChar) {
+ if (str == null) {
+ return null;
+ }
+ final int pads = size - str.length();
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (pads > 8192) {
+ return rightPad(str, size, String.valueOf(padChar));
+ }
+ return str.concat(repeat(padChar, pads));
+ }
+
+ public static String rightPad(final String str, final int size, String padStr) {
+ if (str == null) {
+ return null;
+ }
+ if (isEmpty(padStr)) {
+ padStr = " ";
+ }
+ final int padLen = padStr.length();
+ final int strLen = str.length();
+ final int pads = size - strLen;
+ if (pads <= 0) {
+ return str; // returns original String when possible
+ }
+ if (padLen == 1 && pads <= 8192) {
+ return rightPad(str, size, padStr.charAt(0));
+ }
+
+ if (pads == padLen) {
+ return str.concat(padStr);
+ }
+ if (pads < padLen) {
+ return str.concat(padStr.substring(0, pads));
+ }
+ final char[] padding = new char[pads];
+ final char[] padChars = padStr.toCharArray();
+ for (int i = 0; i < pads; i++) {
+ padding[i] = padChars[i % padLen];
+ }
+ return str.concat(new String(padding));
+ }
+
+ public static String repeat(final char ch, final int repeat) {
+ if (repeat <= 0) {
+ return "";
+ }
+ final char[] buf = new char[repeat];
+ Arrays.fill(buf, ch);
+ return new String(buf);
+ }
public static String stringFromBytes(byte[] bytes) {
- return stringFromBytes(bytes, DEFAULT_CHARSET);
+ return stringFromBytes(bytes, UTF_8);
}
public static String stringFromBytes(byte[] bytes, Charset charset) {
@@ -41,7 +293,7 @@ public static String stringFromBytes(byte[] bytes, Charset charset) {
}
public static byte[] bytesFromString(String str) {
- return bytesFromString(str, DEFAULT_CHARSET);
+ return bytesFromString(str, UTF_8);
}
public static byte[] bytesFromString(String str, Charset charset) {
@@ -55,13 +307,179 @@ public static byte[] bytesFromString(String str, Charset charset) {
public static String wrapIfLongestLineExceedsLimit(String s, int maxLineLength) {
int longestLength = findLongestLineLength(s);
if (longestLength > maxLineLength) {
- String wrapped = WordUtils.wrap(s, maxLineLength, null, true);
+ String wrapped = wrap(s, maxLineLength, null, true);
return wrapped.replaceAll("(?m)^[ \t]*\r?\n", "");
}
return s;
}
+ public static String wrap(
+ final String str,
+ final int wrapLength,
+ final String newLineStr,
+ final boolean wrapLongWords) {
+ return wrap(str, wrapLength, newLineStr, wrapLongWords, " ");
+ }
+
+ public static String wrap(
+ final String str,
+ int wrapLength,
+ String newLineStr,
+ final boolean wrapLongWords,
+ String wrapOn) {
+ if (str == null) {
+ return null;
+ }
+ if (newLineStr == null) {
+ newLineStr = System.lineSeparator();
+ }
+ if (wrapLength < 1) {
+ wrapLength = 1;
+ }
+ if (isBlank(wrapOn)) {
+ wrapOn = " ";
+ }
+ final Pattern patternToWrapOn = Pattern.compile(wrapOn);
+ final int inputLineLength = str.length();
+ int offset = 0;
+ final StringBuilder wrappedLine = new StringBuilder(inputLineLength + 32);
+
+ while (offset < inputLineLength) {
+ int spaceToWrapAt = -1;
+ Matcher matcher =
+ patternToWrapOn.matcher(
+ str.substring(
+ offset,
+ Math.min(
+ (int) Math.min(Integer.MAX_VALUE, offset + wrapLength + 1L),
+ inputLineLength)));
+ if (matcher.find()) {
+ if (matcher.start() == 0) {
+ offset += matcher.end();
+ continue;
+ }
+ spaceToWrapAt = matcher.start() + offset;
+ }
+
+ // only last line without leading spaces is left
+ if (inputLineLength - offset <= wrapLength) {
+ break;
+ }
+
+ while (matcher.find()) {
+ spaceToWrapAt = matcher.start() + offset;
+ }
+
+ if (spaceToWrapAt >= offset) {
+ // normal case
+ wrappedLine.append(str, offset, spaceToWrapAt);
+ wrappedLine.append(newLineStr);
+ offset = spaceToWrapAt + 1;
+
+ } else // really long word or URL
+ if (wrapLongWords) {
+ // wrap really long word one line at a time
+ wrappedLine.append(str, offset, wrapLength + offset);
+ wrappedLine.append(newLineStr);
+ offset += wrapLength;
+ } else {
+ // do not wrap really long word, just extend beyond limit
+ matcher = patternToWrapOn.matcher(str.substring(offset + wrapLength));
+ if (matcher.find()) {
+ spaceToWrapAt = matcher.start() + offset + wrapLength;
+ }
+
+ if (spaceToWrapAt >= 0) {
+ wrappedLine.append(str, offset, spaceToWrapAt);
+ wrappedLine.append(newLineStr);
+ offset = spaceToWrapAt + 1;
+ } else {
+ wrappedLine.append(str, offset, str.length());
+ offset = inputLineLength;
+ }
+ }
+ }
+
+ // Whatever is left in line is short enough to just pass through
+ wrappedLine.append(str, offset, str.length());
+
+ return wrappedLine.toString();
+ }
+
+ public static String substringAfterLast(final String str, final int separator) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ final int pos = str.lastIndexOf(separator);
+ if (pos == -1 || pos == str.length() - 1) {
+ return "";
+ }
+ return str.substring(pos + 1);
+ }
+
+ public static String substringAfterLast(final String str, final String separator) {
+ if (isEmpty(str)) {
+ return str;
+ }
+ if (isEmpty(separator)) {
+ return "";
+ }
+ final int pos = str.lastIndexOf(separator);
+ if (pos == -1 || pos == str.length() - separator.length()) {
+ return "";
+ }
+ return str.substring(pos + separator.length());
+ }
+
+ public static int countMatches(final CharSequence str, final char ch) {
+ if (isEmpty(str)) {
+ return 0;
+ }
+ int count = 0;
+ // We could also call str.toCharArray() for faster lookups but that would generate more garbage.
+ for (int i = 0; i < str.length(); i++) {
+ if (ch == str.charAt(i)) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ public static int ordinalIndexOf(
+ final CharSequence str, final CharSequence searchStr, final int ordinal) {
+ return ordinalIndexOf(str, searchStr, ordinal, false);
+ }
+
+ private static int ordinalIndexOf(
+ final CharSequence str,
+ final CharSequence searchStr,
+ final int ordinal,
+ final boolean lastIndex) {
+ if (str == null || searchStr == null || ordinal <= 0) {
+ return -1;
+ }
+ if (searchStr.length() == 0) {
+ return lastIndex ? str.length() : 0;
+ }
+ int found = 0;
+ // set the initial index beyond the end of the string
+ // this is to allow for the initial index decrement/increment
+ int index = lastIndex ? str.length() : -1;
+ do {
+ if (lastIndex) {
+ index = lastIndexOf(str, searchStr, index - 1); // step backwards through string
+ } else {
+ index = indexOf(str, searchStr, index + 1); // step forwards through string
+ }
+ if (index < 0) {
+ return index;
+ }
+ found++;
+ } while (found < ordinal);
+ return index;
+ }
+
private static int findLongestLineLength(String s) {
String[] lines = s.split("\n");
int longestLength = 0;
@@ -80,7 +498,7 @@ public static double normalisedLevenshteinDistance(String one, String two) {
return 1.0;
}
- double maxDistance = Math.max(one.length(), two.length());
+ double maxDistance = max(one.length(), two.length());
double actualDistance = getLevenshteinDistance(one, two);
return (actualDistance / maxDistance);
}
@@ -90,6 +508,140 @@ public static String normaliseLineBreaks(String s) {
}
public static boolean isNullOrEmpty(String s) {
- return s == null || s.isEmpty();
+ return isNull(s) || s.isEmpty();
+ }
+
+ public static boolean isNotNullOrEmpty(String s) {
+ return !isNullOrEmpty(s);
+ }
+
+ public static boolean isBlank(String s) {
+ return isNull(s) || s.isBlank();
+ }
+
+ public static boolean isNotBlank(String s) {
+ return !isBlank(s);
+ }
+
+ public static boolean isNull(String s) {
+ return s == null;
+ }
+
+ public static boolean isNotNull(String s) {
+ return !isNull(s);
+ }
+
+ public static boolean isEmpty(CharSequence charSequence) {
+ return charSequence == null || charSequence.length() == 0;
+ }
+
+ public static boolean isEmpty(String s) {
+ return isNull(s) || s.isEmpty();
+ }
+
+ public static boolean isNotEmpty(String s) {
+ return !isEmpty(s);
+ }
+
+ public static String removeStart(String str, String remove) {
+ if (isEmpty(str) || isEmpty(remove)) {
+ return str;
+ }
+ if (str.startsWith(remove)) {
+ return str.substring(remove.length());
+ }
+ return str;
+ }
+
+ private static boolean checkLaterThan1(
+ final CharSequence cs, final CharSequence searchChar, final int len2, final int start1) {
+ for (int i = 1, j = len2 - 1; i <= j; i++, j--) {
+ if (cs.charAt(start1 + i) != searchChar.charAt(i)
+ || cs.charAt(start1 + j) != searchChar.charAt(j)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static int indexOf(
+ final CharSequence cs, final CharSequence searchChar, final int start) {
+ if (cs instanceof String) {
+ return ((String) cs).indexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).indexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).indexOf(searchChar.toString(), start);
+ }
+ return cs.toString().indexOf(searchChar.toString(), start);
+ }
+
+ private static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, int start) {
+ if (searchChar == null || cs == null) {
+ return -1;
+ }
+ if (searchChar instanceof String) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf((String) searchChar, start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
+ }
+ }
+
+ final int len1 = cs.length();
+ final int len2 = searchChar.length();
+
+ if (start > len1) {
+ start = len1;
+ }
+
+ if (start < 0 || len2 > len1) {
+ return -1;
+ }
+
+ if (len2 == 0) {
+ return start;
+ }
+
+ if (len2 <= 16) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ }
+
+ if (start + len2 > len1) {
+ start = len1 - len2;
+ }
+
+ final char char0 = searchChar.charAt(0);
+
+ int i = start;
+ while (true) {
+ while (cs.charAt(i) != char0) {
+ i--;
+ if (i < 0) {
+ return -1;
+ }
+ }
+ if (checkLaterThan1(cs, searchChar, len2, i)) {
+ return i;
+ }
+ i--;
+ if (i < 0) {
+ return -1;
+ }
+ }
}
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/UniqueFilenameGenerator.java b/src/main/java/com/github/tomakehurst/wiremock/common/UniqueFilenameGenerator.java
index 5b5f89c028..2ee42dcf18 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/UniqueFilenameGenerator.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/UniqueFilenameGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2023 Thomas Akehurst
+ * Copyright (C) 2013-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
package com.github.tomakehurst.wiremock.common;
import java.net.URI;
-import org.apache.commons.lang3.StringUtils;
public class UniqueFilenameGenerator {
@@ -29,7 +28,7 @@ public static String generate(String url, String prefix, String id, String exten
pathPart = pathPart.isBlank() ? "(root)" : sanitise(pathPart);
if (pathPart.length() > 150) {
- pathPart = StringUtils.truncate(pathPart, 150);
+ pathPart = pathPart.substring(0, 150);
}
return prefix + "-" + pathPart + "-" + id + "." + extension;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/Urls.java b/src/main/java/com/github/tomakehurst/wiremock/common/Urls.java
index 77f77924ef..1e4934a0a6 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/Urls.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/Urls.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2023 Thomas Akehurst
+ * Copyright (C) 2011-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package com.github.tomakehurst.wiremock.common;
import static com.github.tomakehurst.wiremock.common.Exceptions.throwUnchecked;
+import static com.github.tomakehurst.wiremock.common.Strings.ordinalIndexOf;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.github.tomakehurst.wiremock.http.QueryParameter;
@@ -28,7 +29,6 @@
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;
-import org.apache.commons.lang3.StringUtils;
public class Urls {
@@ -76,7 +76,7 @@ public static String getPath(String url) {
}
public static String getPathAndQuery(String url) {
- return isAbsolute(url) ? url.substring(StringUtils.ordinalIndexOf(url, "/", 3)) : url;
+ return isAbsolute(url) ? url.substring(ordinalIndexOf(url, "/", 3)) : url;
}
private static boolean isAbsolute(String url) {
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/filemaker/FilenameMaker.java b/src/main/java/com/github/tomakehurst/wiremock/common/filemaker/FilenameMaker.java
index 647dfb5aef..10465724b0 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/filemaker/FilenameMaker.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/filemaker/FilenameMaker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package com.github.tomakehurst.wiremock.common.filemaker;
import static com.github.tomakehurst.wiremock.extension.responsetemplating.TemplateEngine.defaultTemplateEngine;
+import static java.lang.Math.min;
import com.github.tomakehurst.wiremock.extension.responsetemplating.HandlebarsOptimizedTemplate;
import com.github.tomakehurst.wiremock.extension.responsetemplating.TemplateEngine;
@@ -23,7 +24,6 @@
import java.text.Normalizer;
import java.util.Locale;
import java.util.regex.Pattern;
-import org.apache.commons.lang3.StringUtils;
public class FilenameMaker {
public static final String DEFAULT_FILENAME_TEMPLATE =
@@ -68,7 +68,7 @@ public String sanitizeUrl(String url) {
String pathWithoutWhitespace = WHITESPACE.matcher(startingPath).replaceAll("-");
String normalizedPath = Normalizer.normalize(pathWithoutWhitespace, Normalizer.Form.NFD);
String slug = sanitise(normalizedPath).replaceAll("^[_]*", "").replaceAll("[_]*$", "");
- slug = StringUtils.truncate(slug, 200);
+ slug = slug.substring(0, min(slug.length(), 200));
return slug;
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/common/url/PathTemplate.java b/src/main/java/com/github/tomakehurst/wiremock/common/url/PathTemplate.java
index 1aa655f1b6..7f969eca49 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/common/url/PathTemplate.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/common/url/PathTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2023 Thomas Akehurst
+ * Copyright (C) 2016-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,7 +86,7 @@ public String render(PathParams pathParams) {
}
public String withoutVariables() {
- return templateString.replaceAll(SPECIAL_SYMBOL_REGEX.pattern(), "");
+ return templateString.replaceAll(SPECIAL_SYMBOL_REGEX.pattern(), "_");
}
private static String stripFormatCharacters(String parameter) {
diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/Options.java b/src/main/java/com/github/tomakehurst/wiremock/core/Options.java
index 6611ff96ed..9f3f979e25 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/core/Options.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/core/Options.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2023 Thomas Akehurst
+ * Copyright (C) 2013-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,6 +52,10 @@ enum ChunkedEncodingPolicy {
boolean getHttpDisabled();
+ boolean getHttp2PlainDisabled();
+
+ boolean getHttp2TlsDisabled();
+
HttpsSettings httpsSettings();
JettySettings jettySettings();
@@ -147,4 +151,8 @@ default int getMaxHttpClientConnections() {
Set getTemplatePermittedSystemKeys();
boolean getTemplateEscapingDisabled();
+
+ default Set getSupportedProxyEncodings() {
+ return null;
+ }
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/ProxyHandler.java b/src/main/java/com/github/tomakehurst/wiremock/core/ProxyHandler.java
index 211baac7ab..9b75ce1fb4 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/core/ProxyHandler.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/core/ProxyHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -122,6 +122,7 @@ private ResponseDefinition copyResponseDefinition(
response.getBodyFileName(),
response.getHeaders(),
response.getAdditionalProxyRequestHeaders(),
+ response.getRemoveProxyRequestHeaders(),
response.getFixedDelayMilliseconds(),
response.getDelayDistribution(),
response.getChunkedDribbleDelay(),
@@ -145,6 +146,7 @@ private ResponseDefinition copyResponseDefinition(
response.getBodyFileName(),
response.getHeaders(),
response.getAdditionalProxyRequestHeaders(),
+ response.getRemoveProxyRequestHeaders(),
response.getFixedDelayMilliseconds(),
response.getDelayDistribution(),
response.getChunkedDribbleDelay(),
diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/Version.java b/src/main/java/com/github/tomakehurst/wiremock/core/Version.java
index 0ff6996620..26da5b793b 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/core/Version.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/core/Version.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,19 +22,34 @@
import java.util.Properties;
public class Version {
- private static final Lazy version = lazy(Version::load);
+ private static final Lazy version = lazy(Version::load);
public static String getCurrentVersion() {
- return version.get();
+ return version.get().version;
}
- private static String load() {
+ public static String getGuiVersion() {
+ return version.get().guiVersion;
+ }
+
+ private static EnhancedVersion load() {
try {
Properties properties = new Properties();
- properties.load(Version.class.getResourceAsStream("/version.properties"));
- return properties.getProperty("version");
+ properties.load(Version.class.getResourceAsStream("/wiremock-gui-version.properties"));
+ return new EnhancedVersion(
+ properties.getProperty("version"), properties.getProperty("gui-version"));
} catch (NullPointerException | IOException e) {
- return "unknown";
+ return new EnhancedVersion("unknown", "unknown");
+ }
+ }
+
+ private static class EnhancedVersion {
+ String version;
+ String guiVersion;
+
+ public EnhancedVersion(final String version, final String guiVersion) {
+ this.version = version;
+ this.guiVersion = guiVersion;
}
}
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockApp.java b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockApp.java
index e18d5ff9c3..635a5bf8c5 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockApp.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockApp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2023 Thomas Akehurst
+ * Copyright (C) 2012-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,91 +17,44 @@
import static com.github.tomakehurst.wiremock.common.ParameterUtils.getFirstNonNull;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.mutable.MutableBoolean;
-
import com.github.tomakehurst.wiremock.admin.AdminRoutes;
import com.github.tomakehurst.wiremock.admin.LimitAndOffsetPaginator;
-import com.github.tomakehurst.wiremock.admin.model.GetGlobalSettingsResult;
-import com.github.tomakehurst.wiremock.admin.model.GetScenariosResult;
-import com.github.tomakehurst.wiremock.admin.model.GetServeEventsResult;
-import com.github.tomakehurst.wiremock.admin.model.ListStubMappingsResult;
-import com.github.tomakehurst.wiremock.admin.model.ProxyConfig;
-import com.github.tomakehurst.wiremock.admin.model.ServeEventQuery;
-import com.github.tomakehurst.wiremock.admin.model.SingleServedStubResult;
-import com.github.tomakehurst.wiremock.admin.model.SingleStubMappingResult;
+import com.github.tomakehurst.wiremock.admin.model.*;
import com.github.tomakehurst.wiremock.common.BrowserProxySettings;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.common.xml.Xml;
-import com.github.tomakehurst.wiremock.extension.AdminApiExtension;
-import com.github.tomakehurst.wiremock.extension.Extensions;
-import com.github.tomakehurst.wiremock.extension.GlobalSettingsListener;
-import com.github.tomakehurst.wiremock.extension.MappingsLoaderExtension;
-import com.github.tomakehurst.wiremock.extension.PostServeAction;
-import com.github.tomakehurst.wiremock.extension.ResponseDefinitionTransformer;
-import com.github.tomakehurst.wiremock.extension.ResponseDefinitionTransformerV2;
-import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
-import com.github.tomakehurst.wiremock.extension.ResponseTransformerV2;
-import com.github.tomakehurst.wiremock.extension.ServeEventListener;
-import com.github.tomakehurst.wiremock.extension.StubLifecycleListener;
+import com.github.tomakehurst.wiremock.extension.*;
import com.github.tomakehurst.wiremock.extension.requestfilter.RequestFilter;
import com.github.tomakehurst.wiremock.extension.requestfilter.RequestFilterV2;
import com.github.tomakehurst.wiremock.global.GlobalSettings;
import com.github.tomakehurst.wiremock.gui.GuiServeEventListener;
-import com.github.tomakehurst.wiremock.http.AdminRequestHandler;
-import com.github.tomakehurst.wiremock.http.BasicResponseRenderer;
-import com.github.tomakehurst.wiremock.http.ProxyResponseRenderer;
-import com.github.tomakehurst.wiremock.http.ResponseDefinition;
-import com.github.tomakehurst.wiremock.http.StubRequestHandler;
-import com.github.tomakehurst.wiremock.http.StubResponseRenderer;
+import com.github.tomakehurst.wiremock.http.*;
import com.github.tomakehurst.wiremock.http.client.HttpClient;
import com.github.tomakehurst.wiremock.jetty.websockets.Message;
import com.github.tomakehurst.wiremock.jetty.websockets.WebSocketEndpoint;
import com.github.tomakehurst.wiremock.matching.RequestMatcherExtension;
import com.github.tomakehurst.wiremock.matching.RequestPattern;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
-import com.github.tomakehurst.wiremock.recording.RecordSpec;
-import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
-import com.github.tomakehurst.wiremock.recording.Recorder;
-import com.github.tomakehurst.wiremock.recording.RecordingStatusResult;
-import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult;
+import com.github.tomakehurst.wiremock.recording.*;
import com.github.tomakehurst.wiremock.standalone.MappingsLoader;
import com.github.tomakehurst.wiremock.store.DefaultStores;
import com.github.tomakehurst.wiremock.store.SettingsStore;
import com.github.tomakehurst.wiremock.store.Stores;
-import com.github.tomakehurst.wiremock.stubbing.InMemoryScenarios;
-import com.github.tomakehurst.wiremock.stubbing.Scenarios;
-import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
-import com.github.tomakehurst.wiremock.stubbing.StoreBackedStubMappings;
-import com.github.tomakehurst.wiremock.stubbing.StubImport;
-import com.github.tomakehurst.wiremock.stubbing.StubMapping;
-import com.github.tomakehurst.wiremock.stubbing.StubMappings;
-import com.github.tomakehurst.wiremock.verification.DisabledRequestJournal;
-import com.github.tomakehurst.wiremock.verification.FindNearMissesResult;
-import com.github.tomakehurst.wiremock.verification.FindRequestsResult;
-import com.github.tomakehurst.wiremock.verification.FindServeEventsResult;
-import com.github.tomakehurst.wiremock.verification.LoggedRequest;
-import com.github.tomakehurst.wiremock.verification.NearMiss;
-import com.github.tomakehurst.wiremock.verification.NearMissCalculator;
-import com.github.tomakehurst.wiremock.verification.RequestJournal;
-import com.github.tomakehurst.wiremock.verification.RequestJournalDisabledException;
-import com.github.tomakehurst.wiremock.verification.StoreBackedRequestJournal;
-import com.github.tomakehurst.wiremock.verification.VerificationResult;
+import com.github.tomakehurst.wiremock.stubbing.*;
+import com.github.tomakehurst.wiremock.verification.*;
+import com.jayway.jsonpath.JsonPathException;
+import com.jayway.jsonpath.spi.cache.CacheProvider;
+import com.jayway.jsonpath.spi.cache.NOOPCache;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
public class WireMockApp implements StubServer, Admin {
public static final String FILES_ROOT = "__files";
public static final String ADMIN_CONTEXT_ROOT = "/__admin";
public static final String MAPPINGS_ROOT = "mappings";
- private static final MutableBoolean FACTORIES_LOADING_OPTIMIZED = new MutableBoolean(false);
+ private static final AtomicBoolean FACTORIES_LOADING_OPTIMIZED = new AtomicBoolean(false);
private final Stores stores;
private final Scenarios scenarios;
@@ -125,9 +78,19 @@ public class WireMockApp implements StubServer, Admin {
public WireMockApp(Options options, Container container) {
this.proxyHandler = new ProxyHandler(this);
- if (!options.getDisableOptimizeXmlFactoriesLoading() && FACTORIES_LOADING_OPTIMIZED.isFalse()) {
+ if (!options.getDisableOptimizeXmlFactoriesLoading()
+ && Boolean.FALSE.equals(FACTORIES_LOADING_OPTIMIZED.get())) {
Xml.optimizeFactoriesLoading();
- FACTORIES_LOADING_OPTIMIZED.setTrue();
+ FACTORIES_LOADING_OPTIMIZED.set(true);
+ }
+
+ try {
+ // Disabling JsonPath's cache due to
+ // https://github.com/json-path/JsonPath/issues/975#issuecomment-1867293053 and the fact that
+ // we're now doing our own caching.
+ CacheProvider.setCache(new NOOPCache());
+ } catch (JsonPathException ignored) {
+ // May fail on subsequent runs, but this doesn't matter
}
this.options = options;
@@ -141,22 +104,38 @@ public WireMockApp(Options options, Container container) {
this.settingsStore = stores.getSettingsStore();
extensions =
- new Extensions(options.getDeclaredExtensions(), this, options, stores, options.filesRoot().child(FILES_ROOT));
+ new Extensions(
+ options.getDeclaredExtensions(),
+ this,
+ options,
+ stores,
+ options.filesRoot().child(FILES_ROOT));
extensions.load();
- Map customMatchers = extensions.ofType(RequestMatcherExtension.class);
+ Map customMatchers =
+ extensions.ofType(RequestMatcherExtension.class);
- requestJournal = options.requestJournalDisabled() ?
- new DisabledRequestJournal() :
- new StoreBackedRequestJournal(options.maxRequestJournalEntries().orElse(null), customMatchers,
- stores.getRequestJournalStore());
+ requestJournal =
+ options.requestJournalDisabled()
+ ? new DisabledRequestJournal()
+ : new StoreBackedRequestJournal(
+ options.maxRequestJournalEntries().orElse(null),
+ customMatchers,
+ stores.getRequestJournalStore());
scenarios = new InMemoryScenarios(stores.getScenariosStore());
- stubMappings = new StoreBackedStubMappings(stores.getStubStore(), scenarios, customMatchers,
- extensions.ofType(ResponseDefinitionTransformer.class), extensions.ofType(ResponseDefinitionTransformerV2.class),
- stores.getFilesBlobStore(), List.copyOf(extensions.ofType(StubLifecycleListener.class).values()));
+ stubMappings =
+ new StoreBackedStubMappings(
+ stores.getStubStore(),
+ scenarios,
+ customMatchers,
+ extensions.ofType(ResponseDefinitionTransformer.class),
+ extensions.ofType(ResponseDefinitionTransformerV2.class),
+ stores.getFilesBlobStore(),
+ List.copyOf(extensions.ofType(StubLifecycleListener.class).values()));
nearMissCalculator = new NearMissCalculator(stubMappings, requestJournal, scenarios);
- recorder = new Recorder(this, extensions, stores.getFilesBlobStore(), stores.getRecorderStateStore());
+ recorder =
+ new Recorder(this, extensions, stores.getFilesBlobStore(), stores.getRecorderStateStore());
globalSettingsListeners = List.copyOf(extensions.ofType(GlobalSettingsListener.class).values());
this.mappingsLoaderExtensions = extensions.ofType(MappingsLoaderExtension.class);
@@ -164,12 +143,18 @@ public WireMockApp(Options options, Container container) {
loadDefaultMappings();
}
- public WireMockApp(boolean browserProxyingEnabled, MappingsLoader defaultMappingsLoader,
- Map mappingsLoaderExtensions, MappingsSaver mappingsSaver,
- boolean requestJournalDisabled, Integer maxRequestJournalEntries,
- Map transformers,
- Map v2transformers, Map requestMatchers,
- FileSource rootFileSource, Container container) {
+ public WireMockApp(
+ boolean browserProxyingEnabled,
+ MappingsLoader defaultMappingsLoader,
+ Map mappingsLoaderExtensions,
+ MappingsSaver mappingsSaver,
+ boolean requestJournalDisabled,
+ Integer maxRequestJournalEntries,
+ Map transformers,
+ Map v2transformers,
+ Map requestMatchers,
+ FileSource rootFileSource,
+ Container container) {
this.proxyHandler = new ProxyHandler(this);
@@ -180,77 +165,122 @@ public WireMockApp(boolean browserProxyingEnabled, MappingsLoader defaultMapping
this.mappingsLoaderExtensions = mappingsLoaderExtensions;
this.mappingsSaver = mappingsSaver;
this.settingsStore = stores.getSettingsStore();
- requestJournal = requestJournalDisabled ?
- new DisabledRequestJournal() :
- new StoreBackedRequestJournal(maxRequestJournalEntries, requestMatchers, stores.getRequestJournalStore());
+ requestJournal =
+ requestJournalDisabled
+ ? new DisabledRequestJournal()
+ : new StoreBackedRequestJournal(
+ maxRequestJournalEntries, requestMatchers, stores.getRequestJournalStore());
scenarios = new InMemoryScenarios(stores.getScenariosStore());
stubMappings =
- new StoreBackedStubMappings(stores.getStubStore(), scenarios, requestMatchers, transformers, v2transformers,
- stores.getFilesBlobStore(), Collections.emptyList());
+ new StoreBackedStubMappings(
+ stores.getStubStore(),
+ scenarios,
+ requestMatchers,
+ transformers,
+ v2transformers,
+ stores.getFilesBlobStore(),
+ Collections.emptyList());
this.container = container;
nearMissCalculator = new NearMissCalculator(stubMappings, requestJournal, scenarios);
- recorder = new Recorder(this, extensions, stores.getFilesBlobStore(), stores.getRecorderStateStore());
+ recorder =
+ new Recorder(this, extensions, stores.getFilesBlobStore(), stores.getRecorderStateStore());
globalSettingsListeners = Collections.emptyList();
loadDefaultMappings();
}
public AdminRequestHandler buildAdminRequestHandler() {
- AdminRoutes adminRoutes = AdminRoutes.forServer(extensions.ofType(AdminApiExtension.class).values(), stores);
- return new AdminRequestHandler(adminRoutes, this, new BasicResponseRenderer(), options.getAdminAuthenticator(),
- options.getHttpsRequiredForAdminApi(), getAdminRequestFilters(), getV2AdminRequestFilters(),
- options.getDataTruncationSettings());
+ AdminRoutes adminRoutes =
+ AdminRoutes.forServer(extensions.ofType(AdminApiExtension.class).values(), stores);
+ return new AdminRequestHandler(
+ adminRoutes,
+ this,
+ new BasicResponseRenderer(),
+ options.getAdminAuthenticator(),
+ options.getHttpsRequiredForAdminApi(),
+ getAdminRequestFilters(),
+ getV2AdminRequestFilters(),
+ options.getDataTruncationSettings());
}
public StubRequestHandler buildStubRequestHandler() {
Map postServeActions = extensions.ofType(PostServeAction.class);
- Map concatenatedMap = new HashMap<>(extensions.ofType(ServeEventListener.class));
+ Map concatenatedMap =
+ new HashMap<>(extensions.ofType(ServeEventListener.class));
concatenatedMap.put("wiremock-gui", new GuiServeEventListener());
- Map serveEventListeners = Collections.unmodifiableMap(concatenatedMap);
+ Map serveEventListeners =
+ Collections.unmodifiableMap(concatenatedMap);
BrowserProxySettings browserProxySettings = options.browserProxySettings();
final com.github.tomakehurst.wiremock.http.client.HttpClientFactory httpClientFactory =
- extensions.ofType(com.github.tomakehurst.wiremock.http.client.HttpClientFactory.class).values().stream()
- .findFirst().orElse(options.httpClientFactory());
+ extensions
+ .ofType(com.github.tomakehurst.wiremock.http.client.HttpClientFactory.class)
+ .values()
+ .stream()
+ .findFirst()
+ .orElse(options.httpClientFactory());
final HttpClient reverseProxyClient =
- httpClientFactory.buildHttpClient(options, true, Collections.emptyList(), true);
+ httpClientFactory.buildHttpClient(options, true, Collections.emptyList(), true);
final HttpClient forwardProxyClient =
- httpClientFactory.buildHttpClient(options, browserProxySettings.trustAllProxyTargets(),
- browserProxySettings.trustAllProxyTargets() ?
- Collections.emptyList() :
- browserProxySettings.trustedProxyTargets(), false);
-
- return new StubRequestHandler(this, new StubResponseRenderer(options.getStores().getFilesBlobStore(), settingsStore,
- new ProxyResponseRenderer(options.shouldPreserveHostHeader(), options.proxyHostHeader(), settingsStore,
- options.getStubCorsEnabled(), reverseProxyClient, forwardProxyClient),
- List.copyOf(extensions.ofType(ResponseTransformer.class).values()),
- List.copyOf(extensions.ofType(ResponseTransformerV2.class).values())), this, postServeActions,
- serveEventListeners, requestJournal, getStubRequestFilters(), getV2StubRequestFilters(),
- options.getStubRequestLoggingDisabled(), options.getDataTruncationSettings(),
- options.getNotMatchedRendererFactory().apply(extensions));
+ httpClientFactory.buildHttpClient(
+ options,
+ browserProxySettings.trustAllProxyTargets(),
+ browserProxySettings.trustAllProxyTargets()
+ ? Collections.emptyList()
+ : browserProxySettings.trustedProxyTargets(),
+ false);
+
+ return new StubRequestHandler(
+ this,
+ new StubResponseRenderer(
+ options.getStores().getFilesBlobStore(),
+ settingsStore,
+ new ProxyResponseRenderer(
+ options.shouldPreserveHostHeader(),
+ options.proxyHostHeader(),
+ settingsStore,
+ options.getStubCorsEnabled(),
+ options.getSupportedProxyEncodings(),
+ reverseProxyClient,
+ forwardProxyClient),
+ List.copyOf(extensions.ofType(ResponseTransformer.class).values()),
+ List.copyOf(extensions.ofType(ResponseTransformerV2.class).values())),
+ this,
+ postServeActions,
+ serveEventListeners,
+ requestJournal,
+ getStubRequestFilters(),
+ getV2StubRequestFilters(),
+ options.getStubRequestLoggingDisabled(),
+ options.getDataTruncationSettings(),
+ options.getNotMatchedRendererFactory().apply(extensions));
}
private List getAdminRequestFilters() {
- return extensions.ofType(RequestFilter.class).values().stream().filter(RequestFilter::applyToAdmin)
- .collect(Collectors.toList());
+ return extensions.ofType(RequestFilter.class).values().stream()
+ .filter(RequestFilter::applyToAdmin)
+ .collect(Collectors.toList());
}
private List getV2AdminRequestFilters() {
- return extensions.ofType(RequestFilterV2.class).values().stream().filter(RequestFilterV2::applyToAdmin)
- .collect(Collectors.toList());
+ return extensions.ofType(RequestFilterV2.class).values().stream()
+ .filter(RequestFilterV2::applyToAdmin)
+ .collect(Collectors.toList());
}
private List getStubRequestFilters() {
- return extensions.ofType(RequestFilter.class).values().stream().filter(RequestFilter::applyToStubs)
- .collect(Collectors.toList());
+ return extensions.ofType(RequestFilter.class).values().stream()
+ .filter(RequestFilter::applyToStubs)
+ .collect(Collectors.toList());
}
private List getV2StubRequestFilters() {
- return extensions.ofType(RequestFilterV2.class).values().stream().filter(RequestFilterV2::applyToStubs)
- .collect(Collectors.toList());
+ return extensions.ofType(RequestFilterV2.class).values().stream()
+ .filter(RequestFilterV2::applyToStubs)
+ .collect(Collectors.toList());
}
private void loadDefaultMappings() {
@@ -268,9 +298,12 @@ public void loadMappingsUsing(final MappingsLoader mappingsLoader) {
public ServeEvent serveStubFor(ServeEvent initialServeEvent) {
ServeEvent serveEvent = stubMappings.serveFor(initialServeEvent);
- if (serveEvent.isNoExactMatch() && browserProxyingEnabled && serveEvent.getRequest().isBrowserProxyRequest()
- && getGlobalSettings().getSettings().getProxyPassThrough()) {
- return ServeEvent.ofUnmatched(serveEvent.getRequest(), ResponseDefinition.browserProxy(serveEvent.getRequest()));
+ if (serveEvent.isNoExactMatch()
+ && browserProxyingEnabled
+ && serveEvent.getRequest().isBrowserProxyRequest()
+ && getGlobalSettings().getSettings().getProxyPassThrough()) {
+ return ServeEvent.ofUnmatched(
+ serveEvent.getRequest(), ResponseDefinition.browserProxy(serveEvent.getRequest()));
}
return serveEvent;
@@ -292,11 +325,14 @@ public void addStubMapping(StubMapping stubMapping) {
@Override
public void removeStubMapping(StubMapping stubMapping) {
- stubMappings.get(stubMapping.getId()).ifPresent(stubToDelete -> {
- if (stubToDelete.shouldBePersisted()) {
- mappingsSaver.remove(stubToDelete);
- }
- });
+ stubMappings
+ .get(stubMapping.getId())
+ .ifPresent(
+ stubToDelete -> {
+ if (stubToDelete.shouldBePersisted()) {
+ mappingsSaver.remove(stubToDelete);
+ }
+ });
stubMappings.removeMapping(stubMapping);
@@ -391,7 +427,7 @@ public GetServeEventsResult getServeEvents(ServeEventQuery query) {
return GetServeEventsResult.requestJournalEnabled(LimitAndOffsetPaginator.none(serveEvents));
} catch (RequestJournalDisabledException e) {
return GetServeEventsResult.requestJournalDisabled(
- LimitAndOffsetPaginator.none(requestJournal.getAllServeEvents()));
+ LimitAndOffsetPaginator.none(requestJournal.getAllServeEvents()));
}
}
@@ -423,8 +459,10 @@ public FindRequestsResult findRequestsMatching(RequestPattern requestPattern) {
public FindRequestsResult findUnmatchedRequests() {
try {
List requests =
- requestJournal.getAllServeEvents().stream().filter(ServeEvent::isNoExactMatch).map(ServeEvent::getRequest)
- .collect(Collectors.toList());
+ requestJournal.getAllServeEvents().stream()
+ .filter(ServeEvent::isNoExactMatch)
+ .map(ServeEvent::getRequest)
+ .collect(Collectors.toList());
return FindRequestsResult.withRequests(requests);
} catch (RequestJournalDisabledException e) {
return FindRequestsResult.withRequestJournalDisabled();
@@ -442,15 +480,19 @@ public FindServeEventsResult removeServeEventsMatching(RequestPattern requestPat
}
@Override
- public FindServeEventsResult removeServeEventsForStubsMatchingMetadata(StringValuePattern metadataPattern) {
- return new FindServeEventsResult(requestJournal.removeServeEventsForStubsMatchingMetadata(metadataPattern));
+ public FindServeEventsResult removeServeEventsForStubsMatchingMetadata(
+ StringValuePattern metadataPattern) {
+ return new FindServeEventsResult(
+ requestJournal.removeServeEventsForStubsMatchingMetadata(metadataPattern));
}
@Override
public FindNearMissesResult findNearMissesForUnmatchedRequests() {
List nearMisses = new ArrayList<>();
List unmatchedServeEvents =
- requestJournal.getAllServeEvents().stream().filter(ServeEvent::isNoExactMatch).collect(Collectors.toList());
+ requestJournal.getAllServeEvents().stream()
+ .filter(ServeEvent::isNoExactMatch)
+ .collect(Collectors.toList());
for (ServeEvent serveEvent : unmatchedServeEvents) {
nearMisses.addAll(nearMissCalculator.findNearestTo(serveEvent.getRequest()));
@@ -590,7 +632,8 @@ public RecordingStatusResult getRecordingStatus() {
@Override
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
- return new ListStubMappingsResult(LimitAndOffsetPaginator.none(stubMappings.findByMetadata(pattern)));
+ return new ListStubMappingsResult(
+ LimitAndOffsetPaginator.none(stubMappings.findByMetadata(pattern)));
}
@Override
@@ -604,7 +647,8 @@ public void removeStubsByMetadata(StringValuePattern pattern) {
@Override
public void importStubs(StubImport stubImport) {
List mappings = stubImport.getMappings();
- StubImport.Options importOptions = getFirstNonNull(stubImport.getImportOptions(), StubImport.Options.DEFAULTS);
+ StubImport.Options importOptions =
+ getFirstNonNull(stubImport.getImportOptions(), StubImport.Options.DEFAULTS);
for (int i = mappings.size() - 1; i >= 0; i--) {
StubMapping mapping = mappings.get(i);
diff --git a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java
index 26b743a955..205a3f71da 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/core/WireMockConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2023 Thomas Akehurst
+ * Copyright (C) 2013-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,6 +65,8 @@ public class WireMockConfiguration implements Options {
private boolean disableOptimizeXmlFactoriesLoading = false;
private int portNumber = DEFAULT_PORT;
private boolean httpDisabled = false;
+ private boolean http2PlainDisabled = false;
+ private boolean http2TlsDisabled = false;
private String bindAddress = DEFAULT_BIND_ADDRESS;
private int containerThreads = DEFAULT_CONTAINER_THREADS;
@@ -144,6 +146,8 @@ public class WireMockConfiguration implements Options {
private Long maxTemplateCacheEntries = null;
private boolean templateEscapingDisabled = true;
+ private Set supportedProxyEncodings = null;
+
private MappingsSource getMappingsSource() {
if (mappingsSource == null) {
mappingsSource =
@@ -194,6 +198,16 @@ public WireMockConfiguration httpDisabled(boolean httpDisabled) {
return this;
}
+ public WireMockConfiguration http2PlainDisabled(boolean enabled) {
+ this.http2PlainDisabled = enabled;
+ return this;
+ }
+
+ public WireMockConfiguration http2TlsDisabled(boolean enabled) {
+ this.http2TlsDisabled = enabled;
+ return this;
+ }
+
public WireMockConfiguration httpsPort(Integer httpsPort) {
this.httpsPort = httpsPort;
return this;
@@ -551,6 +565,15 @@ public WireMockConfiguration withMaxTemplateCacheEntries(Long maxTemplateCacheEn
return this;
}
+ public WireMockConfiguration withSupportedProxyEncodings(Set supportedProxyEncodings) {
+ this.supportedProxyEncodings = supportedProxyEncodings;
+ return this;
+ }
+
+ public WireMockConfiguration withSupportedProxyEncodings(String... supportedProxyEncodings) {
+ return withSupportedProxyEncodings(Set.of(supportedProxyEncodings));
+ }
+
@Override
public int portNumber() {
return portNumber;
@@ -561,6 +584,16 @@ public boolean getHttpDisabled() {
return httpDisabled;
}
+ @Override
+ public boolean getHttp2PlainDisabled() {
+ return http2PlainDisabled;
+ }
+
+ @Override
+ public boolean getHttp2TlsDisabled() {
+ return http2TlsDisabled;
+ }
+
@Override
public int containerThreads() {
return containerThreads;
@@ -815,4 +848,9 @@ public Set getTemplatePermittedSystemKeys() {
public boolean getTemplateEscapingDisabled() {
return templateEscapingDisabled;
}
+
+ @Override
+ public Set getSupportedProxyEncodings() {
+ return supportedProxyEncodings;
+ }
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/ExtensionDeclarations.java b/src/main/java/com/github/tomakehurst/wiremock/extension/ExtensionDeclarations.java
index b9fb53eeae..66ac8226fc 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/ExtensionDeclarations.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/ExtensionDeclarations.java
@@ -15,7 +15,6 @@
*/
package com.github.tomakehurst.wiremock.extension;
-import static com.github.tomakehurst.wiremock.common.LocalNotifier.notifier;
import static java.util.Arrays.asList;
import java.util.*;
@@ -77,7 +76,7 @@ public List getFactories() {
private boolean removeWebhook(String className) {
if (className.equals(Webhooks.class.getName())) {
- notifier().info(WEBHOOK_MESSAGE);
+ System.out.println(WEBHOOK_MESSAGE);
return false;
}
return true;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/requestfilter/RequestWrapper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/requestfilter/RequestWrapper.java
index 06d2f26ed1..d9e40ddc82 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/requestfilter/RequestWrapper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/requestfilter/RequestWrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2023 Thomas Akehurst
+ * Copyright (C) 2018-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
import static com.github.tomakehurst.wiremock.common.Encoding.encodeBase64;
import static com.github.tomakehurst.wiremock.common.ParameterUtils.getFirstNonNull;
-import static org.apache.commons.lang3.StringUtils.countMatches;
-import static org.apache.commons.lang3.StringUtils.ordinalIndexOf;
+import static com.github.tomakehurst.wiremock.common.Strings.countMatches;
+import static com.github.tomakehurst.wiremock.common.Strings.ordinalIndexOf;
import com.github.tomakehurst.wiremock.http.*;
import java.util.*;
@@ -88,7 +88,7 @@ public static Builder create() {
public String getUrl() {
String absoluteUrl = getAbsoluteUrl();
int relativeStartIndex =
- countMatches(absoluteUrl, "/") >= 3
+ countMatches(absoluteUrl, '/') >= 3
? ordinalIndexOf(absoluteUrl, "/", 3)
: absoluteUrl.length();
return absoluteUrl.substring(relativeStartIndex);
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/HandlebarsOptimizedTemplate.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/HandlebarsOptimizedTemplate.java
index c48674636e..8f5e908b40 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/HandlebarsOptimizedTemplate.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/HandlebarsOptimizedTemplate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019-2023 Thomas Akehurst
+ * Copyright (C) 2019-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import com.github.tomakehurst.wiremock.common.Exceptions;
+import com.github.tomakehurst.wiremock.common.RequestCache;
import java.io.IOException;
import java.io.Writer;
import org.apache.commons.io.output.StringBuilderWriter;
@@ -62,8 +63,8 @@ private static Template uncheckedCompileTemplate(Handlebars handlebars, String t
}
public String apply(Object contextData) {
- final RenderCache renderCache = new RenderCache();
- Context context = Context.newBuilder(contextData).combine("renderCache", renderCache).build();
+ final RequestCache requestCache = RequestCache.getCurrent();
+ Context context = Context.newBuilder(contextData).combine("requestCache", requestCache).build();
return startContent + applyTemplate(context) + endContent;
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/ResponseTemplateTransformer.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/ResponseTemplateTransformer.java
index 2d24bd0267..94a83f49f3 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/ResponseTemplateTransformer.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/ResponseTemplateTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2023 Thomas Akehurst
+ * Copyright (C) 2016-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -172,6 +172,13 @@ public ResponseDefinition transform(ServeEvent serveEvent) {
key, proxyHttpHeaders.getHeader(key).firstValue());
}
}
+
+ if (responseDefinition.getRemoveProxyRequestHeaders() != null) {
+ for (String key : responseDefinition.getRemoveProxyRequestHeaders()) {
+ newProxyResponseDefBuilder.withRemoveRequestHeader(key);
+ }
+ }
+
return newProxyResponseDefBuilder.build();
} else {
return newResponseDefBuilder.build();
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/TemplatedUrlPath.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/TemplatedUrlPath.java
index 40aeaf05a9..990e64b6d0 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/TemplatedUrlPath.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/TemplatedUrlPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 Thomas Akehurst
+ * Copyright (C) 2023-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,13 @@
*/
package com.github.tomakehurst.wiremock.extension.responsetemplating;
+import static com.github.tomakehurst.wiremock.common.Strings.isNotEmpty;
+
import com.github.tomakehurst.wiremock.common.Urls;
import com.github.tomakehurst.wiremock.common.url.PathTemplate;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
-import org.apache.commons.lang3.StringUtils;
public class TemplatedUrlPath extends LinkedHashMap implements Iterable {
@@ -36,7 +37,7 @@ private void addAllPathSegments() {
final List pathSegments = Urls.getPathSegments(originalPath);
int i = 0;
for (String pathNode : pathSegments) {
- if (StringUtils.isNotEmpty(pathNode)) {
+ if (isNotEmpty(pathNode)) {
String key = String.valueOf(i++);
put(key, pathNode);
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/UrlPath.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/UrlPath.java
index 32dab33835..7dd61e4236 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/UrlPath.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/UrlPath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016-2023 Thomas Akehurst
+ * Copyright (C) 2016-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,11 @@
*/
package com.github.tomakehurst.wiremock.extension.responsetemplating;
+import static com.github.tomakehurst.wiremock.common.Strings.isNotEmpty;
+
import com.github.tomakehurst.wiremock.common.Urls;
import java.net.URI;
import java.util.ArrayList;
-import org.apache.commons.lang3.StringUtils;
public class UrlPath extends ArrayList {
@@ -29,7 +30,7 @@ public UrlPath(String url) {
Urls.getPathSegments(originalPath)
.forEach(
pathNode -> {
- if (StringUtils.isNotEmpty(pathNode)) {
+ if (isNotEmpty(pathNode)) {
add(pathNode);
}
});
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsHelper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsHelper.java
index 14870d65f7..66a8979498 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsHelper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017-2021 Thomas Akehurst
+ * Copyright (C) 2017-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,7 @@
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
-import com.github.tomakehurst.wiremock.extension.responsetemplating.RenderCache;
+import com.github.tomakehurst.wiremock.common.RequestCache;
/**
* This abstract class is the base for all defined Handlebars helper in wiremock. It basically
@@ -74,7 +74,7 @@ private String formatMessage(String message) {
return ERROR_PREFIX + message + ERROR_SUFFIX;
}
- protected static RenderCache getRenderCache(Options options) {
- return options.get("renderCache", new RenderCache());
+ protected static RequestCache getRequestCache(Options options) {
+ return options.get("requestCache", new RequestCache());
}
}
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsJsonPathHelper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsJsonPathHelper.java
index f4dd42d776..8a73eda78b 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsJsonPathHelper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsJsonPathHelper.java
@@ -18,7 +18,7 @@
import static com.github.tomakehurst.wiremock.common.ParameterUtils.getFirstNonNull;
import com.github.jknack.handlebars.Options;
-import com.github.tomakehurst.wiremock.extension.responsetemplating.RenderCache;
+import com.github.tomakehurst.wiremock.common.RequestCache;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.InvalidJsonException;
@@ -60,9 +60,9 @@ public Object apply(final Object input, final Options options) throws IOExceptio
}
private Object getValue(JsonPath jsonPath, DocumentContext jsonDocument, Options options) {
- RenderCache renderCache = getRenderCache(options);
- RenderCache.Key cacheKey = RenderCache.Key.keyFor(Object.class, jsonPath, jsonDocument);
- Object value = renderCache.get(cacheKey);
+ RequestCache requestCache = getRequestCache(options);
+ RequestCache.Key cacheKey = RequestCache.Key.keyFor(Object.class, jsonPath, jsonDocument);
+ Object value = requestCache.get(cacheKey);
if (value == null) {
Object defaultValue = options.hash != null ? options.hash("default") : null;
try {
@@ -75,20 +75,20 @@ private Object getValue(JsonPath jsonPath, DocumentContext jsonDocument, Options
value = getFirstNonNull(defaultValue, "");
}
- renderCache.put(cacheKey, value);
+ requestCache.put(cacheKey, value);
}
return value;
}
private DocumentContext getJsonDocument(Object json, Options options) {
- RenderCache renderCache = getRenderCache(options);
- RenderCache.Key cacheKey = RenderCache.Key.keyFor(DocumentContext.class, json);
- DocumentContext document = renderCache.get(cacheKey);
+ RequestCache requestCache = getRequestCache(options);
+ RequestCache.Key cacheKey = RequestCache.Key.keyFor(DocumentContext.class, json);
+ DocumentContext document = requestCache.get(cacheKey);
if (document == null) {
document =
json instanceof String ? parseContext.parse((String) json) : parseContext.parse(json);
- renderCache.put(cacheKey, document);
+ requestCache.put(cacheKey, document);
}
return document;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsRandomValuesHelper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsRandomValuesHelper.java
index 6ad06927db..114eb779d7 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsRandomValuesHelper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsRandomValuesHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018-2021 Thomas Akehurst
+ * Copyright (C) 2018-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,11 @@
*/
package com.github.tomakehurst.wiremock.extension.responsetemplating.helpers;
+import static com.github.tomakehurst.wiremock.common.Strings.*;
+
import com.github.jknack.handlebars.Options;
import java.io.IOException;
import java.util.UUID;
-import org.apache.commons.lang3.RandomStringUtils;
public class HandlebarsRandomValuesHelper extends HandlebarsHelper {
@@ -32,25 +33,25 @@ public Object apply(Void context, Options options) throws IOException {
switch (type) {
case "ALPHANUMERIC":
- rawValue = RandomStringUtils.randomAlphanumeric(length);
+ rawValue = randomAlphanumeric(length);
break;
case "ALPHABETIC":
- rawValue = RandomStringUtils.randomAlphabetic(length);
+ rawValue = randomAlphabetic(length);
break;
case "NUMERIC":
- rawValue = RandomStringUtils.randomNumeric(length);
+ rawValue = randomNumeric(length);
break;
case "ALPHANUMERIC_AND_SYMBOLS":
- rawValue = RandomStringUtils.random(length, 33, 126, false, false);
+ rawValue = random(length, 33, 126, false, false);
break;
case "UUID":
rawValue = UUID.randomUUID().toString();
break;
case "HEXADECIMAL":
- rawValue = RandomStringUtils.random(length, "ABCDEF0123456789");
+ rawValue = random(length, "ABCDEF0123456789");
break;
default:
- rawValue = RandomStringUtils.randomAscii(length);
+ rawValue = randomAscii(length);
break;
}
return uppercase ? rawValue.toUpperCase() : rawValue.toLowerCase();
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsXPathHelper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsXPathHelper.java
index e9c87f1681..ffe9ec27f5 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsXPathHelper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/HandlebarsXPathHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017-2021 Thomas Akehurst
+ * Copyright (C) 2017-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
import com.github.jknack.handlebars.Options;
import com.github.tomakehurst.wiremock.common.ListOrSingle;
+import com.github.tomakehurst.wiremock.common.RequestCache;
import com.github.tomakehurst.wiremock.common.xml.*;
-import com.github.tomakehurst.wiremock.extension.responsetemplating.RenderCache;
import java.io.IOException;
/**
@@ -62,25 +62,25 @@ public Object apply(final String inputXml, final Options options) throws IOExcep
private ListOrSingle getXmlNodes(
String xPathExpression, XmlDocument doc, Options options) {
- RenderCache renderCache = getRenderCache(options);
- RenderCache.Key cacheKey = RenderCache.Key.keyFor(XmlDocument.class, xPathExpression, doc);
- ListOrSingle nodes = renderCache.get(cacheKey);
+ RequestCache requestCache = getRequestCache(options);
+ RequestCache.Key cacheKey = RequestCache.Key.keyFor(XmlDocument.class, xPathExpression, doc);
+ ListOrSingle nodes = requestCache.get(cacheKey);
if (nodes == null) {
nodes = doc.findNodes(xPathExpression);
- renderCache.put(cacheKey, nodes);
+ requestCache.put(cacheKey, nodes);
}
return nodes;
}
private XmlDocument getXmlDocument(String xml, Options options) {
- RenderCache renderCache = getRenderCache(options);
- RenderCache.Key cacheKey = RenderCache.Key.keyFor(XmlDocument.class, xml);
- XmlDocument document = renderCache.get(cacheKey);
+ RequestCache requestCache = getRequestCache(options);
+ RequestCache.Key cacheKey = RequestCache.Key.keyFor(XmlDocument.class, xml);
+ XmlDocument document = requestCache.get(cacheKey);
if (document == null) {
document = Xml.parse(xml);
- renderCache.put(cacheKey, document);
+ requestCache.put(cacheKey, document);
}
return document;
diff --git a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/JWTHelper.java b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/JWTHelper.java
index 832e550636..09ddd3af5f 100644
--- a/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/JWTHelper.java
+++ b/src/main/java/com/github/tomakehurst/wiremock/extension/responsetemplating/helpers/JWTHelper.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2024 Thomas Akehurst
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.github.tomakehurst.wiremock.extension.responsetemplating.helpers;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -6,10 +21,6 @@
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
-import org.apache.commons.lang3.StringUtils;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
@@ -19,88 +30,93 @@
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
+import javax.crypto.spec.SecretKeySpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class JWTHelper extends HandlebarsHelper