Curl Cheatsheet
Introduction
Curl is an invaluable tool for anyone who needs to debug webapps fequently. Given it’s vast amount of options, it is easy to miss some of it’s simplest yet powerful uses.
Listing here some options that I use everyday. Use the topics below to navigate direct to what you are looking for.
I’ll keep updating it as and when I discover something new! 🤘
Inspect
Response headers
The simplest way to do that is by using the -I
option -
1$ curl -I https://httpbin.org/ip
2
3HTTP/2 200
4date: Thu, 12 Nov 2019 19:08:13 GMT
5content-type: application/json
6content-length: 32
7server: gunicorn/19.9.0
8access-control-allow-origin: *
9access-control-allow-credentials: true
The above works in most cases, but if your webapp/endpoint doesn’t support the HEAD
method or behaves differently to it compared to the usual GET
method, this will dissappoint you.
To inspect the headers with a GET
method, following options can be helpful.
1$ curl -D - https://httpbin.org/ip -s -o /dev/null
2
3HTTP/2 200
4date: Thu, 12 Nov 2019 19:10:39 GMT
5content-type: application/json
6content-length: 32
7server: gunicorn/19.9.0
8access-control-allow-origin: *
9access-control-allow-credentials: true
OK, this works 👍 but there are a lot of options. What do they tell curl
?
-D
dump the headers to a file.-
dump it to stdin instead of a file.-s
suppress the progress update (like the following), helps to keep the output clean.1% Total % Received % Xferd Average Speed Time Time Time Current 2 Dload Upload Total Spent Left Speed 30 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0HTTP/2 200
-o
send any output to file-o /dev/null
discard the response completely.
Request headers
I find -v
option to be the most useful to inspect the request headers. Check the request headers on the lines starting with >
1$ curl -v https://httpbin.org/ip -s -o /dev/null | grep ">"
2
3* Trying 3.211.1.78:443...
4* Connected to httpbin.org (3.211.1.78) port 443 (#0)
5* Using HTTP2, server supports multi-use
6* Connection state changed (HTTP/2 confirmed)
7* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
8} [5 bytes data]
9* Using Stream ID: 1 (easy handle 0x1da3b7de150)
10} [5 bytes data]
11> GET /ip HTTP/2
12> Host: httpbin.org
13> user-agent: curl/7.73.0
14> accept: */*
Redirects
Redirects are implemented for a variety of reasons. Redirect responses return a 30X
response code and a location
header which tells the requestor where to go next. The following request gives us these filtering out the rest.
1$ curl https://httpbin.org/status/302 -w "%{response_code} %{redirect_url}" -s -o /dev/null
2302 https://httpbin.org/redirect/1
OK, this is nice 👌 but what does w
tell curl
?
-w
is write-out option and takes a number of variables. These variables need to be enclosed in a%{ }
block. I have used 2 here.response_code
andredirect_url
which are sort of self explanatory. Full list of variables it supports is here
What if you want to inspect the redirects for multiple pages? Add the urls in a list and run this one liner loop to check all the redirects in one shot, and also format the output a bit while we are at it.
https://httpbin.org/status/301
https://httpbin.org/status/302
https://httpbin.org/status/307
1$ while read url; do curl $url -w " %{response_code} | $url --> %{redirect_url} \n" -s -o /dev/null; done < urls.txt
2
3301 | https://httpbin.org/status/301 --> https://httpbin.org/redirect/1
4302 | https://httpbin.org/status/302 --> https://httpbin.org/redirect/1
5307 | https://httpbin.org/status/307 --> https://httpbin.org/redirect/1
Customize Requests
Change the User-Agent
By default, curl uses a user-agent request header like, user-agent: curl/7.73.0
If you need to send a custom user-agent, simply use the -A
option. Check the User-Agent
key value in the returned json response.
1$ curl https://httpbin.org/headers -A "bob-the-builder"
2
3{
4 "headers": {
5 "Accept": "*/*",
6 "Host": "httpbin.org",
7 "User-Agent": "bob-the-builder",
8 "X-Amzn-Trace-Id": "Root=1-5fadb05b-490211b54febef30592912b5"
9 }
10}
Custom headers
To send custom headers with a request, you can use the -H
option. Check the headers
section in the returned json response.
1$ curl https://httpbin.org/headers -H "CustomHeader1: value1" -H "CustomHeader2: value2"
2
3{
4 "headers": {
5 "Accept": "*/*",
6 "Customheader1": "value1",
7 "Customheader2": "value2",
8 "Host": "httpbin.org",
9 "User-Agent": "curl/7.73.0",
10 "X-Amzn-Trace-Id": "Root=1-5fadb190-26af70e1691093c76d180401"
11 }
12}
Cookies
To send cookies with a request, you can use the -b
option. The cookies can either be provided inline or read from a file.
Check the cookies
in the json response.
Send the cookie values inline
1$ curl https://httpbin.org/cookies -b "country=GB; language=EN; debug=1"
2
3{
4 "cookies": {
5 "country": "GB",
6 "debug": "1",
7 "language": "EN"
8 }
9}
Send the cookie values from a file
1$ curl https://httpbin.org/cookies -b cookies.txt
2
3{
4 "cookies": {
5 "country": "GB",
6 "debug": "2",
7 "language": "EN",
8 "source": "file"
9 }
10}
Note The cookie.txt
file needs to be in the following format for curl to read and parse the cookies
httpbin.org FALSE / FALSE 0 country GB
httpbin.org FALSE / FALSE 0 language EN
httpbin.org FALSE / FALSE 0 source file
httpbin.org FALSE / FALSE 0 debug 2
Reuse cookies
To save cookies received in a response, you can use the -c
option. The cookies can then be easily used in subsequent requests using the -b
option as we saw above.
1$ curl https://httpbin.org/cookies/set/locale/en_GB -c cookies.txt
2
3<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
4<title>Redirecting...</title>
5<h1>Redirecting...</h1>
6<p>You should be redirected automatically to target URL: <a href="/cookies">/cookies</a>. If not click the link.
Let’s inspect the file, if cookie is saved. The contents of the file would be as follows -
# Netscape HTTP Cookie File
# https://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.
httpbin.org FALSE / FALSE 0 locale en_GB
Chaining the above requests we can make a request like this. -L
causes curl to continue following the redirect.
1$ curl https://httpbin.org/cookies/set/locale/en_GB -c cookies.txt -b cookies.txt -L
2
3{
4 "cookies": {
5 "locale": "en_GB"
6 }
7}
POST data
The option to use in this case is -D
flag. When you use this option, the Content-Type: application/x-www-form-urlencoded
request header is automatically set, so you don’t need to specify it explicitly. You can specify the data to be posted immediately after this flag. A sample request and response is added below. Check the response json’s form
field.
1$ curl "https://httpbin.org/post" -d "firstname=John&lastname=Doe"
2
3{
4 "args": {},
5 "data": "",
6 "files": {},
7 "form": {
8 "firstname": "John",
9 "lastname": "Doe"
10 },
11 "headers": {
12 "Accept": "*/*",
13 "Content-Length": "27",
14 "Content-Type": "application/x-www-form-urlencoded",
15 "Host": "httpbin.org",
16 "User-Agent": "curl",
17 "X-Amzn-Trace-Id": "Root=1-60ec27f5-4d461f2d3bbf20ed16291ed3"
18 },
19 "json": null,
20 "url": "https://httpbin.org/post"
21}
You could also hide the data you are submitting from the command line or history by reading it off a file like so -
1$ curl "https://httpbin.org/post" -d "@sensitive-data.txt"
POST multifield form
It’s quite straightforward to submit a multifield form using curl
. The option to use is -F
. You can add as many fields as required by adding multiple -F
flags. When you use this option, the Content-Type: multipart/form-data
request header is automatically set, so you don’t need to specify it explicitly.
Here is one such request and response -
1$ curl -F "firstname=John" -F "lastname=Doe" "https://httpbin.org/post"
2
3{
4 "args": {},
5 "data": "",
6 "files": {},
7 "form": {
8 "firstname": "John",
9 "lastname": "Doe"
10 },
11 "headers": {
12 "Accept": "*/*",
13 "Content-Length": "248",
14 "Content-Type": "multipart/form-data; boundary=------------------------e41227aceee312a6",
15 "Host": "httpbin.org",
16 "User-Agent": "curl",
17 "X-Amzn-Trace-Id": "Root=1-60ec23d7-3a82be0162af35456010c778"
18 },
19 "json": null,
20 "url": "https://httpbin.org/post"
21}
File upload
Similar to using the multifield form above, you can also upload a file using the -F
flag. The only thing to be aware of is the filepath should be prefixed with a @
char. Check the field files
in the response json.
1$ curl -F "firstname=John" -F "lastname=Doe" "https://httpbin.org/post" -F "file=@file.txt"
2
3{
4 "args": {},
5 "data": "",
6 "files": {
7 "file": "This is a test file\n"
8 },
9 "form": {
10 "firstname": "John",
11 "lastname": "Doe"
12 },
13 "headers": {
14 "Accept": "*/*",
15 "Content-Length": "408",
16 "Content-Type": "multipart/form-data; boundary=-----afd9220cdc8dae3d",
17 "Host": "httpbin.org",
18 "User-Agent": "curl",
19 "X-Amzn-Trace-Id": "Root=1-60ec24b5"
20 },
21 "json": null,
22 "url": "https://httpbin.org/post"
23}
Conclusion
While this list is just a start, I hope it helps you use curl more effectively. As promised, I will try to keep this updated, so that over time, it may eventually become a lot more exhaustive. 👍