Skip to content

Header to explicit raw-stream implementation being used#39812

Merged
thaJeztah merged 1 commit intomoby:masterfrom
ndeloof:raw-stream
May 12, 2022
Merged

Header to explicit raw-stream implementation being used#39812
thaJeztah merged 1 commit intomoby:masterfrom
ndeloof:raw-stream

Conversation

@ndeloof
Copy link
Copy Markdown
Contributor

@ndeloof ndeloof commented Aug 28, 2019

closes #35761

- What I did
Document the actual raw-stream mechanism being used (raw or multiplexed)

- How I did it
Added a Content-Type parameter following RFC 7231

- How to verify it
run a container with our without tty option and check Content-type header on attach

- Description for the changelog
attach API declares raw-stream format in use within Content-type header

- A picture of a cute animal (not mandatory but encouraged)
image

@thaJeztah
Copy link
Copy Markdown
Member

Thanks!

Is the same change needed for other endpoints that have a similar "raw" stream? (attach, perhaps logs? (not sure)); I see a couple more occurrences of application/vnd.docker.raw-stream in the swagger

We should probably document the additions to the headers in the Swagger file; at least a note in the version history; https://github.com/moby/moby/blob/53430f5/docs/api/version-history.md#v141-api-changes

Possibly in the section describing the stream format https://github.com/moby/moby/blob/9c94e82/api/swagger.yaml#L5864-L5896

And possibly

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Aug 28, 2019

containers/{id}/logs do not set a Content-type header, will fix this at same time.

@ndeloof ndeloof force-pushed the raw-stream branch 5 times, most recently from a153d14 to d7c8a6f Compare September 2, 2019 12:43
@AkihiroSuda
Copy link
Copy Markdown
Member

the commit description needs to be updated, as this is no longer doc-only change

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Sep 3, 2019

by document I was considering the http header as documentation for the http payload, admitedly confusing.

Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

agreed that the first line of the commit message may be a bit misleading, so would be nice to have it include that it's changing the header

@cpuguy83
Copy link
Copy Markdown
Member

cpuguy83 commented Sep 4, 2019

Do we need an API version switch on this?

Otherwise, very nice. I think this would also make it so the CLI doesn't need to do an inspect (IIRC) to check for TTY

@thaJeztah
Copy link
Copy Markdown
Member

Do we need an API version switch on this?

We may not need to, given that the content-type itself doesn't change, we're only adding parameters (which are optional, and can be ignored unless a client is looking for it specifically). So unless a client takes the raw Content-Type header and does an exact string-match, we should be good (famous last words);

RFC7231;

The type/subtype MAY be followed by parameters in the form of name=value pairs.

https://play.golang.org/p/my367gBiJ5w

package main

import (
	"fmt"
	"mime"
)

func main() {
	mediaType, params, _ := mime.ParseMediaType("application/vnd.docker.raw-stream; stream=raw; something=else; lang=en_US")
	fmt.Println("mediatype:", mediaType)
	fmt.Printf("params: %v\n", params)
}

We could add more documentation around it (if the stream parameter is not present, the client should fall back to calling the GET /containers/{id}/json endpoint to determine if the container has a TTY attached?

@ndeloof ndeloof changed the title Document raw-stream implementation being used Header to explicit raw-stream implementation being used Sep 9, 2019
@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Sep 9, 2019

updated commit message and PR description
rebased on origin/master

Copy link
Copy Markdown
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going back and forth if we should switch on API version here.
I think we need to just because we aren't going to send a non-multiplexed stream to an older client but we may do that in the future (actually I would really like to see this).

api/swagger.yaml Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may claim, if it does not then assume multiplexed.

@ndeloof ndeloof force-pushed the raw-stream branch 2 times, most recently from 8f194c8 to 1f016e1 Compare September 13, 2019 07:28
@ndeloof ndeloof requested a review from cpuguy83 September 13, 2019 08:01
@ndeloof ndeloof force-pushed the raw-stream branch 3 times, most recently from 3340c31 to 4560517 Compare September 14, 2019 08:22
@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Sep 16, 2019

Not sure how to address buid failure
docker-logger-128371389\container.log.1: The process cannot access the file because it is being used by another process.
I tried to rebase and force-push to trigger a fresh new build but other errors still happen on Windows tests.

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Sep 20, 2019

afaict most of the recent commits on master just failed on CI.
so one one hand make me feel I'm (probably?) not responsible for test failure on this PR, but also don't make me confident this should be merged and we won't get side effects in near future

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented Apr 25, 2022

@cpuguy83 updated: new multiplexed mime type is used for version >= 1.42 and client's Accept header is checked so we don't break any client that would be strict with HTTP.

@ndeloof ndeloof force-pushed the raw-stream branch 3 times, most recently from 35a19e4 to 95ca82f Compare April 26, 2022 06:21
Copy link
Copy Markdown
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No requests for change just a point of discussion (sorry!)


type errNotAcceptable struct{ error }

func (errNotAcceptable) NotAcceptable() {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this is necessary over using InvalidParameter?
How will a client respond to the two things differently?
I guess in this case it would strictly be a client misconfiguration as opposed to a user providing invalid/incorrect data.

Reading up on the usage of the error code from https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406 it also seems the recommendation is to go ahead and send an OK response anyway and leave it to the client to understand that the media type is not what they asked for.

Thinking and reading maybe my suggestion to use accept headers was not useful after all.

  1. An older client will continue to get old media types
  2. A new client that did not make changes for the new API (or an un-versioned client) is technically incorrect but likely won't be checking mediatype anyway and will use old behavior (calling /containers/<id>/json)
  3. A "proper" new client will look at the mediatype returned

I guess my original thought around using accept headers was to help ensure compatibility for clients in camp 2.
I was also thinking that we would return the type of stream that was requested in the accept header in all cases, but that's not actually the case and wouldn't really work anyway (at least not well).

So... is camp 2 worth it?

@thaJeztah
Copy link
Copy Markdown
Member

We discussed this PR in the maintainers meeting.

We had some discussion about whether 406 was trying to be "too perfect", and if a plain 400 (hey, something's invalid) would do. We went back-and-forth a bit, but @corhere brought up some valid points;

  • if a client explicitly only wants to use (say) application/vnd.docker.multiplexed-strea, but because of the container-settings, it cannot be, then having a 409 could be useful for it to know "why".
  • similar; possibly we'd want to add different mediatype for (e.g.) log-streams, in which case it's useful to have the correct status for this situation (instead of a plain 400)

So even though the use-cases are currently limited; it was considered good to do it "right", and to already use this status code.

There were some other points discussed, but the consensus was that we're ok with the current approach; I asked some maintainers to have a look at the implementation, and to accept/merge this PR unless there are really major issues (minor issues / improvements / cleanups for follow-ups if needed).

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented May 5, 2022

We're going back and forth on this topic, trying to find a good "HTTP-friendly" way to manage this, but actually we are not negociating content, there's a single stream type we can return, and this PR is all about documenting this. Could have ben a custom header added to the HTTP response. I'm a favor to give up with client's Accept header and just set Content-Type for API >= 1.42.

@corhere
Copy link
Copy Markdown
Contributor

corhere commented May 5, 2022

Continuing to ignore the client's Accept header while we have nothing to negotiate sounds good to me. It wouldn't impact our ability to add new stream formats to the API in the future since the current formats would generally need to remain the default and we could allow clients to opt in... by content negotiation using an Accept header! Generic clients would need to support the existing stream formats anyway. And any specialized clients with more finicky requirements would need to inspect the Content-Type response header anyway to handle negotiation-unaware daemons regardless of whether awareness of the Accept header was added today.

@ndeloof
Copy link
Copy Markdown
Contributor Author

ndeloof commented May 6, 2022

Continuing to ignore the client's Accept header while we have nothing to negotiate sounds good to me

This is the option I selected on my last push, reverting content negociation and attempts to rely on Accept header to detect client expectations. I don't want this to become a complex beast just to avoid client to remember or inspect container config before it collects logs.

@cpuguy83
Copy link
Copy Markdown
Member

cpuguy83 commented May 6, 2022

Can we have a test for this? There may be some API related tests already that can check the response header.

@ndeloof ndeloof force-pushed the raw-stream branch 5 times, most recently from 6cdeb33 to ce52815 Compare May 9, 2022 16:01
type HijackedResponse struct {
Conn net.Conn
Reader *bufio.Reader
Multiplexed *bool
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the content type string here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's an option indeed. But then I'll suggest to define func (HijackedResponse) IsMultiplexed() bool
as the consumer don't really care about content type, just want to know how to access payload streams :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine for me (or a function in the package that defines the content-type values)... and/or a generic ConsumeStdStream.

I like to avoid such bool fields because invariably more than the bool is needed, and then we are dealing with pointers everywhere.

@ndeloof ndeloof force-pushed the raw-stream branch 5 times, most recently from 46449f7 to cc1292c Compare May 10, 2022 17:39
Copy link
Copy Markdown
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

fix moby#35761

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
Copy link
Copy Markdown
Member

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

introduce header to document docker.raw-stream is multiplexed or raw tty

8 participants