Resumen

  • RFC 5229 incorporó set, la expansión de cadenas y las variables de coincidencia, pero solo cuando el script declaraba expresamente la capacidad variables.
  • Esa memoria seguía acotada: las capturas dependían del flujo de control, los valores solo eran visibles en el script en ejecución y los límites de cada implementación podían truncarlos.

El filtro necesitaba un poco de memoria, no un servidor más potente

En enero de 2008, Sieve ya tenía una función reconocible: filtrar mensajes al entregarlos. La especificación base describía un lenguaje útil, pero deliberadamente limitado. No ofrecía variables ni bucles y tampoco permitía ejecutar comandos del sistema. No eran meras funciones pendientes que cualquier extensión pudiera añadir sin más: aquellas ausencias marcaban lo que un filtro escrito por el usuario podía pedirle al servidor de correo.

RFC 5229 abrió una parte de ese límite con cuidado. Un script podía declarar require "variables"; a partir de ahí, set almacenaba una cadena con nombre, que podía insertarse en otra cadena o someterse a una prueba. Una coincidencia con comodines podía exponer el resultado completo como ${0} y sus fragmentos como ${1}, ${2} y sucesivos. Así, una regla podía extraer de una cabecera el nombre de una lista, incorporarlo a una ruta de buzón y evitar repetir el mismo texto en varios lugares.

Eso no equivale a darle al filtro memoria duradera. El RFC dice que las variables solo son visibles para el script que se está ejecutando. No define un almacén común a todo el buzón, un registro de mensajes previos ni estado compartido entre usuarios. La palabra «variable» suena amplia; el objeto estandarizado es más pequeño: un nombre asociado a texto durante la ejecución de ese script.

Declarar la capacidad formaba parte del modelo de seguridad

El script debía solicitar la capacidad antes de usarla. Sin variables, la interpretación de las cadenas no cambiaba de forma implícita. En un lenguaje extensible, esto importa: una función presupone tanto una operación como un acuerdo explícito entre el script y el intérprete de que esa operación está disponible.

La expansión ocurría cuando el flujo llegaba a la instrucción y empleaba los valores vigentes en ese momento. Solo se hacía una pasada. Una referencia a un nombre no definido se sustituía por una cadena vacía, y los nombres no distinguían mayúsculas de minúsculas. La sintaxis era breve, pero algunos errores podían pasar inadvertidos: una errata podía hacer desaparecer un fragmento sin producir un fallo evidente. Si el valor insertado contenía otra referencia ${...}, no se expandía de nuevo en una segunda pasada.

La extensión ofrecía pocas transformaciones: cambio de mayúsculas ASCII, modificación de la primera letra, escape de comodines y cálculo de longitud. También añadía la prueba string. No incorporaba operaciones aritméticas, bucles ni ejecución de código arbitrario. «Más expresivo» significaba que el script podía nombrar y reutilizar unas cuantas cadenas, no que pudiera hacer cualquier cosa.

Una captura depende de la rama que sí se ejecutó

Las variables de coincidencia hacen que el flujo de control forme parte de los datos. RFC 5229 exige evaluar las pruebas de izquierda a derecha y detenerse cuando ya se conoce el resultado booleano. En anyof (true, header :matches ...), por ejemplo, no se llega a evaluar la prueba de cabecera; por tanto, no produce capturas. Una coincidencia posterior que sí tenga éxito puede reemplazar la lista anterior. Una prueba fallida no aporta fragmentos nuevos. En reglas complejas, confiar en ${1} exige saber qué prueba llegó a ejecutarse.

Tampoco todas las extensiones de coincidencia heredan automáticamente ese efecto. RFC 5173, publicado tres meses después, traza una frontera reveladora: con variables habilitada, las referencias incluidas en las claves de la prueba body sí se expanden, pero las coincidencias con comodines de esa prueba no deben llenar las variables de captura. Los estándares permiten algunas combinaciones y, a la vez, se niegan a tratar como idénticas operaciones que solo parecen iguales.

Los límites mínimos convierten esta cautela en una obligación de implementación: al menos 128 variables, nombres de 32 caracteres o más, valores de al menos 4.000 caracteres y capturas ${1} a ${9}. Si el valor superaba la capacidad efectiva del servidor, convenía detectarlo al compilar; si solo se descubría durante la ejecución, debía truncarse y no tratarse como error. Por eso la sección de seguridad desaconseja guardar estructuras grandes y sensibles, y advierte que el remitente puede controlar el texto capturado.

Un largo historial de borradores no demuestra adopción

El historial del Datatracker se remonta a borradores individuales de marzo de 2003; las versiones del grupo de trabajo Sieve aparecen desde finales de 2004 y continúan en varias revisiones durante 2005. El informe del IESG identifica el documento como obra del grupo Sieve. La aprobación de 2006 y la publicación de RFC 5229 en enero de 2008 figuran como hitos distintos. Esa cronología no explica por qué duró el proceso ni cuántos servidores incorporaron la extensión.

La nota de Heng Lu sobre la «especificación inicial mínima» ofrece una lente: require deja que una base pequeña conviva con funciones futuras que cada script activa localmente. «Running-Code Primacy» recuerda que la publicación de una capacidad no prueba que un servidor concreto la implemente o habilite. Su análisis de las capas de realidad ayuda a separar la declaración del script, el estado del intérprete, la conducta del servidor y lo que termina viendo el usuario en su buzón. Son marcos interpretativos posteriores, no evidencia de lo que pretendían los autores del RFC.

El filtro podía recordar lo que capturó una coincidencia y reutilizar algunas cadenas con nombre. Eso, por sí solo, no demuestra que recordase intercambios anteriores, autenticase al remitente o confirmase dónde acabó el mensaje. El cambio histórico de RFC 5229 consistió en hacer más útil una costura declarada, no en eliminar el límite de Sieve.

Fuentes