GET /drip
Starts responding immediately but streams the body in small chunks with a configurable delay between each chunk. Unlike /slow, the response headers arrive right away — only the body trickles.
bytes
Total bytes to stream. Range: 1–100000. Default: 1000.
interval
Milliseconds between chunks. Range: 10–5000. Default: 200.
chunk
Bytes per chunk. Range: 1–4096. Default: 100.
build a request:
expect: 200 OK whose body arrives in chunks over time. Headers are immediate; the connection stays open until all bytes are delivered.
curl -i --no-buffer "https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200"
import sys, urllib.request
url = "https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200"
with urllib.request.urlopen(url) as resp:
while chunk := resp.read(64):
sys.stdout.buffer.write(chunk)
sys.stdout.flush()
// Browser or Node 18+. Read the body as a stream to observe chunks.
const res = await fetch("https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200");
const reader = res.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
process.stdout.write(decoder.decode(value));
}
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, err := http.Get("https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200")
if err != nil {
panic(err)
}
defer resp.Body.Close()
buf := make([]byte, 64)
for {
n, err := resp.Body.Read(buf)
if n > 0 {
fmt.Print(string(buf[:n]))
}
if err == io.EOF {
break
}
}
}
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
use std::io::{Read, Write};
fn main() -> Result<(), Box> {
let mut resp = reqwest::blocking::get(
"https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200",
)?;
let mut buf = [0u8; 64];
loop {
let n = resp.read(&mut buf)?;
if n == 0 { break; }
std::io::stdout().write_all(&buf[..n])?;
std::io::stdout().flush()?;
}
Ok(())
}
// Java 11+ HttpClient. ofInputStream() exposes the raw body stream.
import java.io.InputStream;
import java.net.URI;
import java.net.http.*;
public class Drip {
public static void main(String[] args) throws Exception {
var client = HttpClient.newHttpClient();
var req = HttpRequest.newBuilder(
URI.create("https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200")
).build();
var resp = client.send(req, HttpResponse.BodyHandlers.ofInputStream());
try (InputStream in = resp.body()) {
byte[] buf = new byte[64];
int n;
while ((n = in.read(buf)) > 0) {
System.out.write(buf, 0, n);
System.out.flush();
}
}
}
}
// .NET 6+. ResponseHeadersRead lets the body stream as it arrives.
using var client = new HttpClient();
using var resp = await client.GetAsync(
"https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200",
HttpCompletionOption.ResponseHeadersRead);
using var stream = await resp.Content.ReadAsStreamAsync();
var buf = new byte[64];
int n;
while ((n = await stream.ReadAsync(buf)) > 0) {
Console.Out.Write(System.Text.Encoding.UTF8.GetString(buf, 0, n));
Console.Out.Flush();
}
require "net/http"
uri = URI("https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200")
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
http.request(Net::HTTP::Get.new(uri)) do |res|
res.read_body do |chunk|
print chunk
STDOUT.flush
end
end
end
# Invoke-WebRequest buffers the full response, so use a raw stream to observe drip timing.
$req = [System.Net.WebRequest]::Create('https://chaos.catastrophic.io/drip?bytes=1000&chunk=100&interval=200')
$resp = $req.GetResponse()
$stream = $resp.GetResponseStream()
$buf = New-Object byte[] 64
while (($n = $stream.Read($buf, 0, $buf.Length)) -gt 0) {
Write-Host "Read $n bytes"
}
$stream.Close()
headers
body