Skip to content

Commit 05ca602

Browse files
author
Ronald Holshausen
committedOct 27, 2019
chore: use the charset from the content type when converting bodies #956
1 parent b37c6d7 commit 05ca602

File tree

16 files changed

+219
-118
lines changed

16 files changed

+219
-118
lines changed
 

‎consumer/pact-jvm-consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslRequestWithPath.java

+34-11
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,13 @@ public PactDslRequestWithPath body(JSONObject body) {
266266
requestBody = OptionalBody.body(body.toString().getBytes(),
267267
au.com.dius.pact.core.model.ContentType.Companion.getJSON());
268268
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
269-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
269+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
270+
requestBody = OptionalBody.body(body.toString().getBytes());
271+
} else {
272+
ContentType contentType = ContentType.parse(requestHeaders.get(CONTENT_TYPE).get(0));
273+
Charset charset = contentType.getCharset() != null ? contentType.getCharset() : Charset.defaultCharset();
274+
requestBody = OptionalBody.body(body.toString().getBytes(charset),
275+
new au.com.dius.pact.core.model.ContentType(contentType.toString()));
270276
}
271277
return this;
272278
}
@@ -285,15 +291,24 @@ public PactDslRequestWithPath body(DslPart body) {
285291

286292
requestMatchers.addCategory(parent.getMatchers());
287293
requestGenerators.addGenerators(parent.generators);
294+
295+
Charset charset = Charset.defaultCharset();
296+
String contentType = ContentType.APPLICATION_JSON.toString();
297+
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
298+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(contentType));
299+
} else {
300+
contentType = requestHeaders.get(CONTENT_TYPE).get(0);
301+
ContentType ct = ContentType.parse(contentType);
302+
charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
303+
}
304+
288305
if (parent.getBody() != null) {
289-
requestBody = OptionalBody.body(parent.getBody().toString().getBytes(),
290-
au.com.dius.pact.core.model.ContentType.Companion.getJSON());
306+
requestBody = OptionalBody.body(parent.getBody().toString().getBytes(charset),
307+
new au.com.dius.pact.core.model.ContentType(contentType));
291308
} else {
292309
requestBody = OptionalBody.nullBody();
293310
}
294-
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
295-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
296-
}
311+
297312
return this;
298313
}
299314

@@ -303,12 +318,20 @@ public PactDslRequestWithPath body(DslPart body) {
303318
* @param body XML Document
304319
*/
305320
public PactDslRequestWithPath body(Document body) throws TransformerException {
321+
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
322+
String contentType = ContentType.APPLICATION_XML.toString();
323+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(contentType));
306324
requestBody = OptionalBody.body(ConsumerPactBuilder.xmlToString(body).getBytes(),
307-
new au.com.dius.pact.core.model.ContentType(ContentType.APPLICATION_XML.toString()));
308-
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
309-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_XML.toString()));
310-
}
311-
return this;
325+
new au.com.dius.pact.core.model.ContentType(contentType));
326+
} else {
327+
String contentType = requestHeaders.get(CONTENT_TYPE).get(0);
328+
ContentType ct = ContentType.parse(contentType);
329+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
330+
requestBody = OptionalBody.body(ConsumerPactBuilder.xmlToString(body).getBytes(charset),
331+
new au.com.dius.pact.core.model.ContentType(contentType));
332+
}
333+
334+
return this;
312335
}
313336

314337
/**

‎consumer/pact-jvm-consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslRequestWithoutPath.java

+38-20
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,18 @@ public PactDslRequestWithoutPath bodyWithSingleQuotes(String body, ContentType c
207207
* @param body Request body in JSON form
208208
*/
209209
public PactDslRequestWithoutPath body(JSONObject body) {
210-
requestBody = OptionalBody.body(body.toString().getBytes(),
211-
au.com.dius.pact.core.model.ContentType.Companion.getJSON());
212-
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
213-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
214-
}
215-
return this;
210+
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
211+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
212+
requestBody = OptionalBody.body(body.toString().getBytes());
213+
} else {
214+
String contentType = requestHeaders.get(CONTENT_TYPE).get(0);
215+
ContentType ct = ContentType.parse(contentType);
216+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
217+
requestBody = OptionalBody.body(body.toString().getBytes(charset),
218+
new au.com.dius.pact.core.model.ContentType(contentType));
219+
}
220+
221+
return this;
216222
}
217223

218224
/**
@@ -221,14 +227,20 @@ public PactDslRequestWithoutPath body(JSONObject body) {
221227
* @param body Built using the Pact body DSL
222228
*/
223229
public PactDslRequestWithoutPath body(DslPart body) {
224-
DslPart parent = body.close();
225-
requestMatchers.addCategory(parent.matchers);
226-
requestGenerators.addGenerators(parent.generators);
227-
requestBody = OptionalBody.body(parent.toString().getBytes(), au.com.dius.pact.core.model.ContentType.Companion.getJSON());
228-
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
229-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
230-
}
231-
return this;
230+
DslPart parent = body.close();
231+
requestMatchers.addCategory(parent.matchers);
232+
requestGenerators.addGenerators(parent.generators);
233+
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
234+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_JSON.toString()));
235+
requestBody = OptionalBody.body(parent.toString().getBytes());
236+
} else {
237+
String contentType = requestHeaders.get(CONTENT_TYPE).get(0);
238+
ContentType ct = ContentType.parse(contentType);
239+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
240+
requestBody = OptionalBody.body(parent.toString().getBytes(charset),
241+
new au.com.dius.pact.core.model.ContentType(contentType));
242+
}
243+
return this;
232244
}
233245

234246
/**
@@ -237,12 +249,18 @@ public PactDslRequestWithoutPath body(DslPart body) {
237249
* @param body XML Document
238250
*/
239251
public PactDslRequestWithoutPath body(Document body) throws TransformerException {
240-
requestBody = OptionalBody.body(xmlToString(body).getBytes(),
241-
new au.com.dius.pact.core.model.ContentType(ContentType.APPLICATION_XML.toString()));
242-
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
243-
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_XML.toString()));
244-
}
245-
return this;
252+
if (!requestHeaders.containsKey(CONTENT_TYPE)) {
253+
requestHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_XML.toString()));
254+
requestBody = OptionalBody.body(xmlToString(body).getBytes());
255+
} else {
256+
String contentType = requestHeaders.get(CONTENT_TYPE).get(0);
257+
ContentType ct = ContentType.parse(contentType);
258+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
259+
requestBody = OptionalBody.body(xmlToString(body).getBytes(charset),
260+
new au.com.dius.pact.core.model.ContentType(contentType));
261+
}
262+
263+
return this;
246264
}
247265

248266
/**

‎consumer/pact-jvm-consumer/src/main/java/au/com/dius/pact/consumer/dsl/PactDslResponse.java

+46-26
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,17 @@ public PactDslResponse bodyWithSingleQuotes(String body, ContentType contentType
204204
* @param body Response body in JSON form
205205
*/
206206
public PactDslResponse body(JSONObject body) {
207-
this.responseBody = OptionalBody.body(body.toString().getBytes(),
208-
au.com.dius.pact.core.model.ContentType.Companion.getJSON());
209-
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
210-
matchHeader(CONTENT_TYPE, DEFAULT_JSON_CONTENT_TYPE_REGEX, ContentType.APPLICATION_JSON.toString());
211-
}
212-
return this;
207+
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
208+
matchHeader(CONTENT_TYPE, DEFAULT_JSON_CONTENT_TYPE_REGEX, ContentType.APPLICATION_JSON.toString());
209+
this.responseBody = OptionalBody.body(body.toString().getBytes());
210+
} else {
211+
String contentType = responseHeaders.get(CONTENT_TYPE).get(0);
212+
ContentType ct = ContentType.parse(contentType);
213+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
214+
this.responseBody = OptionalBody.body(body.toString().getBytes(charset),
215+
new au.com.dius.pact.core.model.ContentType(contentType));
216+
}
217+
return this;
213218
}
214219

215220
/**
@@ -218,25 +223,33 @@ public PactDslResponse body(JSONObject body) {
218223
* @param body Response body built using the Pact body DSL
219224
*/
220225
public PactDslResponse body(DslPart body) {
221-
DslPart parent = body.close();
226+
DslPart parent = body.close();
222227

223-
if (parent instanceof PactDslJsonRootValue) {
224-
((PactDslJsonRootValue)parent).setEncodeJson(true);
225-
}
228+
if (parent instanceof PactDslJsonRootValue) {
229+
((PactDslJsonRootValue)parent).setEncodeJson(true);
230+
}
226231

227-
responseMatchers.addCategory(parent.getMatchers());
228-
responseGenerators.addGenerators(parent.generators);
229-
if (parent.getBody() != null) {
230-
responseBody = OptionalBody.body(parent.getBody().toString().getBytes(),
231-
au.com.dius.pact.core.model.ContentType.Companion.getJSON());
232-
} else {
233-
responseBody = OptionalBody.nullBody();
234-
}
232+
responseMatchers.addCategory(parent.getMatchers());
233+
responseGenerators.addGenerators(parent.generators);
234+
235+
Charset charset = Charset.defaultCharset();
236+
String contentType = ContentType.APPLICATION_JSON.toString();
237+
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
238+
matchHeader(CONTENT_TYPE, DEFAULT_JSON_CONTENT_TYPE_REGEX, contentType);
239+
} else {
240+
contentType = responseHeaders.get(CONTENT_TYPE).get(0);
241+
ContentType ct = ContentType.parse(contentType);
242+
charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
243+
}
235244

236-
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
237-
matchHeader(CONTENT_TYPE, DEFAULT_JSON_CONTENT_TYPE_REGEX, ContentType.APPLICATION_JSON.toString());
238-
}
239-
return this;
245+
if (parent.getBody() != null) {
246+
responseBody = OptionalBody.body(parent.getBody().toString().getBytes(charset),
247+
new au.com.dius.pact.core.model.ContentType(contentType));
248+
} else {
249+
responseBody = OptionalBody.nullBody();
250+
}
251+
252+
return this;
240253
}
241254

242255
/**
@@ -245,11 +258,18 @@ public PactDslResponse body(DslPart body) {
245258
* @param body Response body as an XML Document
246259
*/
247260
public PactDslResponse body(Document body) throws TransformerException {
261+
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
262+
responseHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_XML.toString()));
248263
responseBody = OptionalBody.body(ConsumerPactBuilder.xmlToString(body).getBytes());
249-
if (!responseHeaders.containsKey(CONTENT_TYPE)) {
250-
responseHeaders.put(CONTENT_TYPE, Collections.singletonList(ContentType.APPLICATION_XML.toString()));
251-
}
252-
return this;
264+
} else {
265+
String contentType = responseHeaders.get(CONTENT_TYPE).get(0);
266+
ContentType ct = ContentType.parse(contentType);
267+
Charset charset = ct.getCharset() != null ? ct.getCharset() : Charset.defaultCharset();
268+
responseBody = OptionalBody.body(ConsumerPactBuilder.xmlToString(body).getBytes(charset),
269+
new au.com.dius.pact.core.model.ContentType(contentType));
270+
}
271+
272+
return this;
253273
}
254274

255275
/**

‎consumer/pact-jvm-consumer/src/main/kotlin/au/com/dius/pact/consumer/KTorMockServer.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class KTorMockServer(
9696
val body = if (bodyContents.isEmpty()) {
9797
OptionalBody.empty()
9898
} else {
99-
OptionalBody.body(bodyContents.toByteArray())
99+
OptionalBody.body(bodyContents.toByteArray(), ContentType(headers["Content-Type"] ?: ContentType.JSON.contentType))
100100
}
101101
return Request(call.request.httpMethod.value, call.request.path(),
102102
call.request.queryParameters.entries().associate { it.toPair() }.toMutableMap(),

‎consumer/pact-jvm-consumer/src/main/kotlin/au/com/dius/pact/consumer/MessagePactBuilder.kt

+10-8
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ package au.com.dius.pact.consumer
33
import au.com.dius.pact.consumer.dsl.DslPart
44
import au.com.dius.pact.consumer.dsl.Matcher
55
import au.com.dius.pact.core.model.Consumer
6+
import au.com.dius.pact.core.model.ContentType
67
import au.com.dius.pact.core.model.InvalidPactException
78
import au.com.dius.pact.core.model.OptionalBody
89
import au.com.dius.pact.core.model.Provider
910
import au.com.dius.pact.core.model.ProviderState
1011
import au.com.dius.pact.core.model.messaging.Message
1112
import au.com.dius.pact.core.model.messaging.MessagePact
12-
import org.apache.http.entity.ContentType
1313

1414
/**
1515
* PACT DSL builder for v3 specification
@@ -102,19 +102,21 @@ class MessagePactBuilder(
102102

103103
val message = messages.last()
104104
val metadata = message.metaData.toMutableMap()
105-
val contentType = metadata.entries.find {
105+
val contentTypeEntry = metadata.entries.find {
106106
it.key.toLowerCase() == "contenttype" || it.key.toLowerCase() == "content-type"
107107
}
108-
if (contentType == null) {
109-
metadata["contentType"] = ContentType.APPLICATION_JSON.toString()
108+
109+
var contentType = ContentType.JSON
110+
if (contentTypeEntry == null) {
111+
metadata["contentType"] = contentType.toString()
110112
} else {
111-
metadata.remove(contentType.key)
112-
metadata["contentType"] = contentType.value
113+
contentType = ContentType(contentTypeEntry.value)
114+
metadata.remove(contentTypeEntry.key)
115+
metadata["contentType"] = contentTypeEntry.value
113116
}
114117

115118
val parent = body.close()
116-
message.contents = OptionalBody.body(parent.toString().toByteArray(),
117-
au.com.dius.pact.core.model.ContentType(metadata["contentType"].toString()))
119+
message.contents = OptionalBody.body(parent.toString().toByteArray(contentType.asCharset()), contentType)
118120
message.metaData = metadata
119121
message.matchingRules.addCategory(parent.matchers)
120122

‎core/model/src/main/kotlin/au/com/dius/pact/core/model/ContentType.kt

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
package au.com.dius.pact.core.model
22

3+
import mu.KLogging
34
import java.nio.charset.Charset
45

56
private val jsonRegex = Regex("application\\/.*json")
67
private val xmlRegex = Regex("application\\/.*xml")
78

89
data class ContentType(val contentType: String) {
910

11+
private val parsedContentType: org.apache.http.entity.ContentType? = try {
12+
if (contentType.isNotEmpty()) {
13+
org.apache.http.entity.ContentType.parse(contentType)
14+
} else {
15+
null
16+
}
17+
} catch (e: Exception) {
18+
logger.debug { "Failed to parse content type '$contentType'" }
19+
null
20+
}
21+
1022
fun isJson(): Boolean = jsonRegex.matches(contentType.toLowerCase())
1123

1224
fun isXml(): Boolean = xmlRegex.matches(contentType.toLowerCase())
1325

1426
override fun toString() = contentType
1527

16-
fun asCharset(): Charset? {
17-
return try {
18-
org.apache.http.entity.ContentType.parse(contentType)?.charset
19-
} catch (e: Exception) {
20-
HttpPart.logger.debug { "Failed to parse content type '$contentType'" }
21-
null
22-
}
23-
}
28+
fun asCharset(): Charset = parsedContentType?.charset ?: Charset.defaultCharset()
29+
30+
fun asMimeType() = parsedContentType?.mimeType ?: contentType
2431

25-
companion object {
32+
companion object : KLogging() {
2633
val UNKNOWN = ContentType("")
2734
val TEXT_PLAIN = ContentType("text/plain")
2835
val JSON = ContentType("application/json")

‎core/model/src/main/kotlin/au/com/dius/pact/core/model/OptionalBody.kt

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package au.com.dius.pact.core.model
22

3-
import java.nio.charset.Charset
4-
53
/**
64
* Class to represent missing, empty, null and present bodies
75
*/
@@ -101,7 +99,7 @@ data class OptionalBody(
10199

102100
override fun toString(): String {
103101
return when (state) {
104-
State.PRESENT -> "PRESENT(${value!!.toString(Charset.defaultCharset())})"
102+
State.PRESENT -> "PRESENT(${value!!.toString(contentType.asCharset())})"
105103
State.EMPTY -> "EMPTY"
106104
State.NULL -> "NULL"
107105
State.MISSING -> "MISSING"
@@ -110,7 +108,7 @@ data class OptionalBody(
110108

111109
fun valueAsString(): String {
112110
return when (state) {
113-
State.PRESENT -> value!!.toString(Charset.defaultCharset())
111+
State.PRESENT -> value!!.toString(contentType.asCharset())
114112
State.EMPTY -> ""
115113
State.NULL -> ""
116114
State.MISSING -> ""

‎core/model/src/main/kotlin/au/com/dius/pact/core/model/Request.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,19 @@ class Request @JvmOverloads constructor(
112112
} else {
113113
emptyMap()
114114
}
115+
116+
var contentType = ContentType.JSON
117+
val contentTypeEntry = headers.entries.find { it.key.toUpperCase() == "CONTENT-TYPE" }
118+
if (contentTypeEntry != null) {
119+
contentType = ContentType(contentTypeEntry.value.first())
120+
}
121+
115122
val body = if (json.has("body")) {
116123
when {
117124
json["body"].isJsonNull -> OptionalBody.nullBody()
118125
json["body"].isJsonPrimitive && json["body"].asJsonPrimitive.isString ->
119-
OptionalBody.body(json["body"].asJsonPrimitive.asString.toByteArray())
120-
else -> OptionalBody.body(json["body"].toString().toByteArray())
126+
OptionalBody.body(json["body"].asJsonPrimitive.asString.toByteArray(contentType.asCharset()), contentType)
127+
else -> OptionalBody.body(json["body"].toString().toByteArray(contentType.asCharset()), contentType)
121128
}
122129
} else OptionalBody.missing()
123130
val matchingRules = if (json.has("matchingRules") && json["matchingRules"].isJsonObject)

0 commit comments

Comments
 (0)
Please sign in to comment.