Last active
March 18, 2022 12:55
-
-
Save salrashid123/7069399ee128416cf3b8ff162696ea86 to your computer and use it in GitHub Desktop.
GCS SignedURL which restricts the maximum limit size and content (https://blog.salrashid.dev/articles/2022/limit_gcs_signedurl/)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"context" | |
"crypto/md5" | |
"encoding/base64" | |
"flag" | |
"fmt" | |
"net/http" | |
"time" | |
"cloud.google.com/go/storage" | |
) | |
const ( | |
fileName = "file.txt" | |
fiveBytes = "01234" | |
tenBytes = "0123456789" | |
tenBytesReversed = "9876543210" | |
twentyBytes = "01234567890123456789" | |
) | |
var ( | |
bucketName = flag.String("bucketName", "PROJECT_ID-urlsigner", "Bucket Name to upload to") | |
) | |
func main() { | |
flag.Parse() | |
ctx := context.Background() | |
storageClient, err := storage.NewClient(ctx) | |
if err != nil { | |
fmt.Printf("Failed to create client: %v", err) | |
return | |
} | |
fmt.Println("______________________ upload _________________") | |
hasher := md5.New() | |
hasher.Write([]byte(tenBytes)) | |
hashedContent := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) | |
url, err := storageClient.Bucket(*bucketName).SignedURL(fileName, &storage.SignedURLOptions{ | |
Method: http.MethodPut, | |
MD5: hashedContent, | |
Scheme: storage.SigningSchemeV4, | |
ContentType: "text/plain", | |
Expires: time.Now().Add(time.Second * 10), | |
Headers: []string{ | |
fmt.Sprintf("Content-Length: %d", len(tenBytes)), | |
}, | |
}) | |
if err != nil { | |
fmt.Printf("Failed to create client: %v", err) | |
return | |
} | |
fmt.Printf("SignedURL= %s\n", url) | |
client := &http.Client{} | |
for _, payload := range []string{fiveBytes, tenBytes, tenBytesReversed, twentyBytes} { | |
hasher := md5.New() | |
hasher.Write([]byte(payload)) | |
localHashedContent := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) | |
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer([]byte(payload))) | |
req.Header.Set("Content-Type", "text/plain") | |
req.Header.Set("Content-MD5", localHashedContent) | |
if err != nil { | |
fmt.Printf("Error creating request %s\n", err) | |
break | |
} | |
resp, err := client.Do(req) | |
if err != nil { | |
fmt.Printf("Error uploading file of size [%d]bytes: %v\n", len([]byte(payload)), err) | |
} | |
defer resp.Body.Close() | |
fmt.Printf("UploadStatus for file of size [%d] with hash [%s] %s\n", len([]byte(payload)), localHashedContent, resp.Status) | |
// body, err := ioutil.ReadAll(resp.Body) | |
// if err != nil { | |
// fmt.Printf("Error reading body %v",err) | |
// } | |
//fmt.Printf("%s\n", string(body)) | |
} | |
fmt.Println("______________________ resumable _________________") | |
url, err = storageClient.Bucket(*bucketName).SignedURL(fileName, &storage.SignedURLOptions{ | |
Method: http.MethodPost, | |
Scheme: storage.SigningSchemeV4, | |
ContentType: "text/plain", | |
Expires: time.Now().Add(time.Second * 10), | |
Headers: []string{ | |
fmt.Sprintf("x-upload-content-length: %d", len(tenBytes)), | |
"x-goog-resumable: start", | |
}, | |
}) | |
if err != nil { | |
fmt.Printf("Failed to create client: %v", err) | |
return | |
} | |
fmt.Printf("SignedURL= %s\n", url) | |
for _, payload := range []string{fiveBytes, tenBytes, tenBytesReversed, twentyBytes} { | |
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer([]byte(""))) | |
req.Header.Set("Content-Type", "text/plain") | |
req.Header.Set("x-upload-content-length", fmt.Sprintf("%d", len(payload))) | |
req.Header.Set("x-goog-resumable", "start") | |
if err != nil { | |
fmt.Printf("Error creating request %s\n", err) | |
return | |
} | |
client := &http.Client{} | |
resp, err := client.Do(req) | |
if err != nil { | |
fmt.Printf("Error uploading file of size %v", err) | |
return | |
} | |
defer resp.Body.Close() | |
//fmt.Printf("Status %s\n", resp.Status) | |
if resp.StatusCode == http.StatusCreated { | |
locationURL := resp.Header.Get("Location") | |
///fmt.Printf("Location: %s\n", locationURL) | |
lreq, err := http.NewRequest(http.MethodPut, locationURL, bytes.NewBuffer([]byte(payload))) | |
lreq.Header.Set("Content-Type", "text/plain") | |
lreq.Header.Set("Content-Length", fmt.Sprintf("%d", len(payload))) | |
if err != nil { | |
fmt.Printf("Error creating request %s\n", err) | |
return | |
} | |
lresp, err := client.Do(lreq) | |
if err != nil { | |
fmt.Printf("Error uploading file of size %v", err) | |
return | |
} | |
defer lresp.Body.Close() | |
fmt.Printf("UploadStatus for file of size [%d] %s\n", len([]byte(payload)), lresp.Status) | |
} else { | |
fmt.Printf("Could not generate resumable location for size [%d] %s\n", len([]byte(payload)), resp.Status) | |
} | |
// body, err := ioutil.ReadAll(resp.Body) | |
// if err != nil { | |
// fmt.Printf("Error reading body %v", err) | |
// } | |
// fmt.Printf("%s\n", string(body)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment