useragent.go 2.5 KB

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