2016-01-04 21:36:01 +03:00
|
|
|
package dockerversion
|
|
|
|
|
|
|
|
import (
|
2016-03-09 05:18:53 +03:00
|
|
|
"fmt"
|
2016-01-04 21:36:01 +03:00
|
|
|
"runtime"
|
|
|
|
|
|
|
|
"github.com/docker/docker/pkg/parsers/kernel"
|
|
|
|
"github.com/docker/docker/pkg/useragent"
|
2016-03-09 05:18:53 +03:00
|
|
|
"golang.org/x/net/context"
|
2016-01-04 21:36:01 +03:00
|
|
|
)
|
|
|
|
|
2016-12-23 00:51:47 +03:00
|
|
|
// UAStringKey is used as key type for user-agent string in net/context struct
|
|
|
|
const UAStringKey = "upstream-user-agent"
|
|
|
|
|
2016-01-04 21:36:01 +03:00
|
|
|
// DockerUserAgent is the User-Agent the Docker client uses to identify itself.
|
2016-03-09 05:18:53 +03:00
|
|
|
// In accordance with RFC 7231 (5.5.3) is of the form:
|
|
|
|
// [docker client's UA] UpstreamClient([upstream client's UA])
|
2016-03-19 00:42:40 +03:00
|
|
|
func DockerUserAgent(ctx context.Context) string {
|
2016-01-04 21:36:01 +03: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-09 05:18:53 +03:00
|
|
|
dockerUA := useragent.AppendVersions("", httpVersion...)
|
2016-03-19 00:42:40 +03:00
|
|
|
upstreamUA := getUserAgentFromContext(ctx)
|
2016-03-09 05:18:53 +03:00
|
|
|
if len(upstreamUA) > 0 {
|
|
|
|
ret := insertUpstreamUserAgent(upstreamUA, dockerUA)
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
return dockerUA
|
|
|
|
}
|
|
|
|
|
2016-03-19 00:42:40 +03:00
|
|
|
// getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists
|
|
|
|
func getUserAgentFromContext(ctx context.Context) string {
|
2016-03-09 05:18:53 +03:00
|
|
|
var upstreamUA string
|
|
|
|
if ctx != nil {
|
2016-12-23 00:51:47 +03:00
|
|
|
var ki interface{} = ctx.Value(UAStringKey)
|
2016-03-09 05:18:53 +03:00
|
|
|
if ki != nil {
|
2016-12-23 00:51:47 +03:00
|
|
|
upstreamUA = ctx.Value(UAStringKey).(string)
|
2016-03-09 05:18:53 +03: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
|
|
|
|
for _, escapeableRune := range charsToEscape {
|
|
|
|
if currRune == escapeableRune {
|
2016-03-19 00:42:40 +03:00
|
|
|
ret += `\` + string(currRune)
|
2016-03-09 05:18:53 +03: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:
|
|
|
|
// $dockerUA UpstreamClient($upstreamUA)
|
|
|
|
func insertUpstreamUserAgent(upstreamUA string, dockerUA string) string {
|
2016-03-19 00:42:40 +03:00
|
|
|
charsToEscape := `();\`
|
2016-03-09 05:18:53 +03:00
|
|
|
upstreamUAEscaped := escapeStr(upstreamUA, charsToEscape)
|
|
|
|
return fmt.Sprintf("%s UpstreamClient(%s)", dockerUA, upstreamUAEscaped)
|
2016-01-04 21:36:01 +03:00
|
|
|
}
|