You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

504 lines
16 KiB

fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
fix: panic in browser redirect handler for unexpected r.Host (#14844) ``` panic: "GET /": invalid hostname goroutine 148 [running]: runtime/debug.Stack() runtime/debug/stack.go:24 +0x65 github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1() github.com/minio/minio/cmd/generic-handlers.go:469 +0x8e panic({0x2201f00, 0xc001f1ddd0}) runtime/panic.go:1038 +0x215 github.com/minio/pkg/net.URL.String({{0x25aa417, 0x5}, {0x0, 0x0}, 0x0, {0xc000174380, 0xd7}, {0x0, 0x0}, {0x0, ...}, ...}) github.com/minio/pkg@v1.1.23/net/url.go:97 +0xfe github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/generic-handlers.go:136 +0x118 net/http.HandlerFunc.ServeHTTP(0xc00002ea00, {0x49af080, 0xc0003c20e0}, 0xa) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setAuthHandler.func1({0x49af080, 0xc0003c20e0}, 0xc00002ea00) github.com/minio/minio/cmd/auth-handler.go:525 +0x3d8 net/http.HandlerFunc.ServeHTTP(0xc00002e900, {0x49af080, 0xc0003c20e0}, 0xc001f33701) net/http/server.go:2047 +0x2f github.com/gorilla/mux.(*Router).ServeHTTP(0xc0025d0780, {0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/gorilla/mux@v1.8.0/mux.go:210 +0x1cf github.com/rs/cors.(*Cors).Handler.func1({0x49af080, 0xc0003c20e0}, 0xc00002e800) github.com/rs/cors@v1.7.0/cors.go:219 +0x1bd net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0xc00068d9f8) net/http/server.go:2047 +0x2f github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x49af080, 0xc0003c20e0}, 0x4a5cd3) github.com/minio/minio/cmd/generic-handlers.go:476 +0x83 net/http.HandlerFunc.ServeHTTP(0x72, {0x49af080, 0xc0003c20e0}, 0x0) net/http/server.go:2047 +0x2f github.com/minio/minio/internal/http.(*Server).Start.func1({0x49af080, 0xc0003c20e0}, 0x10000c001f1dda0) github.com/minio/minio/internal/http/server.go:105 +0x1b6 net/http.HandlerFunc.ServeHTTP(0x0, {0x49af080, 0xc0003c20e0}, 0x46982e) net/http/server.go:2047 +0x2f net/http.serverHandler.ServeHTTP({0xc003dc1950}, {0x49af080, 0xc0003c20e0}, 0xc00002e800) net/http/server.go:2879 +0x43b net/http.(*conn).serve(0xc000514d20, {0x49cfc38, 0xc0010c0e70}) net/http/server.go:1930 +0xb08 created by net/http.(*Server).Serve net/http/server.go:3034 +0x4e8 ```
3 years ago
  1. // Copyright (c) 2015-2021 MinIO, Inc.
  2. //
  3. // This file is part of MinIO Object Storage stack
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU Affero General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU Affero General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. package cmd
  18. import (
  19. "context"
  20. "errors"
  21. "fmt"
  22. "net/http"
  23. "net/textproto"
  24. "regexp"
  25. "strings"
  26. "sync/atomic"
  27. "github.com/minio/madmin-go/v3"
  28. "github.com/minio/minio/internal/auth"
  29. "github.com/minio/minio/internal/handlers"
  30. xhttp "github.com/minio/minio/internal/http"
  31. "github.com/minio/minio/internal/logger"
  32. "github.com/minio/minio/internal/mcontext"
  33. xnet "github.com/minio/pkg/v3/net"
  34. )
  35. const (
  36. copyDirective = "COPY"
  37. replaceDirective = "REPLACE"
  38. accessDirective = "ACCESS"
  39. )
  40. // Parses location constraint from the incoming reader.
  41. func parseLocationConstraint(r *http.Request) (location string, s3Error APIErrorCode) {
  42. // If the request has no body with content-length set to 0,
  43. // we do not have to validate location constraint. Bucket will
  44. // be created at default region.
  45. locationConstraint := createBucketLocationConfiguration{}
  46. err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
  47. if err != nil && r.ContentLength != 0 {
  48. internalLogOnceIf(GlobalContext, err, "location-constraint-xml-parsing")
  49. // Treat all other failures as XML parsing errors.
  50. return "", ErrMalformedXML
  51. } // else for both err as nil or io.EOF
  52. location = locationConstraint.Location
  53. if location == "" {
  54. location = globalSite.Region()
  55. }
  56. if !isValidLocation(location) {
  57. return location, ErrInvalidRegion
  58. }
  59. return location, ErrNone
  60. }
  61. // Validates input location is same as configured region
  62. // of MinIO server.
  63. func isValidLocation(location string) bool {
  64. region := globalSite.Region()
  65. return region == "" || region == location
  66. }
  67. // Supported headers that needs to be extracted.
  68. var supportedHeaders = []string{
  69. "content-type",
  70. "cache-control",
  71. "content-language",
  72. "content-encoding",
  73. "content-disposition",
  74. "x-amz-storage-class",
  75. xhttp.AmzStorageClass,
  76. xhttp.AmzObjectTagging,
  77. "expires",
  78. xhttp.AmzBucketReplicationStatus,
  79. "X-Minio-Replication-Server-Side-Encryption-Sealed-Key",
  80. "X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm",
  81. "X-Minio-Replication-Server-Side-Encryption-Iv",
  82. "X-Minio-Replication-Encrypted-Multipart",
  83. "X-Minio-Replication-Actual-Object-Size",
  84. ReplicationSsecChecksumHeader,
  85. // Add more supported headers here.
  86. }
  87. // mapping of internal headers to allowed replication headers
  88. var validSSEReplicationHeaders = map[string]string{
  89. "X-Minio-Internal-Server-Side-Encryption-Sealed-Key": "X-Minio-Replication-Server-Side-Encryption-Sealed-Key",
  90. "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm": "X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm",
  91. "X-Minio-Internal-Server-Side-Encryption-Iv": "X-Minio-Replication-Server-Side-Encryption-Iv",
  92. "X-Minio-Internal-Encrypted-Multipart": "X-Minio-Replication-Encrypted-Multipart",
  93. "X-Minio-Internal-Actual-Object-Size": "X-Minio-Replication-Actual-Object-Size",
  94. // Add more supported headers here.
  95. }
  96. // mapping of replication headers to internal headers
  97. var replicationToInternalHeaders = map[string]string{
  98. "X-Minio-Replication-Server-Side-Encryption-Sealed-Key": "X-Minio-Internal-Server-Side-Encryption-Sealed-Key",
  99. "X-Minio-Replication-Server-Side-Encryption-Seal-Algorithm": "X-Minio-Internal-Server-Side-Encryption-Seal-Algorithm",
  100. "X-Minio-Replication-Server-Side-Encryption-Iv": "X-Minio-Internal-Server-Side-Encryption-Iv",
  101. "X-Minio-Replication-Encrypted-Multipart": "X-Minio-Internal-Encrypted-Multipart",
  102. "X-Minio-Replication-Actual-Object-Size": "X-Minio-Internal-Actual-Object-Size",
  103. ReplicationSsecChecksumHeader: ReplicationSsecChecksumHeader,
  104. // Add more supported headers here.
  105. }
  106. // isDirectiveValid - check if tagging-directive is valid.
  107. func isDirectiveValid(v string) bool {
  108. // Check if set metadata-directive is valid.
  109. return isDirectiveCopy(v) || isDirectiveReplace(v)
  110. }
  111. // Check if the directive COPY is requested.
  112. func isDirectiveCopy(value string) bool {
  113. // By default if directive is not set we
  114. // treat it as 'COPY' this function returns true.
  115. return value == copyDirective || value == ""
  116. }
  117. // Check if the directive REPLACE is requested.
  118. func isDirectiveReplace(value string) bool {
  119. return value == replaceDirective
  120. }
  121. // userMetadataKeyPrefixes contains the prefixes of used-defined metadata keys.
  122. // All values stored with a key starting with one of the following prefixes
  123. // must be extracted from the header.
  124. var userMetadataKeyPrefixes = []string{
  125. "x-amz-meta-",
  126. "x-minio-meta-",
  127. }
  128. // extractMetadataFromReq extracts metadata from HTTP header and HTTP queryString.
  129. func extractMetadataFromReq(ctx context.Context, r *http.Request) (metadata map[string]string, err error) {
  130. return extractMetadata(ctx, textproto.MIMEHeader(r.Form), textproto.MIMEHeader(r.Header))
  131. }
  132. func extractMetadata(ctx context.Context, mimesHeader ...textproto.MIMEHeader) (metadata map[string]string, err error) {
  133. metadata = make(map[string]string)
  134. for _, hdr := range mimesHeader {
  135. // Extract all query values.
  136. err = extractMetadataFromMime(ctx, hdr, metadata)
  137. if err != nil {
  138. return nil, err
  139. }
  140. }
  141. // Set content-type to default value if it is not set.
  142. if _, ok := metadata[strings.ToLower(xhttp.ContentType)]; !ok {
  143. metadata[strings.ToLower(xhttp.ContentType)] = "binary/octet-stream"
  144. }
  145. // https://github.com/google/security-research/security/advisories/GHSA-76wf-9vgp-pj7w
  146. for k := range metadata {
  147. if equals(k, xhttp.AmzMetaUnencryptedContentLength, xhttp.AmzMetaUnencryptedContentMD5) {
  148. delete(metadata, k)
  149. }
  150. }
  151. if contentEncoding, ok := metadata[strings.ToLower(xhttp.ContentEncoding)]; ok {
  152. contentEncoding = trimAwsChunkedContentEncoding(contentEncoding)
  153. if contentEncoding != "" {
  154. // Make sure to trim and save the content-encoding
  155. // parameter for a streaming signature which is set
  156. // to a custom value for example: "aws-chunked,gzip".
  157. metadata[strings.ToLower(xhttp.ContentEncoding)] = contentEncoding
  158. } else {
  159. // Trimmed content encoding is empty when the header
  160. // value is set to "aws-chunked" only.
  161. // Make sure to delete the content-encoding parameter
  162. // for a streaming signature which is set to value
  163. // for example: "aws-chunked"
  164. delete(metadata, strings.ToLower(xhttp.ContentEncoding))
  165. }
  166. }
  167. // Success.
  168. return metadata, nil
  169. }
  170. // extractMetadata extracts metadata from map values.
  171. func extractMetadataFromMime(ctx context.Context, v textproto.MIMEHeader, m map[string]string) error {
  172. if v == nil {
  173. bugLogIf(ctx, errInvalidArgument)
  174. return errInvalidArgument
  175. }
  176. nv := make(textproto.MIMEHeader, len(v))
  177. for k, kv := range v {
  178. // Canonicalize all headers, to remove any duplicates.
  179. nv[http.CanonicalHeaderKey(k)] = kv
  180. }
  181. // Save all supported headers.
  182. for _, supportedHeader := range supportedHeaders {
  183. value, ok := nv[http.CanonicalHeaderKey(supportedHeader)]
  184. if ok {
  185. if v, ok := replicationToInternalHeaders[supportedHeader]; ok {
  186. m[v] = strings.Join(value, ",")
  187. } else {
  188. m[supportedHeader] = strings.Join(value, ",")
  189. }
  190. }
  191. }
  192. for key := range v {
  193. for _, prefix := range userMetadataKeyPrefixes {
  194. if !stringsHasPrefixFold(key, prefix) {
  195. continue
  196. }
  197. value, ok := nv[http.CanonicalHeaderKey(key)]
  198. if ok {
  199. m[key] = strings.Join(value, ",")
  200. break
  201. }
  202. }
  203. }
  204. return nil
  205. }
  206. // Returns access credentials in the request Authorization header.
  207. func getReqAccessCred(r *http.Request, region string) (cred auth.Credentials) {
  208. cred, _, _ = getReqAccessKeyV4(r, region, serviceS3)
  209. if cred.AccessKey == "" {
  210. cred, _, _ = getReqAccessKeyV2(r)
  211. }
  212. return cred
  213. }
  214. // Extract request params to be sent with event notification.
  215. func extractReqParams(r *http.Request) map[string]string {
  216. if r == nil {
  217. return nil
  218. }
  219. region := globalSite.Region()
  220. cred := getReqAccessCred(r, region)
  221. principalID := cred.AccessKey
  222. if cred.ParentUser != "" {
  223. principalID = cred.ParentUser
  224. }
  225. // Success.
  226. m := map[string]string{
  227. "region": region,
  228. "principalId": principalID,
  229. "sourceIPAddress": handlers.GetSourceIP(r),
  230. // Add more fields here.
  231. }
  232. if rangeField := r.Header.Get(xhttp.Range); rangeField != "" {
  233. m["range"] = rangeField
  234. }
  235. if _, ok := r.Header[xhttp.MinIOSourceReplicationRequest]; ok {
  236. m[xhttp.MinIOSourceReplicationRequest] = ""
  237. }
  238. return m
  239. }
  240. // Extract response elements to be sent with event notification.
  241. func extractRespElements(w http.ResponseWriter) map[string]string {
  242. if w == nil {
  243. return map[string]string{}
  244. }
  245. return map[string]string{
  246. "requestId": w.Header().Get(xhttp.AmzRequestID),
  247. "nodeId": w.Header().Get(xhttp.AmzRequestHostID),
  248. "content-length": w.Header().Get(xhttp.ContentLength),
  249. // Add more fields here.
  250. }
  251. }
  252. // Trims away `aws-chunked` from the content-encoding header if present.
  253. // Streaming signature clients can have custom content-encoding such as
  254. // `aws-chunked,gzip` here we need to only save `gzip`.
  255. // For more refer http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html
  256. func trimAwsChunkedContentEncoding(contentEnc string) (trimmedContentEnc string) {
  257. if contentEnc == "" {
  258. return contentEnc
  259. }
  260. var newEncs []string
  261. for _, enc := range strings.Split(contentEnc, ",") {
  262. if enc != streamingContentEncoding {
  263. newEncs = append(newEncs, enc)
  264. }
  265. }
  266. return strings.Join(newEncs, ",")
  267. }
  268. func collectInternodeStats(f http.HandlerFunc) http.HandlerFunc {
  269. return func(w http.ResponseWriter, r *http.Request) {
  270. f.ServeHTTP(w, r)
  271. tc, ok := r.Context().Value(mcontext.ContextTraceKey).(*mcontext.TraceCtxt)
  272. if !ok || tc == nil {
  273. return
  274. }
  275. globalConnStats.incInternodeInputBytes(int64(tc.RequestRecorder.Size()))
  276. globalConnStats.incInternodeOutputBytes(int64(tc.ResponseRecorder.Size()))
  277. }
  278. }
  279. func collectAPIStats(api string, f http.HandlerFunc) http.HandlerFunc {
  280. return func(w http.ResponseWriter, r *http.Request) {
  281. resource, err := getResource(r.URL.Path, r.Host, globalDomainNames)
  282. if err != nil {
  283. defer logger.AuditLog(r.Context(), w, r, mustGetClaimsFromToken(r))
  284. apiErr := errorCodes.ToAPIErr(ErrUnsupportedHostHeader)
  285. apiErr.Description = fmt.Sprintf("%s: %v", apiErr.Description, err)
  286. writeErrorResponse(r.Context(), w, apiErr, r.URL)
  287. return
  288. }
  289. bucket, _ := path2BucketObject(resource)
  290. meta, err := globalBucketMetadataSys.Get(bucket) // check if this bucket exists.
  291. countBktStat := bucket != "" && bucket != minioReservedBucket && err == nil && !meta.Created.IsZero()
  292. if countBktStat {
  293. globalBucketHTTPStats.updateHTTPStats(bucket, api, nil)
  294. }
  295. globalHTTPStats.currentS3Requests.Inc(api)
  296. f.ServeHTTP(w, r)
  297. globalHTTPStats.currentS3Requests.Dec(api)
  298. tc, _ := r.Context().Value(mcontext.ContextTraceKey).(*mcontext.TraceCtxt)
  299. if tc != nil {
  300. globalHTTPStats.updateStats(api, tc.ResponseRecorder)
  301. globalConnStats.incS3InputBytes(int64(tc.RequestRecorder.Size()))
  302. globalConnStats.incS3OutputBytes(int64(tc.ResponseRecorder.Size()))
  303. if countBktStat {
  304. globalBucketConnStats.incS3InputBytes(bucket, int64(tc.RequestRecorder.Size()))
  305. globalBucketConnStats.incS3OutputBytes(bucket, int64(tc.ResponseRecorder.Size()))
  306. globalBucketHTTPStats.updateHTTPStats(bucket, api, tc.ResponseRecorder)
  307. }
  308. }
  309. }
  310. }
  311. // Returns "/bucketName/objectName" for path-style or virtual-host-style requests.
  312. func getResource(path string, host string, domains []string) (string, error) {
  313. if len(domains) == 0 {
  314. return path, nil
  315. }
  316. // If virtual-host-style is enabled construct the "resource" properly.
  317. xhost, err := xnet.ParseHost(host)
  318. if err != nil {
  319. return "", err
  320. }
  321. for _, domain := range domains {
  322. if xhost.Name == minioReservedBucket+"."+domain {
  323. continue
  324. }
  325. if !strings.HasSuffix(xhost.Name, "."+domain) {
  326. continue
  327. }
  328. bucket := strings.TrimSuffix(xhost.Name, "."+domain)
  329. return SlashSeparator + pathJoin(bucket, path), nil
  330. }
  331. return path, nil
  332. }
  333. var regexVersion = regexp.MustCompile(`^/minio.*/(v\d+)/.*`)
  334. func extractAPIVersion(r *http.Request) string {
  335. if matches := regexVersion.FindStringSubmatch(r.URL.Path); len(matches) > 1 {
  336. return matches[1]
  337. }
  338. return "unknown"
  339. }
  340. func methodNotAllowedHandler(api string) func(w http.ResponseWriter, r *http.Request) {
  341. return errorResponseHandler
  342. }
  343. // If none of the http routes match respond with appropriate errors
  344. func errorResponseHandler(w http.ResponseWriter, r *http.Request) {
  345. if r.Method == http.MethodOptions {
  346. return
  347. }
  348. desc := "Do not upgrade one server at a time - please follow the recommended guidelines mentioned here https://github.com/minio/minio#upgrading-minio for your environment"
  349. switch {
  350. case strings.HasPrefix(r.URL.Path, peerRESTPrefix):
  351. writeErrorResponseString(r.Context(), w, APIError{
  352. Code: "XMinioPeerVersionMismatch",
  353. Description: desc,
  354. HTTPStatusCode: http.StatusUpgradeRequired,
  355. }, r.URL)
  356. case strings.HasPrefix(r.URL.Path, storageRESTPrefix):
  357. writeErrorResponseString(r.Context(), w, APIError{
  358. Code: "XMinioStorageVersionMismatch",
  359. Description: desc,
  360. HTTPStatusCode: http.StatusUpgradeRequired,
  361. }, r.URL)
  362. case strings.HasPrefix(r.URL.Path, adminPathPrefix):
  363. var desc string
  364. version := extractAPIVersion(r)
  365. switch version {
  366. case "v1", madmin.AdminAPIVersionV2:
  367. desc = fmt.Sprintf("Server expects client requests with 'admin' API version '%s', found '%s', please upgrade the client to latest releases", madmin.AdminAPIVersion, version)
  368. case madmin.AdminAPIVersion:
  369. desc = fmt.Sprintf("This 'admin' API is not supported by server in '%s'", getMinioMode())
  370. default:
  371. desc = fmt.Sprintf("Unexpected client 'admin' API version found '%s', expected '%s', please downgrade the client to older releases", version, madmin.AdminAPIVersion)
  372. }
  373. writeErrorResponseJSON(r.Context(), w, APIError{
  374. Code: "XMinioAdminVersionMismatch",
  375. Description: desc,
  376. HTTPStatusCode: http.StatusUpgradeRequired,
  377. }, r.URL)
  378. default:
  379. defer logger.AuditLog(r.Context(), w, r, mustGetClaimsFromToken(r))
  380. defer atomic.AddUint64(&globalHTTPStats.rejectedRequestsInvalid, 1)
  381. // When we are not running in S3 Express mode, generate appropriate error
  382. // for x-amz-write-offset HEADER specified.
  383. if _, ok := r.Header[xhttp.AmzWriteOffsetBytes]; ok {
  384. tc, ok := r.Context().Value(mcontext.ContextTraceKey).(*mcontext.TraceCtxt)
  385. if ok {
  386. tc.FuncName = "s3.AppendObject"
  387. tc.ResponseRecorder.LogErrBody = true
  388. }
  389. writeErrorResponse(r.Context(), w, getAPIError(ErrNotImplemented), r.URL)
  390. return
  391. }
  392. tc, ok := r.Context().Value(mcontext.ContextTraceKey).(*mcontext.TraceCtxt)
  393. if ok {
  394. tc.FuncName = "s3.ValidRequest"
  395. tc.ResponseRecorder.LogErrBody = true
  396. }
  397. writeErrorResponse(r.Context(), w, APIError{
  398. Code: "BadRequest",
  399. Description: fmt.Sprintf("An unsupported API call for method: %s at '%s'",
  400. r.Method, r.URL.Path),
  401. HTTPStatusCode: http.StatusBadRequest,
  402. }, r.URL)
  403. }
  404. }
  405. // gets host name for current node
  406. func getHostName(r *http.Request) (hostName string) {
  407. if globalIsDistErasure {
  408. hostName = globalLocalNodeName
  409. } else {
  410. hostName = r.Host
  411. }
  412. return
  413. }
  414. // Proxy any request to an endpoint.
  415. func proxyRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, ep ProxyEndpoint, returnErr bool) (success bool) {
  416. success = true
  417. // Make sure we remove any existing headers before
  418. // proxying the request to another node.
  419. for k := range w.Header() {
  420. w.Header().Del(k)
  421. }
  422. f := handlers.NewForwarder(&handlers.Forwarder{
  423. PassHost: true,
  424. RoundTripper: ep.Transport,
  425. ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
  426. success = false
  427. if err != nil && !errors.Is(err, context.Canceled) {
  428. proxyLogIf(GlobalContext, err)
  429. }
  430. if returnErr {
  431. writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
  432. }
  433. },
  434. })
  435. r.URL.Scheme = "http"
  436. if globalIsTLS {
  437. r.URL.Scheme = "https"
  438. }
  439. r.URL.Host = ep.Host
  440. f.ServeHTTP(w, r)
  441. return
  442. }