github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/dockerversion/useragent.go (about)

     1  package dockerversion // import "github.com/demonoid81/moby/dockerversion"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"runtime"
     7  
     8  	"github.com/demonoid81/moby/pkg/parsers/kernel"
     9  	"github.com/demonoid81/moby/pkg/useragent"
    10  )
    11  
    12  // UAStringKey is used as key type for user-agent string in net/context struct
    13  type UAStringKey struct{}
    14  
    15  // DockerUserAgent is the User-Agent the Docker client uses to identify itself.
    16  // In accordance with RFC 7231 (5.5.3) is of the form:
    17  //    [docker client's UA] UpstreamClient([upstream client's UA])
    18  func DockerUserAgent(ctx context.Context) string {
    19  	httpVersion := make([]useragent.VersionInfo, 0, 6)
    20  	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "docker", Version: Version})
    21  	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "go", Version: runtime.Version()})
    22  	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "git-commit", Version: GitCommit})
    23  	if kernelVersion, err := kernel.GetKernelVersion(); err == nil {
    24  		httpVersion = append(httpVersion, useragent.VersionInfo{Name: "kernel", Version: kernelVersion.String()})
    25  	}
    26  	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "os", Version: runtime.GOOS})
    27  	httpVersion = append(httpVersion, useragent.VersionInfo{Name: "arch", Version: runtime.GOARCH})
    28  
    29  	dockerUA := useragent.AppendVersions("", httpVersion...)
    30  	upstreamUA := getUserAgentFromContext(ctx)
    31  	if len(upstreamUA) > 0 {
    32  		ret := insertUpstreamUserAgent(upstreamUA, dockerUA)
    33  		return ret
    34  	}
    35  	return dockerUA
    36  }
    37  
    38  // getUserAgentFromContext returns the previously saved user-agent context stored in ctx, if one exists
    39  func getUserAgentFromContext(ctx context.Context) string {
    40  	var upstreamUA string
    41  	if ctx != nil {
    42  		var ki interface{} = ctx.Value(UAStringKey{})
    43  		if ki != nil {
    44  			upstreamUA = ctx.Value(UAStringKey{}).(string)
    45  		}
    46  	}
    47  	return upstreamUA
    48  }
    49  
    50  // escapeStr returns s with every rune in charsToEscape escaped by a backslash
    51  func escapeStr(s string, charsToEscape string) string {
    52  	var ret string
    53  	for _, currRune := range s {
    54  		appended := false
    55  		for _, escapableRune := range charsToEscape {
    56  			if currRune == escapableRune {
    57  				ret += `\` + string(currRune)
    58  				appended = true
    59  				break
    60  			}
    61  		}
    62  		if !appended {
    63  			ret += string(currRune)
    64  		}
    65  	}
    66  	return ret
    67  }
    68  
    69  // insertUpstreamUserAgent adds the upstream client useragent to create a user-agent
    70  // string of the form:
    71  //   $dockerUA UpstreamClient($upstreamUA)
    72  func insertUpstreamUserAgent(upstreamUA string, dockerUA string) string {
    73  	charsToEscape := `();\`
    74  	upstreamUAEscaped := escapeStr(upstreamUA, charsToEscape)
    75  	return fmt.Sprintf("%s UpstreamClient(%s)", dockerUA, upstreamUAEscaped)
    76  }