Browse Source

Merge pull request #26296 from yongtang/26179-env-file-non-ascii-windows-crash

Return error if env file contains non-ascii or utf8 bytes (for windows)
Sebastiaan van Stijn 8 years ago
parent
commit
d5fe259e12

+ 15 - 1
runconfig/opts/envfile.go

@@ -2,9 +2,12 @@ package opts
 
 import (
 	"bufio"
+	"bytes"
 	"fmt"
 	"os"
 	"strings"
+	"unicode"
+	"unicode/utf8"
 )
 
 // ParseEnvFile reads a file with environment variables enumerated by lines
@@ -29,9 +32,20 @@ func ParseEnvFile(filename string) ([]string, error) {
 
 	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.TrimLeft(scanner.Text(), whiteSpaces)
+		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)

BIN
runconfig/opts/fixtures/utf16.env


BIN
runconfig/opts/fixtures/utf16be.env


+ 3 - 0
runconfig/opts/fixtures/utf8.env

@@ -0,0 +1,3 @@
+FOO=BAR
+HELLO=您好
+BAR=FOO

+ 27 - 0
runconfig/opts/parse_test.go

@@ -666,6 +666,33 @@ func TestParseEnvfileVariables(t *testing.T) {
 	}
 }
 
+func TestParseEnvfileVariablesWithBOMUnicode(t *testing.T) {
+	// UTF8 with BOM
+	config, _, _, err := parseRun([]string{"--env-file=fixtures/utf8.env", "img", "cmd"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	env := []string{"FOO=BAR", "HELLO=" + string([]byte{0xe6, 0x82, 0xa8, 0xe5, 0xa5, 0xbd}), "BAR=FOO"}
+	if len(config.Env) != len(env) {
+		t.Fatalf("Expected a config with %d env variables, got %v: %v", len(env), len(config.Env), config.Env)
+	}
+	for i, v := range env {
+		if config.Env[i] != v {
+			t.Fatalf("Expected a config with [%s], got %v", v, []byte(config.Env[i]))
+		}
+	}
+
+	// UTF16 with BOM
+	e := "contains invalid utf8 bytes at line"
+	if _, _, _, err := parseRun([]string{"--env-file=fixtures/utf16.env", "img", "cmd"}); err == nil || !strings.Contains(err.Error(), e) {
+		t.Fatalf("Expected an error with message '%s', got %v", e, err)
+	}
+	// UTF16BE with BOM
+	if _, _, _, err := parseRun([]string{"--env-file=fixtures/utf16be.env", "img", "cmd"}); err == nil || !strings.Contains(err.Error(), e) {
+		t.Fatalf("Expected an error with message '%s', got %v", e, err)
+	}
+}
+
 func TestParseLabelfileVariables(t *testing.T) {
 	e := "open nonexistent: no such file or directory"
 	if runtime.GOOS == "windows" {