hyper-express icon indicating copy to clipboard operation
hyper-express copied to clipboard

multipart data parser issues

Open George2029 opened this issue 5 months ago • 2 comments

POST HTTP request results in connection drop (HTTP client gets as response something like: curl: (52) Empty reply from server, err_empty_response, socket hang up), if the request handler contains multidata parsing via req.multipart and it takes a long time to process.

The example server handles 3 requests:

/regular-long -- takes 15s to process, test request is successful. /multipart-fast -- uses hyper-express multipart parser, takes 5s to process, test request is successful. /multipart-long -- uses hyper-express multipart parser, takes 15s to process, test request is unsuccessful.

import { Server } from 'hyper-express';

const app = new Server({
  max_body_length: 4 * 1024 * 1024,
});
const PORT = 3000;
app.get('/regular-long', async (_, res) => {
  await new Promise((resolve) => setTimeout(resolve, 15000));
  res.send('OK');
});
app.post('/multipart-long', async (req, res) => {
  const formData = {};

  try {
    await req.multipart(async (field) => {
      if (field.file) {
        const chunks = [];
        for await (const chunk of field.file.stream) {
          chunks.push(chunk);
        }
      } else {
        formData[field.name] = field.value;
      }
    });

    await new Promise((resolve) => setTimeout(resolve, 15000));
    res.send(JSON.stringify({ success: true, formData }));
  } catch (err) {
    console.error('Error:', err);
    res.status(500).send(JSON.stringify({ error: err.message }));
  }
});

app.post('/multipart-fast', async (req, res) => {
  const formData = {};
  try {
    await req.multipart(async (field) => {
      if (field.file) {
        const chunks = [];
        for await (const chunk of field.file.stream) {
          chunks.push(chunk);
        }
        console.log(`File size: ${Buffer.concat(chunks).length} bytes`);
      } else {
        formData[field.name] = field.value;
        console.log(`Field ${field.name}: ${field.value?.substring(0, 50)}...`);
      }
    });

    await new Promise((resolve) => setTimeout(resolve, 5000));

    res.send(JSON.stringify({ success: true, formData }));
  } catch (err) {
    console.error('Error:', err);
    res.status(500).send(JSON.stringify({ error: err.message }));
  }
});

app
  .listen(PORT)
  .then(() => {
    console.log(`Server running on http://localhost:${PORT}`);
  })
  .catch((err) => console.error('Server error:', err));

Another parsers or HTTP libraries do not have this issue.

George2029 avatar Jul 22 '25 21:07 George2029

I have noticed the problem arises when the stream starts to be read by chunks. If the body is downloaded at once everything is fine.

George2029 avatar Jul 24 '25 11:07 George2029

Same problem

ChronoByteCosmonaut avatar Aug 19 '25 12:08 ChronoByteCosmonaut