github.com/rumpl/bof@v23.0.0-rc.2+incompatible/dockerversion/useragent.go (about)

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