Settings and activity
14 results found
-
3 votesAlexandre Paradis supported this idea ·
-
22 votesAlexandre Paradis supported this idea ·
-
2 votes
An error occurred while saving the comment -
5 votesAlexandre Paradis supported this idea ·
-
5 votesAlexandre Paradis supported this idea ·
-
2 votesAlexandre Paradis shared this idea ·
-
29 votesAlexandre Paradis supported this idea ·
-
25 votesAlexandre Paradis supported this idea ·
-
43 votesAlexandre Paradis supported this idea ·
-
91 votesAlexandre Paradis supported this idea ·
-
245 votes
Hi folks, this is being actively worked on, and is expected to preview sometime in H1 2024. Thank you for using UserVoice to help us prioritize!
Alexandre Paradis supported this idea · -
12 votesAlexandre Paradis supported this idea ·
-
17 votesAlexandre Paradis supported this idea ·
-
36 votesAlexandre Paradis supported this idea ·
You can create a hosting configuration that redirects to a function. Ex.
```
{
"target": "my-cdn",
"headers": [
{
"source": "/**",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
},
{ "key": "X-Content-Type-Options", "value": "nosniff" }
]
},
{
"source": "**/*.@(jpg|jpeg|gif|png|webp|svg|ico)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=2592000, s-maxage=7776000"
}
]
}
],
"rewrites": [
{
"source": "**",
"function": "cdn",
"region": "northamerica-northeast1"
}
]
},
```
This is the function I'm using to serve images from a Firebase Storage bucket:
```
import { error as logError } from 'firebase-functions/logger';
import { onRequest } from 'firebase-functions/v2/https';
import { Agent, get as httpsGet } from 'https';
import { initializeFirebaseAdminApp } from '../infrastructure/firebase/initializeAdminApp';
import { initializeExpressApp } from '../infrastructure/express/initializeApp';
import { Request, Response } from 'express';
import { lookup } from 'mime-types';
initializeFirebaseAdminApp();
const expressApp = initializeExpressApp('cdn');
// Configure persistent connection
const agent = new Agent({ keepAlive: true });
// Set CDN caching duration in seconds
const cacheMaxAge = 2592000; // 30 days
const cacheSMaxAge = 7776000; // 90 days
const allowedPrefix = '/';
const isUrlAllowed = (url: string): boolean => url.startsWith(allowedPrefix);
// Get firebase URL from received request
const getFirebaseUrl = (url: string): string => {
if (!isUrlAllowed(url)) {
logError('URL is not allowed');
throw new Error('URL is not allowed');
}
// Configure source image URLs. This assumes that we store images on Firebase Storage
const projectId = process.env.GCLOUD_PROJECT;
const pathSeparator = '%2F';
const sourcePrefix = `https://firebasestorage.googleapis.com/v0/b/${projectId}-cdn/o/`;
const sourceSuffix = `?alt=media`;
const urlNoPrefix = url.slice(allowedPrefix.length);
const sourceKey = urlNoPrefix.replace(/\//g, pathSeparator);
return `${sourcePrefix}${sourceKey}${sourceSuffix}`;
};
expressApp.get('*', ({ url }: Request, response: Response) => {
const firebaseUrl = getFirebaseUrl(url);
httpsGet(firebaseUrl, { agent }, (res) => {
const statusCode = res.statusCode || 404;
const headerPipe = response;
if (statusCode < 400) {
headerPipe.set(
'Cache-Control',
`public, max-age=${cacheMaxAge}, s-maxage=${cacheSMaxAge}`,
);
const contentType = lookup(url);
if (contentType) {
headerPipe.set('Content-Type', contentType); // Some images were saved on Google Storage with a wrong content-type, so we try to set the good one here!
}
}
headerPipe.status(statusCode);
return res.pipe(headerPipe);
});
});
export const cdn = onRequest(
{ region: ['northamerica-northeast1'] },
expressApp,
);
```