diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index 8b47dac026..b1457bdcc2 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -28,6 +28,8 @@ import ( const ( // DefaultDockerfileName is the Default filename with Docker commands, read by docker build DefaultDockerfileName string = "Dockerfile" + // archiveHeaderSize is the number of bytes in an archive header + archiveHeaderSize = 512 ) // ValidateContextDirectory checks if all the contents of the directory @@ -84,12 +86,12 @@ func ValidateContextDirectory(srcPath string, excludes []string) error { func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) { buf := bufio.NewReader(r) - magic, err := buf.Peek(archive.HeaderSize) + magic, err := buf.Peek(archiveHeaderSize) if err != nil && err != io.EOF { return nil, "", errors.Errorf("failed to peek context header from STDIN: %v", err) } - if archive.IsArchive(magic) { + if IsArchive(magic) { return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil } @@ -133,6 +135,18 @@ func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCl } +// IsArchive checks for the magic bytes of a tar or any supported compression +// algorithm. +func IsArchive(header []byte) bool { + compression := archive.DetectCompression(header) + if compression != archive.Uncompressed { + return true + } + r := tar.NewReader(bytes.NewBuffer(header)) + _, err := r.Next() + return err == nil +} + // GetContextFromGitURL uses a Git URL as context for a `docker build`. The // git repo is cloned into a temporary directory used as the context directory. // Returns the absolute path to the temporary context directory, the relative diff --git a/cli/command/image/build/context_test.go b/cli/command/image/build/context_test.go index cda0bfb3f1..8bcbea48dd 100644 --- a/cli/command/image/build/context_test.go +++ b/cli/command/image/build/context_test.go @@ -266,3 +266,35 @@ func chdir(t *testing.T, dir string) func() { require.NoError(t, os.Chdir(dir)) return func() { require.NoError(t, os.Chdir(workingDirectory)) } } + +func TestIsArchive(t *testing.T) { + var testcases = []struct { + doc string + header []byte + expected bool + }{ + { + doc: "nil is not a valid header", + header: nil, + expected: false, + }, + { + doc: "invalid header bytes", + header: []byte{0x00, 0x01, 0x02}, + expected: false, + }, + { + doc: "header for bzip2 archive", + header: []byte{0x42, 0x5A, 0x68}, + expected: true, + }, + { + doc: "header for 7zip archive is not supported", + header: []byte{0x50, 0x4b, 0x03, 0x04}, + expected: false, + }, + } + for _, testcase := range testcases { + assert.Equal(t, testcase.expected, IsArchive(testcase.header), testcase.doc) + } +}