01d3a16f58
This fix tries to address the issue raised in 26179 where an env file with non-ascii or utf8 bytes will crash on windows platform. The issue is two-fold: - Windows will adds a BOM mark at the begining with Notepad as the editor - Non-utf8 bytes can not be handled by env file parser. This fix removes utf8 BOM marker if exists so that utf8 encoded env file could be processed. This fix also returns an error (instead of a runtime CreateProcess crash) if env file contains non-utf8 bytes, thus giving users better experiences. Additional test cases has been added in unit tests. This fix fixes 26179. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
81 lines
2.5 KiB
Go
81 lines
2.5 KiB
Go
package opts
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// ParseEnvFile reads a file with environment variables enumerated by lines
|
|
//
|
|
// ``Environment variable names used by the utilities in the Shell and
|
|
// Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase
|
|
// letters, digits, and the '_' (underscore) from the characters defined in
|
|
// Portable Character Set and do not begin with a digit. *But*, other
|
|
// characters may be permitted by an implementation; applications shall
|
|
// tolerate the presence of such names.''
|
|
// -- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
|
|
//
|
|
// As of #16585, it's up to application inside docker to validate or not
|
|
// environment variables, that's why we just strip leading whitespace and
|
|
// nothing more.
|
|
func ParseEnvFile(filename string) ([]string, error) {
|
|
fh, err := os.Open(filename)
|
|
if err != nil {
|
|
return []string{}, err
|
|
}
|
|
defer fh.Close()
|
|
|
|
lines := []string{}
|
|
scanner := bufio.NewScanner(fh)
|
|
currentLine := 0
|
|
utf8bom := []byte{0xEF, 0xBB, 0xBF}
|
|
for scanner.Scan() {
|
|
scannedBytes := scanner.Bytes()
|
|
if !utf8.Valid(scannedBytes) {
|
|
return []string{}, fmt.Errorf("env file %s contains invalid utf8 bytes at line %d: %v", filename, currentLine+1, scannedBytes)
|
|
}
|
|
// We trim UTF8 BOM
|
|
if currentLine == 0 {
|
|
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
|
|
}
|
|
// trim the line from all leading whitespace first
|
|
line := strings.TrimLeftFunc(string(scannedBytes), unicode.IsSpace)
|
|
currentLine++
|
|
// line is not empty, and not starting with '#'
|
|
if len(line) > 0 && !strings.HasPrefix(line, "#") {
|
|
data := strings.SplitN(line, "=", 2)
|
|
|
|
// trim the front of a variable, but nothing else
|
|
variable := strings.TrimLeft(data[0], whiteSpaces)
|
|
if strings.ContainsAny(variable, whiteSpaces) {
|
|
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)}
|
|
}
|
|
|
|
if len(data) > 1 {
|
|
|
|
// pass the value through, no trimming
|
|
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1]))
|
|
} else {
|
|
// if only a pass-through variable is given, clean it up.
|
|
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line)))
|
|
}
|
|
}
|
|
}
|
|
return lines, scanner.Err()
|
|
}
|
|
|
|
var whiteSpaces = " \t"
|
|
|
|
// ErrBadEnvVariable typed error for bad environment variable
|
|
type ErrBadEnvVariable struct {
|
|
msg string
|
|
}
|
|
|
|
func (e ErrBadEnvVariable) Error() string {
|
|
return fmt.Sprintf("poorly formatted environment: %s", e.msg)
|
|
}
|