< prev index next >
src/java.base/share/classes/java/util/jar/Attributes.java
Print this page
rev 51096 : 8205525: Improve exception messages during manifest parsing of jar archives
@@ -24,11 +24,15 @@
*/
package java.util.jar;
import java.io.DataOutputStream;
+import java.io.File;
import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -59,10 +63,43 @@
* The attribute name-value mappings.
*/
protected Map<Object,Object> map;
/**
+ * Security or system property which specifies categories of
+ * (potentially sensitive) information that may be included
+ * in exception text. This class only defines one category:
+ * "jarpath" which represents the path of a jar file
+ * relating to an IO exception.
+ * The property value is a comma separated list of
+ * case insignificant category names.
+ */
+ private static final String enhancedTextPropname = "jdk.includeInExceptions";
+
+ private static final boolean jarPathInExceptionText = initTextProp();
+
+ private static boolean initTextProp() {
+ return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ String val = System.getProperty(enhancedTextPropname);
+ if (val == null) {
+ val = Security.getProperty(enhancedTextPropname);
+ if (val == null)
+ return false;
+ }
+ String[] tokens = val.split(",");
+ for (String token : tokens) {
+ if (token.equalsIgnoreCase("jarpath"))
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+
+ /**
* Constructs a new, empty Attributes object with default size.
*/
public Attributes() {
this(11);
}
@@ -367,21 +404,28 @@
/*
* Reads attributes from the specified input stream.
* XXX Need to handle UTF8 values.
*/
- @SuppressWarnings("deprecation")
void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException {
+ read(is, lbuf, null, 0);
+ }
+
+ @SuppressWarnings("deprecation")
+ int read(Manifest.FastInputStream is, byte[] lbuf, String filename, int offset) throws IOException {
String name = null, value;
byte[] lastline = null;
+ int lineNumber = offset;
int len;
while ((len = is.readLine(lbuf)) != -1) {
boolean lineContinued = false;
byte c = lbuf[--len];
+ lineNumber++;
+
if (c != '\n' && c != '\r') {
- throw new IOException("line too long");
+ throw new IOException("line too long (" + getErrorPosition(filename, lineNumber) + ")");
}
if (len > 0 && lbuf[len-1] == '\r') {
--len;
}
if (len == 0) {
@@ -389,11 +433,11 @@
}
int i = 0;
if (lbuf[0] == ' ') {
// continuation of previous line
if (name == null) {
- throw new IOException("misplaced continuation line");
+ throw new IOException("misplaced continuation line (" + getErrorPosition(filename, lineNumber) + ")");
}
lineContinued = true;
byte[] buf = new byte[lastline.length + len - 1];
System.arraycopy(lastline, 0, buf, 0, lastline.length);
System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
@@ -404,15 +448,15 @@
value = new String(buf, 0, buf.length, "UTF8");
lastline = null;
} else {
while (lbuf[i++] != ':') {
if (i >= len) {
- throw new IOException("invalid header field");
+ throw new IOException("invalid header field (" + getErrorPosition(filename, lineNumber) + ")");
}
}
if (lbuf[i++] != ' ') {
- throw new IOException("invalid header field");
+ throw new IOException("invalid header field (" + getErrorPosition(filename, lineNumber) + ")");
}
name = new String(lbuf, 0, 0, i - 2);
if (is.peek() == ' ') {
lastline = new byte[len - i];
System.arraycopy(lbuf, i, lastline, 0, len - i);
@@ -431,13 +475,27 @@
+ "individual sections in both your\n"
+ "manifest and in the META-INF/MANIFEST.MF "
+ "entry in the jar file.");
}
} catch (IllegalArgumentException e) {
- throw new IOException("invalid header field name: " + name);
+ throw new IOException("invalid header field name: " + name + " (" + getErrorPosition(filename, lineNumber) + ")");
+ }
}
+ return lineNumber;
+ }
+
+ static String getErrorPosition(String filename, final int lineNumber) {
+ if (filename == null || !jarPathInExceptionText) {
+ return "line " + lineNumber;
+ }
+
+ final File file = new File(filename);
+ return AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return file.getAbsolutePath() + ":" + lineNumber;
}
+ });
}
/**
* The Attributes.Name class represents an attribute name stored in
* this Map. Valid attribute names are case-insensitive, are restricted
< prev index next >