Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improved error reporting in result messages #1462

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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