func call(ctx context.Context, method string, req proto.Message, resp proto.Message) error { payload, err := proto.Marshal(req) if err != nil { return err } url := baseUrl(ctx) + internal.ProjID(ctx) + "/" + method r, err := internal.HTTPClient(ctx).Post(url, "application/x-protobuf", bytes.NewReader(payload)) if err != nil { return err } defer r.Body.Close() all, err := ioutil.ReadAll(r.Body) if r.StatusCode != http.StatusOK { e := &errHTTP{ StatusCode: r.StatusCode, err: err, } if err == nil { e.Body = string(all) } return e } if err != nil { return err } if err = proto.Unmarshal(all, resp); err != nil { return err } return nil }
// NewReader creates a new io.ReadCloser to read the contents // of the object. func NewReader(ctx context.Context, bucket, name string) (io.ReadCloser, error) { hc := internal.HTTPClient(ctx) res, err := hc.Get(fmt.Sprintf("https://storage.googleapis.com/%s/%s", bucket, name)) if err != nil { return nil, err } if res.StatusCode == http.StatusNotFound { res.Body.Close() return nil, ErrObjectNotExist } if res.StatusCode < 200 || res.StatusCode > 299 { res.Body.Close() return res.Body, fmt.Errorf("storage: can't read object %v/%v, status code: %v", bucket, name, res.Status) } return res.Body, nil }
// NewClient returns a new log client, logging to the named log. The // log must exist in the Google Cloud Platform project ID associated // with the provided context. Use the google.golang.org/cloud package // to create a context. // // The exported fields on the returned client may be modified before // the client is used for logging. Once log entries are in flight, // the fields must not be modified. func NewClient(ctx context.Context, logName string) (*Client, error) { projID := internal.ProjID(ctx) httpClient := internal.HTTPClient(ctx) if projID == "" || httpClient == nil { return nil, errors.New("logging: invalid or non-google.golang.org/cloud Context") } svc, err := api.New(httpClient) if err != nil { return nil, err } c := &Client{ svc: svc, logs: api.NewProjectsLogsEntriesService(svc), logName: logName, projID: projID, } for i := range c.writer { level := Level(i) c.writer[level] = levelWriter{level, c} c.logger[level] = log.New(c.writer[level], "", 0) } return c, nil }
func TestObjects(t *testing.T) { ctx := testutil.Context(ScopeFullControl) bucket = os.Getenv(envBucket) // Cleanup. cleanup(t, "obj") const defaultType = "text/plain" // Test Writer. for _, obj := range objects { t.Logf("Writing %v", obj) wc := NewWriter(ctx, bucket, obj) wc.ContentType = defaultType c := randomContents() if _, err := wc.Write(c); err != nil { t.Errorf("Write for %v failed with %v", obj, err) } if err := wc.Close(); err != nil { t.Errorf("Close for %v failed with %v", obj, err) } contents[obj] = c } // Test Reader. for _, obj := range objects { t.Logf("Creating a reader to read %v", obj) rc, err := NewReader(ctx, bucket, obj) if err != nil { t.Errorf("Can't create a reader for %v, errored with %v", obj, err) } slurp, err := ioutil.ReadAll(rc) if err != nil { t.Errorf("Can't ReadAll object %v, errored with %v", obj, err) } if got, want := slurp, contents[obj]; !bytes.Equal(got, want) { t.Errorf("Contents (%v) = %q; want %q", obj, got, want) } rc.Close() // Test SignedURL opts := &SignedURLOptions{ GoogleAccessID: "xxx@clientid", PrivateKey: dummyKey("rsa"), Method: "GET", MD5: []byte("202cb962ac59075b964b07152d234b70"), Expires: time.Date(2020, time.October, 2, 10, 0, 0, 0, time.UTC), ContentType: "application/json", Headers: []string{"x-header1", "x-header2"}, } u, err := SignedURL(bucket, obj, opts) if err != nil { t.Fatalf("SignedURL(%q, %q) errored with %v", bucket, obj, err) } hc := internal.HTTPClient(ctx) res, err := hc.Get(u) if err != nil { t.Fatalf("Can't get URL %q: %v", u, err) } slurp, err = ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("Can't ReadAll signed object %v, errored with %v", obj, err) } if got, want := slurp, contents[obj]; !bytes.Equal(got, want) { t.Errorf("Contents (%v) = %q; want %q", obj, got, want) } res.Body.Close() } // Test NotFound. _, err := NewReader(ctx, bucket, "obj-not-exists") if err != ErrObjectNotExist { t.Errorf("Object should not exist, err found to be %v", err) } name := objects[0] // Test StatObject. o, err := StatObject(ctx, bucket, name) if err != nil { t.Error(err) } if got, want := o.Name, name; got != want { t.Errorf("Name (%v) = %q; want %q", name, got, want) } if got, want := o.ContentType, defaultType; got != want { t.Errorf("ContentType (%v) = %q; want %q", name, got, want) } // Test object copy. copy, err := CopyObject(ctx, bucket, name, bucket, copyObj, nil) if err != nil { t.Errorf("CopyObject failed with %v", err) } if copy.Name != copyObj { t.Errorf("Copy object's name = %q; want %q", copy.Name, copyObj) } if copy.Bucket != bucket { t.Errorf("Copy object's bucket = %q; want %q", copy.Bucket, bucket) } // Test UpdateAttrs. updated, err := UpdateAttrs(ctx, bucket, name, ObjectAttrs{ ContentType: "text/html", ACL: []ACLRule{{Entity: "domain-google.com", Role: RoleReader}}, }) if err != nil { t.Errorf("UpdateAttrs failed with %v", err) } if want := "text/html"; updated.ContentType != want { t.Errorf("updated.ContentType == %q; want %q", updated.ContentType, want) } // Test checksums. checksumCases := []struct { name string contents [][]byte size int64 md5 string crc32c uint32 }{ { name: "checksum-object", contents: [][]byte{[]byte("hello"), []byte("world")}, size: 10, md5: "fc5e038d38a57032085441e7fe7010b0", crc32c: 1456190592, }, { name: "zero-object", contents: [][]byte{}, size: 0, md5: "d41d8cd98f00b204e9800998ecf8427e", crc32c: 0, }, } for _, c := range checksumCases { wc := NewWriter(ctx, bucket, c.name) for _, data := range c.contents { if _, err := wc.Write(data); err != nil { t.Errorf("Write(%q) failed with %q", data, err) } } if err = wc.Close(); err != nil { t.Errorf("%q: close failed with %q", c.name, err) } obj := wc.Object() if got, want := obj.Size, c.size; got != want { t.Errorf("Object (%q) Size = %v; want %v", c.name, got, want) } if got, want := fmt.Sprintf("%x", obj.MD5), c.md5; got != want { t.Errorf("Object (%q) MD5 = %q; want %q", c.name, got, want) } if got, want := obj.CRC32C, c.crc32c; got != want { t.Errorf("Object (%q) CRC32C = %v; want %v", c.name, got, want) } } // Test public ACL. publicObj := objects[0] if err = PutACLRule(ctx, bucket, publicObj, AllUsers, RoleReader); err != nil { t.Errorf("PutACLRule failed with %v", err) } publicCtx := testutil.NoAuthContext() rc, err := NewReader(publicCtx, bucket, publicObj) if err != nil { t.Error(err) } slurp, err := ioutil.ReadAll(rc) if err != nil { t.Errorf("ReadAll failed with %v", err) } if string(slurp) != string(contents[publicObj]) { t.Errorf("Public object's content is expected to be %s, found %s", contents[publicObj], slurp) } rc.Close() // Test writer error handling. wc := NewWriter(publicCtx, bucket, publicObj) if _, err := wc.Write([]byte("hello")); err != nil { t.Errorf("Write unexpectedly failed with %v", err) } if err = wc.Close(); err == nil { t.Error("Close expected an error, found none") } // DeleteObject object. // The rest of the other object will be deleted during // the initial cleanup. This tests exists, so we still can cover // deletion if there are no objects on the bucket to clean. if err := DeleteObject(ctx, bucket, copyObj); err != nil { t.Errorf("Deletion of %v failed with %v", copyObj, err) } _, err = StatObject(ctx, bucket, copyObj) if err != ErrObjectNotExist { t.Errorf("Copy is expected to be deleted, stat errored with %v", err) } }