0
votes

I'm having some trouble with serving some dynamic content from Firebase Hosting.

I've written an http.onRequest() cloud function that returns an image (content-type: image/jpeg) as its response. The function works as expected if I access it directly at its url:

https://us-central1-my-project-id.cloudfunctions.net/hosting-getPartnerImg

Per the documentation, I am using the us-central1 region.

I would like to be able to invoke this function using Firebase Hosting as well, which I've configured as follows:

firebase.json (snippet)

"rewrites" : [
{
    "source" : "/pimg",
    "function" : "hosting-getPartnerImage"
}
],
"headers": [ 
{
    "source": "/pimg",
    "headers": [ {
            "key": "Cache-Control",
            "value": "max-age=60"
        },
        {
            "key": "Access-Control-Allow-Origin",
            "value": "*"
        } 
    ]

}]

index.js (snippet)

const functions = require('firebase-functions');
const admin = require('firebase-admin');

let firebaseDefaultConfig = JSON.parse(process.env.FIREBASE_CONFIG);

admin.initializeApp(firebaseDefaultConfig);

const fn = process.env.FUNCTION_NAME;

if(!fn || fn === 'hosting-getPartnerImg'){
    exports.hosting = require('./hosting.js');
}

hosting.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');

exports.getPartnerImg = functions.region("us-central1").https.onRequest((req, res) => {
    const partnerId = req.query.partner;
    const fileName = req.query.file;

    res.set("content-type", "image/jpeg");

    const bucket = admin.storage().bucket();

    let file = bucket.file("partnerImgs/" + partnerId + "/" + fileName);
    let readStream = file.createReadStream();
    readStream.pipe(res);

});

This one has me stumped. Navigating to a URL like:

https://my-project-id.web.app/pimg?partner=BLAH&file=foo.jpg does not generate a Page Not Found as other URLs, so I'm reasonably confident that the rewrite is taking hold as it should. Be that the case though, why am I immediately taken to:

appengine.google.com/_ah/loginform... with the message:

** An application is requesting permission to your Google Account **

Can't HTTP onRequest cloud functions be used anonymously via Firebase Hosting? Why does the function work when I hit it directly, yet requests permission when I access it via the Firebase Hosting rewrite.

Any ideas would be appreciated.

1
What is index.js in this case? Is it the source that is in the public directory?robsiemb
Also, can you confirm that you actually have deployed a cloud function that works called hosting-getPartnerImg and show the code for that?robsiemb
@robsiemb index.js is in the functions directory. I put it in as a snippet as it has many statements similar to the conditional shown to segment individual functions into groups. When this pattern is used, the process.env.FUNCTION_NAME becomes hosting-getPartnerImg rather than hosting.getPartnerImg, so yes, I have deployed that function, and it is working fine if I access it directly.HondaGuy
OK, I can't deploy a function with this source code / name pattern with the firebase SDK to replicate, are you manually creating this (either via gcloud or the cloud console or some other mechanism?). I ask because the login page behavior is what happens when the function being called doesn't exist (regardless of if it is via a rewrite or not).robsiemb
@robsiemb I got it! First, I moved the getPartnerImg function out of the hosting group. No dice. Then, I changed the name from getPartnerImg to getpartnerimg, and it worked! It was the character casing! You were right about it not being able to find the function - it couldn't, due to the fact that I had camel-cased the function name. Took forever to crack. Thanks for providing a crucial hint! Many thanks!HondaGuy

1 Answers

5
votes

The AppEngine login page behavior is what happens when the function being called doesn't exist (regardless of if it is via a rewrite or not).

Your problem is this rewrite:

"function" : "hosting-getPartnerImage"

vs the actual function name:

if(!fn || fn === 'hosting-getPartnerImg'){

or

exports.getPartnerImg = ...

Notably, the rewrite doesn't call the correct function.

You should change the rewrite to call hosting-getPartnerImg instead.