0

I am using NodeJS to generate a signed URL to allow my users to upload files.

The code to generate the URL is pretty simple and works with URLs that have the Google Cloud domain.

However, I want the signed url to have my custom domain so the URL I am generating starts with https://example.com.

async function generateSignedUrl(file) {
  const bucketName = '<bucket-name>';
  const storage = new Storage({keyFilename: '<path-to-key>'});
  const options = {
    version: 'v4',
    action: 'write',
    expires: Date.now() + 15 * 60 * 1000, // 5 minutes
    contentType: 'application/octet-stream',
    cname: 'https://example.com'
  };

  const [url] = await storage
    .bucket(bucketName)
    .file(file)
    .getSignedUrl(options)
    .catch(error => console.log(error))

  return url
}

The infrastructure is such that the bucket is configured as a backend to a load balancer so my DNS server has the load balancer IP and it routes the requests to the load balancer. The load balancer then routes the requests to the bucket.

I tried a simple DNS redirection to the Google Cloud URL and though the redirection works, the upload does not as the browser first sends an OPTIONS request and results in a OPTIONS request cannot be redirected error. The OPTIONS request is also triggered when the request is sent from one sub-domain to another. For example, front-end deployed at https://staging.app.com and the signed URL starts with https://upload.staging.app.com so if I understand it correctly, CORS is not an issue here and DNS redirection is simply not an option?

The problem is the upload works for small files(< 5MB) but for large files, the upload stops suddenly and then fails after some time as the progress update in Axios shows. The load balancer logs show the client_timed_out error, with 408 or 504. I have also tried using CURL but the behaviour is exactly the same.

If it matters, here is the Axios code that performs the upload.

axios.put(
  url,
  file,
  {
    headers: {
      'content-type': 'application/octet-stream',
    },
    onUploadProgress(progressEvent) {
      console.log(`Upload Progress: ${JSON.stringify(progressEvent)}`)
    },
  }
)

I have searched for hours and hours over the last month but cannot find a resource that shows how to implement it. It seems too good to be true but I feel nobody has ever tried it.

Just a note that the exact code works as expected without a CNAME based url.

Noman Ur Rehman
  • 6,707
  • 3
  • 24
  • 39
  • 1
    1) If OPTIONS is being sent, that means you are making a cross-origin request. If you are using your own domain name, why is the request cross-origin? 2) For Signed URLs you should specify the Google endpoint and not the load balancer. You will be paying for the network traffic several times. – John Hanley Jul 10 '23 at 17:51
  • The request is cross-origin because I am testing from localhost. However, with the uploaded version, it also does not work with a subdomain. Example: App at app.com and upload url starts with upload.app.com. Can you add more details to specifying Google endpoint? I want the URL to have my domain, that is the whole point. – Noman Ur Rehman Jul 10 '23 at 17:57

1 Answers1

1

Google Cloud Storage have a documentation regarding with Control public access to data:

According to this documentation

Because Cloud Storage doesn't support custom domains with HTTPS on its own, this tutorial uses Cloud Storage with an external Application Load Balancer to serve content from a custom domain over HTTPS. For more ways to serve content from a custom domain over HTTPS, see troubleshooting for HTTPS serving. You can also use Cloud Storage to serve custom domain content over HTTP, which doesn't require a load balancer.

This inform you to create a load balancer service that can be used for user content from your own domain, using the buckets as the service backend. On the other hand, you can check this out for possible way around that create a custom domain CDN with google.

Main objectives of this blog is the ff:

  • I want to serve images on my website (comparison for contact lenses) from a cloud bucket.

  • I want to serve it from my domain, cdn.kontaktlinsen-preisvergleich.de

  • I need HTTPS for that domain, because my website uses HTTPS everywhere and I don’t want to mix that.

This stackoverflow post can provide additional information with the implementation of CDN to handle custom domain to server your Cloud Storage objects.

Other reference that might help:

The next thing I would suggest is to file a bug under the Issue tracking system and product feature request.

Disclaimer:

This doesn't have a specific ETA but you can keep track of its progress once you create the bug.

DominicT
  • 388
  • 1
  • 9
  • this seems to have gotten wrongly auto-flagged by a bot :/ ([link](https://chat.stackoverflow.com/transcript/message/56490944#56490944)) – starball Jul 12 '23 at 00:34