-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Escape json when writing in html (#312)
We're writing the json messages inside a `<script>` element. This means that the `</script>` element must be escaped. Or more generally, any `/`.
- Loading branch information
1 parent
5d6c999
commit 8bfb97c
Showing
10 changed files
with
506 additions
and
265 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 62 additions & 0 deletions
62
java/src/main/java/io/cucumber/htmlformatter/JsonInHtmlWriter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package io.cucumber.htmlformatter; | ||
|
||
import java.io.IOException; | ||
import java.io.Writer; | ||
|
||
/** | ||
* Writes json with the forward slash ({@code /}) escaped. Assumes | ||
* JSON has not been escaped yet. | ||
*/ | ||
class JsonInHtmlWriter extends Writer { | ||
private static final int BUFFER_SIZE = 1024; | ||
private final Writer delegate; | ||
private char[] escapeBuffer; | ||
|
||
JsonInHtmlWriter(Writer delegate) { | ||
this.delegate = delegate; | ||
} | ||
|
||
@Override | ||
public void write(char[] source, int offset, int length) throws IOException { | ||
char[] destination = prepareBuffer(); | ||
int flushAt = BUFFER_SIZE - 2; | ||
int written = 0; | ||
for (int i = offset; i < offset + length; i++) { | ||
char c = source[i]; | ||
|
||
// Flush buffer if (nearly) full | ||
if (written >= flushAt) { | ||
delegate.write(destination, 0, written); | ||
written = 0; | ||
} | ||
|
||
// Write with escapes | ||
if (c == '/') { | ||
destination[written++] = '\\'; | ||
} | ||
destination[written++] = c; | ||
} | ||
// Flush any remaining | ||
if (written > 0) { | ||
delegate.write(destination, 0, written); | ||
} | ||
} | ||
|
||
private char[] prepareBuffer() { | ||
// Reuse the same buffer, avoids repeated array allocation | ||
if (escapeBuffer == null) { | ||
escapeBuffer = new char[BUFFER_SIZE]; | ||
} | ||
return escapeBuffer; | ||
} | ||
|
||
@Override | ||
public void flush() throws IOException { | ||
delegate.flush(); | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
delegate.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
java/src/test/java/io/cucumber/htmlformatter/JsonInHtmlWriterTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package io.cucumber.htmlformatter; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStreamWriter; | ||
import java.util.Arrays; | ||
|
||
import static java.nio.charset.StandardCharsets.UTF_8; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
class JsonInHtmlWriterTest { | ||
|
||
private final ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||
private final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(out, UTF_8); | ||
private final JsonInHtmlWriter writer = new JsonInHtmlWriter(outputStreamWriter); | ||
|
||
@Test | ||
void writes() throws IOException { | ||
writer.write("{\"hello\": \"world\"}"); | ||
assertEquals("{\"hello\": \"world\"}", output()); | ||
} | ||
|
||
@Test | ||
void escapes_single() throws IOException { | ||
writer.write("/"); | ||
assertEquals("\\/", output()); | ||
} | ||
|
||
@Test | ||
void escapes_multiple() throws IOException { | ||
writer.write("</script><script></script>"); | ||
assertEquals("<\\/script><script><\\/script>", output()); | ||
} | ||
|
||
@Test | ||
void partial_writes() throws IOException { | ||
char[] buffer = new char[100]; | ||
String text = "</script><script></script>"; | ||
|
||
text.getChars(0, 9, buffer, 0); | ||
writer.write(buffer, 0, 9); | ||
|
||
text.getChars(9, 17, buffer, 2); | ||
writer.write(buffer, 2, 8); | ||
|
||
text.getChars(17, 26, buffer, 4); | ||
writer.write(buffer, 4, 9); | ||
|
||
assertEquals("<\\/script><script><\\/script>", output()); | ||
} | ||
|
||
@Test | ||
void large_writes_with_odd_boundaries() throws IOException { | ||
char[] buffer = new char[1024]; | ||
// This forces the buffer to flush after every 1023 written characters. | ||
buffer[0] = 'a'; | ||
Arrays.fill(buffer, 1, buffer.length, '/'); | ||
writer.write(buffer); | ||
|
||
StringBuilder expected = new StringBuilder(); | ||
expected.append("a"); | ||
for (int i = 1; i < buffer.length; i++) { | ||
expected.append("\\/"); | ||
} | ||
assertEquals(expected.toString(), output()); | ||
} | ||
|
||
|
||
@Test | ||
void really_large_writes() throws IOException { | ||
char[] buffer = new char[2048]; | ||
Arrays.fill(buffer, '/'); | ||
writer.write(buffer); | ||
|
||
StringBuilder expected = new StringBuilder(); | ||
for (int i = 0; i < buffer.length; i++) { | ||
expected.append("\\/"); | ||
} | ||
assertEquals(expected.toString(), output()); | ||
} | ||
|
||
@Test | ||
void empty_write() throws IOException { | ||
char[] buffer = new char[0]; | ||
writer.write(buffer); | ||
assertEquals("", output()); | ||
} | ||
|
||
private String output() throws IOException { | ||
writer.flush(); | ||
return new String(out.toByteArray(), UTF_8); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.