Repository: fsouza/fake-gcs-server
Pull request #498 (2021-05-18 16:56:27)

added POST endpoint for acls
Besides the `PATCH` for object-level ACLs, there is also a `POST`: https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/insert

It is called for example by the nodeJS lib when calling `file.makePublic()`.

I added the endpoint and reused the `PATCH` code. I suspect the code is actually correct for `POST` but might be incomplete for `PATCH`. Anyhow, with this PR `file.makePublic()` works like a charm.



fsouza: @dpoetzsch thanks for contributing. fake-gcs-server doesn't support patch right now, only update: https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/update. It looks like the payload for update and insert are the same, so this should be compatible.

Could you write a test to confirm? If you're not familiar with the Go SDK, I can give it a try later.
dpoetzsch: I'll give it a shot
dpoetzsch: tl;dr: I think the Go Storage SDK does not use the POST endpoint which makes it difficult to confirm with a Go test I think.

If you search for `ObjectAccessControls.` in https://github.com/googleapis/google-cloud-go/blob/master/storage/acl.go you only find calls to `List`, `Update`, `Delete`.

I went on and also checked the request lib that is used underneath and actually found a definition for the POST endpoint: `DefaultObjectAccessControlsInsertCall` in https://github.com/googleapis/google-api-go-client/blob/master/storage/v1/storage-gen.go#L6051 However, this endpoint does not seem to be used at all.

The only option I see to write a test would be to call a nodeJS app from Go, because we know that `file.makePublic()` calls this endpoint. But this feels a bit over-complicated. What do you think?
dpoetzsch: Also, I haven't checked, but this PR might also fix https://github.com/fsouza/fake-gcs-server/issues/392

Patch:
diff --git a/fakestorage/server.go b/fakestorage/server.go
index 1823125..852ee52 100644
--- a/fakestorage/server.go
+++ b/fakestorage/server.go
@@ -192,6 +192,7 @@ func (s *Server) buildMuxer() {
 		r.Path("/b/{bucketName}/o").Methods("POST").HandlerFunc(jsonToHTTPHandler(s.insertObject))
 		r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("PATCH").HandlerFunc(jsonToHTTPHandler(s.patchObject))
 		r.Path("/b/{bucketName}/o/{objectName:.+}/acl").Methods("GET").HandlerFunc(jsonToHTTPHandler(s.listObjectACL))
+		r.Path("/b/{bucketName}/o/{objectName:.+}/acl").Methods("POST").HandlerFunc(jsonToHTTPHandler(s.setObjectACL))
 		r.Path("/b/{bucketName}/o/{objectName:.+}/acl/{entity}").Methods("PUT").HandlerFunc(jsonToHTTPHandler(s.setObjectACL))
 		r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("GET").HandlerFunc(s.getObject)
 		r.Path("/b/{bucketName}/o/{objectName:.+}").Methods("DELETE").HandlerFunc(jsonToHTTPHandler(s.deleteObject))
diff --git a/fakestorage/upload.go b/fakestorage/upload.go
index 5416a34..223733e 100644
--- a/fakestorage/upload.go
+++ b/fakestorage/upload.go
@@ -414,6 +414,7 @@ func (s *Server) uploadFileContent(r *http.Request) jsonResponse {
 //   bytes 0-1023/4096 (first 1024 bytes of a 4096-byte document)
 //   bytes 1024-2047/* (second 1024 bytes of a streaming document)
 //   bytes */4096      (The end of 4096 byte streaming document)
+//   bytes 0-*/*       (start and end of a streaming document as sent by nodeJS client lib)
 func parseContentRange(r string) (parsed contentRange, err error) {
 	invalidErr := fmt.Errorf("invalid Content-Range: %v", r)
 
@@ -438,22 +439,28 @@ func parseContentRange(r string) (parsed contentRange, err error) {
 		if len(rangeParts) != 2 {
 			return parsed, invalidErr
 		}
-		parsed.KnownRange = true
+
 		parsed.Start, err = strconv.Atoi(rangeParts[0])
 		if err != nil {
 			return parsed, invalidErr
 		}
-		parsed.End, err = strconv.Atoi(rangeParts[1])
-		if err != nil {
-			return parsed, invalidErr
+
+		if rangeParts[1] == "*" {
+			parsed.End = -1
+		} else {
+			parsed.KnownRange = true
+			parsed.End, err = strconv.Atoi(rangeParts[1])
+			if err != nil {
+				return parsed, invalidErr
+			}
 		}
 	}
 
 	// Process total length
 	if parts[1] == "*" {
 		parsed.Total = -1
-		if !parsed.KnownRange {
-			// Must know either range or total
+
+		if parsed.Start < 0 {
 			return parsed, invalidErr
 		}
 	} else {


Test patch:
diff --git a/fakestorage/upload_test.go b/fakestorage/upload_test.go
index 6970b71..94a0cb0 100644
--- a/fakestorage/upload_test.go
+++ b/fakestorage/upload_test.go
@@ -487,6 +487,10 @@ func TestParseContentRange(t *testing.T) {
 			"bytes */1024", // End of a streaming request, total is now known
 			contentRange{KnownTotal: true, Start: -1, End: -1, Total: 1024},
 		},
+		{
+			"bytes 0-*/*", // Start and end of a streaming request as done by nodeJS client lib
+			contentRange{KnownTotal: false, Start: 0, End: -1, Total: -1},
+		},
 		{
 			"bytes 1024-2047/4096", // Range with a known total
 			contentRange{KnownRange: true, KnownTotal: true, Start: 1024, End: 2047, Total: 4096},