Properly escapes query parameters; fixes gh-1441

This commit is contained in:
Marcin Grzejszczak
2021-03-09 10:02:04 +01:00
parent fcf3f154ba
commit 6993f1492e
5 changed files with 144 additions and 26 deletions

View File

@@ -78,7 +78,15 @@ interface GroovyBodyParser extends BodyParser {
@Override
default String quotedLongText(Object text) {
return "'''" + groovyEscapedString(text) + "'''";
String escapedString = groovyEscapedString(text);
if (escapedString.startsWith("'")) {
escapedString = "\\'" + escapedString.substring(1);
}
if (escapedString.endsWith("'")) {
escapedString = escapedString.substring(0, escapedString.length() - 1)
+ "\\'";
}
return "'''" + escapedString + "'''";
}
default String groovyEscapedString(Object text) {

View File

@@ -33,9 +33,13 @@ class JaxRsUrlPathWhen implements When, JaxRsAcceptor, QueryParamsResolver {
private final GeneratedClassMetaData generatedClassMetaData;
JaxRsUrlPathWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData) {
private final BodyParser bodyParser;
JaxRsUrlPathWhen(BlockBuilder blockBuilder, GeneratedClassMetaData metaData,
BodyParser bodyParser) {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = metaData;
this.bodyParser = bodyParser;
}
@Override
@@ -72,7 +76,8 @@ class JaxRsUrlPathWhen implements When, JaxRsAcceptor, QueryParamsResolver {
.iterator();
while (iterator.hasNext()) {
QueryParameter param = iterator.next();
String text = ".queryParam(\"" + param.getName() + "\", \"" + resolveParamValue(param) + "\")";
String text = ".queryParam(\"" + param.getName() + "\", "
+ this.bodyParser.quotedShortText(resolveParamValue(param)) + ")";
if (iterator.hasNext()) {
this.blockBuilder.addLine(text);
}

View File

@@ -36,7 +36,9 @@ class JaxRsWhen implements When, BodyMethodVisitor, JaxRsAcceptor {
this.blockBuilder = blockBuilder;
this.generatedClassMetaData = generatedClassMetaData;
this.bodyParser = bodyParser;
this.whens.addAll(Arrays.asList(new JaxRsUrlPathWhen(this.blockBuilder, this.generatedClassMetaData),
this.whens.addAll(Arrays.asList(
new JaxRsUrlPathWhen(this.blockBuilder, this.generatedClassMetaData,
bodyParser),
new JaxRsRequestWhen(this.blockBuilder, this.generatedClassMetaData),
new JaxRsRequestHeadersWhen(this.blockBuilder, bodyParser),
new JaxRsRequestCookiesWhen(this.blockBuilder, bodyParser),

View File

@@ -632,7 +632,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
} | ['entity("\\"\\"", "text/plain")', 'header("Timer", "123")']
}
def "should generate a call with an url path and query parameters with #methodBuilderName"() {
def "should generate a call with an url path and query parameters with jaxrs"() {
given:
Contract contractDsl = Contract.make {
request {
@@ -646,6 +646,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55"))
parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99"))
parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov"))
parameter 'nameWithDoubleQuote': '"quote"'
parameter 'nameWithQuote': "'quote'"
parameter 'email': "bob@email.com"
parameter 'hello': $(consumer(matching("Denis.*")), producer(absent()))
parameter 'hello': absent()
@@ -666,14 +668,16 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains(modifyStringIfRequired.call('''queryParam("limit", "10"'''))
test.contains(modifyStringIfRequired.call('''queryParam("offset", "20"'''))
test.contains(modifyStringIfRequired.call('''queryParam("filter", "email"'''))
test.contains(modifyStringIfRequired.call('''queryParam("sort", "name"'''))
test.contains(modifyStringIfRequired.call('''queryParam("search", "55"'''))
test.contains(modifyStringIfRequired.call('''queryParam("age", "99"'''))
test.contains(modifyStringIfRequired.call('''queryParam("name", "Denis.Stepanov"'''))
test.contains(modifyStringIfRequired.call('''queryParam("email", "bob@email.com"'''))
test.contains('''queryParam("limit", "10"''')
test.contains('''queryParam("offset", "20"''')
test.contains('''queryParam("filter", "email"''')
test.contains('''queryParam("sort", "name"''')
test.contains('''queryParam("search", "55"''')
test.contains('''queryParam("age", "99"''')
test.contains('''queryParam("name", "Denis.Stepanov"''')
test.contains('''queryParam("nameWithDoubleQuote", "\\"quote\\""''')
test.contains('''queryParam("nameWithQuote", "'quote'"''')
test.contains('''queryParam("email", "bob@email.com"''')
test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""")
test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""")
and:
@@ -681,13 +685,69 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder | modifyStringIfRequired
"jaxrs-spock" | {
properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT
} | { String paramString -> paramString }
methodBuilderName | methodBuilder
"jaxrs" | {
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
} | { String paramString -> paramString.replace("'", "\"") }
}
}
def "should generate a call with an url path and query parameters with jaxrs-spock"() {
given:
Contract contractDsl = Contract.make {
request {
method 'GET'
urlPath('/users') {
queryParameters {
parameter 'limit': $(consumer(equalTo("20")), producer(equalTo("10")))
parameter 'offset': $(consumer(containing("20")), producer(equalTo("20")))
parameter 'filter': "email"
parameter 'sort': equalTo("name")
parameter 'search': $(consumer(notMatching(~/^\/[0-9]{2}$/)), producer("55"))
parameter 'age': $(consumer(notMatching("^\\w*\$")), producer("99"))
parameter 'name': $(consumer(matching("Denis.*")), producer("Denis.Stepanov"))
parameter 'nameWithDoubleQuote': '"quote"'
parameter 'nameWithQuote': "'quote'"
parameter 'email': "bob@email.com"
parameter 'hello': $(consumer(matching("Denis.*")), producer(absent()))
parameter 'hello': absent()
}
}
}
response {
status OK()
body """
{
"property1": "a",
"property2": "b"
}
"""
}
}
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains('''queryParam("limit", '10\'''')
test.contains('''queryParam("offset", '20\'''')
test.contains('''queryParam("filter", 'email\'''')
test.contains('''queryParam("sort", 'name\'''')
test.contains('''queryParam("search", '55\'''')
test.contains('''queryParam("age", '99\'''')
test.contains('''queryParam("name", 'Denis.Stepanov\'''')
test.contains("""queryParam("nameWithDoubleQuote", '''"quote"'''""")
test.contains("""queryParam("nameWithQuote", '''\\'quote\\''''""")
test.contains('''queryParam("email", 'bob@email.com\'''')
test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""")
test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""")
and:
stubMappingIsValidWireMockStub(contractDsl)
and:
SyntaxChecker.tryToCompile(methodBuilderName, test)
where:
methodBuilderName | methodBuilder
"jaxrs-spock" | {
properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT
}
}
@Issue('#169')
@@ -725,14 +785,14 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
when:
String test = singleTestGenerator(contractDsl)
then:
test.contains(modifyStringIfRequired.call('''queryParam("limit", "10"'''))
test.contains(modifyStringIfRequired.call('''queryParam("offset", "20"'''))
test.contains(modifyStringIfRequired.call('''queryParam("filter", "email"'''))
test.contains(modifyStringIfRequired.call('''queryParam("sort", "name"'''))
test.contains(modifyStringIfRequired.call('''queryParam("search", "55"'''))
test.contains(modifyStringIfRequired.call('''queryParam("age", "99"'''))
test.contains(modifyStringIfRequired.call('''queryParam("name", "Denis.Stepanov"'''))
test.contains(modifyStringIfRequired.call('''queryParam("email", "bob@email.com"'''))
test.contains(modifyStringIfRequired.call('''queryParam("limit", '10\''''))
test.contains(modifyStringIfRequired.call('''queryParam("offset", '20\''''))
test.contains(modifyStringIfRequired.call('''queryParam("filter", 'email\''''))
test.contains(modifyStringIfRequired.call('''queryParam("sort", 'name\''''))
test.contains(modifyStringIfRequired.call('''queryParam("search", '55\''''))
test.contains(modifyStringIfRequired.call('''queryParam("age", '99\''''))
test.contains(modifyStringIfRequired.call('''queryParam("name", 'Denis.Stepanov\''''))
test.contains(modifyStringIfRequired.call('''queryParam("email", 'bob@email.com\''''))
test.contains("""assertThatJson(parsedJson).field("['property1']").isEqualTo("a")""")
test.contains("""assertThatJson(parsedJson).field("['property2']").isEqualTo("b")""")
and:

View File

@@ -1814,6 +1814,49 @@ response:
}
}
@Issue("#1441")
def "should work with query parameters that need to be escaped [#methodBuilderName]"() {
given:
Contract contractDsl = Contract.make {
request {
method 'POST'
urlPath("/rest/something") {
queryParameters {
parameter 'quote': equalTo("\"")
}
}
}
response {
status OK()
}
}
methodBuilder()
when:
String test = singleTestGenerator(contractDsl)
then:
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
!test.contains('''.queryParam("quote",""")''')
and:
stubMappingIsValidWireMockStub(contractDsl)
where:
methodBuilderName | methodBuilder
"spock" | {
properties.testFramework = TestFramework.SPOCK
}
"mockmvc" | {
properties.testMode = TestMode.MOCKMVC
}
"jaxrs-spock" | {
properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT
}
"jaxrs" | {
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
}
"testNG" | {
properties.testFramework = TestFramework.TESTNG
}
}
@Issue("#1262")
def "should work with the timeout flag for groovy [#methodBuilderName]"() {
given: