Apply byte limit in axios Promise + expressjs

Viewed 308

One way I applied a byte limit in ExpressJS was to pipe the data stream from a request, and asynchronously examine properties:

const byteLimit = (process.env.BYTELIMIT || 32*1024*1024);
app.all('/:url', (req, res, next) => {
  let url = req.params.url;
  req
    .pipe(request(url))
    .on('response', function(response) {
      let contentLength = req.socket.bytesRead;
      if (contentLength > byteLimit) {
        res.status(400).send("Went over content byte limit");
      }
    })
    .pipe(res);
});

If I use axios, would I modify its Promise in a similar way?

app.all('/:url', (req, res, next) => {
  let url = req.params.url;
  // https, privateKey and certificate variables defined upstream
  const agent = new https.Agent({  
    key: privateKey,
    cert: certificate,
  });
  axios({
    method: 'get',
    url: url,
    responseType: 'stream',
    httpsAgent: agent,
  })
  .then((response) => {
    // I would like to measure bytes received here, sending an error if limit is met or exceeded
    response.data.pipe(res);
  })
  .catch(err => console.log(err));
});

I don't think I have the syntax correct when attempting to test content length or other properties via axios in an asynchronous fashion. So, as the request is processed, I want to be able to send an error once some property meets criteria, e.g. content length threshold, but without downloading the entire file. Thanks for any advice.

1 Answers

Solution 1:

You can use content-length to get total content size in bytes

const byteLimit = (process.env.BYTELIMIT || 32*1024*1024);
axios({
    method: 'get',
    url: url,
    responseType: 'stream',
    httpsAgent: agent,
  })
  .then((response) => {
    if (Number(response.headers['content-length']) > byteLimit) {
      res.status(400).send("Went over content byte limit");
    }
    else {
      response.data.pipe(res);
    }
  })
  .catch(err => console.log(err));

Solution 2:

If content-length is not correct for some reason you can stream and store send bytes and if it reaches limit you can close the connection and send 404

const byteLimit = (process.env.BYTELIMIT || 32*1024*1024);
axios({
    method: 'get',
    url: url,
    responseType: 'stream',
    httpsAgent: agent,
  })
  .then((response) => {
    const progress = 0;
    response.data.on('data', (data) => {
      progress += Buffer.byteLength(data);
      if (progress > byteLimit) {
        response.data.destroy();
        res.status(400).send("Went over content byte limit");
      }
      else {
        res.write(data);
      }
    });

    response.data.on('end', () => {
        res.status(200).send()
    });
  })
  .catch(err => console.log(err));

Solution3:

You can use maxContentLength or maxBodyLength option provided by axios

maxContentLength defines the max size of the http response content in bytes allowed in node.js maxContentLength: 2000,

maxBodyLength (Node only option) defines the max size of the http request content in bytes allowed maxBodyLength: 2000,

Related