¡Esta es una revisión vieja del documento!
Curl
curl significa “cliente para URL”. Es un cliente para lograr transferencias de datos por medio de Internet.
Una transferencia de internet es una carga o descarga empleando un protocolo específico (curl soporta varios de ellos), mientras que su punto final resulta identificado por medio de una URL.
Soporta una gran cantidad de protocolos, desde HTTP, FTP y TELNET a IMAP, LDAP, y GOPHER. Operae en 92 sistemas operativos en cuenta con más de 20 mil millones de instalaciones en todo el mundo. Curl está liberado bajo una licencia MIT ligeramente modificada.
curl comenzó originalmente en 1996 como un proyecto llamado httpget, de Rafael Sagula, quien luego transfirió el control del mismo a Daniel Stenberg. Daniel lo renombró a curl en 1998, y en 2000 dividió la funcionalidad de red de datos para colocarla en la biblioteca libcurl. Por lo cual curl en sí se trasnformó en un envolvedor para la línea de comandos alrededor de dicha biblioteca.
En total, Curl+libcurl cuentan con unas 160.000 líneas de código. Curl se actualiza cada 8 semanas y cuenta con unas 250 versiones (agosto de 2023).
Ciclo de Lanzamientos
Luego del lanzamiento, hay 10 días de espera, seguido por una ventana de 21 días para presentar funcionalidades nuevas, seguidas por un período de congelado de 25 días.
Curl cuenta con una extensa documentación de referencia. Puede verse una versión corta en línea con
curl –help
Para ver la versión completa, puedes probar con curl –manual | less
Opciones de la línea de Comando
Curl se utiliza para realizar transferencias en Internet, donde actúa como cliente, cargando y descargando datos desde un servidor remoto. Los datos pueden ser de cualquier tipo: texto, imágenes, audio, video, etcétera.
Curl soporta tanto protocolos no autenticados (como HTTP o FTP), como sus contrapartes autenticados (como HTTPS o SFTP). Los datos transferidos sobre un protocolo no autenticado pueden ser intereceptados y utilizados, de manera que siempre es mejor usar los autenticados. Curl puede desactivar la verificación de servidor con la opción –insecure, pero es mejor no hacer esto por seguridad.
Curl actualmente cuenta con unas 250 opciones.
Existen versiones cortas (con un guión)
curl -V
…y opciones largas (con guión doble):
curl --version
Todas las opciones están disponibles en el formato “largo”, pero las más usadas son las que usan la versión “corta”.
Opciones de Línea de Comandos
Algunas opciones son del tipo booleano. Podremos activarlas con
curl --silent http://httpbin/uuid
o apagarlas:
curl --no-silent http://httpbin/uuid
Algunas opciones aceptan argumentos
curl --output /tmp/uuid.json http://httpbin/uuid
Los argumentos que contienen espacios deben ir entrecomillados:
curl -o /dev/null --write-out "type: %{content_type}" http://httpbin/uuid
URLs
Curl soporta URLs (en realidad, URIs) de manera similar a lo que define la RFC 3986:
scheme://user:password@host:port/path?query#fragment
- scheme define un protocolo (como https o ftp). Se es omitido, curl intentará adivinarlo. Los usuarios y contraseñas son credenciales de autenticación (pasar las credenciales en la URL generalmente no se permite por motivos de seguridad).
- Host es el nombre de host, nombre de dominio o dirección IP del servidor.
- port es el número de puerto. Si se omite, curl usará el puerto por defecto asociado con el scheme (tal como 80 para http o 443 para https).
- path es la ruta al recurso en el servidor.
- query es usualmente una secuencia de pares
nombre=valorseparada por&.
Para curl, todo lo que comience con - o – es una opción, y todo lo demás es una URL.
Solicitud
Si debemos pasar un montón de parámetros de URL, la parte de la solicitud puede ser bastante larga. La opción –url-query permite especificar las partes a solicitar de forma separada:
curl http://httpbin/get --url-query "name=Alice" --url-query "age=25"
URL Múltiples
Curl acepta cualquier número de URLs, cada una de las cuales requiere un destino (ya sea un fichero o stdout). Por ejemplo, este comando guardará la primer UUID en /tmp/uuid1.json y la segunda UUID como /tmp/uuid.json:
curl -o /tmp/uuid1.json http://httpbin/uuid -o /tmp/uuid2.json http://httpbin/uuid && cat /tmp/uuid1.json && cat /tmp/uuid2.json
(de aquí en mas, en ocasiones mostraré comandos multilíneas a modo ilustrativo. En realidad curl espera una única línea o a lo sumo líneas divididas conm \)
La opción -O deriva el nombre de fichero desde la URL:
curl --output-dir /tmp -O http://httpbin/anything/one -O http://httpbin/anything/two && ls /tmp
Para guardar ambas respuestas en el mismo fichero, podemos usar la redirección:
curl http://httpbin/uuid http://httpbin/uuid > /tmp/uuid.json && cat /tmp/uuid.json
Englobado de URL
Curl expande automáticamente las expresiones englobadas en URLs a múltiples URLs específicas.
Pore ejemplo, este comando solicita tres rutas distintas (al, bt, gm), cada una con dos parámetros distintos (num=1 y num=2), para totalizar seis URLs:
curl --output-dir /tmp -o "salida_#1_#2.txt" http://httpbin/anything/{al,bt,gm}?num=[1-2] && ls /tmp
Podremos desactivar el englobado si usamos la opción –globoff si existen caracteres válidos []{} en las URLs indicadas. Luego Curl los tratará de manera literal.
Transferencias en paralelo
Es posible usar –parallel (-Z) para indicarle a Curl procesar las URLs de forma concurrente.
Fichero de Configuración
En la medida que se incrementa el número de opciones, el comando Curl se volverá más difícil de descifrar. Para hacerlo más legible, podremos preparar un fichero de configuración que liste una opción por línea (el – es opcional):
Config file output-dir /tmp show-error silent
Por defecto, Curl lee el fichero de configuración desde $HOME/.curlrc, pero puede cambiar esto indicándolo con la opción –config (-K):
curl --config /sandbox/.curlrc http://httpbin/uuid
Medidores de Progreso
Curl cuenta con dos medidores de progreso. Por defecto es verboso:
curl --no-silent http://httpbin/uuid
El otro es compacto:
curl --no-silent --progress-bar http://httpbin/uuid
La opción –silent apaga completamente el medidor:
curl --silent http://httpbin/uuid
Reseteo de estado
Cuando configuras opciones, se aplican a todas las URLs que procesa Curl. Por ejemplo, aquí ambos encabezados se envían a ambas URLs:
curl -H "x-num: one" http://httpbin/headers?1 -H "x-num: two" http://httpbin/headers?2
A veces esto no es lo que se desea. Para resetear el estado entre las llamadas a URLS, se usa la opción –next:
curl -H "x-num: one" http://httpbin/headers?1 --next -H "x-num: two" http://httpbin/headers?2
Curl Básico
Ahora que entendemos cómo funciona Curl y sus opciones, podremos ver sus opciones específicas.
–version (-V) explica todo sobre la versión instalada de curl:
curl -V
Lista linea a línea las versiones de Curl en sí y sus dependencias, la fecha de lanzamiento, los protocolos disponibles, y las características activadas.
–verbose (-v) hace que Curl sea verboso, lo que puede ser útil en depuración:
curl -v http://httpbin/uuid
Si –verbose es insuficiente podrías intentar con –trace (el - envía la salida de trace a stdout):
curl --trace - http://httpbin/uuid
o bien –trace-ascii:
</code bash>
curl –trace-ascii - http://httpbin/uuid
</code>
Usa –write-out (-w) para extraer información específica sobre la respuestas. Soporta más de 50 variables. Por ejemplo, aquí extraemos el código de status y la respuesta del tipo de contenido:
curl -w "\nstatus: %{response_code}\ntype: %{content_type}" http://httpbin/status/429
…o algunos encabezados de la respuesta:
curl -w "\ndate: %header{date}\nlength: %header{content-length}" http://httpbin/status/429
Descargas
–remote-name (-O) le dice a curl que guarde la salida a un fichero especificado por la URL, (específicamente, por la parte que sigue a la última / de ésta). A menudo se usa en conjunto con –output-dir, lo que le dice a Curl donde poner exactamente el fichero a guardar:
curl --output-dir /tmp -O http://httpbin/uuid && cat /tmp/uuid
Si dicho directorio fuese inexistente, –output-dir no lo creará por tí. Usa –create-dirs para que esto suceda:
curl --output-dir /tmp/alguna/ruta --create-dirs -O http://httpbin/uuid && cat /tmp/some/place/uuid
Puedes usar –max-filesize (en bytes) para limitar el tamaño de respuesta permitido, pero a menudo no lo sabe por adelantado, de modo que podría fallar.
Reintentar
A veces puede que el huésped remoto no esté disponible. Para hacer caso a estas situaciones, Curl provee la opción –retry [num]. Si la solicitud falla, Curl reintentará pero no más de la cantidad de veces indicada num:
curl -i --retry 3 http://httpbin/unstable
(esta URL falla el 50% de las veces)
Podrás indicar la cantidad máxima de tiempo con la que Curl reintentará la solicitud con la opción –retry-max-time (en segundos) o el retrato entre reintentos con –retry-delay (también en segundos):
curl -i --retry 3 http://httpbin/unstable --retry-max-time 2 --retry-delay 1
Para Curl, “request failed” significa alguno de los códigos HHTP: 408, 429, 500, 502, 503 o 504. Si la solicitud falla con un error de “connection refused”, Curl no reintentará. Pero puede cambiarse esto con –retry-connrefused, o incluso activar los reintentos para todo tipo de problemas con –retry-all-errors.
Subidas
Curl a menudo se usa para bajar información (descargar) del servidor, pero también puede subirla. Para ello use la opción –upload-file (-T):
echo hola > /tmp/hola.txt && curl -T /tmp/hola.txt http://httpbin/put
Para cargas HTTP, Curl usa el método PUT.
Controles de Transferencia
Para detener descargas lentas, configure la velocidad de descarga mínima permitida (en bytes por segundo) con –speed-limit. Por defecto, Curl revisa la velocidad en intervalos de 30 segunods, pero esto puede cambiarse con –speed-time.
Por ejemplo, para permitir no menos de 10 bytes/segundo durante un intervalo de 3 segundos:
curl -v --speed-limit 10 --speed-time 3 http://httpbin/get
Para limitar el uso de ancho de banda, utilice –limit-rate. Acepta cualquier cantidad, desde bytes a petabytes:
curl --limit-rate 3 http://httpbin/get curl --limit-rate 3k http://httpbin/get curl --limit-rate 3m http://httpbin/get curl --limit-rate 3g http://httpbin/get curl --limit-rate 3t http://httpbin/get curl --limit-rate 3p http://httpbin/get
Otra cosa para limitar es el número de solicitudes concurrentes (ej, si descargas muchos ficheros). Usa –rate para tal cosa. Acepta segundos, minutos, horas o días:
curl --rate 3/s http://httpbin/anything/[1-9].txt curl --rate 3/m http://httpbin/anything/[1-9].txt curl --rate 3/h http://httpbin/anything/[1-9].txt curl --rate 3/d http://httpbin/anything/[1-9].txt
Resolución de nombre
Por defecto, curl usa tu servidor DNS para resolver los nombres de host a direcciones IP. Pero puedes forzarlo a resolver una IP específica con –resolve:
curl --resolve httpbingo.org:8080:127.0.0.1 http://httpbingo.org:8080/get
(este falla porque nadie escucha en 127.0.0.1)
O puedes incluso mapear un par hostname:puerto a otro par hostname:puerto con –connect-to:
curl --connect-to httpbingo.org:8080:httpbin:80 http://httpbingo.org:8080/get
(este funcionará bien)
Opciones a nivel conexión
También existen configuraciones a nivel conexión.
timeouts
Para limitar la cantidad de tiempo que curl se pasa interactuando con una única URL, usa –max-time (en fraccionales de segundo):
curl --max-time 0.5 http:/httpbin/delay/1
(este falla)
En lugar de limitar el tiempo total, puedes usar –connect-timeout para limitar sólo el tiempo que toma establecer la conexión en la red:
curl --connect-timeout 0.5 http:/httpbin/delay/1
(este funciona bien)
Credenciales
Casi nunca querrás pasar nombre de usuario y contraseña en el comando de curl en s{i. Una forma de evitarlo es usar el fichero ~/netrc. Especifica los nombres de host y credenciales para accederlos:
machine httpbin login pedro password chori machine ejemplo.com login pablo password pan
Pasa la opción –netrc para usar el fichero $HOME/.netrc, o –netrc-file para usar uno específico:
echo -e "machine httpbin\nlogin pedro\npassword chori" > /tmp/netrc && curl --netrc-file /tmp/netrc http://httpbin/basic-auth/pedro/chori
Estados de Salida
Cuando curl finaliza (“sale”), devuelve un valor numérico a la shell denominado status de salida. El éxito se señala con 0, y los errores tienen 100 valores distintos.
Por ejemplo, aquí hay un exit status 7 (“failed to connect to host”):
curl http://httpbin:1313/get
Puede acceder al status de salida a través de la variable de intérprete $?.
HTTP
Principalmente, Curl se usa para trabajar con HTTP, de modo que hablemos un poco de esto.
HTTP/1.x es un protocolo de texto plano que describe la comunicación entre el cliente y el servidor. El cliente envía mensajes como este:
POST /fulana/sitio HTTP/1.1
host: texto-plano.xyz
content-type: application/json
user-agent: curl/7.87.0
{
"message": "Hola Tercer Mundo!"
}
- La primer línea es una línea de solicitud. El método (POST) define la operación que el cliente desea realizar. La ruta (
/fulana/sitio) es la URL del recurso solicitado (sin poner protocolo, dominio ni puerto). La versión (HTTP/1.1) indica la versión del protocolo HTTP usado. - Las líneas siguientes (hasta la línea en blanco) son encabezados. Cada envabzado tiene un par clave-valor que le dice al servidor información útil sobre la solicitud. En este caso es el nombre de host del servidor (
texto-plano.xyz), el tipo de contenido (application/json) y la auto-identificación del cliente (user-agent). - Finalmente, estos son los datos que el cliente envía al servidor.
En respuesta a esto, el cliente recibirá un mensaje como este:
HTTP/1.1 200 OK
date: Mon, 28 Aug 2023 07:51:49 GMT
content-type: application/json
{
"message": "Como va!"
}
- La primer línea es la línea de status. La versión (
HTTP/1.1) indica la versión del protocolo HTTP. El código de status (200) informa si la solicitud fue exitosa o no, y porqué (existen muchos códigos de status para distintas situaciones). El mensaje de status es una descripción para el humano del código de status (HTTP/2 no la tiene). - Las siguientes líneas (hasta la línea en blanco) son encabezados. Al igual que los encabezados de solicitud, estos dan información útil sobre la respuesta del cliente.
- Finalmente, va la información real que el servidor envía al cliente.
El protocolo HTTP carece de estado, por lo cual cualquier estado deberá estar contenido dentro de la solicitud en sí (ya sea en el encabezado o en el cuerpo).
HTTP/2
HTTP/2, es el sucesor de HTTP/1.1, y en realidad es un protocolo binario. Sin embargo, curl presenta los mensajes de HTTP/2 en texto plano (al igual que en HTTP/1.1), así que para propósitos de uso de curl, podemos ignorar este hecho.
Método HTTP
Curl soporta todos los métodos HTTP (a menudos referidos como verbos).
GET (el que es por defecto, no necesita opciones):
curl http://httpbin/get
HEAD (-I/–head, sólo devuelve los encabezados):
curl -I http://httpbin/head
POST (-d/–data para datos o -F/–form para el formulario HTTP):
curl -d "name=fulana" http://httpbin/post
O cualquier otro método con –request (-X):
curl -X PATCH -d "name=fulana" http://httpbin/patch
Código de Respuesta
Típicamente, los códigos de status 2xx (200, específicamente) son considerados “éxitosos”, mientras que los 4xx son tratados como errores del lado del cliente, y los 5xx como errores del lado del servidor. Pero a curl no les importan los códigos, para él, cualquier respuesta HTTP obtenida es considerada un éxito:
curl http://httpbin/status/503 && echo OK
Para hacer que curl trate los códigos 4xx y 5xx como errores, use –fail (-f):
curl -f http://httpbin/status/503 && echo OK
Para presentar el código de respuesta, use –write-out con la variable response_code:
curl -w "%{response_code}" http://httpbin/status/200
Encabezados de Respuesta
Para presentar los encabezados de respuesta, use –head (-i):
curl -i http://httpbin/status/200
O guárdelos en un fichero usando –dump-header (-D):
curl -D /tmp/encabezados http://httpbin/status/200 && cat /tmp/encabezados
Cuerpo de Respuesta
Lo que devuelve por defecto curl es el cuerpo de respuesta, a menudo llamado payload o cabeza de guerra.
curl http://httpbin/get
Puede solicitar al servidor comprimir los datos por medio de –compressed, pero aún así curl los presentará descomprimidos:
curl --compressed http://httpbin/get
(note como el encabezado de solicitud Accept-Encoding ha cambiado)
Rangos
Para solicitar al servidor una sección de los datos en lugar del todo el entero, se usa la opción –range (r). Esto provocará que curl solicite el rango de bytes especificados.
Por ejemplo, para solicitar 50 bytes de datos a partir del 100° byte:
curl --range 100-150 http://httpbin/range/1024
Tenga presente que el server puede ignorar un pedido delimitado, y devolver la respuesta entera y completa (dependiendo de su propia configuración de seguridad).
Si está descargando datos de un servidor, también puede usar –continue-at (-C) para continuar la transmisión previa en un offset determinado:
curl --continue-at 1000 http://httpbin/range/1024
Versiones HTTP
Por defecto, curl usa HTTP/1.1 para el esquema de transmisión http, y HTTP/2 para https. Se puede cambiar esto con modificadores:
curl --http0.9 curl --http1.0 curl --http1.1 curl --http2 curl --http3
Para saber qué versión de HTTP soporta el server, use la variable de respuesta http_version:
curl -w "%{http_version}" http://httpbin/status/200
Solicitudes Condicionales
Las solicitudes condicionales son útiles cuando queremos evitar descargar datos ya descargados (asumiendo que la transmisión no está detenida). Curl soporta dos condiciones distintas: etiquetado de hora de fichero (“file timestamp”) y etiquetado electrónico (“etag”).
Para condiciones de Timestamp use –time-cond (-z).
Descargar datos sólo si el recurso remoto es más nuevo (la condición se retiene):
curl --time-cond "Aug 30, 2023" http://httpbin/etag/etag
…o mas viejo (la condición falla):
curl -i --time-cond "-Aug 30, 2023" http://httpbin/etag/etag
Las condiciones Etag son un poco mas completas. Un etag es un valor devuelto por el servidor que identifica unívocamente la versión actual del recurso solicitado. A menudo es un hash de los datos.
Para revisar un etag, curl debe primero guardarlo con –etag-save:
curl --etag-save /tmp/etags http://httpbin/etag/etag
…y usar –etag-compare en las solicitudes subsecuentes:
curl --etag-save /tmp/etags -o /dev/null http://httpbin/etag/etag && curl -i --etag-compare /tmp/etags http://httpbin/etag/etag
Las condiciones Timestamp confían en el encabezado de respuesta Last-Modified (“modificado por última vez”), de modo que si el servidor no lo ofrece, el recurso siempre será considerado el más actual. Lo mismo sucede para las condiciones etag y para el encabezado de respuesta Etag.
