Une petite précision avant de passer aux commandes : nous sommes Geonode et nous vendons des proxys ; il est donc honnête de préciser d’emblée qu’un délai d’expiration de curl n’est presque jamais dû à un problème de proxy. Si vos requêtes expirent face à un serveur simplement lent, à un hébergeur hors service ou à un pare-feu qui rejette les paquets sans le signaler, les acheminer via nos serveurs ne changera rien, si ce n’est le montant de la facture. Les proxys sont utiles lorsque le problème réside dans l’origine apparente de votre requête : contenu soumis à des restrictions géographiques, limites de débit liées à votre adresse, ou encore une adresse IP bloquée. Ils ne transforment pas un serveur lent en serveur rapide. Commencez par régler correctement vos délais d’expiration ; vous constaterez peut-être que vous n’aviez besoin de rien d’autre.
Exact. Voici ce que la plupart des gens découvrent à leurs dépens : curl n’a pas de délai d’expiration global par défaut. Il dispose d’un délai d’expiration de connexion par défaut de 300 secondes, mais une fois la connexion établie, curl attendra joyeusement indéfiniment une réponse qui n’arrivera jamais complètement. Dans un script shell s’exécutant via cron, cela se traduit par une tâche qui ne se termine jamais et un fichier de verrouillage que personne ne libère.
Les deux délais d'attente qui comptent
Tout le reste n'est qu'un approfondissement de ces deux éléments.
--max-time
(forme abrégée : -m
) encadre l'ensemble de l'opération. D'après le manuel de curl : « Durée maximale, en secondes, que vous autorisez pour l'opération de transfert. » Connexion, établissement de la connexion, requête, réponse, tout y passe. Lorsque la limite est atteinte, curl interrompt l’opération et se termine avec le code 28.
curl -m 10 https://example.com
Dix secondes au total, puis curl abandonne quelle que soit l’étape atteinte.
--connect-timeout
ne limite que la phase d’établissement de la connexion. Le manuel précise clairement ce que cela inclut : « La phase de connexion est considérée comme terminée lorsque la recherche DNS et les handshakes TCP, TLS ou QUIC demandés sont effectués. » Une fois la connexion établie, cette option ne s’applique plus.
curl --connect-timeout 3 https://example.com
Trois secondes pour résoudre le nom et terminer les handshakes. Après cela, curl attend le temps nécessaire au transfert.
En pratique, les deux options sont utiles, car elles répondent à des questions différentes :
| Option | Couvre | Valeur typique | Contre quoi protège-t-elle ? |
|---|
--connect-timeout | | | |
| Poignée de main DNS + TCP/TLS/QUIC | 3 à 10 s | Hôtes inactifs, paquets perdus, défaillances DNS |
| --max-time
| L’opération dans son ensemble | 10 à 60 s, en fonction de la charge de travail | Réponses lentes, transferts bloqués, flux interminables |
Au total :
curl --connect-timeout 5 -m 30 https://example.com
Cinq secondes pour établir la connexion, trente secondes pour l’ensemble du processus. Si l’hôte est inaccessible, l’échec survient au bout de cinq secondes plutôt que de trente, ce qui a une grande importance lorsque l’on parcourt une liste de mille URL.
Choisir des valeurs qui ne sont pas des approximations
L'approche habituelle consiste à choisir un chiffre rond et à l'ajuster à la hausse chaque fois qu'une opération échoue. Cela conduit à une valeur suffisamment élevée pour que le délai d'expiration ne serve plus à rien.
Une meilleure méthode nécessite une commande supplémentaire. curl peut indiquer où le temps s'est réellement écoulé :
curl -o /dev/null -s -w "dns: %{time_namelookup}\nconnect: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n" https://example.com
Exécutez cette commande sur votre cible réelle vingt ou trente fois et vous obtiendrez une distribution plutôt qu’une estimation. Ensuite :
Définissez --connect-timeout à partir de time_appconnect. Prenez la valeur p95 et doublez-la approximativement. Le temps de connexion est principalement déterminé par les allers-retours réseau et est relativement stable ; s’il prend deux fois plus de temps que d’habitude, c’est qu’il y a véritablement un problème et non pas simplement un ralentissement.
Définissez --max-time à partir de time_total. Ici, le multiplicateur doit être plus généreux — trois à cinq fois le p95 — car le temps total dépend de la taille de la réponse et de la charge du serveur, deux facteurs qui varient légitimement. Une valeur trop stricte de --max-time produit des scripts instables qui échouent lors de simples jours difficiles.
Deux ajustements spécifiques à la charge de travail. Si vous téléchargez des fichiers volumineux, --max-time n’est absolument pas l’outil adapté, car un téléchargement légitime peut dépasser n’importe quelle limite fixe raisonnable — utilisez plutôt l’option basée sur la vitesse ci-dessous. Et si vous appelez une API qui effectue un véritable travail côté serveur, renseignez-vous sur son propre délai d’expiration et définissez le vôtre à une valeur légèrement supérieure ; un délai d’expiration de 10 secondes pour un service qui renvoie une réponse au bout de 12 secondes signifie que vous payez pour le travail effectué et que vous perdez le résultat.
Précision au centième de seconde et à la milliseconde
Ces deux options acceptent les nombres décimaux, en utilisant un point comme séparateur, quel que soit votre paramètre régional. Cette fonctionnalité est prise en charge depuis la version 7.32.0 de curl.
curl --connect-timeout 0.5 -m 2.5 https://example.com
Une demi-seconde pour se connecter, deux secondes et demie au total. Utile pour les contrôles d'intégrité et pour toute boucle où une seconde entière d'attente par échec finit par s'accumuler.
Une mise en garde à connaître : la précision diminue à mesure que la valeur augmente. La documentation de curl indique que le délai d’expiration réel perd en précision à mesure que la précision décimale du délai spécifié augmente. Écrire --max-time 30.001 n’apporte pas de différence significative par rapport à --max-time 30. Les décimales sont destinées aux valeurs inférieures à la seconde ; au-delà de quelques secondes, utilisez des nombres entiers.
L’option associée --expect100-timeout accepte également les décimales. Elle contrôle le temps pendant lequel curl attend une réponse « 100 Continue » avant d’envoyer le corps de la requête ; la valeur par défaut est d’une seconde. Si vous envoyez des corps de requête volumineux via POST à un serveur qui ne renvoie jamais de « 100 Continue », vous payez cette seconde à chaque requête — réduisez-la ou désactivez cette attente avec -H "Expect:".
Détection des transferts bloqués qui n'atteignent jamais le délai d'expiration
Voici le problème. Un transfert qui envoie un octet toutes les quelques secondes n'est jamais inactif ; par conséquent, aucun délai d'expiration au niveau de la connexion ne se déclenche, et si la valeur « --max-time
» est définie à un niveau suffisamment élevé pour les téléchargements volumineux légitimes, elle ne se déclenchera pas non plus. La requête avance tout simplement au ralenti.
Les options --speed-limit
et --speed-time
permettent de gérer ce cas. D’après le manuel : « Si un téléchargement est plus lent que --speed-limit
octets par seconde pendant une période de --speed-time
, le transfert est interrompu. »
curl --speed-limit 1000 --speed-time 30 -O https://example.com/large-file.zip
Si le débit reste inférieur à 1 000 octets par seconde pendant 30 secondes consécutives, curl interrompt le téléchargement — là encore avec le code de sortie 28. Un téléchargement qui s’effectue pendant six heures à un rythme satisfaisant n’est pas affecté. Un téléchargement qui stagne est interrompu au bout de trente secondes.
Il s’agit du délai d’expiration approprié pour tout élément de taille imprévisible, et il s’intègre bien :
curl --connect-timeout 5 --speed-limit 1000 --speed-time 30 -O https://example.com/large-file.zip
Échec rapide sur un hôte inactif, pas de limite globale, mais un détecteur de ralentissement permanent. Pour les téléchargements de fichiers en particulier, ce modèle a sa place dans chaque script — consultez notre guide sur le téléchargement de fichiers avec curl pour connaître les options associées.
Les délais d'expiration et les tentatives de réessai interagissent mal par défaut
C’est là que beaucoup se font piéger. L’option `
--retry N
fait quecurl réessaie jusqu’à N fois en cas d’erreurs transitoires. Ce qu’on oublie facilement, c’est que l’option ``--max-time
s’applique à *chaque tentative*, et non à la commande dans son ensemble, et quecurl` attend entre chaque tentative en appliquant un délai d’attente exponentiel commençant à une seconde et doublant à chaque fois.
Ainsi, ceci :
curl -m 10 --retry 5 https://example.com
peut légitimement prendre bien plus d’une minute : cinq tentatives pouvant durer jusqu’à dix secondes chacune, plus des délais d’attente de 1, 2, 4, 8 et 16 secondes. Si vous l’avez écrit en vous attendant à un plafond de dix secondes, vous vous êtes trompé d’un facteur six.
--retry-max-time
est la solution. Elle limite la durée totale consacrée aux tentatives :
curl -m 10 --retry 5 --retry-max-time 40 https://example.com
Désormais, curl cesse de lancer de nouvelles tentatives une fois que 40 secondes se sont écoulées. Notez bien la formulation : il ne lancera pas de nouvelle tentative après la limite, mais une tentative déjà en cours se poursuivra jusqu’à son propre --max-time
. Le pire cas réel correspond à --retry-max-time
plus un --max-time
.
--retry-delay
remplace le délai d’attente exponentiel par un délai fixe, ce qui rend la durée d’exécution totale prévisible :
curl -m 10 --retry 3 --retry-delay 2 --retry-max-time 40 https://example.com
Autre indicateur à connaître : par défaut, ``--retry`
ne se déclenche que dans un ensemble restreint de conditions transitoires. ``--retry-all-errors
` élargit considérablement ce champ — le manuel décrit cette option comme permettant de réessayer « toutes les erreurs transitoires, y compris les codes de réponse FTP 4xx et 5xx ». C’est vraiment utile dans les scripts fonctionnant sur des réseaux instables, mais vraiment dangereux face à une requête POST non idempotente. Réfléchissez bien avant de l’ajouter.
Délais d'expiration lorsque vous passez par un proxy
Ajoutez -x
et le comportement en matière de délai change, car il y a désormais deux connexions au lieu d'une seule : celle entre vous et le proxy, et celle entre le proxy et la cible.
curl -x http://user:pass@proxy.example.com:9000 --connect-timeout 10 -m 45 https://example.com
Trois éléments se comportent différemment par rapport au cas d'une connexion directe.
**--connect-timeout
mesure le temps de transit entre vous et le proxy, et non celui entre le proxy et la cible.** Pour le HTTPS, curl envoie une requête « CONNECT
» et le proxy établit la connexion vers la cible ; le temps nécessaire à cette opération est comptabilisé dans « --max-time
», et non dans « --connect-timeout
». Un délai d’expiration de connexion court ne vous protégera donc pas contre un proxy qui accepte votre connexion rapidement, mais met ensuite vingt secondes pour atteindre la cible.
Les proxys résidentiels sont plus lents, et ce à juste titre. Le trafic transite par une véritable connexion grand public ; un surcroît de quelques centaines de millisecondes est donc normal et ne constitue pas un dysfonctionnement. Des valeurs de délai d’expiration réglées pour une connexion directe entraîneront des échecs qui ressembleront à des proxys défaillants, alors qu’il s’agit en réalité d’un phénomène physique. Effectuez des mesures via le proxy à l’aide de la commande -w
ci-dessus et définissez les valeurs à partir de ces mesures, et non à partir de vos chiffres de connexion directe.
Les échecs sont ambigus. Un code de sortie 28 via un proxy peut signifier que le proxy est lent, que la cible est lente ou que la cible bloque délibérément votre requête. Pour les distinguer, il faut tester les composants séparément, ce qui constitue un sujet suffisamment vaste pour que nous ayons rédigé un guide dédié au test des proxys.
Une approche pratique pour les requêtes via un proxy : un délai d’--connect-timeout
généreux (10 s), un délai d’--max-time
défini en fonction du comportement mesuré plutôt que d’une simple hypothèse, et pas de --retry-all-errors
, car via un proxy, un code 5xx signifie souvent que la cible vous refuse l’accès plutôt qu’elle traverse un moment difficile, et une nouvelle tentative ne ferait qu’empirer la situation.
Interprétation du code de sortie
Le code de sortie de curl vous indique à quelle étape l'échec s'est produit, ce qui représente davantage d'informations que la plupart des scripts ne prennent la peine d'exploiter.
| Code | Nom | Signification |
|---|
| 6 | CURLE_COULDNT_RESOLVE_HOST | Échec DNS — aucun délai d'attente |
| 7 | CURLE_COULDNT_CONNECT | « Échec de la fonction connect() vers l’hôte ou le proxy » |
| 28 | CURLE_OPERATION_TIMEDOUT | « Le délai d’expiration spécifié a été atteint » |
| 56 | CURLE_RECV_ERROR | Échec de la réception des données réseau — connexion interrompue en cours de transfert |
Les descriptions sont tirées de la référence des erreurs libcurl.
La distinction entre les codes 7 et 28 est utile. Le code 7 signifie que la connexion a été activement refusée — une réponse a été renvoyée rapidement pour indiquer « non ». Le code 28 signifie qu’aucune réponse n’a été reçue à temps. Le premier indique généralement un port incorrect ou un service fermé ; le second indique un paquet perdu, un pare-feu filtrant silencieusement ou un hôte véritablement surchargé. Il est raisonnable de réessayer en cas de code 28, mais cela est généralement inutile pour le code 7.
Dans un script :
curl --connect-timeout 5 -m 30 -sS https://example.com > out.txt
case $? in
0) echo "ok" ;;
6) echo "dns failure" ;;
7) echo "connection refused" ;;
28) echo "timed out" ;;
*) echo "other failure" ;;
esac
Notez que les trois mécanismes de délai d’expiration — --max-time, --connect-timeout et la paire de limites de vitesse — renvoient le code 28. Le code de sortie indique qu’une limite a été atteinte, sans préciser laquelle. Si vous avez besoin de le savoir, utilisez -w "%{time_total}" et comparez les résultats avec vos valeurs configurées.
Quand ne pas définir de délai d'expiration
Contrairement à ce que l'on conseille généralement, il existe des cas où un délai d'expiration n'est pas la bonne solution.
Téléchargements interactifs. Si vous saisissez une commande curl dans un terminal pour récupérer un fichier volumineux, c'est vous qui fixez le délai d'expiration. Vous pouvez voir la barre de progression et appuyer sur Ctrl-C. Ajouter -m dans ce cas ne fait qu’entraîner la frustration d’un téléchargement qui s’interrompt à 90 %.
Flux de longue durée. Événements envoyés par le serveur, suivi de journaux, réponses fragmentées qui restent ouvertes par conception — --max-time mettra fin à ces flux exactement au mauvais moment. Utilisez --speed-limit et --speed-time si vous avez besoin d’un détecteur de blocage, ou rien du tout.
Tout ce qui est déjà soumis à une limite externe. Si curl s’exécute sous timeout(1), une unité systemd avec RuntimeMaxSec, ou une étape de CI disposant de son propre budget, une deuxième couche n’apporte rien d’autre qu’un deuxième chiffre à synchroniser. Choisissez la couche qui génère le message d’erreur que vous souhaitez lire et configurez-la à cet endroit.
Pour remédier à une cible lente. Un délai d’expiration fait échouer plus rapidement une requête lente. Il ne la fait pas aboutir. Si votre véritable problème est qu’un serveur met 40 secondes à répondre, les options sont la mise en cache, la pagination, un point de terminaison différent ou une discussion avec la personne qui le gère — et c’est là que nous allons répéter la mise en garde du début, car c’est le problème le plus courant pour lequel les gens achètent des proxys et l’un des rares problèmes que les proxys ne peuvent absolument pas résoudre. Nos tarifs commencent à 0,79 $/Go pour le trafic résidentiel et à 0,14 $/Go pour le trafic de centre de données, selon les informations disponibles en septembre 2026, et aucun d’entre eux ne permettra d’accélérer un serveur d’origine lent.
Questions fréquentes
Quel est le délai d’expiration par défaut dans curl ?
Il n’y a pas de délai d’expiration global par défaut : une fois connecté, curl attend indéfiniment une réponse. La phase de connexion a toutefois un délai par défaut de 300 secondes. C’est pourquoi l’option -m est importante dans les scripts : sans elle, une requête bloquée bloque le script.
Quelle est la différence entre --max-time et --connect-timeout ?
L’option --connect-timeout ne couvre que la résolution DNS et les handshakes TCP/TLS/QUIC, et cesse de s’appliquer une fois la connexion établie. L’option --max-time couvre l’ensemble de l’opération du début à la fin, y compris le transfert de la réponse. Utilisez les deux : un délai d’expiration de connexion court pour détecter rapidement les hôtes inactifs, et un délai maximal plus long pour la limite globale.
Pourquoi ma commande curl prend-elle plus de temps que le délai d’expiration que j’ai défini ?
C’est presque toujours dû aux tentatives de réessai. --max-time s’applique à chaque tentative, et --retry ajoute à la fois des tentatives supplémentaires et un délai d’attente exponentiel entre celles-ci. Ajoutez --retry-max-time pour limiter le nombre total de tentatives, et n’oubliez pas que le pire scénario correspond à cette valeur plus une --max-time supplémentaire.
Comment définir un délai d’expiration curl en millisecondes ?
Utilisez une valeur décimale : --connect-timeout 0.25 correspond à 250 millisecondes. Les options --max-time et --connect-timeout acceptent toutes deux les nombres décimaux séparés par un point, une fonctionnalité prise en charge depuis la version 7.32.0 de curl. Il est préférable de ne pas dépasser quelques secondes ; pour des valeurs plus élevées, la précision de la partie décimale se dégrade.
Quel code de sortie curl renvoie en cas de délai d’expiration ?
28, CURLE_OPERATION_TIMEDOUT. Les trois mécanismes de délai d’expiration renvoient ce code ; celui-ci indique donc qu’une limite a été atteinte, mais sans préciser laquelle. À distinguer des codes 7 (connexion refusée) et 6 (échec DNS), qui ont une signification différente et ne doivent généralement pas faire l’objet d’une nouvelle tentative.
Comment limiter la durée d’un téléchargement lent sans interrompre les fichiers volumineux ?
Utilisez --speed-limit et --speed-time à la place de --max-time. Ces options n’interrompent le téléchargement que lorsque le débit reste en dessous d’un seuil pendant une période prolongée ; ainsi, un téléchargement légitime de plusieurs heures n’est pas affecté, tandis qu’un téléchargement bloqué est rapidement interrompu.
Les délais d’expiration fonctionnent-ils différemment via un proxy ?
Oui. --connect-timeout mesure uniquement votre connexion au proxy ; la connexion du proxy vers la cible est prise en compte par --max-time. Les proxys résidentiels ajoutent également une latence réelle, de sorte que les valeurs réglées pour les connexions directes produiront de faux échecs. Effectuez la mesure via le proxy et définissez les valeurs en fonction de celle-ci.
Puis-je définir un délai d’expiration uniquement pour la résolution DNS ?
Pas en tant qu’option distincte — le DNS est inclus dans --connect-timeout. Si vous avez besoin de limiter spécifiquement le DNS, effectuez la résolution séparément et transmettez le résultat avec --resolve, ce qui ignore complètement la recherche effectuée par curl.
En conclusion
Deux options couvrent pratiquement tous les cas de figure : « --connect-timeout » pour un arrêt rapide lorsqu’un hôte est inaccessible, et « --max-time » pour définir la limite maximale globale. Définissez toujours ces deux options, dans chaque script. La valeur par défaut, qui consiste à attendre indéfiniment, est un choix raisonnable pour un outil interactif, mais catastrophique pour l’automatisation.
Il convient de rappeler les deux points qui posent le plus souvent problème. --max-time s’applique à chaque tentative ; ainsi, toute utilisation de --retry doit être accompagnée de --retry-max-time, sans quoi votre commande de dix secondes se transformera en une commande d’une minute. De plus, une limite de temps fixe n’est pas adaptée aux transferts de taille imprévisible : utilisez --speed-limit avec --speed-time pour obtenir un détecteur de blocage qui ne perturbera pas les téléchargements légitimes de longue durée.
Définissez les valeurs à partir de mesures plutôt qu’à partir d’un chiffre rond qui vous semble correct. Une seule exécution de curl -w sur votre cible réelle vous fournit une distribution, et un délai d’expiration dérivé de cette distribution ne se déclenche que lorsqu’il y a véritablement un problème, et non pas simplement lorsque le réseau connaît un après-midi difficile.