Reputation: 664
I am trying to convert the io.ReadCloser
(interface) that I am getting after running the Docker image via Go docker-sdk
to []byte
for further use.
When I read from the io.ReadCloser
using stdcopy.StdCopy
to stdout
, it prints the data perfectly.
The code stdcopy.StdCopy(os.Stderr, os.Stdout, out)
prints:
Content-Type: text/html
<html>
<head><title>HTML response</title></head>
<body><h1>Hello, Goodbye</h1></body>
</html>
Because I need to send this entire content as a Response I need to convert the content to []byte
or string
. But, once I convert the io.ReadCloser
to []byte
or string
using any method but stdcopy.StdCopy
, it adds a special character to some lines.
The snippet I used to read from out
to buf
using *bytes.Buffer.ReadFrom
:
buf := new(bytes.Buffer)
buf.ReadFrom(out)
fmt.Println(buf.String())
Prints:
Content-Type: text/html
<html>
*<head><title>HTML response</title></head>
%<body><h1>Hello, Goodbye</h1></body>
</html>
As you can see extra characters like *
and %
are being added. I have also tried ioutil.ReadAll
function as well, no luck. Any suggestion would be much appreciated.
Upvotes: 1
Views: 428
Reputation: 4204
Those are stray bytes like *
, %
, etc. prefixed with some of the lines.
The stray bytes appear to be a custom stream multiplexing protocol, allowing STDOUT
and STDERR
to be sent down the same connection.
Using stdcopy.StdCopy()
interprets these custom headers and those stray characters are avoided by removing the protocol header for each piece of data.
Refer: https://github.com/moby/moby/blob/master/pkg/stdcopy/stdcopy.go#L42
// Write sends the buffer to the underneath writer.
// It inserts the prefix header before the buffer,
// so stdcopy.StdCopy knows where to multiplex the output.
// It makes stdWriter to implement io.Writer.
So, stdcopy.StdCopy
is your friend and an alternative for io.Copy
and friends when working with Docker.
A sample example to give you an idea:
package main
import (
"bytes"
"fmt"
"io"
"strings"
)
var resp string = `
Content-Type: text/html
<html>
<head><title>HTML response</title></head>
<body><h1>Hello, Goodbye</h1></body>
</html>`
func main() {
src := strings.NewReader(resp)
dst := &bytes.Buffer{}
_, _ = io.Copy(dst, src)
fmt.Println(dst.String())
// Output:
//
// Content-Type: text/html
// <html>
// <head><title>HTML response</title></head>
// <body><h1>Hello, Goodbye</h1></body>
// </html>
}
Signature for: func io.Copy(dst io.Writer, src io.Reader)
As dst
(*bytes.Buffer)
has a Write
method and hence it implements the io.Writer
interface and it works.
Now use the same idea when using stdcopy.StdCopy()
as the signature is the same. https://pkg.go.dev/github.com/docker/docker/pkg/stdcopy#StdCopy
Upvotes: 5