GET on an object gets the contents of the object. http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html
(a *action)
| 576 | // GET on an object gets the contents of the object. |
| 577 | // http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html |
| 578 | func (objr objectResource) get(a *action) interface{} { |
| 579 | obj := objr.object |
| 580 | if obj == nil { |
| 581 | fatalError(404, "NoSuchKey", "The specified key does not exist.") |
| 582 | } |
| 583 | h := a.w.Header() |
| 584 | // add metadata |
| 585 | for name, d := range obj.meta { |
| 586 | h[name] = d |
| 587 | } |
| 588 | // override header values in response to request parameters. |
| 589 | for name, vals := range a.req.Form { |
| 590 | if strings.HasPrefix(name, "response-") { |
| 591 | name = name[len("response-"):] |
| 592 | if !responseParams[name] { |
| 593 | continue |
| 594 | } |
| 595 | h.Set(name, vals[0]) |
| 596 | } |
| 597 | } |
| 598 | if r := a.req.Header.Get("Range"); r != "" { |
| 599 | fatalError(400, "NotImplemented", "range unimplemented") |
| 600 | } |
| 601 | // TODO Last-Modified-Since |
| 602 | // TODO If-Modified-Since |
| 603 | // TODO If-Unmodified-Since |
| 604 | // TODO If-Match |
| 605 | // TODO If-None-Match |
| 606 | // TODO Connection: close ?? |
| 607 | // TODO x-amz-request-id |
| 608 | h.Set("Content-Length", fmt.Sprint(len(obj.data))) |
| 609 | h.Set("ETag", hex.EncodeToString(obj.checksum)) |
| 610 | h.Set("Last-Modified", obj.mtime.UTC().Format(http.TimeFormat)) |
| 611 | if a.req.Method == "HEAD" { |
| 612 | return nil |
| 613 | } |
| 614 | // TODO avoid holding the lock when writing data. |
| 615 | _, err := a.w.Write(obj.data) |
| 616 | if err != nil { |
| 617 | // we can't do much except just log the fact. |
| 618 | log.Printf("error writing data: %v", err) |
| 619 | } |
| 620 | return nil |
| 621 | } |
| 622 | |
| 623 | var metaHeaders = map[string]bool{ |
| 624 | "Content-MD5": true, |