Repository: fsouza/fake-gcs-server (go)

Issue:
Custom metadata missing in Public and Signed URLs
I noticed that the existing implementation does not provide the custom metadata with the `x-goog-meta-` prefix as indicated [here](https://cloud.google.com/storage/docs/xml-api/reference-headers#xgoogmeta). 

I am creating this issue with the intention of submitting a PR. However, I am not a golang dev so feel free to turn it down.

Pull request description:
Custom metadata missing in Public and Signed URLs #1019
Fixes #1019 

NB: I am not a golang dev - feel free to suggest a proper alternative to resolve #1019.

Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index de11d4e..e421cf4 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -75,7 +75,7 @@ jobs:
 
       - name: staticcheck cache
         id: staticcheck-cache
-        uses: actions/cache@v3.2.0
+        uses: actions/cache@v3.2.2
         with:
           path: ~/.cache/staticcheck
           key: "${{ steps.get-staticcheck-version.outputs.version }}"
diff --git a/fakestorage/object.go b/fakestorage/object.go
index e413f4c..6cf298f 100644
--- a/fakestorage/object.go
+++ b/fakestorage/object.go
@@ -810,6 +810,9 @@ func (s *Server) downloadObject(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("X-Goog-Generation", strconv.FormatInt(obj.Generation, 10))
 	w.Header().Set("X-Goog-Hash", fmt.Sprintf("crc32c=%s,md5=%s", obj.Crc32c, obj.Md5Hash))
 	w.Header().Set("Last-Modified", obj.Updated.Format(http.TimeFormat))
+	for name, value := range obj.Metadata {
+		w.Header().Set("X-Goog-Meta-"+name, value)
+	}
 
 	if ranged && !satisfiable {
 		status = http.StatusRequestedRangeNotSatisfiable


Test patch:
diff --git a/fakestorage/object_test.go b/fakestorage/object_test.go
index 4d3f3b1..19f270d 100644
--- a/fakestorage/object_test.go
+++ b/fakestorage/object_test.go
@@ -721,11 +721,18 @@ func TestServerClientObjectReaderError(t *testing.T) {
 
 func TestServerClientObjectReadBucketCNAME(t *testing.T) {
 	url := "https://mybucket.mydomain.com:4443/files/txt/text-01.txt"
-	expectedHeaders := map[string]string{"accept-ranges": "bytes", "content-length": "9"}
+	expectedHeaders := map[string]string{"accept-ranges": "bytes", "content-length": "9", "x-goog-meta-marco": "Polo"}
 	expectedBody := "something"
 	opts := Options{
 		InitialObjects: []Object{
-			{ObjectAttrs: ObjectAttrs{BucketName: "mybucket.mydomain.com", Name: "files/txt/text-01.txt"}, Content: []byte("something")},
+			{
+				ObjectAttrs: ObjectAttrs{
+					BucketName: "mybucket.mydomain.com",
+					Name:       "files/txt/text-01.txt",
+					Metadata:   map[string]string{"Marco": "Polo"},
+				},
+				Content: []byte("something"),
+			},
 		},
 	}
 	server, err := NewServerWithOptions(opts)