[go: nahoru, domu]

Skip to content

Commit

Permalink
feat: GsonFactory to have read leniency option (#1819)
Browse files Browse the repository at this point in the history
* feat: GsonFactory to have read leniency option
  • Loading branch information
suztomo committed Feb 24, 2023
1 parent 0664e17 commit 00d61b9
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,23 @@ public static GsonFactory getDefaultInstance() {
return InstanceHolder.INSTANCE;
}

/** Controls the behavior of leniency in reading JSON value */
private boolean readLeniency = false;

/** Holder for the result of {@link #getDefaultInstance()}. */
@Beta
static class InstanceHolder {
static final GsonFactory INSTANCE = new GsonFactory();
}

// Keeping the default, non-arg constructor for backward compatibility. Users should use
// getDefaultInstance() or builder() instead.
public GsonFactory() {}

private GsonFactory(Builder builder) {
readLeniency = builder.readLeniency;
}

@Override
public JsonParser createJsonParser(InputStream in) {
return createJsonParser(new InputStreamReader(in, StandardCharsets.UTF_8));
Expand Down Expand Up @@ -90,4 +101,36 @@ public JsonGenerator createJsonGenerator(OutputStream out, Charset enc) {
public JsonGenerator createJsonGenerator(Writer writer) {
return new GsonGenerator(this, new JsonWriter(writer));
}

/** Returns true if it is lenient to input JSON value. */
boolean getReadLeniency() {
return readLeniency;
}

/** Returns the builder * */
public static Builder builder() {
return new Builder();
}

/** Builder for GsonFactory. */
public static final class Builder {
// Do not directly call this constructor
private Builder() {}

private boolean readLeniency = false;

/**
* Set to {@code true} when you want to the JSON parser to be lenient to reading JSON value. By
* default, it is {@code false}.
*/
public Builder setReadLeniency(boolean readLeniency) {
this.readLeniency = readLeniency;
return this;
}

/** Builds GsonFactory instance. */
public GsonFactory build() {
return new GsonFactory(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class GsonParser extends JsonParser {
GsonParser(GsonFactory factory, JsonReader reader) {
this.factory = factory;
this.reader = reader;
reader.setLenient(false);
reader.setLenient(factory.getReadLeniency());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@

package com.google.api.client.json.gson;

import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.JsonParser;
import com.google.api.client.test.json.AbstractJsonFactoryTest;
import com.google.gson.stream.MalformedJsonException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

/**
Expand Down Expand Up @@ -94,4 +100,30 @@ public final void testGetByteValue() throws IOException {
assertNotNull(ex.getMessage());
}
}

public final void testReaderLeniency_lenient() throws IOException {
JsonObjectParser parser =
new JsonObjectParser(GsonFactory.builder().setReadLeniency(true).build());

// This prefix in JSON body is used to prevent Cross-site script inclusion (XSSI).
InputStream inputStream =
new ByteArrayInputStream((")]}'\n" + JSON_ENTRY_PRETTY).getBytes(StandardCharsets.UTF_8));
GenericJson json = parser.parseAndClose(inputStream, StandardCharsets.UTF_8, GenericJson.class);

assertEquals("foo", json.get("title"));
}

public final void testReaderLeniency_not_lenient_by_default() throws IOException {
JsonObjectParser parser = new JsonObjectParser(GsonFactory.getDefaultInstance());

try {
// This prefix in JSON body is used to prevent Cross-site script inclusion (XSSI).
InputStream inputStream =
new ByteArrayInputStream((")]}'\n" + JSON_ENTRY_PRETTY).getBytes(StandardCharsets.UTF_8));
parser.parseAndClose(inputStream, StandardCharsets.UTF_8, GenericJson.class);
fail("The read leniency should fail the JSON input with XSSI prefix.");
} catch (MalformedJsonException ex) {
assertNotNull(ex.getMessage());
}
}
}

0 comments on commit 00d61b9

Please sign in to comment.