npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

slow-body

v1.0.11

Published

Express-compatible middleware to handle badly behaved or slow clients

Readme

slow-body

The handling of badly behaved or slow clients is a bit fragmented and not well-solved in the Express ecosystem. Node is not helping matters, and Express does not attempt to handle it for you.

To be fair, this specific scenario is limited by the HTTP 1.1 spec, which Node is adhering to strictly here. It requires that the entirety of request bodies are read before a response can be written.

Servers supporting GraphQL operations, and/or supporting Mobile clients, are particularly vulnerable to the problem of clients slowly drip-feeding their request bodies. These bad clients effectively act as a slow loris attack. Rather than keep the sockets open until the request eventually, maybe completes, this package will close the connections after a configurable timeout.

This is rather rude, and clients will probably throw exceptions when they try to write their next byte to a closed socket.

How It Works

When a client connects, the server-level handler attaches custom event emitters (such as 'timeout' and 'incompleteBody') to each socket. These events are triggered if the client is too slow to send headers or the full body.

The provided Express middleware (slowBodyTimeout) listens for these socket events and handles them at the request/response layer, making it easier to integrate with your existing Express error handling and logging. This separation of concerns allows you to handle slow clients at both a low level (socket) and a high level (Express), which is rare in the Node/Express ecosystem.

If you prefer, you can listen to these socket events yourself and implement custom handling, bypassing the provided middleware.

flowchart TD
    A[Client connects] --> B[Socket created]
    B --> C{Socket-level handler}
    C -->|Headers/body too slow| D[Emit 'timeout' or 'incompleteBody' event]
    C -->|Headers/body OK| E[Request proceeds]
    D --> F[Express middleware listens for events]
    F -->|Event received| G[Send error response, destroy socket]
    E --> H[Express body parser & routes]
    H --> I[Normal response]

Features

  • Socket-level monitoring before Express middleware processing
  • Precise tracking of headers vs body data
  • Configurable timeout for body delivery
  • Works with Express's error handling system
  • Compatible with other Express middleware
  • TypeScript support

Installation

npm install slow-body

Usage

import express from 'express';
import { setupSocketTimeout, slowBodyTimeout } from 'slow-body';

const app = express();
const port = 3000;

// Basic request logging middleware
app.use((req, res, next) => {
  const start = Date.now();
  res.on("finish", () => {
    const duration = Date.now() - start;
    console.log(`${req.method} ${req.url} ${res.statusCode} - ${duration}ms`);
  });
  next();
});

// Use the slow-body middleware with custom options
app.use(slowBodyTimeout(console.error));

// Parse JSON bodies - this should not hang if the body is slow to arrive
app.use(express.json());

// Test endpoint for normal requests
app.post("/upload", (req, res) => {
  console.log("Received request body:", req.body);
  res.json({
    message: "Request processed successfully",
    bodySize: JSON.stringify(req.body).length,
  });
});

// Generic error handler (slow body errors are handled directly by the middleware above)
app.use((err, req, res, next) => {
  console.error("Error:", {
    name: err.name,
    message: err.message,
    stack: err.stack,
    url: req.url,
    method: req.method,
    headers: req.headers,
  });
  res.status(500).json({
    error: err.message,
    name: err.name,
  });
});

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

// Set up socket-level timeout handling (must be called after app.listen)
setupSocketTimeout(10000, server); // 10s timeout

API

setupSocketTimeout(time: number, server: Server)

Sets up socket-level timeout handling. Must be called after creating the HTTP server.

  • time: Timeout in milliseconds (default: 10000)
  • server: The HTTP server instance

slowBodyTimeout(loggingFn?: (error: Error) => void)

Creates Express middleware to handle socket timeouts.

  • loggingFn: Optional function to log timeout errors (default: console.error)

Error Handling & Node.js HTTP Protocol Limitations

The middleware attempts to send a 408 (timeout) or 400 (incomplete body) response and then destroys the request. However, due to Node.js's strict HTTP/1.1 protocol enforcement, if the request body is not fully received, the response may not actually be sent and the client may see a connection reset or protocol error instead.

This is a limitation of Node.js and the HTTP/1.1 spec: the server is expected to read the entire request body before sending a response. Destroying the socket is the only way to immediately free resources, but it means the client will not receive a valid HTTP response.

When a timeout or incomplete body is detected, the middleware will:

  1. Log the error using the provided logging function
  2. Send a 408 (timeout) or 400 (incomplete body) response, if possible
  3. Call req.destroy() to ensure the socket is closed and not left in-use (this prevents resource leaks and slowloris attacks)

Note: You do not need to handle slow body errors in your error handler, but you should still have a generic error handler for other errors.

Example

See the examples/basic directory for a complete working example that demonstrates:

  • Basic request handling
  • Slow client detection
  • Error handling
  • Request logging

License

MIT