Skip to content
Open
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 @@ -21,6 +21,7 @@
import io.swagger.v3.parser.util.ResolverFully;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
Expand Down Expand Up @@ -209,6 +210,7 @@ private SwaggerParseResult resolve(SwaggerParseResult result, List<Authorization
String location) {
if (location != null) {
location = location.replace('\\', '/');
location = toUriSafeLocation(location);
}
try {
if (options != null) {
Expand Down Expand Up @@ -265,6 +267,29 @@ private SwaggerParseResult resolve(SwaggerParseResult result, List<Authorization
return result;
}

/**
* Normalizes a location that is used as the base URI for reference resolution.
* <p>
* {@code readLocation} accepts raw local filesystem paths, but reference resolution builds
* {@code java.net.URI} instances from that base (e.g. in {@code ReferenceUtils} and {@code Visitor#readURI}).
* A raw path containing characters that are illegal in a URI (most commonly a space) makes those
* constructions fail with "Illegal character in path", which surfaces as a parse error even for a
* self-contained single-file spec. When the location is not already a valid URI, convert it to a proper
* {@code file:} URI so the base is URI-safe; valid URIs (including scheme-less relative paths) are left untouched.
*/
private static String toUriSafeLocation(String location) {
try {
new URI(location);
return location;
} catch (URISyntaxException e) {
try {
return Paths.get(location).toUri().toString();
} catch (Exception ex) {
return location;
}
}
}

private String getParseErrorMessage(String originalMessage, String location) {
if (Objects.isNull(originalMessage)) {
return String.format("Unable to parse `%s`", location);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.swagger.v3.parser.test;

import io.swagger.v3.parser.OpenAPIV3Parser;
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.testng.annotations.Test;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;

/**
* Regression test for https://github.com/swagger-api/swagger-parser/issues/2365
*
* A raw local filesystem path accepted by {@link OpenAPIV3Parser#readLocation} must not
* produce an "Illegal character in path" error while resolving same-file OpenAPI 3.1 refs,
* even when the path contains characters that are illegal in a URI (e.g. spaces).
*/
public class OpenAPIV31RawPathWithSpacesTest {

@Test
public void resolveSameFileReferenceFromRawPathWithSpaces() throws Exception {
Path directory = Files.createTempDirectory("openapi path with spaces");
Path root = directory.resolve("openapi.yaml");

Files.write(root, (
"openapi: 3.1.0\n" +
"info:\n" +
" title: Path With Spaces\n" +
" version: 1.0.0\n" +
"paths:\n" +
" /examples:\n" +
" get:\n" +
" responses:\n" +
" '200':\n" +
" $ref: '#/components/responses/ExampleResponse'\n" +
"components:\n" +
" responses:\n" +
" ExampleResponse:\n" +
" description: OK\n" +
" content:\n" +
" application/json:\n" +
" schema:\n" +
" $ref: '#/components/schemas/Example'\n" +
" schemas:\n" +
" Example:\n" +
" type: object\n" +
" properties:\n" +
" id:\n" +
" type: string\n").getBytes(StandardCharsets.UTF_8));

ParseOptions options = new ParseOptions();
options.setResolve(true);
options.setResolveResponses(true);

SwaggerParseResult result = new OpenAPIV3Parser().readLocation(root.toString(), null, options);

assertNotNull(result.getOpenAPI());
assertNotNull(result.getOpenAPI().getComponents().getResponses().get("ExampleResponse"));

String illegalCharMessage = result.getMessages().stream()
.filter(message -> message.contains("Illegal character in path"))
.findFirst()
.orElse(null);
assertNull(illegalCharMessage, "unexpected parse error: " + illegalCharMessage);
}
}