mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
Try to use Content-Type when loading a URL
This is intended to fix #67. Unfortunately we don't have test coverage for URL loading, so not feeling super confident.
This commit is contained in:
parent
54ec27ec2a
commit
868a50a53d
4
HOCON.md
4
HOCON.md
@ -1111,6 +1111,10 @@ The details:
|
|||||||
"2" then the resulting array would have indices "0" and "1",
|
"2" then the resulting array would have indices "0" and "1",
|
||||||
i.e. missing indices in the object are eliminated.
|
i.e. missing indices in the object are eliminated.
|
||||||
|
|
||||||
|
## MIME Type
|
||||||
|
|
||||||
|
Use "application/hocon" for Content-Type.
|
||||||
|
|
||||||
## API Recommendations
|
## API Recommendations
|
||||||
|
|
||||||
Implementations of HOCON ideally follow certain conventions and
|
Implementations of HOCON ideally follow certain conventions and
|
||||||
|
@ -18,6 +18,7 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -104,6 +105,10 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigSyntax contentType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ConfigParseable relativeTo(String filename) {
|
ConfigParseable relativeTo(String filename) {
|
||||||
// fall back to classpath; we treat the "filename" as absolute
|
// fall back to classpath; we treat the "filename" as absolute
|
||||||
// (don't add a package name in front),
|
// (don't add a package name in front),
|
||||||
@ -186,8 +191,23 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
protected AbstractConfigValue rawParseValue(ConfigOrigin origin, ConfigParseOptions finalOptions)
|
protected AbstractConfigValue rawParseValue(ConfigOrigin origin, ConfigParseOptions finalOptions)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Reader reader = reader();
|
Reader reader = reader();
|
||||||
|
|
||||||
|
// after reader() we will have loaded the Content-Type.
|
||||||
|
ConfigSyntax contentType = contentType();
|
||||||
|
|
||||||
|
ConfigParseOptions optionsWithContentType;
|
||||||
|
if (contentType != null) {
|
||||||
|
if (ConfigImpl.traceLoadsEnabled() && finalOptions.getSyntax() != null)
|
||||||
|
trace("Overriding syntax " + finalOptions.getSyntax()
|
||||||
|
+ " with Content-Type which specified " + contentType);
|
||||||
|
|
||||||
|
optionsWithContentType = finalOptions.setSyntax(contentType);
|
||||||
|
} else {
|
||||||
|
optionsWithContentType = finalOptions;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return rawParseValue(reader, origin, finalOptions);
|
return rawParseValue(reader, origin, optionsWithContentType);
|
||||||
} finally {
|
} finally {
|
||||||
reader.close();
|
reader.close();
|
||||||
}
|
}
|
||||||
@ -240,12 +260,16 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static Reader readerFromStream(InputStream input) {
|
private static Reader readerFromStream(InputStream input) {
|
||||||
|
return readerFromStream(input, "UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Reader readerFromStream(InputStream input, String encoding) {
|
||||||
try {
|
try {
|
||||||
// well, this is messed up. If we aren't going to close
|
// well, this is messed up. If we aren't going to close
|
||||||
// the passed-in InputStream then we have no way to
|
// the passed-in InputStream then we have no way to
|
||||||
// close these readers. So maybe we should not have an
|
// close these readers. So maybe we should not have an
|
||||||
// InputStream version, only a Reader version.
|
// InputStream version, only a Reader version.
|
||||||
Reader reader = new InputStreamReader(input, "UTF-8");
|
Reader reader = new InputStreamReader(input, encoding);
|
||||||
return new BufferedReader(reader);
|
return new BufferedReader(reader);
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new ConfigException.BugOrBroken("Java runtime does not support UTF-8", e);
|
throw new ConfigException.BugOrBroken("Java runtime does not support UTF-8", e);
|
||||||
@ -390,6 +414,7 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
|
|
||||||
private final static class ParseableURL extends Parseable {
|
private final static class ParseableURL extends Parseable {
|
||||||
final private URL input;
|
final private URL input;
|
||||||
|
private String contentType = null;
|
||||||
|
|
||||||
ParseableURL(URL input, ConfigParseOptions options) {
|
ParseableURL(URL input, ConfigParseOptions options) {
|
||||||
this.input = input;
|
this.input = input;
|
||||||
@ -400,7 +425,22 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
protected Reader reader() throws IOException {
|
protected Reader reader() throws IOException {
|
||||||
if (ConfigImpl.traceLoadsEnabled())
|
if (ConfigImpl.traceLoadsEnabled())
|
||||||
trace("Loading config from a URL: " + input.toExternalForm());
|
trace("Loading config from a URL: " + input.toExternalForm());
|
||||||
InputStream stream = input.openStream();
|
URLConnection connection = input.openConnection();
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
// save content type for later
|
||||||
|
contentType = connection.getContentType();
|
||||||
|
if (contentType != null) {
|
||||||
|
if (ConfigImpl.traceLoadsEnabled())
|
||||||
|
trace("URL sets Content-Type: '" + contentType + "'");
|
||||||
|
contentType = contentType.trim();
|
||||||
|
int semi = contentType.indexOf(';');
|
||||||
|
if (semi >= 0)
|
||||||
|
contentType = contentType.substring(0, semi);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream stream = connection.getInputStream();
|
||||||
|
|
||||||
return readerFromStream(stream);
|
return readerFromStream(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +449,25 @@ public abstract class Parseable implements ConfigParseable {
|
|||||||
return syntaxFromExtension(input.getPath());
|
return syntaxFromExtension(input.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ConfigSyntax contentType() {
|
||||||
|
if (contentType != null) {
|
||||||
|
if (contentType.equals("application/json"))
|
||||||
|
return ConfigSyntax.JSON;
|
||||||
|
else if (contentType.equals("text/x-java-properties"))
|
||||||
|
return ConfigSyntax.PROPERTIES;
|
||||||
|
else if (contentType.equals("application/hocon"))
|
||||||
|
return ConfigSyntax.CONF;
|
||||||
|
else {
|
||||||
|
if (ConfigImpl.traceLoadsEnabled())
|
||||||
|
trace("'" + contentType + "' isn't a known content type");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ConfigParseable relativeTo(String filename) {
|
ConfigParseable relativeTo(String filename) {
|
||||||
URL url = relativeTo(input, filename);
|
URL url = relativeTo(input, filename);
|
||||||
|
Loading…
Reference in New Issue
Block a user