Handle extra empty lines in Java manifest parsing (#687)

* Add failing test for extra empty lines in manifest

Signed-off-by: Dan Luhring <dan+github@luhrings.com>

* Handle extra empty lines in Java manifests

Signed-off-by: Dan Luhring <dan+github@luhrings.com>
This commit is contained in:
Dan Luhring 2021-12-14 11:53:50 -05:00 committed by GitHub
parent 3d8c16649d
commit 85ac5bcbf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 21 deletions

View File

@ -19,48 +19,60 @@ const manifestGlob = "/META-INF/MANIFEST.MF"
// For more information: https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#jar-manifest
func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error) {
var manifest pkg.JavaManifest
sections := []map[string]string{
make(map[string]string),
var sections []map[string]string
currentSection := func() int {
return len(sections) - 1
}
currentSection := 0
scanner := bufio.NewScanner(reader)
var lastKey string
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
line := scanner.Text()
// empty lines denote section separators
if strings.TrimSpace(line) == "" {
currentSection++
// we don't want to allocate a new section map that wont necessarily be used, do that once there is
// we don't want to allocate a new section map that won't necessarily be used, do that once there is
// a non-empty line to process
// do not process line continuations after this
lastKey = ""
continue
} else if currentSection >= len(sections) {
sections = append(sections, make(map[string]string))
}
if line[0] == ' ' {
// this is a continuation
if lastKey == "" {
return nil, fmt.Errorf("found continuation with no previous key (%s)", line)
}
sections[currentSection][lastKey] += strings.TrimSpace(line)
} else {
// this is a new key-value pair
idx := strings.Index(line, ":")
if idx == -1 {
return nil, fmt.Errorf("unable to split java manifest key-value pairs: %q", line)
}
key := strings.TrimSpace(line[0:idx])
value := strings.TrimSpace(line[idx+1:])
sections[currentSection][key] = value
sections[currentSection()][lastKey] += strings.TrimSpace(line)
// keep track of key for potential future continuations
lastKey = key
continue
}
if lastKey == "" {
// we're entering a new section
sections = append(sections, make(map[string]string))
}
// this is a new key-value pair
idx := strings.Index(line, ":")
if idx == -1 {
return nil, fmt.Errorf("unable to split java manifest key-value pairs: %q", line)
}
key := strings.TrimSpace(line[0:idx])
value := strings.TrimSpace(line[idx+1:])
sections[currentSection()][key] = value
// keep track of key for potential future continuations
lastKey = key
}
if err := scanner.Err(); err != nil {
@ -75,7 +87,7 @@ func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error)
name, ok := s["Name"]
if !ok {
// per the manifest spec (https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#jar-manifest)
// this should never happen. If it does we want to know about it, but not necessarily stop
// this should never happen. If it does, we want to know about it, but not necessarily stop
// cataloging entirely... for this reason we only log.
log.Warnf("java manifest section found without a name: %s", path)
name = strconv.Itoa(i)

View File

@ -58,6 +58,21 @@ func TestParseJavaManifest(t *testing.T) {
},
},
},
{
fixture: "test-fixtures/manifest/extra-empty-lines",
expected: pkg.JavaManifest{
Main: map[string]string{
"Manifest-Version": "1.0",
"Archiver-Version": "Plexus Archiver",
"Created-By": "Apache Maven 3.6.3",
},
NamedSections: map[string]map[string]string{
"thing-1": {
"Built-By": "?",
},
},
},
},
{
fixture: "test-fixtures/manifest/continuation",
expected: pkg.JavaManifest{

View File

@ -0,0 +1,7 @@
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.6.3
Name: thing-1
Built-By: ?