"fmt"
"hash"
"io"
+ "mime"
"net/http"
"net/textproto"
"net/url"
if r.Method == "HEAD" && !objectNameGiven {
// HeadBucket
if err == nil && fi.IsDir() {
- setFileInfoHeaders(w.Header(), fs, fspath)
+ err = setFileInfoHeaders(w.Header(), fs, fspath)
+ if err != nil {
+ s3ErrorResponse(w, InternalError, err.Error(), r.URL.Path, http.StatusBadGateway)
+ return true
+ }
w.WriteHeader(http.StatusOK)
} else if os.IsNotExist(err) {
s3ErrorResponse(w, NoSuchBucket, "The specified bucket does not exist.", r.URL.Path, http.StatusNotFound)
return true
}
if err == nil && fi.IsDir() && objectNameGiven && strings.HasSuffix(fspath, "/") && h.Cluster.Collections.S3FolderObjects {
- setFileInfoHeaders(w.Header(), fs, fspath)
+ err = setFileInfoHeaders(w.Header(), fs, fspath)
+ if err != nil {
+ s3ErrorResponse(w, InternalError, err.Error(), r.URL.Path, http.StatusBadGateway)
+ return true
+ }
w.Header().Set("Content-Type", "application/x-directory")
w.WriteHeader(http.StatusOK)
return true
// shallow copy r, and change URL path
r := *r
r.URL.Path = fspath
- setFileInfoHeaders(w.Header(), fs, fspath)
+ err = setFileInfoHeaders(w.Header(), fs, fspath)
+ if err != nil {
+ s3ErrorResponse(w, InternalError, err.Error(), r.URL.Path, http.StatusBadGateway)
+ return true
+ }
http.FileServer(fs).ServeHTTP(w, &r)
return true
case r.Method == http.MethodPut:
}
}
-func setFileInfoHeaders(header http.Header, fs arvados.CustomFileSystem, path string) {
+func setFileInfoHeaders(header http.Header, fs arvados.CustomFileSystem, path string) error {
+ maybeEncode := func(s string) string {
+ for _, c := range s {
+ if c > '\u007f' {
+ return mime.BEncoding.Encode("UTF-8", s)
+ }
+ }
+ return s
+ }
path = strings.TrimSuffix(path, "/")
var props map[string]interface{}
for {
fi, err := fs.Stat(path)
if err != nil {
- return
+ return err
}
switch src := fi.Sys().(type) {
case *arvados.Collection:
case *arvados.Group:
props = src.Properties
default:
+ if err, ok := src.(error); ok {
+ return err
+ }
// Try parent
cut := strings.LastIndexByte(path, '/')
if cut < 0 {
- return
+ return nil
}
path = path[:cut]
continue
}
k = "x-amz-meta-" + k
if s, ok := v.(string); ok {
- header.Set(k, s)
+ header.Set(k, maybeEncode(s))
} else if j, err := json.Marshal(v); err == nil {
- header.Set(k, string(j))
+ header.Set(k, maybeEncode(string(j)))
}
}
+ return nil
}
func validMIMEHeaderKey(k string) bool {