mirror of
https://github.com/containers/podman.git
synced 2025-08-24 10:04:57 +08:00
API attach: return vnd.docker.multiplexed-stream header
The attach API used to always return the Content-Type `vnd.docker.raw-stream`, however docker api v1.42 added the `vnd.docker.multiplexed-stream` type when no tty was used. Follow suit and return the same header for docker api v1.42 and libpod v4.7.0. This technically allows clients to make a small optimization as they no longer need to inspect the container to see if they get a raw or multiplexed stream. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
@ -614,7 +614,7 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
|
||||
|
||||
hijackDone <- true
|
||||
|
||||
writeHijackHeader(req, httpBuf)
|
||||
writeHijackHeader(req, httpBuf, isTerminal)
|
||||
|
||||
// Force a flush after the header is written.
|
||||
if err := httpBuf.Flush(); err != nil {
|
||||
|
@ -569,7 +569,7 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp
|
||||
hijackDone <- true
|
||||
|
||||
// Write a header to let the client know what happened
|
||||
writeHijackHeader(r, httpBuf)
|
||||
writeHijackHeader(r, httpBuf, isTerminal)
|
||||
|
||||
// Force a flush after the header is written.
|
||||
if err := httpBuf.Flush(); err != nil {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v4/libpod/define"
|
||||
"github.com/containers/podman/v4/pkg/api/handlers/utils/apiutil"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -182,22 +183,36 @@ func makeHTTPAttachHeader(stream byte, length uint32) []byte {
|
||||
|
||||
// writeHijackHeader writes a header appropriate for the type of HTTP Hijack
|
||||
// that occurred in a hijacked HTTP connection used for attach.
|
||||
func writeHijackHeader(r *http.Request, conn io.Writer) {
|
||||
func writeHijackHeader(r *http.Request, conn io.Writer, tty bool) {
|
||||
// AttachHeader is the literal header sent for upgraded/hijacked connections for
|
||||
// attach, sourced from Docker at:
|
||||
// https://raw.githubusercontent.com/moby/moby/b95fad8e51bd064be4f4e58a996924f343846c85/api/server/router/container/container_routes.go
|
||||
// Using literally to ensure compatibility with existing clients.
|
||||
|
||||
// New docker API uses a different header for the non tty case.
|
||||
// Lets do the same for libpod. Only do this for the new api versions to not break older clients.
|
||||
header := "application/vnd.docker.raw-stream"
|
||||
if !tty {
|
||||
version := "4.7.0"
|
||||
if !apiutil.IsLibpodRequest(r) {
|
||||
version = "1.42.0" // docker only used two digest "1.42" but our semver lib needs the extra .0 to work
|
||||
}
|
||||
if _, err := apiutil.SupportedVersion(r, ">= "+version); err == nil {
|
||||
header = "application/vnd.docker.multiplexed-stream"
|
||||
}
|
||||
}
|
||||
|
||||
c := r.Header.Get("Connection")
|
||||
proto := r.Header.Get("Upgrade")
|
||||
if len(proto) == 0 || !strings.EqualFold(c, "Upgrade") {
|
||||
// OK - can't upgrade if not requested or protocol is not specified
|
||||
fmt.Fprintf(conn,
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n\r\n", header)
|
||||
} else {
|
||||
// Upgraded
|
||||
fmt.Fprintf(conn,
|
||||
"HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: %s\r\n\r\n",
|
||||
proto)
|
||||
"HTTP/1.1 101 UPGRADED\r\nContent-Type: %s\r\nConnection: Upgrade\r\nUpgrade: %s\r\n\r\n",
|
||||
proto, header)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1376,6 +1376,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
||||
//
|
||||
// When the TTY setting is disabled for the container,
|
||||
// the HTTP Content-Type header is set to application/vnd.docker.multiplexed-stream
|
||||
// (starting with v4.7.0, previously application/vnd.docker.raw-stream was always used)
|
||||
// and the stream over the hijacked connected is multiplexed to separate out
|
||||
// `stdout` and `stderr`. The stream consists of a series of frames, each
|
||||
// containing a header and a payload.
|
||||
|
@ -30,6 +30,21 @@ podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42"
|
||||
# Looks like it is missing the required 0 bytes from the message, why?
|
||||
t POST "containers/foo/attach?logs=true&stream=false" 200 \
|
||||
$'\001\031'$mytext
|
||||
|
||||
# check old docker header
|
||||
response_headers=$(cat "$WORKDIR/curl.headers.out")
|
||||
like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream docker v1.40"
|
||||
# check new vnd.docker.multiplexed-stream header
|
||||
t POST "/v1.42/containers/foo/attach?logs=true&stream=false" 200
|
||||
response_headers=$(cat "$WORKDIR/curl.headers.out")
|
||||
like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream docker v1.42"
|
||||
t POST "/v4.6.0/libpod/containers/foo/attach?logs=true&stream=false" 200
|
||||
response_headers=$(cat "$WORKDIR/curl.headers.out")
|
||||
like "$response_headers" ".*Content-Type: application/vnd\.docker\.raw-stream.*" "vnd.docker.raw-stream libpod v4.6.0"
|
||||
t POST "/v4.7.0/libpod/containers/foo/attach?logs=true&stream=false" 200
|
||||
response_headers=$(cat "$WORKDIR/curl.headers.out")
|
||||
like "$response_headers" ".*Content-Type: application/vnd\.docker\.multiplexed-stream.*" "vnd.docker.multiplexed-stream libpod v4.7.0"
|
||||
|
||||
t POST "containers/foo/kill" 204
|
||||
|
||||
podman run --replace --name=foo -v /tmp:/tmp $IMAGE true
|
||||
|
Reference in New Issue
Block a user