cURL allows developers immense power to customize and control HTTP requests directly from the command line. While cURL has many useful features, its header manipulation capabilities are invaluable for interfacing with modern web services.
In this comprehensive 3200+ word guide, we will dig deep into all facets of working with cURL headers from an experienced full-stack developer‘s perspective.
HTTP Headers – A Fundamental Review
Before jumping into using headers with cURL specifically, it is worthwhile to thoroughly understand what HTTP headers are and how they are used in requests and responses.
HTTP headers are components of HTTP communication that contain supplemental data about the transaction beyond just the core content. They consist of a case-sensitive identifier followed by a colon and value:
Header-Name: Value
Headers may appear in both HTTP requests made by the client and HTTP responses served by the server. They serve a vast array of purposes including:
- Specifying client capabilities and settings
- Describing response properties
- Managing caching policies
- Securing communication with authentication
- Enabling compression or encoding
- Conveying metadata about the data
- …and many more!
There are countless different headers defined by various RFC specifications and additional custom application-specific ones.
But at a high level, we can categorize headers into a few core types:
General Headers
General headers contain information broadly applicable to both requests and responses:
Connection: Keep-Alive
Date: Thu, 07 Dec 2022 15:44:04 GMT
Trailer: Custom-Checksum, Custom-Algorithm
Transfer-Encoding: chunked
Request Headers
Request headers provide details about the client making the request to inform the server‘s response:
Accept: application/json
Accept-Charset: utf-8
Authorization: Bearer xxx
Cache-Control: no-cache
User-Agent: Mozilla/5.0
Response Headers
Response headers describe aspects of the served response to the client:
Allow: GET, POST, DELETE
Content-Encoding: gzip
Content-Length: 3495
Content-Type: application/json
Expires: Thu, 07 Dec 2023 15:44:04 GMT
Last-Modified: Tue, 07 Dec 2021 15:44:04 GMT
There are far more specific header types beyond these broad categories, but this foundation already reveals the extensive flexibility headers provide to HTTP.
Now let‘s see how that flexibility enables customizing cURL requests!
Viewing Headers in cURL
When debugging requests made by cURL, it is extremely useful to see the full HTTP conversation – headers included…
Verbose Output
We can use the -v
or --verbose
flag to output full header details:
$ curl -v https://example.com
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.79.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/html
< Content-Length: 1234
< Cache-Control: max-age=600
< ...
The verbose output shows all request headers cURL sends by default followed by all response headers received from the server.
Response Headers Only
Alternatively, we can view just the response headers with -i
/--include
:
$ curl -i https://example.com
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
Cache-Control: max-age=600
...
<html>
... page content ...
</html>
Request Headers Only
Or see only the request headers using -I
/--head
:
$ curl -I https://example.com
GET / HTTP/1.1
Host: example.com
User-Agent: curl/7.79.1
Accept: */*
Having visibility into headers during testing can help identify problems and debug unexpected application behavior.
Setting Custom Headers
Beyond passive inspection, the most common action when working with cURL headers is setting custom request headers using the -H
flag:
$ curl -H "Header-Name: Value" https://example.com
This will add, override, or replace any default headers cURL might otherwise send.
Some examples:
# Set Accept header
$ curl -H "Accept: application/json" https://api.example.com/data
# Set API key authentication
$ curl -H "X-API-Key: 123456789" https://api.example.com
# Override user agent
$ curl -H "User-Agent: My-App-1.0" https://example.com
We can also pass multiple headers by providing multiple -H
flags:
$ curl -H "Accept: application/json" -H "Authorization: Bearer xyz" https://api.example.com
When interacting with different web services, being able to finely control headers is extremely useful for consumption of different APIs.
Modifying Headers
Sometimes we want to modify the value of a header rather than replace it entirely.
For example, appending to the User-Agent
instead of overwriting:
User-Agent: curl/7.79.1 **Custom Agent**
We can achieve this by using --header-append
instead of -H
:
$ curl --header-append "User-Agent: Custom Agent 1.0" https://example.com
Now both the original cURL user agent and our custom one will be included!
Removing Headers
To explicitly remove a header, use --header
without any value specified:
$ curl --header "User-Agent:" https://example.com
This can be useful to remove default headers that may negatively interact with certain servers. Headers can also be conditionally removed based on previous response codes which we‘ll cover next…
Conditional Headers
One extremely powerful trick with cURL is setting headers conditionally based on server response codes.
For example, to only send authorization on 401 errors:
/request.txt:
GET /api HTTP/1.1
Host: api.example.com
/auth.txt:
Authorization: Bearer abc123
Command:
$ curl -i -K request.txt --next auth.txt https://api.example.com
This first sends the default request.txt
headers, but will retry with auth.txt
on 401.
We can leverage this technique for header manipulation like:
- Adding compression headers
- Changing user agents
- Adjusting caching policy
…and more, all conditionally!
Debugging with Headers
While discussing the viewing options earlier, verbose headers are immensely useful for debugging issues with requests:
Log to File
We can log the full conversation to a file using --trace-ascii
:
$ curl --trace-ascii curl.log https://example.com
Then inspect the headers in depth:
=== Info: About to connect() to example.com port 80 (#0)
=== Info: Trying 93.184.216.34... * Connected to example.com (93.184.216.34) port 80 (#0)
=> Send header, 142 bytes
0000: GET / HTTP/1.1
0010: Host: example.com
...
002C: User-Agent: curl/7.79.1
0036: Accept: */*
0041:
<= Recv header, 16 bytes
0000: HTTP/1.1 301 Moved Permanently
<= Recv header, 25 bytes
...
We can check for missing headers, authentication issues, caching policies leading to unexpected responses, and more.
Other Tools
There are many great CLI and GUI tools for deeply inspecting HTTP traffic which are useful complements to built-in cURL options like:
Optimizing Performance
Beyond functionality, carefully configuring headers can also optimize performance.
Choosing the right caching policy is a great example…
Cache Control Headers
Browser Caching:
Savings from proper cache headers – HTTPArchive
Properly configuring headers like Cache-Control
and expiration dates can save unnecessary transfer time for repeat visitors.
Surrogate/CDN Caching
Headers also help CDNs cache and serve responses instead of hitting origin infrastructure:
Guidelines
Some cache header guidelines per resource type:
- Static Assets: Longer max-age, must-revalidate
- Homepage: Shorter max-age, no-cache, no-store
- APIs: no-store, private
Following RFC-7234 caching best practices pays dividends.
Compression
Enabling compression with headers can also speed transfers:
Transfer size savings by enabling encoded content
The Accept-Encoding
request header and Content-Encoding
response headers are used to enable compression on supported content.
Security Considerations
While headers provide tons of control, they can also expose vulnerabilities if set improperly.
Some common risks include:
- Browser fingerprinting via
User-Agent
- Information disclosure from headers like
X-Powered-By
- Sensitive data in referrer leakage
- Broken authentication from missing security headers
It‘s important to analyze the headers being sent for unnecessary or dangerous information.
Best Practices
Some header security guidelines:
- Omit unnecessary headers like
X-Powered-By
- Set Content Security Policy
- Referrer-Policy: same-origin
- Enable CORS safely
- Never transmit secrets!
Following standards like OWASP Secure Headers helps minimize issues.
Conclusion
This guide explored a plethora of techniques and best practices for working with HTTP headers in cURL requests. The ability to fully control headers unlocks the true potential and versatility of cURL for interfacing with web APIs and services.
We covered viewing, setting, modifying, and removing headers for complete request customization. We also looked at more advanced usage like conditional headers for response-dependent control flow. Lastly, we considered performance and security implications of header configuration.
Mastering headers is a vital skill for any developer working with cURL. Whether creating CLI scripts, developing applications, or analyzing network traffic, understanding how to manipulate headers grants power over the underlying HTTP transactions.
cURL empowers developers to easily reach out across the internet to tap into vital resources. Headers give us fine-grained control over those handshakes to truly enable robust systems integration in modern service-oriented architectures.