Negociación de contenido

El soporte de Apache para la negociación de contenidos ha sido actualizado para adecuarse a la especificación HTTP/1.1. Apache puede escoger la mejor representación de un recurso basado en las preferencias proporcionadas por el navegador (browser) para los distintos tipos de medios, idiomas, conjunto de de caracteres y codificación. También proporciona un par de características que dan una mayor inteligencia en el manejo de peticiones de los navegadores cuando envían información de negociación incompleta.

El módulo mod_negotiation es el encargado de proveer la negociación de contenido y ya viene compilado por defecto.


Acerca de la negociación de contenidos

Un recurso puede estar disponible en diferentes representaciones. Por ejemplo, puede estar disponible en diferentes idiomas o en diferentes tipos de medio o una combinación de ambos. Una manera de tomar la decisión adecuada es la de dar al usuario una página índice y dejarle elegir. Sin embargo, a menudo es posible que el servidor haga una selección automáticamente. Esto funciona porque los navegadores pueden enviar como parte de su petición información sobre qué representación prefieren. Por ejemplo, un navegador podría indicar que prefiere ver información en francés y, si no fuera posible, en inglés. Los navegadores indican sus preferencias a través de cabeceras en la petición. Para pedir representaciones únicamente en francés, el navegador podría enviar algo así:

  Accept-Language: fr

Tenga en cuenta que esta preferencia se aplicará únicamente cuando haya una posibilidad de elección de representaciones y éstas varían por idioma.

Como ejemplo de una petición más compleja, digamos que el navegador ha sido configurado para aceptar francés e inglés, pero la preferencia es francés, y también ha sido configurado para aceptar varios tipos de medio, siendo el preferente HTML antes que texto plano o cualquier otro tipo de texto y configurado también para que GIF o JPEG sean los preferentes sobre cualquier otro tipo de medio, pero también permitiendo cualquier otro tipo de medio como último recurso:

  Accept-Language: fr; q=1.0, en; q=0.5
  Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6,
        image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1

Apache 1.2 soporta negociación de contenido "guiado por el servidor", tal y como los define la especificación HTTP/1.1. Soporta plenamente peticiones de cabecera de tipo Accept, Accept-Language, Accept-Charset y Accept-Encoding. Apache 1.3.4 también soporta negociación de contenido "transparente", que es un protocolo de negociación experimental definido en RFC 2295 y RFC 2296. No obstante, no ofrece soporte para "negociación de características" (feature negotiation) como la definen estas RFCs.

Un recurso es una entidad conceptual identificada por un URI (RFC 2396). Un servidor HTTP como Apache proporciona acceso a representaciones de recurso(s) dentro de su espacio de nombres, siendo cada representación en forma de una secuencia de bytes con un tipo de medio definido, un conjunto de caracteres, codificación, etc. Cada recurso puede ser asociado con cero, uno o más de una representación en un momento dado. Si hay disponibles múltiples representaciones, se referencia al recurso como negotiable (negociable) y cada uno de sus representaciones como variant (variante). Las maneras en las que las variantes para un recurso negociable varían se llaman dimensions (dimensiones) de la negociación.

Negociación en Apache

Para que un servidor pueda negociar un recurso, necesita que se le proporcione información sobre cada una de las variantes. Esto se hace de una de estas maneras:

Uso de un fichero de tipo mapa

Un tipo mapa es un documento que se asocia con el manejador llamado type-map (también conocido de tipo mime application/x-type-map) por cuestiones de compatibilidad con versiones anteriores de Apache). Tenga en cuenta que para utilizar esta característica debe tener un manejador configurado que defina un sufijo de fichero como type-map. La manera idónea de hacerlo es poner lo siguiente en el fichero de configuración del servidor:

  AddHandler type-map .var

Véanse los comentarios en el fichero de configuración para más detalles.

Los ficheros de tipo mapa tienen una entrada para cada variante disponible. Estas entradas consisten en líneas de cabecera contiguas en formato HTTP. Las entradas para diferentes variantes se separan con líneas en blanco. Las líneas en blanco no están permitidas dentro de una entrada. Existe el acuerdo de empezar un fichero mapa con una entrada para la entidad combinada como un todo (aunque esto no se requiere, y si está presente, será ignorado). A continuación se muestra un ejemplo de un fichero mapa:

  URI: foo

  URI: foo.en.html
  Content-type: text/html
  Content-language: en

  URI: foo.fr.de.html
  Content-type: text/html;charset=iso-8859-2
  Content-language: fr, de

Si las variantes tienen calidades origen (source qualities) diferentes, esto se puede indicar con el parámetro "qs" al tipo de medio:

  URI: foo

  URI: foo.jpeg
  Content-type: image/jpeg; qs=0.8

  URI: foo.gif
  Content-type: image/gif; qs=0.5

  URI: foo.txt
  Content-type: text/plain; qs=0.01

Los valores de qs pueden tomar valores en el rango comprendido entre 0.000 y 1.000. Tenga en cuenta que cualquier variante con un valor de qs igual a 0.000 nunca será elegido. A las variantes sin un parámetro qs se les da como valor 1.0. El parámetro qs indica la "calidad" relativa de esta variante comparada con el resto de variantes disponibles, independientemente de las capacidades del cliente. Por ejemplo, un fichero jpeg normalmente es de mayor calidad que un fichero ascii si se intenta representar una fotografía. Sin embargo, si la fuente que se quiere representar es ascii, la representación ascci tendrá una mayor calidad que un jpeg. De este modo, un valor qs es específico de una variante dada dependiendo de la naturaleza de la fuente que representa.

La lista completa de cabeceras reconocidas es la siguiente:

URI:
uri del fichero que contiene la variante (del tipo de medio, codificado con la codificación del contenido dado). Son interpretados como URLs relativos al fichero mapa. Deben estar en el mismo servidor y deben hacer referencia a ficheros a los que el cliente tenga garantizado el acceso cuando sean solicitados directamente.
Content-Type:
El tipo de medio charset, así los parámetros nivel y qs han de ser dados. En ocasiones se les referencia como tipos MIME. Los tipos de medio más frecuentes serían image/gif, text/plain o text/html; level=3.
Content-Language:
El idioma de la variante (variant), que está especificado como etiqueta de idioma en el estándar de Internet RFC 1766 (por ejemplo, en para el inglés, kr para el coreano etc.)
Content-Encoding:
Si el fichero está comprimido o codificado de algún otro modo en vez de estar en su forma original, esto indica cómo se hizo. Apache sólo reconoce codificaciones que estén definidas por una directiva del tipo AddEncoding. Generalmente esto incluye las codificaciones x-compress para ficheros comprimidos y x-gzip para ficheros comprimidos con gzip. El prefijo x- es ignorado en comparaciones de codificación.
Content-Length:
Tamaño del fichero. Al especificar la longitud del contenido en el tipo de mapa el servidor puede comparar los tamaños de los ficheros sin tener que chequear los ficheros en curso.
Description:
Es un texto que describe la variante en un formato legible por los humanos. Si Apache no pude encontrar ninguna variante apropiada que devolver, devolverá un error con una lista de las variantes disponibles. Esta lista incluye una descripción de las variantes en un formato legible.

Multivistas (multiviews)

Las MultiViews es una opción por cada directorio, o sea que puede ser configurado la directiva Options dentro de <Directory>, <Location> o <Files> en access.conf o (si se configura AllowOverride) en ficheros .htaccess files. Tenga en cuenta que Options All no configura MultiViews; usted debe preguntar especificar su nombre.

MultiViews actúa de la siguiente manera: si el servidor recibe una petición para /directorio/fichero y /directorio/fichero tiene habilitado MultiViews y /directorio/ficherono existe, entonces el servidor lee el directorio en busca de ficheros llamados fichero.* "falsifica" un tipo mapa que nombra a aquellos, asignándoles los mismos tipos de medio y codificaciones de contenido que tendrían si el cliente hubiera preguntado por uno de ellos por nombre. El servidor escogería entonces el que mejor se ajustara a los requerimientos del cliente.

MultiViews se puede usar también para búsquedas de ficheros referidos en la directiva DirectoryIndex, si el servidor está tratando de indexar un directorio. Si los ficheros de configuración especifican algo como

  DirectoryIndex index
el servidor elegirá entre index.html y index.html3 si ambos están presentes. Si ninguno de ellos existe y index.cgi está, el servidor lo ejecutará.

Si uno de los ficheros que encuentra cuando lea la directiva es un script CGI, no está claro qué es lo que pasaría. El código da esto un tratamiento especial: si la petición es de tipo POST o de tipo GET con QUERY_ARGS o PATH_INFO, al script se le da un ratio de calidad extremadamente alto. De otro modo se le da un ratio de calidad extremadamente bajo, lo que generalmente provoca que una de las otras vistas (si es que hay alguna) sea recuperada.

Los métodos de negociación

Después de que Apache haya obtenido una lista de variantes para un recurso, tanto desde un fichero tipo mapa o desde un fichero en el directorio, invoca uno de dos métodos posibles para decidir cuál es la mejor variante que devolver, si existe alguna. Para usar las características de negociación de contenido de Apache, no es necesario conocer ninguno de los detalles de cómo una negociación se da. A pesar de ello y para los interesados, este documento explica los métodos que se utilizan.

Existen dos métodos de negociación:

  1. La negociación llevada por el algoritmo de Apache se usa en casos normales. El algoritmo de apache se explica con más detalle abajo. Cuando se usa este algoritmo, Apache puede "falsear" el factor de calidad en alguna medida para conseguir un mejor resultado. El modo en que Apache puede falsear los factores de calidad se explica en más detalle abajo.
  2. La negociación transparente de contenido se utiliza cuando el navegador lo pide específicamente a través del mecanismo especificado en la RFC 2295. Este método de negociación le da al navegador pleno control sobre la decisión de cuál es la mejor variante, por lo que el resultado depende de los algoritmos específicos usados por el navegador. Como parte del proceso de negociación transparente, el navegador puede pedir a Apache que ejecute "un algoritmo de selección remota de variante", definida en RFC 2296.

Dimensiones de negociación

Dimensión Notas
Tipo de medio El navegador indica preferencias con el campo cabecera Accept header field. Cada elemento puede tener un factor de calidad asociado. La descripción de variante puede tener también un factor de calidad (el parámetro "qs").
Idioma El navegador indica las preferencias con el campo de cabecera Accept-Language. Cada elemento puede tener un factor de calidad. Las variantes se pueden asociar con ninguno, uno o más de un idioma.
Codificación El navegador indica preferencias con el campo de cabecera Accept-Encoding. Cada elemento puede tener un factor de calidad.
Conjunto de caracteres El navegador indica preferencias en el campo de cabecera Accept-Charset. Cada elemento puede tener un factor de calidad. Las variantes pueden indicar un conjunto de caracteres como parámetro del tipo de medio.

El algoritmo de negociación

Apache puede usar el siguiente algoritmo para seleccionar la mejor variante (si hay alguna) y devolverla al navegador. Este algoritmo no es muy configurable y opera del siguiente modo:

  1. Primero, para cada dimensión de la negociación, chequea el campo cabecera Accept* y asigna una cualidad a cada variante. Si la cabecera Accept* de cada dimensión implica que esta variante no es aceptable, la elimina. Si no queda ninguna variante, va al paso 4.
  2. Selecciona la mejor variante por medio de un proceso de eliminación. Cada uno de los siguientes test se realizan en orden. Cualesquiera variantes no seleccionadas en cada teste son eliminadas. Después de cada test, si sólo queda un variant, lo selecciona como el más apropiado y procede con el paso 3. Si queda más de un variant, pasa al siguiente test.
    1. Multiplica el factor de cualidad de la cabecera Accept con el factor de cualidad de la fuente para el tipo de medio de esa variante y selecciona las variantes con el valor más alto.
    2. Selecciona las variantes con la cualidad idioma de más alto valor.
    3. Selecciona los variants con la mejor concordancia de idioma, usando para ello, bien el orden de idiomas en la cabecera Accept-Language, bien el orden de idiomas en la directiva LanguagePriority.
    4. Escoge las variantes con el nivel más alto en el parámetro de medio (usado para dar la versión de los tipos de medio text/html).
    5. Elige variants con el mejor parámetro conjunto de caracteres del medio (charset media), proporcionado por la línea de cabecera en Accept-Charset header line. El conjunto de caracteres ISO-8859-1 es aceptado a menos que se excluya explícitamente. Las variantes con el tipo de medio text/* no explícitamente asociadas con un conjunto de caracteres particular son asumidas como ISO-8859-1.
    6. Selecciona aquellas variantes que tienen asociadas los parámetros del conjunto de caracteres que no sean ISO-8859-1. Si no existen estas variantes, selecciona todas los variantes en su lugar.
    7. Selecciona las variantes con la mejor codificación. Si existen variantes con una codificación que es aceptable para el agente de usuario (user-agent), selecciona sólo estas variantes. De otro modo, si hay una mezcla de variantes codificadas y no codificadas, selecciona únicamente las no codificadas. Tanto si todas las variantes están codificadas como si no lo están, selecciona todas.
    8. Selecciona las variantes con el contenido más pequeño.
    9. Selecciona la primera variante de las restantes. Esta será o bien la primera en la lista del fichero type-map file o, cuando las variantes se lean del directorio, el cual cuyo nombre de de fichero venga primero cuando se ordene usando el orden basado en códigos ASCII.
  3. Ahora el algoritmo ha seleccionado la "mejor" variante, por lo que la devuelve como respuesta. La cabecera HTTP de respuesta Vary se fija para indicar las dimensiones de la negociación (los navegadores y cachés pueden usar esta información cuando se meta en caché el recurso). Fin.
  4. Si hemos llegado aquí significa que ninguna variante ha sido seleccionada (porque ninguna es aceptable para el navegador). Entonces se devuelve un estado 406 (que significa que no hay una representación aceptable, "No acceptable representation") con una respuesta consistente en un documento HTML mostrando las variantes disponibles. También se configura la cabecera HTTP Vary con las dimensiones de la variante.

Manipular los valores de cualidad

A veces Apache cambia los valores de cualidad esperados en base a una estricta interpretación del algoritmo de negociación expuesto arriba. Esto se produce para obtener un mejor resultado del algoritmo para los navegadores que no envían una información completa o adecuada. Algunos de los navegadores más extendidos envían información de la cabecera Accept que daría en muchos casos como resultado la selección del variant erróneo. Si el navegador envía información completa y correcta, no se aplicará la manipulación.

Tipos de medio y caracteres comodín (wildcards)

Accept: petición de cabecera indica preferencias para tipos de medio. Puede incluir también tipos de medio con caracteres comodín, tales como "image/*" o "*/*", en el que * significa cualquier cadena. Así que una petición del tipo:

  Accept: image/*, */*
indicaría que cualquier tipo que comience con "image/" es aceptable, del mismo modo que lo sería cualquier otro (el ejemplo anterior, "image/*", es redundante). Algunos navegadores envían caracteres comodín de manera rutinaria además de los tipos explícitos que pueden manejar. Por ejemplo:
  Accept: text/html, text/plain, image/gif, image/jpeg, */*

La intención de esto es la de indicar que los tipos explícitamente listados son los preferidos, pero que si existe una representación diferente, también es correcto. Sin embargo, bajo el algoritmo básico, tal como se mostró más arriba, los caracteres comodín */* tienen exactamente igual preferencia que los otros tipos, así que no son los preferidos. El navegador debería haber enviado una petición con un valor de calidad (preferencia) más baja para */*, tal como:

  Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01

Los tipos explícitos no tienen ningún factor de calidad, de modo que toman el valor de preferencia 1.0 (el más alto). Al carácter comodín se le da un valor de preferencia bajo de 0.0.1, por lo que otros tipos sólo serán devueltos si ningún variant concuerda con un tipo explícitamente listado.

Si la cabecera Accept: no no contiene factores q de ningún tipo, Apache fija el valor q de "*/*", si existe, a 0.01 para emular el comportamiento deseado. También fija el valor q de los caracteres comodín del formato "type/*" a 0.02, por los que estos son los preferidos en vez de "*/*". Si cualquier tipo de medio en la cabecera Accept: contiene un factor q, estos valores especiales no se aplican, así que las peticiones desde navegadores que envían la información correcta de comienzo funcionan como se esperaba.

Variants sin idioma

Si algunos de los variant para un recurso en particular tienen un atributo de idioma y algunos otros no, a estos sin idioma se les da un factor de calidad de idioma muy bajo: 0.001.

La razón para configurar este factor de calidad a un valor tan bajo es la de permitir que se proporcione un variant por defecto cuando ninguno de los otros variant concuerde con las preferencias de idioma del navegador.

Por ejemplo, considere la situación con tres variants:

El significado de un variant sin idioma es que siempre es aceptable por el navegador. Si la cabecera Accept-Language incluye "en" o "fr" (o ambos), bien se devolverá el fichero foo.en.html, o bien el fichero foo.fr.html. Si el navegador no muestra ni "en" ni "fr", como aceptables, entonces se usará foo.html.

Extensiones a la negociación transparente de contenido

Apache amplía el protocolo de negociación transparente de contenido (RFC 2295) de la siguiente manera. Se utiliza un nuevo elemento de tipo {encoding ..} en las listas de variant para etiquetar variants que sólo están disponibles con una sola codificación de contenido. La implementación del algoritmo RVSA/1.0 (RFC 2296) es ampliado para reconocer variants codificados en la lista y para usarlos como candidatos cada vez que su codificación sea aceptable de acuerdo a la petición en la cabecera Accept-Encoding. La implementación de RVSA/1.0 no "redondea" los factores de calidad a 5 dígitos decimales antes de escoger el mejor variant.

Nota sobre hiperenlaces y convenciones de nombres

Si está utilizando negociación de idioma, puede escoger entre diferentes convenciones de nombres ya que los ficheros pueden tener más de una extensión y el orden de las extensiones es generalmente irrelevante (vea el documento mod_mime para más detalles).

Un fichero normal y corriente tiene una extensión de tipo MIME (por ejemplo, , html), quizás una extensión de codificación (como, por ejemplo, gz) y por supuesto una extensión de idioma (por ejemplo, en) cuando tenemos diferentes variants de idioma para ese fichero.

Ejemplos:

Algunos ejemplos de ficheros junto con hiperenlaces válidos y no válidos:
Fichero Hiperenlace válido Hiperenlance no válido
foo.html.en foo
foo.html
-
foo.en.html foo foo.html
foo.html.en.gz foo
foo.html
foo.gz
foo.html.gz
foo.en.html.gz foo foo.html
foo.html.gz
foo.gz
foo.gz.html.en foo
foo.gz
foo.gz.html
foo.html
foo.html.gz.en foo
foo.html
foo.html.gz
foo.gz

Mirando la tabla anterior, notará que es siempre posible usar en un hiperenlace el nombre sin ninguna extensión (por ejemplo, foo). La ventaja es que usted puede ocultar el tipo de fichero rsp de un documento y cambiarlo más tarde, por ejemplo, de html a shtml o cgi sin tener que cambiar las referencias del hiperenlace.

Si usted quiere continuar usando un tipo MIME en sus hiperenlances (por ejemplo foo.html), la extensión de idioma (incluyendo una extensión de codificación, si existe) debería estar en la parte derecha de la extensión de tipos MIME (por ejemplo, foo.html.en).

Nota sobre utilización de caché

Cuando un caché almacena una representación, lo asocia con la URL pedida. La próxima vez que la URL sea pedida, el caché podrá utilizar la representación en caché. Pero, si el recurso es negociable en el servidor, esto dará lugar a que solamente el primer variant pedido esté en caché y que los las siguientes coincidencias con la caché den respuestas erróneas. Para prevenir esto, Apache normalmente marca todas las respuestas que son devueltas después de una negociación de contenido como "no cacheables" por los clientes HTTP/1.0. Apache también soporta las características del protocolo de HTTP/1.1 para permitir el "cacheado" de respuestas negociadas.

Para las respuestas que vienen de un cliente compatible con HTTP/1.0 (tanto un navegador o una caché), se puede utilizar la directiva CacheNegotiatedDocs para permitir el "cacheado" de respuestas que están sujetas a negociación. Esta directiva puede ser especificada en la configuración del servidor o del host virtual y no toma ningún argumento. No tiene ningún efecto sobre peticiones de clientes HTTP/1.1.