api/PostPolicy: Allow location header fully qualified URL (#4926)

req.Host is used to construct the final object location.

Fixes #4910
master
Harshavardhana 7 years ago committed by Dee Koder
parent c3ff402fcb
commit 4cadb33da2
  1. 22
      cmd/api-response.go
  2. 74
      cmd/api-response_test.go
  3. 6
      cmd/bucket-handlers.go
  4. 7
      cmd/event-notifier.go
  5. 7
      cmd/net.go

@ -275,9 +275,25 @@ func getLocation(r *http.Request) string {
return path.Clean(r.URL.Path) // Clean any trailing slashes. return path.Clean(r.URL.Path) // Clean any trailing slashes.
} }
// getObjectLocation gets the relative URL for an object // returns "https" if the tls boolean is true, "http" otherwise.
func getObjectLocation(bucketName string, key string) string { func getURLScheme(tls bool) string {
return "/" + bucketName + "/" + key if tls {
return httpsScheme
}
return httpScheme
}
// getObjectLocation gets the fully qualified URL of an object.
func getObjectLocation(host, proto, bucket, object string) string {
if proto == "" {
proto = getURLScheme(globalIsSSL)
}
u := url.URL{
Host: host,
Path: path.Join(slashSeparator, bucket, object),
Scheme: proto,
}
return u.String()
} }
// generates ListBucketsResponse from array of BucketInfo which can be // generates ListBucketsResponse from array of BucketInfo which can be

@ -0,0 +1,74 @@
/*
* Minio Cloud Storage, (C) 2017 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cmd
import (
"testing"
)
// Tests object location.
func TestObjectLocation(t *testing.T) {
testCases := []struct {
host, proto, bucket, object string
expectedLocation string
}{
// Server binding to localhost IP with https.
{
host: "127.0.0.1:9000",
proto: httpsScheme,
bucket: "testbucket1",
object: "test/1.txt",
expectedLocation: "https://127.0.0.1:9000/testbucket1/test/1.txt",
},
// Server binding to fqdn.
{
host: "s3.mybucket.org",
proto: httpScheme,
bucket: "mybucket",
object: "test/1.txt",
expectedLocation: "http://s3.mybucket.org/mybucket/test/1.txt",
},
// Server binding to fqdn.
{
host: "mys3.mybucket.org",
proto: "",
bucket: "mybucket",
object: "test/1.txt",
expectedLocation: "http://mys3.mybucket.org/mybucket/test/1.txt",
},
}
for i, testCase := range testCases {
gotLocation := getObjectLocation(testCase.host, testCase.proto, testCase.bucket, testCase.object)
if testCase.expectedLocation != gotLocation {
t.Errorf("Test %d: expected %s, got %s", i+1, testCase.expectedLocation, gotLocation)
}
}
}
// Tests getURLScheme function behavior.
func TestGetURLScheme(t *testing.T) {
tls := false
gotScheme := getURLScheme(tls)
if gotScheme != httpScheme {
t.Errorf("Expected %s, got %s", httpScheme, gotScheme)
}
tls = true
gotScheme = getURLScheme(tls)
if gotScheme != httpsScheme {
t.Errorf("Expected %s, got %s", httpsScheme, gotScheme)
}
}

@ -569,8 +569,10 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
return return
} }
port := r.Header.Get("X-Forward-Proto")
location := getObjectLocation(r.Host, port, bucket, object)
w.Header().Set("ETag", `"`+objInfo.ETag+`"`) w.Header().Set("ETag", `"`+objInfo.ETag+`"`)
w.Header().Set("Location", getObjectLocation(bucket, object)) w.Header().Set("Location", location)
// Get host and port from Request.RemoteAddr. // Get host and port from Request.RemoteAddr.
host, port, err := net.SplitHostPort(r.RemoteAddr) host, port, err := net.SplitHostPort(r.RemoteAddr)
@ -603,7 +605,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
Bucket: objInfo.Bucket, Bucket: objInfo.Bucket,
Key: objInfo.Name, Key: objInfo.Name,
ETag: `"` + objInfo.ETag + `"`, ETag: `"` + objInfo.ETag + `"`,
Location: getObjectLocation(objInfo.Bucket, objInfo.Name), Location: location,
}) })
writeResponse(w, http.StatusCreated, resp, "application/xml") writeResponse(w, http.StatusCreated, resp, "application/xml")
case "200": case "200":

@ -101,12 +101,7 @@ func newNotificationEvent(event eventData) NotificationEvent {
host = localIP4.ToSlice()[0] host = localIP4.ToSlice()[0]
} }
scheme := httpScheme return fmt.Sprintf("%s://%s:%s", getURLScheme(globalIsSSL), host, globalMinioPort)
if globalIsSSL {
scheme = httpsScheme
}
return fmt.Sprintf("%s://%s:%s", scheme, host, globalMinioPort)
} }
// Fetch the region. // Fetch the region.

@ -175,13 +175,8 @@ func getAPIEndpoints(serverAddr string) (apiEndpoints []string) {
ipList = []string{host} ipList = []string{host}
} }
scheme := httpScheme
if globalIsSSL {
scheme = httpsScheme
}
for _, ip := range ipList { for _, ip := range ipList {
apiEndpoints = append(apiEndpoints, fmt.Sprintf("%s://%s:%s", scheme, ip, port)) apiEndpoints = append(apiEndpoints, fmt.Sprintf("%s://%s:%s", getURLScheme(globalIsSSL), ip, port))
} }
return apiEndpoints return apiEndpoints

Loading…
Cancel
Save