Skip to content

Instantly share code, notes, and snippets.

@salrashid123
Last active March 18, 2022 12:55
Show Gist options
  • Save salrashid123/7069399ee128416cf3b8ff162696ea86 to your computer and use it in GitHub Desktop.
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/)
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