Large HTTP uploads either start streaming immediately or pause briefly while endpoints negotiate expectations. The Expect: 100-continue header controls whether a client sends a request body right away or waits for a small green light from the server. Tuning that behavior in curl keeps latency, bandwidth use, and server compatibility under control during sizeable POST and PUT operations.

In HTTP/1.1, the Expect header requests a provisional 100 Continue status before the body is transmitted. When payloads cross an internal size threshold, curl automatically adds Expect: 100-continue and waits briefly for the provisional response, governed by the –expect100-timeout option. If a custom Expect header is supplied, curl stops guessing and preserves the exact value that was provided.

Some servers and middleboxes implement expectations poorly, returning 417 Expectation Failed, delaying responses, or ignoring the header entirely. Moving large bodies without the handshake can sidestep compatibility bugs but increases wasted bandwidth when validation fails, especially on slow or metered links. Examples assume a terminal on Linux with curl 7.47.0 or newer, where –expect100-timeout is available and HTTP diagnostics rely on –verbose output.

Steps to control Expect: 100-continue handling in cURL:

  1. Check the installed curl version from a shell prompt to confirm support for –expect100-timeout and HTTP/1.1.
    $ curl --version
    curl 7.88.1 (x86_64-pc-linux-gnu) libcurl/7.88.1 OpenSSL/3.0.2 zlib/1.2.13 brotli/1.0.9
    Release-Date: 2023-02-15
    Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
    Features: AsynchDNS HTTP2 HTTPS-proxy IPv6 Largefile libz NTLM NTLM_WB SSL TLS-SRP UnixSockets
    ##### snipped #####

    curl 7.47.0 or newer accepts the –expect100-timeout option for fine‑grained control over expectation handling.

  2. Send a verbose POST with a large payload to see when curl automatically injects Expect: 100-continue.
    $ curl --verbose --request POST --data-binary @large.bin http://example.com/upload
    *   Trying 93.184.216.34:80...
    * Connected to example.com (93.184.216.34) port 80 (#0)
    > POST /upload HTTP/1.1
    > Host: example.com
    > User-Agent: curl/7.88.1
    > Accept: */*
    > Content-Length: 10485760
    > Expect: 100-continue
    < HTTP/1.1 100 Continue
    ##### snipped #####

    The line starting with `> Expect: 100-continue` in verbose output indicates that curl injected the header automatically for this upload.

  3. Disable automatic Expect: 100-continue behavior by overriding the header with an empty value when immediate body transmission is preferred.
    $ curl --verbose --header "Expect:" --request POST --data-binary @large.bin http://example.com/upload
    *   Trying 93.184.216.34:80...
    * Connected to example.com (93.184.216.34) port 80 (#0)
    > POST /upload HTTP/1.1
    > Host: example.com
    > User-Agent: curl/7.88.1
    > Accept: */*
    > Content-Length: 10485760
    ##### snipped #####

    Disabling Expect: 100-continue on multi‑megabyte uploads can waste bandwidth and prolong failed attempts when the origin rejects the request based on headers alone.

  4. Force an explicit Expect: 100-continue header on requests where upstream infrastructure expects handshake semantics regardless of payload size.
    $ curl --verbose --header "Expect: 100-continue" --request POST --data @small.json https://api.example.net/endpoint
    *   Trying 203.0.113.10:443...
    * Connected to api.example.net (203.0.113.10) port 443 (#0)
    > POST /endpoint HTTP/1.1
    > Host: api.example.net
    > User-Agent: curl/7.88.1
    > Accept: application/json
    > Content-Type: application/json
    > Content-Length: 128
    > Expect: 100-continue
    < HTTP/1.1 100 Continue
    ##### snipped #####

    Explicitly setting the header ensures consistent handshake behavior for both small and large payloads when a gateway, load‑balancer, or API firewall relies on expectations.

  5. Configure the wait time for a provisional 100 Continue response using –expect100-timeout so the body starts flowing promptly when the timer expires or a provisional response arrives.
    $ curl --verbose --expect100-timeout 0.5 --request POST --data-binary @large.bin http://example.com/upload
    *   Trying 93.184.216.34:80...
    * Connected to example.com (93.184.216.34) port 80 (#0)
    > POST /upload HTTP/1.1
    > Host: example.com
    > User-Agent: curl/7.88.1
    > Accept: */*
    > Content-Length: 10485760
    > Expect: 100-continue
    < HTTP/1.1 100 Continue
    ##### snipped #####

    The –expect100-timeout value is expressed in seconds, accepts fractional values such as 0.5, and falls back to sending the body once the timer elapses without a provisional response.

  6. Repeat a verbose request using the chosen header and timeout configuration to verify that response headers, status codes, and transfer timing match the intended behavior.
    $ curl --verbose --header "Expect:" --expect100-timeout 0.5 --request POST --data-binary @large.bin http://example.com/upload
    *   Trying 93.184.216.34:80...
    * Connected to example.com (93.184.216.34) port 80 (#0)
    > POST /upload HTTP/1.1
    > Host: example.com
    > User-Agent: curl/7.88.1
    > Accept: */*
    > Content-Length: 10485760
    ##### snipped #####

    Success signals: requests that intentionally disable expectations show no Expect header, handshaked uploads show both Expect: 100-continue and HTTP/1.1 100 Continue lines, and latency spikes from one‑second stalls disappear once –expect100-timeout and header overrides are tuned appropriately.

Discuss the article:

Comment anonymously. Login not required.