2018-02-05 16:05:59 -05:00
|
|
|
package dockerversion // import "github.com/docker/docker/dockerversion"
|
2016-01-04 13:36:01 -05:00
|
|
|
|
|
|
|
import (
|
2018-04-19 18:30:59 -04:00
|
|
|
"context"
|
2016-03-08 21:18:53 -05:00
|
|
|
"fmt"
|
2016-01-04 13:36:01 -05:00
|
|
|
"runtime"
|
|
|
|
|
|
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
|
|
"github.com/docker/docker/pkg/useragent"
|
|
|
|
)
|
|
|
|
|
2016-12-22 16:51:47 -05:00
|
|
|
// UAStringKey is used as key type for user-agent string in net/context struct
|
2018-08-21 22:20:22 -04:00
|
|
|
type UAStringKey struct{}
|
2016-12-22 16:51:47 -05:00
|
|
|
|
2016-01-04 13:36:01 -05:00
|
|
|
// DockerUserAgent is the User-Agent the Docker client uses to identify itself.
|
2016-03-08 21:18:53 -05:00
|
|
|
// In accordance with RFC 7231 (5.5.3) is of the form:
|
2022-07-08 12:27:07 -04:00
|
|
|
//
|
|
|
|
// [docker client's UA] UpstreamClient([upstream client's UA])
|
2016-03-18 17:42:40 -04:00
|
|
|
func DockerUserAgent(ctx context.Context) string {
|
2016-01-04 13:36:01 -05:00
|
|
|
httpVersion := make([]useragent.VersionInfo, 0, 6)
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: Version})
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: GitCommit})
|
|
|
|
if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
|
|
|
|
}
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
|
|
|
|
httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})
|
|
|
|
|
2016-03-08 21:18:53 -05:00
|
|
|
dockerUA := useragent.AppendVersions("", httpVersion...)
|
2016-03-18 17:42:40 -04:00
|
|
|
upstreamUA := getUserAgentFromContext(ctx)
|
2016-03-08 21:18:53 -05:00
|
|
|
if len(upstreamUA) > 0 {
|
|
|
|
ret := insertUpstreamUserAgent(upstreamUA, dockerUA)
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
return dockerUA
|
|
|
|
}
|
|
|
|
|
2016-03-18 17:42:40 -04:00
|
|
|
// getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists
|
|
|
|
func getUserAgentFromContext(ctx context.Context) string {
|
2016-03-08 21:18:53 -05:00
|
|
|
var upstreamUA string
|
|
|
|
if ctx != nil {
|
2018-08-21 22:20:22 -04:00
|
|
|
var ki interface{} = ctx.Value(UAStringKey{})
|
2016-03-08 21:18:53 -05:00
|
|
|
if ki != nil {
|
2018-08-21 22:20:22 -04:00
|
|
|
upstreamUA = ctx.Value(UAStringKey{}).(string)
|
2016-03-08 21:18:53 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return upstreamUA
|
|
|
|
}
|
|
|
|
|
|
|
|
// escapeStr returns s with every rune in charsToEscape escaped by a backslash
|
|
|
|
func escapeStr(s string, charsToEscape string) string {
|
|
|
|
var ret string
|
|
|
|
for _, currRune := range s {
|
|
|
|
appended := false
|
2017-05-21 19:24:07 -04:00
|
|
|
for _, escapableRune := range charsToEscape {
|
|
|
|
if currRune == escapableRune {
|
2016-03-18 17:42:40 -04:00
|
|
|
ret += `\` + string(currRune)
|
2016-03-08 21:18:53 -05:00
|
|
|
appended = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !appended {
|
|
|
|
ret += string(currRune)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
// insertUpstreamUserAgent adds the upstream client useragent to create a user-agent
|
|
|
|
// string of the form:
|
2022-07-08 12:27:07 -04:00
|
|
|
//
|
|
|
|
// $dockerUA UpstreamClient($upstreamUA)
|
2016-03-08 21:18:53 -05:00
|
|
|
func insertUpstreamUserAgent(upstreamUA string, dockerUA string) string {
|
2016-03-18 17:42:40 -04:00
|
|
|
charsToEscape := `();\`
|
2016-03-08 21:18:53 -05:00
|
|
|
upstreamUAEscaped := escapeStr(upstreamUA, charsToEscape)
|
|
|
|
return fmt.Sprintf("%s UpstreamClient(%s)", dockerUA, upstreamUAEscaped)
|
2016-01-04 13:36:01 -05:00
|
|
|
}
|