CodeGenieApp / CodeGenieApp/serverless-express

Getting "stream is not readable" since 4.16.0

Ouverte
#693 2 commentaires 12 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
JavaScript
Étoiles
5.3k
Forks
676
Métriques de merge des PR
Aucune PR mergée en 30 j

Description

The #692 PR introduced a bug when using with express and an async middleware: the IncomingMessage/Request (stream) is marked as not readable and fails when used with body-parser (for example).

Affected version: 4.16.0
Express version: 4 (didn't test it on 5)
Body parser version: 1.20.3

For the code attached, running with 4.15.0 yields:
```
{
statusCode: 200,
body: 'Hello World!',
isBase64Encoded: false,
headers: {
'x-powered-by': 'Express',
'content-type': 'text/html; charset=utf-8',
'content-length': '12',
etag: 'W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"'
}
}
```

Running with 4.16.0 yields:

```
{
statusCode: 500,
body: '\n' +
'\n' +
'\n' +
'\n' +
'Error\n' +
'\n' +
'\n' +
'

InternalServerError: stream is not readable
   at readStream (node_modules/raw-body/index.js:185:17)
   at getRawBody ... (same as below)' +
'\n' +
'\n',
isBase64Encoded: false,
headers: {
'x-powered-by': 'Express',
'content-security-policy': "default-src 'none'",
'x-content-type-options': 'nosniff',
'content-type': 'text/html; charset=utf-8',
'content-length': 1262
}
}
InternalServerError: stream is not readable
at readStream (node_modules/raw-body/index.js:185:17)
at getRawBody (node_modules/raw-body/index.js:116:12)
at read (node_modules/body-parser/lib/read.js:79:3)
at jsonParser (node_modules/body-parser/lib/types/json.js:138:5)
at Layer.handle [as handle_request] (node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (node_modules/express/lib/router/index.js:328:13)
at node_modules/express/lib/router/index.js:286:9
at Function.process_params (node_modules/express/lib/router/index.js:346:12)
at next (node_modules/express/lib/router/index.js:280:10)
at src/example.ts:10:3
```

Code to reproduce:
```typescript
import serverlessExpress from '@codegenie/serverless-express';
import express from 'express';
import bodyParser from 'body-parser';
import { promisify } from 'node:util';

const app = express();

app.use(async (req, res, next) => {
// Remove this line to "remove the problem"
await promisify(setTimeout)(1000);
next();
});

app.use(bodyParser.json());

app.use((req, res) => {
res.send('Hello World!');
});

const serverlessExpressInstance = serverlessExpress({ app });

export async function handler(event: any, context: any, callback: any) {
return serverlessExpressInstance(event, context, callback);
}

handler(
{
version: '2.0',
rawPath: '/path/to/resource',
headers: {
"Content-Type": "application/json",
"Content-Length": "2",
},
requestContext: {
http: {
method: 'POST',
path: '/path/to/resource',
protocol: 'HTTP/1.1',
sourceIp: '192.168.0.1/32',
userAgent: 'agent',
},
},
body: "{}",
isBase64Encoded: false,
},
{} as any,
() => {},
)
.then(console.log.bind(console))
.catch(console.error.bind(console));
```

I believe [this](https://github.com/CodeGenieApp/serverless-express/blob/5944638c128e82ea41915fc724e72cb8b3189bbd/src/transport.js#L163) is the culprit. Express doesn't return a promise from the handle function, so if there's a middleware that starts an async operation the function will return and the stream will be marked as not readable.

```typescript
await framework.sendRequest({ app, request, response })
markHttpRequestAsCompleted(request) // <-- maybe this should be moved down to after the the stream completes?
await waitForStreamComplete(response)
```

Small note, initially I had trouble finding this because I thought we were actually using vendia's serverless-express version. After fiddling with it for a couple of hours I realized it was actually "exporting" codegenie's version. So leaving this note here, in case someone else thinks they're using vendia's.

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Commencez dans src/transport.js autour de la ligne liée 163 et reproduisez l’échec avec l’exemple TypeScript fourni en utilisant async middleware et body-parser. Suivez le moment où le flux de la requête est marqué comme terminé par rapport au middleware Express et à la fin de la réponse, puis vérifiez que l’exemple réussit avec la version concernée et que sa régression est couverte par un test.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
aws, express, javascript, node.js, typescript
Domaine
api, backend, cloud
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.