firebase / firebase-functions

Firebase SDK for Cloud Functions
https://firebase.google.com/docs/functions/
MIT License
1.02k stars 201 forks source link

The HTTP request cancellation event is not fired in the Firebase HTTP Function #1585

Open wiesjan opened 1 month ago

wiesjan commented 1 month ago

Related issues

[REQUIRED] Version info

node:

v20.13.1

firebase-functions:

5.0.1

firebase-tools:

13.9.0

firebase-admin: 12.1.0

express

4.19.2

[REQUIRED] Test case


* `firebase-function.ts`

import express, { Request, Response } from 'express'; import cors from 'cors'; import { https, region } from 'firebase-functions/v1';

const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const app = express(); app.use(cors());

app.use('/*', async (req: Request, res: Response) => { console.log('start processing...');

// Detecting close event req.on('close', function() { const { destroyed } = req; console.log('Client connection close....!', { destroyed }); });

await delay(5000);

if (!req.destroyed) { console.log('sending response'); res.send('Hello World!'); } });

export const firebaseFunction = region('europe-west1').runWith({ invoker: 'public' }) .https.onRequest((request: https.Request, response: Response) => app(request, response));


* `express-server.js`

const express = require('express'); const cors = require('cors');

const app = express(); const port = 3001; app.use(cors());

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

app.get('/', async (expressRequest, expressResponse) => { console.log('start processing...');

// Detecting close event expressRequest.on('close', function () { const { destroyed } = expressRequest; console.log('Client connection close....!', { destroyed }); });

await delay(5000);

if (!expressRequest.destroyed) { console.log('sending response'); expressResponse.send('Hello World!') } })

app.listen(port, () => { console.log(Example app listening at http://localhost:${ port }) })



### [REQUIRED] Steps to reproduce

<!-- Provide the steps needed to reproduce the issue given the above test case. -->

Run the Firebase function defined in the `firebase-function.ts` file locally in the emulator, via `firebase emulators:start --only functions`, and the native Express application, via `node express-server.js`.
Open the `frontend.html` file in your browser. When the `firebase-function` function is loaded by the emulator, click the `send to function` button in your browser and then (after about a second) the `abort` button. 
Notice in the network tab of the browser's developer tools that the function call was canceled by the browser, but no information about it appeared in the emulator console.
Then click the `send to express app` button in your browser and, as before, after about a second, click `abort`. Similarly to the previous case, in the network dev tools tab of the browser you will see that the call has been canceled, but also in the console where the express application is running (`express-server.js`) you can see a log proving that the event informing about the request cancellation has been received by the application.

### [REQUIRED] Expected behavior

<!-- What is the expected behavior? -->

The expected behavior is for the `req.on('close')` event to be triggered when the client (browser) cancels the HTTP request also for the requests received by Firebase Functions, just as it is for the native Express.js application.

### [REQUIRED] Actual behavior

<!-- Please copy and paste any error logs from https://console.firebase.google.com/project/_/functions/logs.
     If you're experiencing a deployment issue, please copy and paste the entirety of firebase-debug.log -->

Currently, for calls received by the Firebase Function, the `req.on('close')` event fires only when the call completes, and nothing happens when the client cancels the call.

### Were you able to successfully deploy your functions?

<!-- When you ran `firebase deploy`, did you see any error messages? -->

There are no problems with deploy
google-oss-bot commented 1 month ago

I found a few problems with this issue:

exaby73 commented 3 weeks ago

Hey @wiesjan. Does the same occur on deployed functions as well?

wiesjan commented 3 weeks ago

@exaby73 yes, we observe the same behavior when the function is deployed. The req.on('close') event is fired only after the call is completed, i.e. after 5 seconds in the example provided.