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:
Havoc Pennington 2013-09-27 13:26:40 -04:00
parent 54ec27ec2a
commit 868a50a53d
2 changed files with 66 additions and 3 deletions

View File

@ -1111,6 +1111,10 @@ The details:
"2" then the resulting array would have indices "0" and "1",
i.e. missing indices in the object are eliminated.
## MIME Type
Use "application/hocon" for Content-Type.
## API Recommendations
Implementations of HOCON ideally follow certain conventions and

View File

@ -18,6 +18,7 @@ import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
@ -104,6 +105,10 @@ public abstract class Parseable implements ConfigParseable {
return null;
}
ConfigSyntax contentType() {
return null;
}
ConfigParseable relativeTo(String filename) {
// fall back to classpath; we treat the "filename" as absolute
// (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)
throws IOException {
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 {
return rawParseValue(reader, origin, finalOptions);
return rawParseValue(reader, origin, optionsWithContentType);
} finally {
reader.close();
}
@ -240,12 +260,16 @@ public abstract class Parseable implements ConfigParseable {
}
private static Reader readerFromStream(InputStream input) {
return readerFromStream(input, "UTF-8");
}
private static Reader readerFromStream(InputStream input, String encoding) {
try {
// well, this is messed up. If we aren't going to close
// the passed-in InputStream then we have no way to
// close these readers. So maybe we should not have an
// InputStream version, only a Reader version.
Reader reader = new InputStreamReader(input, "UTF-8");
Reader reader = new InputStreamReader(input, encoding);
return new BufferedReader(reader);
} catch (UnsupportedEncodingException 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 {
final private URL input;
private String contentType = null;
ParseableURL(URL input, ConfigParseOptions options) {
this.input = input;
@ -400,7 +425,22 @@ public abstract class Parseable implements ConfigParseable {
protected Reader reader() throws IOException {
if (ConfigImpl.traceLoadsEnabled())
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);
}
@ -409,6 +449,25 @@ public abstract class Parseable implements ConfigParseable {
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
ConfigParseable relativeTo(String filename) {
URL url = relativeTo(input, filename);