Merge branch '16774-keep-web-errors' refs #16774
authorPeter Amstutz <peter.amstutz@curii.com>
Mon, 30 Nov 2020 16:03:53 +0000 (11:03 -0500)
committerPeter Amstutz <peter.amstutz@curii.com>
Mon, 30 Nov 2020 16:03:53 +0000 (11:03 -0500)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

1  2 
services/keep-web/s3.go
services/keep-web/s3_test.go
services/keep-web/server_test.go

index 373fd9a25d56608d1c418da45221836b1f5cdb16,37fee37604ccd0280b93d142587852382d4e6fd1..7fb90789a55b164bd2465bf8d2454cf2d30e4f52
@@@ -186,9 -170,36 +186,36 @@@ func (h *handler) checks3signature(r *h
        } else if expect != signature {
                return "", fmt.Errorf("signature does not match (scope %q signedHeaders %q stringToSign %q)", scope, signedHeaders, stringToSign)
        }
 -      return secret, nil
 +      return aca.TokenV2(), nil
  }
  
+ func s3ErrorResponse(w http.ResponseWriter, s3code string, message string, resource string, code int) {
+       w.Header().Set("Content-Type", "application/xml")
+       w.Header().Set("X-Content-Type-Options", "nosniff")
+       w.WriteHeader(code)
+       var errstruct struct {
+               Code      string
+               Message   string
+               Resource  string
+               RequestId string
+       }
+       errstruct.Code = s3code
+       errstruct.Message = message
+       errstruct.Resource = resource
+       errstruct.RequestId = ""
+       enc := xml.NewEncoder(w)
+       fmt.Fprint(w, xml.Header)
+       enc.EncodeElement(errstruct, xml.StartElement{Name: xml.Name{Local: "Error"}})
+ }
+ var NoSuchKey = "NoSuchKey"
+ var NoSuchBucket = "NoSuchBucket"
+ var InvalidArgument = "InvalidArgument"
+ var InternalError = "InternalError"
+ var UnauthorizedAccess = "UnauthorizedAccess"
+ var InvalidRequest = "InvalidRequest"
+ var SignatureDoesNotMatch = "SignatureDoesNotMatch"
  // serveS3 handles r and returns true if r is a request from an S3
  // client, otherwise it returns false.
  func (h *handler) serveS3(w http.ResponseWriter, r *http.Request) bool {
        if auth := r.Header.Get("Authorization"); strings.HasPrefix(auth, "AWS ") {
                split := strings.SplitN(auth[4:], ":", 2)
                if len(split) < 2 {
-                       http.Error(w, "malformed Authorization header", http.StatusUnauthorized)
+                       s3ErrorResponse(w, InvalidRequest, "malformed Authorization header", r.URL.Path, http.StatusUnauthorized)
                        return true
                }
 -              token = split[0]
 +              token = unescapeKey(split[0])
        } else if strings.HasPrefix(auth, s3SignAlgorithm+" ") {
                t, err := h.checks3signature(r)
                if err != nil {
                return true
        case r.Method == http.MethodPut:
                if !objectNameGiven {
-                       http.Error(w, "missing object name in PUT request", http.StatusBadRequest)
+                       s3ErrorResponse(w, InvalidArgument, "Missing object name in PUT request.", r.URL.Path, http.StatusBadRequest)
                        return true
                }
 -              fspath := "by_id" + r.URL.Path
                var objectIsDir bool
                if strings.HasSuffix(fspath, "/") {
                        if !h.Config.cluster.Collections.S3FolderObjects {
                return true
        case r.Method == http.MethodDelete:
                if !objectNameGiven || r.URL.Path == "/" {
-                       http.Error(w, "missing object name in DELETE request", http.StatusBadRequest)
+                       s3ErrorResponse(w, InvalidArgument, "missing object name in DELETE request", r.URL.Path, http.StatusBadRequest)
                        return true
                }
 -              fspath := "by_id" + r.URL.Path
                if strings.HasSuffix(fspath, "/") {
                        fspath = strings.TrimSuffix(fspath, "/")
                        fi, err := fs.Stat(fspath)
Simple merge
Simple merge