libpod: fix header length in http attach with logs

When we read logs there can be full or partial lines, when it is full we
need to append a newline, thus the message length must be incremented by
one.

Fixes #16856

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger 2022-12-15 18:32:55 +01:00
parent d6c2fa6452
commit 1424f0958f
No known key found for this signature in database
GPG Key ID: EB145DD938A3CAF2
3 changed files with 37 additions and 5 deletions

View File

@ -594,6 +594,10 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http.
device := logLine.Device device := logLine.Device
var header []byte var header []byte
headerLen := uint32(len(logLine.Msg)) headerLen := uint32(len(logLine.Msg))
if !logLine.Partial() {
// we append an extra newline in this case so we need to increment the len as well
headerLen++
}
logSize += len(logLine.Msg) logSize += len(logLine.Msg)
switch strings.ToLower(device) { switch strings.ToLower(device) {
case "stdin": case "stdin":

View File

@ -26,9 +26,10 @@ like "$response_headers" ".*Content-Type: application/json.*" "header does not c
# Regression test for #12904 (race condition in logging code) # Regression test for #12904 (race condition in logging code)
mytext="hi-there-$(random_string 15)" mytext="hi-there-$(random_string 15)"
podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42" podman run --rm -d --replace --name foo $IMAGE sh -c "echo $mytext;sleep 42"
# Logs output is prepended by ^A^X # Logs output is prepended by ^A^Y (stdout = 1, length = 25 (with newline))
# Looks like it is missing the required 0 bytes from the message, why?
t POST "containers/foo/attach?logs=true&stream=false" 200 \ t POST "containers/foo/attach?logs=true&stream=false" 200 \
$'\001\030'$mytext $'\001\031'$mytext
t POST "containers/foo/kill" 204 t POST "containers/foo/kill" 204
podman run -v /tmp:/tmp $IMAGE true podman run -v /tmp:/tmp $IMAGE true

View File

@ -133,9 +133,36 @@ class ContainerTestCase(APITestCase):
self.assertEqual(r.text, "", r.text) self.assertEqual(r.text, "", r.text)
def test_attach(self): def test_attach(self):
self.skipTest("FIXME: Test timeouts") r = requests.post(
r = requests.post(self.uri(self.resolve_container("/containers/{}/attach?logs=true")), timeout=5) self.podman_url + "/v1.40/containers/create?name=topcontainer",
self.assertIn(r.status_code, (101, 500), r.text) json={"Cmd": ["sh", "-c", "echo podman; sleep 100"], "Image": "alpine:latest"},
)
self.assertEqual(r.status_code, 201, r.text)
payload = r.json()
r = requests.post(
self.podman_url
+ f"/v1.40/containers/{payload['Id']}/start"
)
self.assertEqual(r.status_code, 204, r.text)
r = requests.post(
self.podman_url
+ f"/v1.40/containers/{payload['Id']}/attach?logs=true&stream=false"
)
self.assertIn(r.status_code, (101, 200), r.text)
# see the attach format docs, stdout = 1, length = 7, message = podman\n
self.assertEqual(r.content, b"\x01\x00\x00\x00\x00\x00\x00\x07podman\n", r.text)
r = requests.post(
self.podman_url
+ f"/v1.40/containers/{payload['Id']}/stop?t=0"
)
self.assertEqual(r.status_code, 204, r.text)
requests.delete(
self.podman_url + f"/v1.40/containers/{payload['Id']}?force=true"
)
def test_logs(self): def test_logs(self):
r = requests.get(self.uri(self.resolve_container("/containers/{}/logs?stdout=true"))) r = requests.get(self.uri(self.resolve_container("/containers/{}/logs?stdout=true")))