useragent.go 2.6 KB

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