dockerversion/useragent.go
61a49bb6
 package dockerversion
 
 import (
d1502afb
 	"fmt"
61a49bb6
 	"runtime"
 
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/useragent"
d1502afb
 	"golang.org/x/net/context"
61a49bb6
 )
 
64981b9f
 // UAStringKey is used as key type for user-agent string in net/context struct
 const UAStringKey = "upstream-user-agent"
 
61a49bb6
 // DockerUserAgent is the User-Agent the Docker client uses to identify itself.
d1502afb
 // In accordance with RFC 7231 (5.5.3) is of the form:
 //    [docker client's UA] UpstreamClient([upstream client's UA])
c44e7a3e
 func DockerUserAgent(ctx context.Context) string {
61a49bb6
 	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})
 
d1502afb
 	dockerUA := useragent.AppendVersions("", httpVersion...)
c44e7a3e
 	upstreamUA := getUserAgentFromContext(ctx)
d1502afb
 	if len(upstreamUA) > 0 {
 		ret := insertUpstreamUserAgent(upstreamUA, dockerUA)
 		return ret
 	}
 	return dockerUA
 }
 
c44e7a3e
 // getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists
 func getUserAgentFromContext(ctx context.Context) string {
d1502afb
 	var upstreamUA string
 	if ctx != nil {
64981b9f
 		var ki interface{} = ctx.Value(UAStringKey)
d1502afb
 		if ki != nil {
64981b9f
 			upstreamUA = ctx.Value(UAStringKey).(string)
d1502afb
 		}
 	}
 	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
39bcaee4
 		for _, escapableRune := range charsToEscape {
 			if currRune == escapableRune {
c44e7a3e
 				ret += `\` + string(currRune)
d1502afb
 				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 {
c44e7a3e
 	charsToEscape := `();\`
d1502afb
 	upstreamUAEscaped := escapeStr(upstreamUA, charsToEscape)
 	return fmt.Sprintf("%s UpstreamClient(%s)", dockerUA, upstreamUAEscaped)
61a49bb6
 }