func (c *Client) PutObject(name, bucket string, md5 hash.Hash, size int64, body io.Reader) error { req := newReq("http://" + bucket + "." + c.hostname() + "/" + name) req.Method = "PUT" req.ContentLength = size if md5 != nil { b64 := new(bytes.Buffer) encoder := base64.NewEncoder(base64.StdEncoding, b64) encoder.Write(md5.Sum(nil)) encoder.Close() req.Header.Set("Content-MD5", b64.String()) } if c.DefaultACL != "" { req.Header.Set("x-amz-acl", c.DefaultACL) } contentType := mime.TypeByExtension(path.Ext(name)) if contentType == "" { contentType = "application/octet-stream" } req.Header.Set("Content-Type", contentType) c.Auth.SignRequest(req) req.Body = ioutil.NopCloser(body) res, err := c.httpClient().Do(req) if res != nil && res.Body != nil { defer httputil.CloseBody(res.Body) } if err != nil { return err } if res.StatusCode != http.StatusOK { res.Write(os.Stderr) return fmt.Errorf("Got response code %d from s3", res.StatusCode) } return nil }
func (c *Client) Buckets() ([]*Bucket, error) { req := newReq("https://" + c.hostname() + "/") c.Auth.SignRequest(req) res, err := c.httpClient().Do(req) if err != nil { return nil, err } defer httputil.CloseBody(res.Body) if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("s3: Unexpected status code %d fetching bucket list", res.StatusCode) } return parseListAllMyBuckets(res.Body) }
// ListBucket returns 0 to maxKeys (inclusive) items from the provided // bucket. Keys before startAt will be skipped. (This is the S3 // 'marker' value). If the length of the returned items is equal to // maxKeys, there is no indication whether or not the returned list is // truncated. func (c *Client) ListBucket(bucket string, startAt string, maxKeys int) (items []*Item, err error) { if maxKeys < 0 { return nil, errors.New("invalid negative maxKeys") } marker := startAt for len(items) < maxKeys { fetchN := maxKeys - len(items) if fetchN > maxList { fetchN = maxList } var bres listBucketResults url_ := fmt.Sprintf("http://%s.%s/?marker=%s&max-keys=%d", bucket, c.hostname(), url.QueryEscape(marker), fetchN) // Try the enumerate three times, since Amazon likes to close // https connections a lot, and Go sucks at dealing with it: // https://code.google.com/p/go/issues/detail?id=3514 const maxTries = 5 for try := 1; try <= maxTries; try++ { time.Sleep(time.Duration(try-1) * 100 * time.Millisecond) req := newReq(url_) c.Auth.SignRequest(req) res, err := c.httpClient().Do(req) if err != nil { if try < maxTries { continue } return nil, err } if res.StatusCode != 200 { err = fmt.Errorf("s3.enumerate: status code %v", res.StatusCode) } else { bres = listBucketResults{} var logbuf bytes.Buffer err = xml.NewDecoder(io.TeeReader(res.Body, &logbuf)).Decode(&bres) if err != nil { log.Printf("Error parsing s3 XML response: %v for %q", err, logbuf.Bytes()) } else if bres.MaxKeys != fetchN || bres.Name != bucket || bres.Marker != marker { err = fmt.Errorf("Unexpected parse from server: %#v from: %s", bres, logbuf.Bytes()) log.Print(err) } } httputil.CloseBody(res.Body) if err != nil { if try < maxTries-1 { continue } log.Print(err) return nil, err } break } for _, it := range bres.Contents { if it.Key == marker && it.Key != startAt { // Skip first dup on pages 2 and higher. continue } if it.Key < startAt { return nil, fmt.Errorf("Unexpected response from Amazon: item key %q but wanted greater than %q", it.Key, startAt) } items = append(items, it) marker = it.Key } if !bres.IsTruncated { break } } return items, nil }