mirror of
https://github.com/minio/minio.git
synced 2025-01-27 06:33:18 -05:00
handler: simplify parsing valid location constraint. (#4040)
Separate out validating v/s parsing logic in isValidLocationConstraint() into parseLocationConstraint() and isValidLocation() Additionally also set `X-Amz-Bucket-Region` as part of the common headers for the clients to fallback on in-case of any region related errors.
This commit is contained in:
parent
4041e5f20d
commit
3fe33e7b15
@ -1346,6 +1346,11 @@ func TestToAdminAPIErr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteSetConfigResponse(t *testing.T) {
|
func TestWriteSetConfigResponse(t *testing.T) {
|
||||||
|
rootPath, err := newTestConfig(globalMinioDefaultRegion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeAll(rootPath)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
status bool
|
status bool
|
||||||
errs []error
|
errs []error
|
||||||
|
@ -36,6 +36,7 @@ func setCommonHeaders(w http.ResponseWriter) {
|
|||||||
// Set unique request ID for each reply.
|
// Set unique request ID for each reply.
|
||||||
w.Header().Set(responseRequestIDKey, mustGetRequestID(UTCNow()))
|
w.Header().Set(responseRequestIDKey, mustGetRequestID(UTCNow()))
|
||||||
w.Header().Set("Server", globalServerUserAgent)
|
w.Header().Set("Server", globalServerUserAgent)
|
||||||
|
w.Header().Set("X-Amz-Bucket-Region", serverConfig.GetRegion())
|
||||||
w.Header().Set("Accept-Ranges", "bytes")
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,13 +370,20 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req
|
|||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
bucket := vars["bucket"]
|
bucket := vars["bucket"]
|
||||||
|
|
||||||
// Validate if incoming location constraint is valid, reject
|
// Parse incoming location constraint.
|
||||||
// requests which do not follow valid region requirements.
|
location, s3Error := parseLocationConstraint(r)
|
||||||
if s3Error := isValidLocationConstraint(r); s3Error != ErrNone {
|
if s3Error != ErrNone {
|
||||||
writeErrorResponse(w, s3Error, r.URL)
|
writeErrorResponse(w, s3Error, r.URL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate if location sent by the client is valid, reject
|
||||||
|
// requests which do not follow valid region requirements.
|
||||||
|
if !isValidLocation(location) {
|
||||||
|
writeErrorResponse(w, ErrInvalidRegion, r.URL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bucketLock := globalNSMutex.NewNSLock(bucket, "")
|
bucketLock := globalNSMutex.NewNSLock(bucket, "")
|
||||||
bucketLock.Lock()
|
bucketLock.Lock()
|
||||||
defer bucketLock.Unlock()
|
defer bucketLock.Unlock()
|
||||||
|
@ -24,36 +24,29 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Validates location constraint in PutBucket request body.
|
// Parses location constraint from the incoming reader.
|
||||||
// The location value in the request body should match the
|
func parseLocationConstraint(r *http.Request) (location string, s3Error APIErrorCode) {
|
||||||
// region configured at serverConfig, otherwise error is returned.
|
|
||||||
func isValidLocationConstraint(r *http.Request) (s3Error APIErrorCode) {
|
|
||||||
serverRegion := serverConfig.GetRegion()
|
|
||||||
// If the request has no body with content-length set to 0,
|
// If the request has no body with content-length set to 0,
|
||||||
// we do not have to validate location constraint. Bucket will
|
// we do not have to validate location constraint. Bucket will
|
||||||
// be created at default region.
|
// be created at default region.
|
||||||
locationConstraint := createBucketLocationConfiguration{}
|
locationConstraint := createBucketLocationConfiguration{}
|
||||||
err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
|
err := xmlDecoder(r.Body, &locationConstraint, r.ContentLength)
|
||||||
if err == nil || err == io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
// Successfully decoded, proceed to verify the region.
|
errorIf(err, "Unable to xml decode location constraint")
|
||||||
// Once region has been obtained we proceed to verify it.
|
// Treat all other failures as XML parsing errors.
|
||||||
incomingRegion := locationConstraint.Location
|
return "", ErrMalformedXML
|
||||||
if incomingRegion == "" {
|
} // else for both err as nil or io.EOF
|
||||||
// Location constraint is empty for region globalMinioDefaultRegion,
|
location = locationConstraint.Location
|
||||||
// in accordance with protocol.
|
if location == "" {
|
||||||
incomingRegion = globalMinioDefaultRegion
|
location = globalMinioDefaultRegion
|
||||||
}
|
|
||||||
// Return errInvalidRegion if location constraint does not match
|
|
||||||
// with configured region.
|
|
||||||
s3Error = ErrNone
|
|
||||||
if serverRegion != incomingRegion {
|
|
||||||
s3Error = ErrInvalidRegion
|
|
||||||
}
|
|
||||||
return s3Error
|
|
||||||
}
|
}
|
||||||
errorIf(err, "Unable to xml decode location constraint")
|
return location, ErrNone
|
||||||
// Treat all other failures as XML parsing errors.
|
}
|
||||||
return ErrMalformedXML
|
|
||||||
|
// Validates input location is same as configured region
|
||||||
|
// of Minio server.
|
||||||
|
func isValidLocation(location string) bool {
|
||||||
|
return serverConfig.GetRegion() == location
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supported headers that needs to be extracted.
|
// Supported headers that needs to be extracted.
|
||||||
|
@ -39,7 +39,7 @@ func TestIsValidLocationContraint(t *testing.T) {
|
|||||||
Body: ioutil.NopCloser(bytes.NewBuffer([]byte("<>"))),
|
Body: ioutil.NopCloser(bytes.NewBuffer([]byte("<>"))),
|
||||||
ContentLength: int64(len("<>")),
|
ContentLength: int64(len("<>")),
|
||||||
}
|
}
|
||||||
if err := isValidLocationConstraint(malformedReq); err != ErrMalformedXML {
|
if _, err := parseLocationConstraint(malformedReq); err != ErrMalformedXML {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +68,6 @@ func TestIsValidLocationContraint(t *testing.T) {
|
|||||||
// Test case - 2.
|
// Test case - 2.
|
||||||
// In case of empty request body ErrNone is returned.
|
// In case of empty request body ErrNone is returned.
|
||||||
{"", globalMinioDefaultRegion, ErrNone},
|
{"", globalMinioDefaultRegion, ErrNone},
|
||||||
// Test case - 3.
|
|
||||||
{"eu-central-1", globalMinioDefaultRegion, ErrInvalidRegion},
|
|
||||||
}
|
}
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
inputRequest, e := createExpectedRequest(&http.Request{}, testCase.locationForInputRequest)
|
inputRequest, e := createExpectedRequest(&http.Request{}, testCase.locationForInputRequest)
|
||||||
@ -77,7 +75,7 @@ func TestIsValidLocationContraint(t *testing.T) {
|
|||||||
t.Fatalf("Test %d: Failed to Marshal bucket configuration", i+1)
|
t.Fatalf("Test %d: Failed to Marshal bucket configuration", i+1)
|
||||||
}
|
}
|
||||||
serverConfig.SetRegion(testCase.serverConfigRegion)
|
serverConfig.SetRegion(testCase.serverConfigRegion)
|
||||||
actualCode := isValidLocationConstraint(inputRequest)
|
_, actualCode := parseLocationConstraint(inputRequest)
|
||||||
if testCase.expectedCode != actualCode {
|
if testCase.expectedCode != actualCode {
|
||||||
t.Errorf("Test %d: Expected the APIErrCode to be %d, but instead found %d", i+1, testCase.expectedCode, actualCode)
|
t.Errorf("Test %d: Expected the APIErrCode to be %d, but instead found %d", i+1, testCase.expectedCode, actualCode)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user