Browse code

move stdcopy to pkg/stdcopy

Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)

unclejack authored on 2014/09/18 00:04:56
Showing 6 changed files
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/docker/docker/api"
15 15
 	"github.com/docker/docker/dockerversion"
16 16
 	"github.com/docker/docker/pkg/log"
17
+	"github.com/docker/docker/pkg/stdcopy"
17 18
 	"github.com/docker/docker/pkg/term"
18 19
 	"github.com/docker/docker/utils"
19 20
 )
... ...
@@ -96,7 +97,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
96 96
 			if setRawTerminal && stdout != nil {
97 97
 				_, err = io.Copy(stdout, br)
98 98
 			} else {
99
-				_, err = utils.StdCopy(stdout, stderr, br)
99
+				_, err = stdcopy.StdCopy(stdout, stderr, br)
100 100
 			}
101 101
 			log.Debugf("[hijack] End of stdout")
102 102
 			return err
... ...
@@ -22,6 +22,7 @@ import (
22 22
 	"github.com/docker/docker/dockerversion"
23 23
 	"github.com/docker/docker/engine"
24 24
 	"github.com/docker/docker/pkg/log"
25
+	"github.com/docker/docker/pkg/stdcopy"
25 26
 	"github.com/docker/docker/pkg/term"
26 27
 	"github.com/docker/docker/registry"
27 28
 	"github.com/docker/docker/utils"
... ...
@@ -174,7 +175,7 @@ func (cli *DockerCli) streamHelper(method, path string, setRawTerminal bool, in
174 174
 		if setRawTerminal {
175 175
 			_, err = io.Copy(stdout, resp.Body)
176 176
 		} else {
177
-			_, err = utils.StdCopy(stdout, stderr, resp.Body)
177
+			_, err = stdcopy.StdCopy(stdout, stderr, resp.Body)
178 178
 		}
179 179
 		log.Debugf("[stream] End of stdout")
180 180
 		return err
... ...
@@ -28,6 +28,7 @@ import (
28 28
 	"github.com/docker/docker/pkg/listenbuffer"
29 29
 	"github.com/docker/docker/pkg/log"
30 30
 	"github.com/docker/docker/pkg/parsers"
31
+	"github.com/docker/docker/pkg/stdcopy"
31 32
 	"github.com/docker/docker/pkg/systemd"
32 33
 	"github.com/docker/docker/pkg/version"
33 34
 	"github.com/docker/docker/registry"
... ...
@@ -399,8 +400,8 @@ func getContainersLogs(eng *engine.Engine, version version.Version, w http.Respo
399 399
 	outStream = utils.NewWriteFlusher(w)
400 400
 
401 401
 	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
402
-		errStream = utils.NewStdWriter(outStream, utils.Stderr)
403
-		outStream = utils.NewStdWriter(outStream, utils.Stdout)
402
+		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
403
+		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
404 404
 	} else {
405 405
 		errStream = outStream
406 406
 	}
... ...
@@ -843,8 +844,8 @@ func postContainersAttach(eng *engine.Engine, version version.Version, w http.Re
843 843
 	fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
844 844
 
845 845
 	if c.GetSubEnv("Config") != nil && !c.GetSubEnv("Config").GetBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
846
-		errStream = utils.NewStdWriter(outStream, utils.Stderr)
847
-		outStream = utils.NewStdWriter(outStream, utils.Stdout)
846
+		errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
847
+		outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
848 848
 	} else {
849 849
 		errStream = outStream
850 850
 	}
... ...
@@ -1091,8 +1092,8 @@ func postContainerExecStart(eng *engine.Engine, version version.Version, w http.
1091 1091
 
1092 1092
 		fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
1093 1093
 		if !job.GetenvBool("Tty") && version.GreaterThanOrEqualTo("1.6") {
1094
-			errStream = utils.NewStdWriter(outStream, utils.Stderr)
1095
-			outStream = utils.NewStdWriter(outStream, utils.Stdout)
1094
+			errStream = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
1095
+			outStream = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
1096 1096
 		} else {
1097 1097
 			errStream = outStream
1098 1098
 		}
1099 1099
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+Cristian Staretu <cristian.staretu@gmail.com> (@unclejack)
0 1
new file mode 100644
... ...
@@ -0,0 +1,164 @@
0
+package stdcopy
1
+
2
+import (
3
+	"encoding/binary"
4
+	"errors"
5
+	"io"
6
+
7
+	"github.com/docker/docker/pkg/log"
8
+)
9
+
10
+const (
11
+	StdWriterPrefixLen = 8
12
+	StdWriterFdIndex   = 0
13
+	StdWriterSizeIndex = 4
14
+)
15
+
16
+type StdType [StdWriterPrefixLen]byte
17
+
18
+var (
19
+	Stdin  StdType = StdType{0: 0}
20
+	Stdout StdType = StdType{0: 1}
21
+	Stderr StdType = StdType{0: 2}
22
+)
23
+
24
+type StdWriter struct {
25
+	io.Writer
26
+	prefix  StdType
27
+	sizeBuf []byte
28
+}
29
+
30
+func (w *StdWriter) Write(buf []byte) (n int, err error) {
31
+	if w == nil || w.Writer == nil {
32
+		return 0, errors.New("Writer not instanciated")
33
+	}
34
+	binary.BigEndian.PutUint32(w.prefix[4:], uint32(len(buf)))
35
+	buf = append(w.prefix[:], buf...)
36
+
37
+	n, err = w.Writer.Write(buf)
38
+	return n - StdWriterPrefixLen, err
39
+}
40
+
41
+// NewStdWriter instanciates a new Writer.
42
+// Everything written to it will be encapsulated using a custom format,
43
+// and written to the underlying `w` stream.
44
+// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection.
45
+// `t` indicates the id of the stream to encapsulate.
46
+// It can be utils.Stdin, utils.Stdout, utils.Stderr.
47
+func NewStdWriter(w io.Writer, t StdType) *StdWriter {
48
+	if len(t) != StdWriterPrefixLen {
49
+		return nil
50
+	}
51
+
52
+	return &StdWriter{
53
+		Writer:  w,
54
+		prefix:  t,
55
+		sizeBuf: make([]byte, 4),
56
+	}
57
+}
58
+
59
+var ErrInvalidStdHeader = errors.New("Unrecognized input header")
60
+
61
+// StdCopy is a modified version of io.Copy.
62
+//
63
+// StdCopy will demultiplex `src`, assuming that it contains two streams,
64
+// previously multiplexed together using a StdWriter instance.
65
+// As it reads from `src`, StdCopy will write to `dstout` and `dsterr`.
66
+//
67
+// StdCopy will read until it hits EOF on `src`. It will then return a nil error.
68
+// In other words: if `err` is non nil, it indicates a real underlying error.
69
+//
70
+// `written` will hold the total number of bytes written to `dstout` and `dsterr`.
71
+func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) {
72
+	var (
73
+		buf       = make([]byte, 32*1024+StdWriterPrefixLen+1)
74
+		bufLen    = len(buf)
75
+		nr, nw    int
76
+		er, ew    error
77
+		out       io.Writer
78
+		frameSize int
79
+	)
80
+
81
+	for {
82
+		// Make sure we have at least a full header
83
+		for nr < StdWriterPrefixLen {
84
+			var nr2 int
85
+			nr2, er = src.Read(buf[nr:])
86
+			nr += nr2
87
+			if er == io.EOF {
88
+				if nr < StdWriterPrefixLen {
89
+					log.Debugf("Corrupted prefix: %v", buf[:nr])
90
+					return written, nil
91
+				}
92
+				break
93
+			}
94
+			if er != nil {
95
+				log.Debugf("Error reading header: %s", er)
96
+				return 0, er
97
+			}
98
+		}
99
+
100
+		// Check the first byte to know where to write
101
+		switch buf[StdWriterFdIndex] {
102
+		case 0:
103
+			fallthrough
104
+		case 1:
105
+			// Write on stdout
106
+			out = dstout
107
+		case 2:
108
+			// Write on stderr
109
+			out = dsterr
110
+		default:
111
+			log.Debugf("Error selecting output fd: (%d)", buf[StdWriterFdIndex])
112
+			return 0, ErrInvalidStdHeader
113
+		}
114
+
115
+		// Retrieve the size of the frame
116
+		frameSize = int(binary.BigEndian.Uint32(buf[StdWriterSizeIndex : StdWriterSizeIndex+4]))
117
+		log.Debugf("framesize: %d", frameSize)
118
+
119
+		// Check if the buffer is big enough to read the frame.
120
+		// Extend it if necessary.
121
+		if frameSize+StdWriterPrefixLen > bufLen {
122
+			log.Debugf("Extending buffer cap by %d (was %d)", frameSize+StdWriterPrefixLen-bufLen+1, len(buf))
123
+			buf = append(buf, make([]byte, frameSize+StdWriterPrefixLen-bufLen+1)...)
124
+			bufLen = len(buf)
125
+		}
126
+
127
+		// While the amount of bytes read is less than the size of the frame + header, we keep reading
128
+		for nr < frameSize+StdWriterPrefixLen {
129
+			var nr2 int
130
+			nr2, er = src.Read(buf[nr:])
131
+			nr += nr2
132
+			if er == io.EOF {
133
+				if nr < frameSize+StdWriterPrefixLen {
134
+					log.Debugf("Corrupted frame: %v", buf[StdWriterPrefixLen:nr])
135
+					return written, nil
136
+				}
137
+				break
138
+			}
139
+			if er != nil {
140
+				log.Debugf("Error reading frame: %s", er)
141
+				return 0, er
142
+			}
143
+		}
144
+
145
+		// Write the retrieved frame (without header)
146
+		nw, ew = out.Write(buf[StdWriterPrefixLen : frameSize+StdWriterPrefixLen])
147
+		if ew != nil {
148
+			log.Debugf("Error writing frame: %s", ew)
149
+			return 0, ew
150
+		}
151
+		// If the frame has not been fully written: error
152
+		if nw != frameSize {
153
+			log.Debugf("Error Short Write: (%d on %d)", nw, frameSize)
154
+			return 0, io.ErrShortWrite
155
+		}
156
+		written += int64(nw)
157
+
158
+		// Move the rest of the buffer to the beginning
159
+		copy(buf, buf[frameSize+StdWriterPrefixLen:])
160
+		// Move the index
161
+		nr -= frameSize + StdWriterPrefixLen
162
+	}
163
+}
0 164
deleted file mode 100644
... ...
@@ -1,164 +0,0 @@
1
-package utils
2
-
3
-import (
4
-	"encoding/binary"
5
-	"errors"
6
-	"io"
7
-
8
-	"github.com/docker/docker/pkg/log"
9
-)
10
-
11
-const (
12
-	StdWriterPrefixLen = 8
13
-	StdWriterFdIndex   = 0
14
-	StdWriterSizeIndex = 4
15
-)
16
-
17
-type StdType [StdWriterPrefixLen]byte
18
-
19
-var (
20
-	Stdin  StdType = StdType{0: 0}
21
-	Stdout StdType = StdType{0: 1}
22
-	Stderr StdType = StdType{0: 2}
23
-)
24
-
25
-type StdWriter struct {
26
-	io.Writer
27
-	prefix  StdType
28
-	sizeBuf []byte
29
-}
30
-
31
-func (w *StdWriter) Write(buf []byte) (n int, err error) {
32
-	if w == nil || w.Writer == nil {
33
-		return 0, errors.New("Writer not instanciated")
34
-	}
35
-	binary.BigEndian.PutUint32(w.prefix[4:], uint32(len(buf)))
36
-	buf = append(w.prefix[:], buf...)
37
-
38
-	n, err = w.Writer.Write(buf)
39
-	return n - StdWriterPrefixLen, err
40
-}
41
-
42
-// NewStdWriter instanciates a new Writer.
43
-// Everything written to it will be encapsulated using a custom format,
44
-// and written to the underlying `w` stream.
45
-// This allows multiple write streams (e.g. stdout and stderr) to be muxed into a single connection.
46
-// `t` indicates the id of the stream to encapsulate.
47
-// It can be utils.Stdin, utils.Stdout, utils.Stderr.
48
-func NewStdWriter(w io.Writer, t StdType) *StdWriter {
49
-	if len(t) != StdWriterPrefixLen {
50
-		return nil
51
-	}
52
-
53
-	return &StdWriter{
54
-		Writer:  w,
55
-		prefix:  t,
56
-		sizeBuf: make([]byte, 4),
57
-	}
58
-}
59
-
60
-var ErrInvalidStdHeader = errors.New("Unrecognized input header")
61
-
62
-// StdCopy is a modified version of io.Copy.
63
-//
64
-// StdCopy will demultiplex `src`, assuming that it contains two streams,
65
-// previously multiplexed together using a StdWriter instance.
66
-// As it reads from `src`, StdCopy will write to `dstout` and `dsterr`.
67
-//
68
-// StdCopy will read until it hits EOF on `src`. It will then return a nil error.
69
-// In other words: if `err` is non nil, it indicates a real underlying error.
70
-//
71
-// `written` will hold the total number of bytes written to `dstout` and `dsterr`.
72
-func StdCopy(dstout, dsterr io.Writer, src io.Reader) (written int64, err error) {
73
-	var (
74
-		buf       = make([]byte, 32*1024+StdWriterPrefixLen+1)
75
-		bufLen    = len(buf)
76
-		nr, nw    int
77
-		er, ew    error
78
-		out       io.Writer
79
-		frameSize int
80
-	)
81
-
82
-	for {
83
-		// Make sure we have at least a full header
84
-		for nr < StdWriterPrefixLen {
85
-			var nr2 int
86
-			nr2, er = src.Read(buf[nr:])
87
-			nr += nr2
88
-			if er == io.EOF {
89
-				if nr < StdWriterPrefixLen {
90
-					log.Debugf("Corrupted prefix: %v", buf[:nr])
91
-					return written, nil
92
-				}
93
-				break
94
-			}
95
-			if er != nil {
96
-				log.Debugf("Error reading header: %s", er)
97
-				return 0, er
98
-			}
99
-		}
100
-
101
-		// Check the first byte to know where to write
102
-		switch buf[StdWriterFdIndex] {
103
-		case 0:
104
-			fallthrough
105
-		case 1:
106
-			// Write on stdout
107
-			out = dstout
108
-		case 2:
109
-			// Write on stderr
110
-			out = dsterr
111
-		default:
112
-			log.Debugf("Error selecting output fd: (%d)", buf[StdWriterFdIndex])
113
-			return 0, ErrInvalidStdHeader
114
-		}
115
-
116
-		// Retrieve the size of the frame
117
-		frameSize = int(binary.BigEndian.Uint32(buf[StdWriterSizeIndex : StdWriterSizeIndex+4]))
118
-		log.Debugf("framesize: %d", frameSize)
119
-
120
-		// Check if the buffer is big enough to read the frame.
121
-		// Extend it if necessary.
122
-		if frameSize+StdWriterPrefixLen > bufLen {
123
-			log.Debugf("Extending buffer cap by %d (was %d)", frameSize+StdWriterPrefixLen-bufLen+1, len(buf))
124
-			buf = append(buf, make([]byte, frameSize+StdWriterPrefixLen-bufLen+1)...)
125
-			bufLen = len(buf)
126
-		}
127
-
128
-		// While the amount of bytes read is less than the size of the frame + header, we keep reading
129
-		for nr < frameSize+StdWriterPrefixLen {
130
-			var nr2 int
131
-			nr2, er = src.Read(buf[nr:])
132
-			nr += nr2
133
-			if er == io.EOF {
134
-				if nr < frameSize+StdWriterPrefixLen {
135
-					log.Debugf("Corrupted frame: %v", buf[StdWriterPrefixLen:nr])
136
-					return written, nil
137
-				}
138
-				break
139
-			}
140
-			if er != nil {
141
-				log.Debugf("Error reading frame: %s", er)
142
-				return 0, er
143
-			}
144
-		}
145
-
146
-		// Write the retrieved frame (without header)
147
-		nw, ew = out.Write(buf[StdWriterPrefixLen : frameSize+StdWriterPrefixLen])
148
-		if ew != nil {
149
-			log.Debugf("Error writing frame: %s", ew)
150
-			return 0, ew
151
-		}
152
-		// If the frame has not been fully written: error
153
-		if nw != frameSize {
154
-			log.Debugf("Error Short Write: (%d on %d)", nw, frameSize)
155
-			return 0, io.ErrShortWrite
156
-		}
157
-		written += int64(nw)
158
-
159
-		// Move the rest of the buffer to the beginning
160
-		copy(buf, buf[frameSize+StdWriterPrefixLen:])
161
-		// Move the index
162
-		nr -= frameSize + StdWriterPrefixLen
163
-	}
164
-}