Skip to content

Commit

Permalink
Merge pull request #1462 from swagger-api/better-parser-erros
Browse files Browse the repository at this point in the history
improved error reporting in result messages
  • Loading branch information
frantuma authored Oct 16, 2020
2 parents 0e5cdd3 + 707b37f commit af4fdc4
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public SwaggerDeserializationResult readWithInfo(JsonNode node) {
@Override
public SwaggerDeserializationResult readWithInfo(String location, List<AuthorizationValue> auths) {
String data;

SwaggerDeserializationResult errorOutput = new SwaggerDeserializationResult();
try {
location = location.replaceAll("\\\\","/");
if (location.toLowerCase().startsWith("http")) {
Expand All @@ -61,26 +61,28 @@ public SwaggerDeserializationResult readWithInfo(String location, List<Authoriza
ObjectMapper mapper = Json.mapper();
rootNode = mapper.readTree(data);
} else {
rootNode = deserializeYaml(data);
rootNode = deserializeYaml(data, errorOutput);
}
return readWithInfo(rootNode);
}
catch (SSLHandshakeException e) {
SwaggerDeserializationResult output = new SwaggerDeserializationResult();
output.message("unable to read location `" + location + "` due to a SSL configuration error. " +
errorOutput.message("unable to read location `" + location + "` due to a SSL configuration error. " +
"It is possible that the server SSL certificate is invalid, self-signed, or has an untrusted " +
"Certificate Authority.");
return output;
return errorOutput;
}
catch (Exception e) {
SwaggerDeserializationResult output = new SwaggerDeserializationResult();
output.message("unable to read location `" + location + "`");
return output;
errorOutput.message("unable to read location `" + location + "`");
return errorOutput;
}
}

protected JsonNode deserializeYaml(String data) throws IOException{
return DeserializationUtils.readYamlTree(data);
return deserializeYaml(data, null);
}

protected JsonNode deserializeYaml(String data, SwaggerDeserializationResult errorOutput) throws IOException{
return DeserializationUtils.readYamlTree(data, errorOutput);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public SwaggerDeserializationResult readWithInfo(String location, List<Authoriza
.message("The swagger definition could not be read");
}
}catch (Exception e) {
output.setMessages(Arrays.asList(e.getMessage()));
output.message(e.getMessage());
}
return output;
}
Expand Down Expand Up @@ -99,7 +99,7 @@ public SwaggerDeserializationResult readWithInfo(String swaggerAsString) {
}

protected JsonNode deserializeYaml(String data) throws IOException{
return DeserializationUtils.readYamlTree(data);
return DeserializationUtils.readYamlTree(data, null);
}

public SwaggerDeserializationResult readWithInfo(String swaggerAsString, boolean resolve) {
Expand Down Expand Up @@ -197,4 +197,4 @@ public List<SwaggerParserExtension> getExtensions() {
}
return output;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,17 @@ public static Options getOptions() {
}

public static JsonNode deserializeIntoTree(String contents, String fileOrHost) {
return deserializeIntoTree(contents, fileOrHost, null);
}

public static JsonNode deserializeIntoTree(String contents, String fileOrHost, SwaggerDeserializationResult errorOutput) {
JsonNode result;

try {
if (isJson(contents)) {
result = Json.mapper().readTree(contents);
} else {
result = readYamlTree(contents);
result = readYamlTree(contents, errorOutput);
}
} catch (IOException e) {
throw new RuntimeException("An exception was thrown while trying to deserialize the contents of " + fileOrHost + " into a JsonNode tree", e);
Expand All @@ -130,6 +134,9 @@ public static JsonNode deserializeIntoTree(String contents, String fileOrHost) {
}

public static <T> T deserialize(Object contents, String fileOrHost, Class<T> expectedType) {
return deserialize(contents, fileOrHost, expectedType, null);
}
public static <T> T deserialize(Object contents, String fileOrHost, Class<T> expectedType, SwaggerDeserializationResult errorOutput) {
T result;

boolean isJson = false;
Expand All @@ -143,7 +150,7 @@ public static <T> T deserialize(Object contents, String fileOrHost, Class<T> exp
if (isJson) {
result = Json.mapper().readValue((String) contents, expectedType);
} else {
result = Yaml.mapper().convertValue(readYamlTree((String) contents), expectedType);
result = Yaml.mapper().convertValue(readYamlTree((String) contents, errorOutput), expectedType);
}
} else {
result = Json.mapper().convertValue(contents, expectedType);
Expand Down Expand Up @@ -182,7 +189,7 @@ public static org.yaml.snakeyaml.Yaml buildSnakeYaml(BaseConstructor constructor
}


public static JsonNode readYamlTree(String contents) throws IOException {
public static JsonNode readYamlTree(String contents, SwaggerDeserializationResult errorOutput) throws IOException {

if (!options.isSupportYamlAnchors()) {
return Yaml.mapper().readTree(contents);
Expand All @@ -197,7 +204,7 @@ public static JsonNode readYamlTree(String contents) throws IOException {

Object o = yaml.load(contents);
if (options.isValidateYamlInput()) {
boolean res = exceedsLimits(o, null, new Integer(0), new IdentityHashMap<Object, Long>());
boolean res = exceedsLimits(o, null, new Integer(0), new IdentityHashMap<Object, Long>(), errorOutput);
if (res) {
LOGGER.warn("Error converting snake-parsed yaml to JsonNode");
return Yaml.mapper().readTree(contents);
Expand All @@ -207,16 +214,23 @@ public static JsonNode readYamlTree(String contents) throws IOException {
return n;
} catch (Throwable e) {
LOGGER.warn("Error snake-parsing yaml content", e);
if (errorOutput != null) {
errorOutput.message(e.getMessage());
}
return Yaml.mapper().readTree(contents);
}
}

private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map<Object, Long> visited) {
private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map<Object, Long> visited, SwaggerDeserializationResult errorOutput) {

if (o == null) return false;
if (!(o instanceof List) && !(o instanceof Map)) return false;
if (depth > options.getMaxYamlDepth()) {
LOGGER.warn("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth());
String msg = String.format("snake-yaml result exceeds max depth %d; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth());
LOGGER.warn(msg);
if (errorOutput != null) {
errorOutput.message(msg);
}
return true;
}
int currentDepth = depth;
Expand All @@ -226,13 +240,17 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map
target = o;
}
if (options.isYamlCycleCheck()) {
boolean res = hasReference(o, target, new Integer(0), new IdentityHashMap<Object, Long>());
boolean res = hasReference(o, target, new Integer(0), new IdentityHashMap<Object, Long>(), errorOutput);
if (res) {
return true;
}
}
if (visited.get(o) > options.getMaxYamlReferences()) {
LOGGER.warn("snake-yaml result exceeds max references {}; threshold can be increased if needed by setting system property `maxYamlReferences` to a higher value.", options.getMaxYamlReferences());
String msg = String.format("snake-yaml result exceeds max references %d; threshold can be increased if needed by setting system property `maxYamlReferences` to a higher value.", options.getMaxYamlReferences());
LOGGER.warn(msg);
if (errorOutput != null) {
errorOutput.message(msg);
}
return true;
}
visited.put(o, visited.get(o) + 1);
Expand All @@ -243,21 +261,21 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map

if (o instanceof Map) {
for (Object k : ((Map) o).keySet()) {
boolean res = exceedsLimits(k, o, currentDepth + 1, visited);
boolean res = exceedsLimits(k, o, currentDepth + 1, visited, errorOutput);
if (res) {
return true;
}
}
for (Object v : ((Map) o).values()) {
boolean res = exceedsLimits(v, o, currentDepth + 1, visited);
boolean res = exceedsLimits(v, o, currentDepth + 1, visited, errorOutput);
if (res) {
return true;
}
}

} else if (o instanceof List) {
for (Object v: ((List)o)) {
boolean res = exceedsLimits(v, o, currentDepth + 1, visited);
boolean res = exceedsLimits(v, o, currentDepth + 1, visited, errorOutput);
if (res) {
return true;
}
Expand All @@ -266,13 +284,17 @@ private static boolean exceedsLimits(Object o, Object parent, Integer depth, Map
return false;
}

private static boolean hasReference(Object o, Object target, Integer depth, Map<Object, Long> visited) {
private static boolean hasReference(Object o, Object target, Integer depth, Map<Object, Long> visited, SwaggerDeserializationResult errorOutput) {

if (o == null || target == null) return false;
if (!(o instanceof List) && !(o instanceof Map)) return false;
if (!(target instanceof List) && !(target instanceof Map)) return false;
if (depth > options.getMaxYamlDepth()) {
LOGGER.warn("snake-yaml result exceeds max depth {}; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth());
String msg = String.format("snake-yaml result exceeds max depth %d; threshold can be increased if needed by setting system property `maxYamlDepth` to a higher value.", options.getMaxYamlDepth());
LOGGER.warn(msg);
if (errorOutput != null) {
errorOutput.message(msg);
}
return true;
}
int currentDepth = depth;
Expand All @@ -290,10 +312,14 @@ private static boolean hasReference(Object o, Object target, Integer depth, Map<
}
for (Object v : children) {
if (v == target) {
LOGGER.warn("detected cycle in snake-yaml result; cycle check can be disabled by setting system property `yamlCycleCheck` to false.");
return true;
String msg = "detected cycle in snake-yaml result; cycle check can be disabled by setting system property `yamlCycleCheck` to false.";
LOGGER.warn(msg);
if (errorOutput != null) {
errorOutput.message(msg);
}
return true;
}
boolean res = hasReference(v, target, currentDepth + 1, visited);
boolean res = hasReference(v, target, currentDepth + 1, visited, errorOutput);
if (res) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.swagger.parser;

import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.matchers.SerializationMatchers;
import io.swagger.models.*;
import io.swagger.models.parameters.Parameter;
Expand Down Expand Up @@ -266,7 +265,7 @@ public void testIssue205() {
assertNotNull(definition);
assertTrue(definition instanceof ModelImpl);
}

@Test
public void testIssue136() {
String spec =
Expand Down

0 comments on commit af4fdc4

Please sign in to comment.