useragent.go 2.6 KB

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