Use binary frame for websocket attach endpoint

This fix tries to address the issue raised in 28176 where
text frame was used in websocket attach endpoint. In case
the data send out contains non utf8 data, the connection
will be closed in certain browsers, e.g., Safari.

This fix address the issue by change `PayloadType` to `BinaryFrame`.

This fix is tested manually with Safari. The docker daemon is inside a Linux Virtual Machine.

Create a container with:
```
docker run -itd --name websocket busybox sh -c "while true; do echo -e 'he\\xc3\\x28o'; sleep 5; done"
```

Use the following url (172.16.66.128:2375 is the tcp address of the daemon):
```
file:///websocket.html?url=ws://172.16.66.128:2375/v1.25/containers/websocket/attach/ws?logs=1&stderr=1&stdout=1&stream=1&stdin=1
```

and the following html:
```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Websocket</title>
  <script type="text/javascript">
    function DockerWebSocket() {
      if ("WebSocket" in window) {
        console.log("WebSocket is supported by Browser...")
        // Remove '?url=' prefix
        url = window.location.search.replace(/^(\?url=)/,"");
        console.log("URL ["+url+"]...");
        var ws = new WebSocket(url);
        ws.onopen = function() {
          console.log("Connection is opened...");
        };
        ws.onclose = function() {
          console.log("Connection is closed...");
        };
        ws.onmessage = function (e) {
          if (typeof e.data === "string") {
            alert("WebSocket received text message ["+e.data+"]!")
          } else {
            console.log("Message is received...")
            var blobReader = new FileReader();
            blobReader.onload = function(event) {
              console.log(JSON.stringify(blobReader.result))
            };
            blobReader.readAsText(e.data)
            console.log("Message complete...")
          }
        };
      } else {
        alert("WebSocket is not supported by Browser!");
      }
    }
  </script>
</head>
<body>
  <div>
    <a href="javascript:DockerWebSocket()">Run DockerWebSocket</a>
  </div>
</body>
</html>
```

This fix fixes 28176.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang 2017-01-25 19:07:27 -08:00
parent ebaf1ced72
commit e82dcaab52
2 changed files with 10 additions and 0 deletions

View File

@ -502,6 +502,8 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
done := make(chan struct{})
started := make(chan struct{})
version := httputils.VersionFromContext(ctx)
setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) {
wsChan := make(chan *websocket.Conn)
h := func(conn *websocket.Conn) {
@ -516,6 +518,11 @@ func (s *containerRouter) wsContainersAttach(ctx context.Context, w http.Respons
}()
conn := <-wsChan
// In case version is higher than 1.26, a binary frame will be sent.
// See 28176 for details.
if versions.GreaterThanOrEqualTo(version, "1.26") {
conn.PayloadType = websocket.BinaryFrame
}
return conn, conn, conn, nil
}

View File

@ -17,6 +17,9 @@ keywords: "API, Docker, rcli, REST, documentation"
[Docker Engine API v1.26](v1.26/) documentation
* `GET /containers/(id or name)/attach/ws` now returns WebSocket in binary frame format for API version >= v1.26,
and returns WebSocket in text frame format for API version< v1.26, for the purpose of backward-compatibility.
## v1.25 API changes
[Docker Engine API v1.25](v1.25.md) documentation