Skip to content

Commit 513ab6e

Browse files
committed
Backport #1597 in 2.8 branch too
1 parent b55b04f commit 513ab6e

File tree

4 files changed

+76
-16
lines changed

4 files changed

+76
-16
lines changed

release-notes/CREDITS

+5-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,11 @@ Joshua Jones
599599
Ivo Studens ([email protected])
600600
* Contributed #1585: Invoke ServiceLoader.load() inside of a privileged block
601601
when loading modules using `ObjectMapper.findModules()`
602-
(2.8.9)
602+
(2.8.9)
603+
604+
Marco Catania ([email protected])
605+
* Contributed #1597: Escape JSONP breaking characters
606+
(2.8.9)
603607

604608
Connor Kuhn (ckuhn@github)
605609
* Contributed #1341: FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY

release-notes/VERSION

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ Project: jackson-databind
33
=== Releases ===
44
------------------------------------------------------------------------
55

6+
2.8.9 (not yet released)
7+
8+
#1597: Escape JSONP breaking characters
9+
(contributed by Marco C)
10+
611
2.8.8.1 (19-Apr-2017)
712

813
#1585: Invoke ServiceLoader.load() inside of a privileged block when loading

src/main/java/com/fasterxml/jackson/databind/util/JSONPObject.java

+29-15
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
* <a href="http://en.wikipedia.org/wiki/JSONP">JSONP</a> wrapping.
1414
*
1515
* @see com.fasterxml.jackson.databind.util.JSONWrappedObject
16-
*
17-
* @author tatu
1816
*/
1917
public class JSONPObject
2018
implements JsonSerializable
@@ -55,29 +53,45 @@ public JSONPObject(String function, Object value, JavaType asType)
5553
*/
5654

5755
@Override
58-
public void serializeWithType(JsonGenerator jgen, SerializerProvider provider, TypeSerializer typeSer)
59-
throws IOException, JsonProcessingException
56+
public void serializeWithType(JsonGenerator gen, SerializerProvider provider, TypeSerializer typeSer)
57+
throws IOException
6058
{
6159
// No type for JSONP wrapping: value serializer will handle typing for value:
62-
serialize(jgen, provider);
60+
serialize(gen, provider);
6361
}
6462

6563
@Override
66-
public void serialize(JsonGenerator jgen, SerializerProvider provider)
67-
throws IOException, JsonProcessingException
64+
public void serialize(JsonGenerator gen, SerializerProvider provider)
65+
throws IOException
6866
{
6967
// First, wrapping:
70-
jgen.writeRaw(_function);
71-
jgen.writeRaw('(');
68+
gen.writeRaw(_function);
69+
gen.writeRaw('(');
70+
7271
if (_value == null) {
73-
provider.defaultSerializeNull(jgen);
74-
} else if (_serializationType != null) {
75-
provider.findTypedValueSerializer(_serializationType, true, null).serialize(_value, jgen, provider);
72+
provider.defaultSerializeNull(gen);
7673
} else {
77-
Class<?> cls = _value.getClass();
78-
provider.findTypedValueSerializer(cls, true, null).serialize(_value, jgen, provider);
74+
// NOTE: Escape line-separator characters that break JSONP only if no custom character escapes are set.
75+
// If custom escapes are in place JSONP-breaking characters will not be escaped and it is recommended to
76+
// add escaping for those (see JsonpCharacterEscapes class).
77+
boolean override = (gen.getCharacterEscapes() == null);
78+
if (override) {
79+
gen.setCharacterEscapes(JsonpCharacterEscapes.instance());
80+
}
81+
82+
try {
83+
if (_serializationType != null) {
84+
provider.findTypedValueSerializer(_serializationType, true, null).serialize(_value, gen, provider);
85+
} else {
86+
provider.findTypedValueSerializer(_value.getClass(), true, null).serialize(_value, gen, provider);
87+
}
88+
} finally {
89+
if (override) {
90+
gen.setCharacterEscapes(null);
91+
}
92+
}
7993
}
80-
jgen.writeRaw(')');
94+
gen.writeRaw(')');
8195
}
8296

8397
/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.databind.BaseMapTest;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
8+
public class JSONPObjectTest extends BaseMapTest {
9+
10+
private final String CALLBACK = "callback";
11+
private final ObjectMapper MAPPER = new ObjectMapper();
12+
13+
/**
14+
* Unit tests for checking that JSONP breaking characters U+2028 and U+2029 are escaped when creating a {@link JSONPObject}.
15+
*/
16+
17+
public void testU2028Escaped() throws IOException {
18+
String containsU2028 = String.format("This string contains %c char", '\u2028');
19+
JSONPObject jsonpObject = new JSONPObject(CALLBACK, containsU2028);
20+
String valueAsString = MAPPER.writeValueAsString(jsonpObject);
21+
assertFalse(valueAsString.contains("\u2028"));
22+
}
23+
24+
public void testU2029Escaped() throws IOException {
25+
String containsU2029 = String.format("This string contains %c char", '\u2029');
26+
JSONPObject jsonpObject = new JSONPObject(CALLBACK, containsU2029);
27+
String valueAsString = MAPPER.writeValueAsString(jsonpObject);
28+
assertFalse(valueAsString.contains("\u2029"));
29+
}
30+
31+
public void testU2030NotEscaped() throws IOException {
32+
String containsU2030 = String.format("This string contains %c char", '\u2030');
33+
JSONPObject jsonpObject = new JSONPObject(CALLBACK, containsU2030);
34+
String valueAsString = MAPPER.writeValueAsString(jsonpObject);
35+
assertTrue(valueAsString.contains("\u2030"));
36+
}
37+
}

0 commit comments

Comments
 (0)