Skip to the content.

How to send a curl HEAD request in C#

To send a curl HEAD request in C#, run curl -I <url> with Curl.ExecuteAsync, or call CurlRequestBuilder.Head(url). You get the status code and headers, and no response body is downloaded.

dotnet add package CurlDotNet

The curl command

using CurlDotNet;

var result = await Curl.ExecuteAsync("curl -I https://httpbin.org/get");

Console.WriteLine(result.StatusCode);                   // 200
Console.WriteLine(result.GetHeader("Content-Length"));  // size the GET would return
Console.WriteLine(result.Body);                         // HTTP/1.1 200 OK, then the headers

As with the curl CLI, which prints the headers of a -I request to standard output, result.Body holds the status line and header block exactly as received. With -I -L it holds every hop’s headers. --head does the same. -X HEAD also sends a HEAD request but, like curl, does not print the headers. Even if a misbehaving server sends a body with a HEAD response, CurlDotNet discards it.

The fluent builder and LibCurl

using CurlDotNet.Core;
using CurlDotNet.Lib;

var viaBuilder = await CurlRequestBuilder.Head("https://httpbin.org/get").ExecuteAsync();

using var curl = new LibCurl();
var viaLib = await curl.HeadAsync("https://httpbin.org/get");

Console.WriteLine($"{viaBuilder.StatusCode} {viaLib.StatusCode}");

These two return the headers in result.Headers only; their Body is empty.

Check whether a URL exists

using CurlDotNet;

var result = await Curl.ExecuteAsync("curl -I -L https://httpbin.org/status/404");
Console.WriteLine(result.IsSuccess ? "exists" : $"missing ({result.StatusCode})");

Add -L so a redirect to the real location is followed.

Check size before downloading

using CurlDotNet;

var head = await Curl.ExecuteAsync("curl -I -L https://httpbin.org/image/png");
if (long.TryParse(head.GetHeader("Content-Length"), out var bytes) && bytes < 10_000_000)
{
    await Curl.ExecuteAsync("curl -L -o image.png https://httpbin.org/image/png");
}

Not every server sends Content-Length (chunked responses usually do not), so handle a missing header.

Useful headers to read

Header Use
Content-Length Size in bytes
Content-Type What a GET would return
Last-Modified / ETag Has the resource changed?
Location Redirect target (without -L)
Accept-Ranges Whether -r byte ranges are supported

Header lookups are case-insensitive: result.Headers["etag"] and result.GetHeader("ETag") are equivalent.

HEAD versus -i

-I sends a HEAD request and puts only the headers in result.Body. -i sends the normal request and prepends the status line and headers to the body. Use -I when you only need the metadata. To keep the headers out of result.Body while downloading, -D headers.txt saves them to a file instead.