You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2019/07/16 01:42:46 UTC

svn commit: r1863109 - in /jackrabbit/commons/filevault-package-maven-plugin/trunk/src: main/java/org/apache/jackrabbit/filevault/maven/packaging/ test/java/org/apache/jackrabbit/filevault/maven/packaging/

Author: tripod
Date: Tue Jul 16 01:42:46 2019
New Revision: 1863109

URL: http://svn.apache.org/viewvc?rev=1863109&view=rev
Log:
JCRVLT-324 correctly escape multiline values in the manifest (closes #25)

Added:
    jackrabbit/commons/filevault-package-maven-plugin/trunk/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java
Modified:
    jackrabbit/commons/filevault-package-maven-plugin/trunk/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojo.java

Modified: jackrabbit/commons/filevault-package-maven-plugin/trunk/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojo.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault-package-maven-plugin/trunk/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojo.java?rev=1863109&r1=1863108&r2=1863109&view=diff
==============================================================================
--- jackrabbit/commons/filevault-package-maven-plugin/trunk/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojo.java (original)
+++ jackrabbit/commons/filevault-package-maven-plugin/trunk/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojo.java Tue Jul 16 01:42:46 2019
@@ -729,6 +729,20 @@ public class GenerateMetadataMojo extend
         return dependenciesString;
     }
 
+    /**
+     * Escapes multiline manifest values to work around bug <a href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8222547">JDK-8222547</a>
+     * Java itself only adds leading SPACE in case a line is longer than 72 chars.
+     *
+     * If the value contains a newline, suffix it with an additional space (continuation character)!
+     *
+     * Unfortunately although the generated manifests for such escaped values are perfectly valid according to the spec,
+     * when reading those via {@link java.util.jar.Manifest} the new lines are stripped.
+     */
+    static final String escapeManifestValue(String value) {
+        return value.replaceAll("\n", "\n ")    // this covers CRLF and LF
+               .replaceAll("\r(?!\n)", "\r ");  // only CR (not followed by LF)
+    }
+
     private MavenArchiveConfiguration getMavenArchiveConfiguration(Properties vaultProperties, String dependenciesString) throws IOException {
         if (archive == null) {
             archive = new MavenArchiveConfiguration();
@@ -743,11 +757,11 @@ public class GenerateMetadataMojo extend
 
             // TODO: split up manifest generation
             PackageId id = new PackageId(group, name, version);
-            archive.addManifestEntry(MF_KEY_PACKAGE_TYPE, packageType.name().toLowerCase());
-            archive.addManifestEntry(MF_KEY_PACKAGE_ID, id.toString());
-            archive.addManifestEntry(MF_KEY_PACKAGE_DESC, vaultProperties.getProperty("description", ""));
+            archive.addManifestEntry(MF_KEY_PACKAGE_TYPE, escapeManifestValue(packageType.name().toLowerCase()));
+            archive.addManifestEntry(MF_KEY_PACKAGE_ID, escapeManifestValue(id.toString()));
+            archive.addManifestEntry(MF_KEY_PACKAGE_DESC, escapeManifestValue(vaultProperties.getProperty("description", "")));
             if (dependenciesString != null && dependenciesString.length() > 0) {
-                archive.addManifestEntry(MF_KEY_PACKAGE_DEPENDENCIES, dependenciesString);
+                archive.addManifestEntry(MF_KEY_PACKAGE_DEPENDENCIES, escapeManifestValue(dependenciesString));
             }
             // be sure to avoid duplicates
             Set<String> rts = new TreeSet<>();
@@ -756,11 +770,11 @@ public class GenerateMetadataMojo extend
             }
             String[] roots = rts.toArray(new String[rts.size()]);
             Arrays.sort(roots);
-            archive.addManifestEntry(MF_KEY_PACKAGE_ROOTS, StringUtils.join(roots, ","));
+            archive.addManifestEntry(MF_KEY_PACKAGE_ROOTS, escapeManifestValue(StringUtils.join(roots, ",")));
 
             // import package is not yet there!
             if (StringUtils.isNotEmpty(importPackage)) {
-                archive.addManifestEntry(MF_KEY_IMPORT_PACKAGE, StringUtils.deleteWhitespace(importPackage));
+                archive.addManifestEntry(MF_KEY_IMPORT_PACKAGE, escapeManifestValue(StringUtils.deleteWhitespace(importPackage)));
             }
         }
 

Added: jackrabbit/commons/filevault-package-maven-plugin/trunk/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault-package-maven-plugin/trunk/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java?rev=1863109&view=auto
==============================================================================
--- jackrabbit/commons/filevault-package-maven-plugin/trunk/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java (added)
+++ jackrabbit/commons/filevault-package-maven-plugin/trunk/src/test/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateMetadataMojoTest.java Tue Jul 16 01:42:46 2019
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.filevault.maven.packaging;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class GenerateMetadataMojoTest {
+
+    private static final String MANIFEST_ATTRIBUTE_NAME = "test";
+
+    @Test
+    public void testEscapeManifestValue() throws IOException {
+        assertEscapedValueWorksInManifest("Paragraph\r\rAnother paragraph");
+        assertEscapedValueWorksInManifest("single line value");
+        assertEscapedValueWorksInManifest("Paragraph\n\nAnother paragraph");
+        assertEscapedValueWorksInManifest("Paragraph\r\n\r\nAnother paragraph");
+        assertEscapedValueWorksInManifest("some very long line above 72 chars. some very long line above 72 chars. some very long line above 72 chars\n\nAnother paragraph");
+        assertEscapedValueWorksInManifest("some very long line above 72 chars. some very long line above 72 chars. some very long line above 72 chars\r\rAnother paragraph");
+    }
+
+    private void assertEscapedValueWorksInManifest(String value) throws IOException {
+        String escapedValue = GenerateMetadataMojo.escapeManifestValue(value);
+        Manifest manifest = new Manifest();
+        Attributes attributes = manifest.getMainAttributes();
+        attributes.putValue(MANIFEST_ATTRIBUTE_NAME, escapedValue);
+        attributes.putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");
+        
+        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+            manifest.write(outputStream);
+            //System.out.println(new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
+            try (ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray())) {
+                manifest = new Manifest(inputStream);
+                // java.util.jar.Manifest removes the new lines unfortunately from values, but maybe this gets fixed by Oracle at some point in time...
+                String actualValue = manifest.getMainAttributes().getValue(MANIFEST_ATTRIBUTE_NAME);
+                Assert.assertEquals(removeNewlines(value), unescapeContinuations(actualValue));
+            }
+        };
+        
+    }
+
+    private static String removeNewlines(String value) {
+        return value.replaceAll("\n|\r", "");
+    }
+
+    /**
+     * Java's Manifest parser {@link java.util.jar.Manifest} does not correctly remove the continuation for values in the form
+     * {@code SomeText CR SPACE CR}
+     * @param value
+     * @return the given value with all {@code CR}s followed by {@code SPACE} removed
+     */
+    private static String unescapeContinuations(String value) {
+        return value.replaceAll("\r ", "");
+    }
+    
+}