PUT on an object creates the object.
(a *action)
| 630 | |
| 631 | // PUT on an object creates the object. |
| 632 | func (objr objectResource) put(a *action) interface{} { |
| 633 | // TODO Cache-Control header |
| 634 | // TODO Expires header |
| 635 | // TODO x-amz-server-side-encryption |
| 636 | // TODO x-amz-storage-class |
| 637 | |
| 638 | // TODO is this correct, or should we erase all previous metadata? |
| 639 | obj := objr.object |
| 640 | if obj == nil { |
| 641 | obj = &object{ |
| 642 | name: objr.name, |
| 643 | meta: make(http.Header), |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | var expectHash []byte |
| 648 | if c := a.req.Header.Get("Content-MD5"); c != "" { |
| 649 | var err error |
| 650 | expectHash, err = base64.StdEncoding.DecodeString(c) |
| 651 | if err != nil || len(expectHash) != md5.Size { |
| 652 | fatalError(400, "InvalidDigest", "The Content-MD5 you specified was invalid") |
| 653 | } |
| 654 | } |
| 655 | sum := md5.New() |
| 656 | // TODO avoid holding lock while reading data. |
| 657 | data, err := io.ReadAll(io.TeeReader(a.req.Body, sum)) |
| 658 | if err != nil { |
| 659 | fatalError(400, "TODO", "read error") |
| 660 | } |
| 661 | gotHash := sum.Sum(nil) |
| 662 | if expectHash != nil && !bytes.Equal(gotHash, expectHash) { |
| 663 | fatalError(400, "BadDigest", "The Content-MD5 you specified did not match what we received") |
| 664 | } |
| 665 | if a.req.ContentLength >= 0 && int64(len(data)) != a.req.ContentLength { |
| 666 | fatalError(400, "IncompleteBody", "You did not provide the number of bytes specified by the Content-Length HTTP header") |
| 667 | } |
| 668 | |
| 669 | // PUT request has been successful - save data and metadata |
| 670 | for key, values := range a.req.Header { |
| 671 | key = http.CanonicalHeaderKey(key) |
| 672 | if metaHeaders[key] || strings.HasPrefix(key, "X-Amz-Meta-") { |
| 673 | obj.meta[key] = values |
| 674 | } |
| 675 | } |
| 676 | obj.data = data |
| 677 | obj.checksum = gotHash |
| 678 | obj.mtime = time.Now() |
| 679 | objr.bucket.objects[objr.name] = obj |
| 680 | return nil |
| 681 | } |
| 682 | |
| 683 | func (objr objectResource) delete(a *action) interface{} { |
| 684 | delete(objr.bucket.objects, objr.name) |
nothing calls this directly
no test coverage detected