{
"$type": "site.standard.document",
"canonicalUrl": "https://rednafi.com/misc/http-requests-via-dev-tcp/",
"description": "Make raw HTTP requests with Bash's /dev/tcp file descriptor. Build health check scripts without curl or wget using TCP socket connections.",
"path": "/misc/http-requests-via-dev-tcp/",
"publishedAt": "2024-08-08T00:00:00.000Z",
"site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
"tags": [
"TIL",
"Shell",
"Unix",
"Networking"
],
"textContent": "I learned this neat Bash trick today where you can make a raw HTTP request using the\n/dev/tcp file descriptor without using tools like curl or wget. This came in handy\nwhile writing a health check script that needed to make a TCP request to a service.\n\nThe following script opens a TCP connection and makes a simple GET request to example.com:\n\nRunning this will print the response from the site to your console.\n\nThe snippet first opens a TCP connection to example.com on port 80 and assigns file\ndescriptor 3 to manage this connection. The exec ensures that the file descriptor 3\nremains open for the duration of the script, allowing multiple read and write operations\nwithout needing to reopen the connection each time. Using a file descriptor makes the code\ncleaner. Without it, we'd need to redirect input and output directly to\n/dev/tcp/example.com/80 for each read and write operation, making the script more\ncumbersome and harder to read.\n\nThen we send an HTTP GET request to the server by echoing the request to file descriptor 3.\nThe server's response is read and printed using cat <&3, which reads from the file\ndescriptor and prints the output to the console. Finally, the script closes the connection\nby terminating file descriptor 3 with exec 3>&-.\n\nThis is a Bash-specific trick and won't work in other shells like Zsh or Fish. It also\nallows you to open UDP connections in the same manner. The Bash manpage explains the usage\nlike this:\n\nI used this to write the following health check script. I didn't want to install curl in a\nsidecar container that just runs a single health check process, keeping things simpler.\n\nThe script makes a GET request to the service and checks that the HTTP status from the raw\nresponse is 200. If not, it exits with a non-zero status.\n\nNote that the script will fail if your service returns a 301 redirect code. Plus, you need\nto make raw textual HTTP requests, which can become cumbersome if you need to do anything\nbeyond a simple GET call. At that point, you're better off using curl.",
"title": "HTTP requests via /dev/tcp"
}