host.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package protocol
  2. import (
  3. "github.com/aws/aws-sdk-go/aws/request"
  4. "net"
  5. "strconv"
  6. "strings"
  7. )
  8. // ValidateEndpointHostHandler is a request handler that will validate the
  9. // request endpoint's hosts is a valid RFC 3986 host.
  10. var ValidateEndpointHostHandler = request.NamedHandler{
  11. Name: "awssdk.protocol.ValidateEndpointHostHandler",
  12. Fn: func(r *request.Request) {
  13. err := ValidateEndpointHost(r.Operation.Name, r.HTTPRequest.URL.Host)
  14. if err != nil {
  15. r.Error = err
  16. }
  17. },
  18. }
  19. // ValidateEndpointHost validates that the host string passed in is a valid RFC
  20. // 3986 host. Returns error if the host is not valid.
  21. func ValidateEndpointHost(opName, host string) error {
  22. paramErrs := request.ErrInvalidParams{Context: opName}
  23. var hostname string
  24. var port string
  25. var err error
  26. if strings.Contains(host, ":") {
  27. hostname, port, err = net.SplitHostPort(host)
  28. if err != nil {
  29. paramErrs.Add(request.NewErrParamFormat("endpoint", err.Error(), host))
  30. }
  31. if !ValidPortNumber(port) {
  32. paramErrs.Add(request.NewErrParamFormat("endpoint port number", "[0-65535]", port))
  33. }
  34. } else {
  35. hostname = host
  36. }
  37. labels := strings.Split(hostname, ".")
  38. for i, label := range labels {
  39. if i == len(labels)-1 && len(label) == 0 {
  40. // Allow trailing dot for FQDN hosts.
  41. continue
  42. }
  43. if !ValidHostLabel(label) {
  44. paramErrs.Add(request.NewErrParamFormat(
  45. "endpoint host label", "[a-zA-Z0-9-]{1,63}", label))
  46. }
  47. }
  48. if len(hostname) == 0 {
  49. paramErrs.Add(request.NewErrParamMinLen("endpoint host", 1))
  50. }
  51. if len(hostname) > 255 {
  52. paramErrs.Add(request.NewErrParamMaxLen(
  53. "endpoint host", 255, host,
  54. ))
  55. }
  56. if paramErrs.Len() > 0 {
  57. return paramErrs
  58. }
  59. return nil
  60. }
  61. // ValidHostLabel returns if the label is a valid RFC 3986 host label.
  62. func ValidHostLabel(label string) bool {
  63. if l := len(label); l == 0 || l > 63 {
  64. return false
  65. }
  66. for _, r := range label {
  67. switch {
  68. case r >= '0' && r <= '9':
  69. case r >= 'A' && r <= 'Z':
  70. case r >= 'a' && r <= 'z':
  71. case r == '-':
  72. default:
  73. return false
  74. }
  75. }
  76. return true
  77. }
  78. // ValidPortNumber return if the port is valid RFC 3986 port
  79. func ValidPortNumber(port string) bool {
  80. i, err := strconv.Atoi(port)
  81. if err != nil {
  82. return false
  83. }
  84. if i < 0 || i > 65535 {
  85. return false
  86. }
  87. return true
  88. }