Listener Timeouts

Control how long the listener waits for clients at each stage of the HTTP connection. These timeouts protect against slow clients, aborted connections, and resource exhaustion attacks.

Configuration

{
  "timeouts": {
    "clientHeader": "10s",
    "clientRequest": "60s",
    "clientResponse": "60s",
    "idleBetweenRequests": "120s"
  }
}

All fields

FieldTypeDefaultDescription
clientHeaderstring10sTime for client to send all request headers
clientRequeststring60sTime to receive the complete request including body
clientResponsestring60sTime to send the complete response to the client
idleBetweenRequestsstring120sKeep-alive idle time between requests from the same client

All values are Go duration strings: 5s, 100ms, 2m30s, 1h.

Examples

Default (no changes)

Omit the timeouts field entirely. Vrata uses sensible defaults:

{
  "name": "default",
  "port": 8080
}

API server (fast requests, short timeouts)

{
  "name": "api",
  "port": 8080,
  "timeouts": {
    "clientHeader": "5s",
    "clientRequest": "10s",
    "clientResponse": "30s",
    "idleBetweenRequests": "60s"
  }
}

API clients send small payloads and expect fast responses. Short timeouts free connections quickly.

File upload endpoint

{
  "name": "uploads",
  "port": 8081,
  "timeouts": {
    "clientHeader": "10s",
    "clientRequest": "300s",
    "clientResponse": "60s",
    "idleBetweenRequests": "30s"
  }
}

Large uploads need a long clientRequest timeout. The header timeout stays short — even large uploads send headers quickly.

Streaming / Server-Sent Events

{
  "name": "streaming",
  "port": 8082,
  "timeouts": {
    "clientHeader": "10s",
    "clientRequest": "30s",
    "clientResponse": "0s",
    "idleBetweenRequests": "300s"
  }
}

Set clientResponse to 0s (unlimited) for long-lived streaming responses. The upstream controls when the response ends.

Aggressive anti-slowloris

{
  "name": "hardened",
  "port": 443,
  "timeouts": {
    "clientHeader": "3s",
    "clientRequest": "15s",
    "clientResponse": "30s",
    "idleBetweenRequests": "30s"
  }
}

Short clientHeader (3s) drops slowloris attackers quickly. Short idleBetweenRequests (30s) reclaims idle connections faster.

How they work

clientHeader

Starts when the connection is accepted. Ends when all request headers have been received. If the timer fires, the connection is closed with no response.

Protects against: Slowloris attacks where a client sends headers one byte at a time to exhaust connections.

clientRequest

Starts when the connection is accepted. Ends when the complete request (headers + body) has been received. This is a superset of clientHeader.

Protects against: Slow uploads that tie up connections. If an upload stalls, this timeout closes the connection.

clientResponse

Starts when Vrata begins writing the response. Ends when the complete response has been sent to the client. If the client reads slowly, this timeout fires.

Protects against: Slow-read attacks where a client accepts data one byte at a time, tying up the goroutine.

idleBetweenRequests

On keep-alive connections, this is the idle time between the end of one request/response cycle and the start of the next. When it fires, the connection is closed gracefully.

Protects against: Connection pool exhaustion from clients that open connections but don’t send requests.

Relationship with destination timeouts

Listener timeouts operate on the client ↔ proxy side. Destination timeouts operate on the proxy ↔ upstream side. They are independent:

Client ──[listener timeouts]──► Proxy ──[destination timeouts]──► Backend

A common mistake is setting clientResponse shorter than the upstream’s response time. If your backend takes 10s to respond but clientResponse is 5s, the client connection closes before the response arrives.