\chapter{El protocolo HTTP/1.1}

\section{Introducción}

El Protocolo de Transferencia de HiperTexto (\emph{HyperText
Transfer Protocol}), HTTP, es un sencillo protocolo
cliente-servidor que articula los intercambios de información
entre los clientes Web y los servidores HTTP. Fue propuesto por
Tim Berners-Lee, atendiendo a las necesidades de un sistema global
de distribución de información como el \emph{World Wide Web}. La
especificación completa del protocolo HTTP en su última versión,
la 1.1, está recogida en el RFC 2068 \cite{http}.

El protocolo HTTP trabaja sobre el protocolo TCP y define una
arquitectura típica cliente-servidor: un servidor se mantiene
escuchando a través de un puerto de comunicaciones, por defecto el
80, esperando solicitudes de conexión de los clientes Web. Una vez
que se establece la conexión, el protocolo TCP se encarga de
mantener la comunicación y garantizar un intercambio de datos
libre de errores.

HTTP se basa en sencillas operaciones de petición/respuesta. Un
cliente establece una conexión con un servidor y envía un mensaje
con los datos de la petición. El servidor responde con un mensaje
similar, que contiene el estado de la operación y su posible
resultado. Todas las operaciones se realizan sobre un recurso u
objeto (documento HTML, aplicación CGI, archivo de imagen, etc.),
el cual es conocido por su URL.

Las principales características del protocolo HTTP son:

\begin{itemize}

\item Toda la comunicación entre los clientes y servidor se
realiza a partir de caracteres de 8 bits. De esta forma, se puede
transmitir cualquier tipo de documento, ya sea texto o datos
binarios, respetando su formato original.

\item Permite la transferencia de objetos multimedia. El contenido
de cada objeto intercambiado está identificado por su
clasificación MIME.

\item Existen tres tipos de peticiones básicas (existen más pero
no son muy utilizados) que un cliente puede realizar a un
servidor: solicitar un objeto (GET), enviar un objeto (POST), o
solicitar la información de un objeto (HEAD).

\item No mantiene el estado. Cada petición de un cliente a un
servidor no es influida por las peticiones anteriores. El servidor
trata cada petición como una operación totalmente independiente
del resto. Si se quisiera mantener el estado, sería necesario el
empleo de \emph{Magic Cookies}.

\end{itemize}

\section{Mensajes}

El diálogo entre el cliente y el servidor se establece a través de
mensajes.

\subsection{Estructura}

La estructura de un mensaje la siguiente:

\begin{verbatim}
<línea inicial>
[<cabeceras>]

[<cuerpo del mensaje>]
\end{verbatim}

La primera parte del mensaje, la línea inicial, es una línea de
texto en ASCII que finaliza con una secuencia CRLF (un carácter de
8 bits con el valor 13 seguido de otro con el valor 10). La
segunda parte, opcional, es el conjunto de cabeceras, cada una de
las cuales está formada por una o más líneas de texto en ASCII,
todas ellas delimitadas por la secuencia CRLF. El cuerpo del
mensaje, si existe, no tiene por qué ser texto. El tipo de los
datos incluidos en el cuerpo del mensaje vendrá especificado en
alguna de las cabeceras.

Los mensajes se clasifican en dos tipos: mensajes de petición,
enviados por el cliente al servidor, y mensajes de respuesta,
enviados por el servidor al cliente.

Para los mensajes de petición, la línea inicial tiene la siguiente
forma:

\begin{verbatim}
<Comando> <URL> <Protocolo>
\end{verbatim}

Como se puede ver, la línea de petición es dividida en 3 partes,
separadas entre sí por un solo espacio en blanco. El comando
especifica la acción a llevar a cabo sobre el objeto identificado
por la URL incluida. El protocolo especifica la versión el
protocolo que requiere el cliente. En el caso de la versión 1.1,
la cadena del protocolo sería \verb+HTTP/1.1+.

Un ejemplo de línea de petición, en la cual solicitamos una página
Web, sería la siguiente:

\begin{verbatim}
GET /mipagina.html HTTP/1.1
\end{verbatim}

En el caso de los mensajes de respuesta, a la línea inicial se le
llama línea de estado y tiene la siguiente estructura:

\begin{verbatim}
<protocolo> <código de estado> <frase aclaratoria>
\end{verbatim}

Al igual que ocurre con la línea inicial del mensaje de petición,
la línea de estado también se divide en tres partes, separadas
entre sí por un único espacio en blanco. El protocolo es la
versión del protocolo que acepta el servidor y sigue la misma
estructura que para los mensajes de petición. El código de estado
es un número decimal de tres dígitos con el código del resultado
del intento del servidor por llevar a cabo la acción requerida. La
última parte es una pequeña frase aclaratoria, de una sola línea,
del código de estado.

Un ejemplo de línea de estado devuelta por un servidor que no ha
encontrado el objeto especificado en la URL de la petición, podría
ser la siguiente:

\begin{verbatim}
HTTP/1.1 404 Not Found
\end{verbatim}

\subsection{Comandos}

Algunos de los comandos aceptados en la versión 1.1 del protocolo
HTTP son los siguientes:

\begin{itemize}
\item \emph{GET}: Se utiliza para solicitar el recurso u objeto
del servidor identificado por la URL.

\item \emph{HEAD}: Solicita información sobre un objeto, como
puede ser el tamaño, el tipo, la fecha de modificación, etc. Es
utilizado por los gestores de \emph{caches} de páginas o los
servidores \emph{proxy}, para conocer cuando es necesario
actualizar la copia que se mantiene de un fichero.

\item \emph{POST}: Sirve para enviar información al servidor, que
puede ser por ejemplo los datos contenidos en un formulario de una
página Web.

\item \emph{PUT}: Permite actualizar información de un objeto
determinado del servidor. Es similar a \emph{POST} pero en este
caso la información enviada al servidor debe ser almacenada en la
URL que acompaña al comando.

\end{itemize}

Otros de los comandos permitidos en HTTP/1.1 son \emph{OPTIONS},
\emph{TRACE} y \emph{DELETE}.

\subsection{Códigos de estado}

Existen cinco categorías de códigos de estado, organizadas por el
primer dígito del código:

\begin{itemize}

\item 1xx: Para mensajes informativos.

\item 2xx: Asociados con operaciones realizadas correctamente.

\item 3xx: Para informar de operaciones complementarias que se
deben realizar para finalizar la operación requerida por el
cliente.

\item 4xx: Indican error por parte del cliente, como puede ser
error de sintaxis en el mensaje de petición, o petición invalida.

\item 5xx: Indican error por parte del servidor, al no poder
completar una petición que realizó una petición aparentemente
correcta.

\end{itemize}

La lista de todos los códigos definidos para el protocolo HTTP/1.1
se muestra en la tabla \ref{tab:codigosHTTP}. Esta lista es la
lista básica que deben de soportar los clientes, pero se pueden
definir otros tipos códigos para aplicaciones específicas.

\begin{table}
\begin{center}
\begin{tabular}{|l|l|}
  \hline
  Código & Frase aclaratoria \\
  \hline
  100 & Continue \\
  101 & Switching Protocols  \\
  200 & OK \\
  201 & Created \\
  202 & Accepted \\
  203 & Non-Authoritative Information \\
  204 & No Content \\
  205 & Reset Content \\
  206 & Partial Content \\
  300 & Multiple Choices \\
  301 & Moved Permanently \\
  302 & Moved Temporarily \\
  303 & See Other \\
  304 & Not Modified \\
  305 & Use proxy \\
  400 & Bad Request \\
  401 & Unauthorized \\
  402 & Payment required \\
  403 & Forbidden \\
  404 & Not Found \\
  405 & Method Not Allowed \\
  406 & Not Acceptable \\
  407 & Proxy Authentication Required \\
  408 & Request Time-out \\
  409 & Conflict \\
  410 & Gone \\
  411 & Length Required \\
  412 & Precondition failed \\
  413 & Request Entity Too Large \\
  414 & Request-URI Too Large \\
  415 & Unsupported Media Type  \\
  500 & Internal Server Error \\
  501 & Not Implemented \\
  502 & Bad Gateway \\
  503 & Service Unavailable \\
  504 & Gateway Time-out \\
  505 & HTTP Version not supported \\
  \hline
\end{tabular}
\end{center}
\caption{Códigos de estado del protocolo HTTP/1.1.}
\label{tab:codigosHTTP}
\end{table}

 Los códigos de estado más comunes son los siguientes:

\begin{itemize}

\item 200 (``OK''): Operación realizada satisfactoriamente.

\item 201 (``Created''): La operación ha sido realizada
correctamente y como resultado se ha creado un nuevo objeto, cuya
URL de acceso se proporciona en el cuerpo de la respuesta. Este
nuevo objeto ya está disponible.

\item 202 (``Accepted''): La operación ha sido realizada
correctamente y como resultado se ha creado un nuevo objeto, cuya
URL de acceso se proporciona en el cuerpo de la respuesta. El
nuevo objeto no está disponible por el momento.

\item 204 (``No Content''): La operación ha sido aceptada, pero no
ha producido ningún  resultado de interés. El cliente no deberá
modificar el documento que está mostrando en este momento.

\item 301 (``Moved Permanently''): El objeto al que se accede ha
sido movido a otro lugar de forma permanente. El servidor
proporciona, además, la nueva URL en la variable \emph{Location}
de la respuesta.

\item 302 (``Moved Temporarily''): El objeto al cual se accede ha
sido movido a otro lugar de forma temporal. El servidor
proporciona además la nueva URL en la variable \emph{Location} de
la respuesta.

\item 304 (``Not Modified''): Cuando se hace un \emph{GET}
condicional, y el documento no ha sido modificado, se devuelve
este código de estado.

\item 400 (``Bad Request''): La petición tiene un error de
sintaxis y no es entendida por el servidor.

\item 401 (``Unauthorized''): La petición requiere una
autorización especial, que normalmente consiste en un nombre y
clave que el servidor verificará. El campo \emph{WWW-Authenticate}
informa de los protocolos de autentificación aceptados para este
recurso.

\item 403 (``Forbidden''): Está prohibido el acceso a este
recurso. No es posible utilizar una clave para modificar la
protección.

\item 404 (``Not Found''): La URL solicitada no existe.

\item 500 (``Internal Server Error''): El servidor ha tenido un
error interno, y no puede continuar con el procesamiento.

\item 501 (``Not Implemented''): El servidor no tiene capacidad,
por su diseño interno, para llevar a cabo el requerimiento del
cliente.

\item 503 (``Service Unavaliable''): El servidor está actualmente
deshabilitado, y no es capaz de atender el requerimiento.

\end{itemize}

\subsection{Cabeceras}

Las cabeceras son un conjunto de variables que se incluyen en los
mensajes HTTP con el fin de modificar su comportamiento o incluir
información información de interés. La estructura de una cabecera
es la siguiente:

\begin{verbatim}
<Nombre de la variable>: <valor>
\end{verbatim}

Los nombres de las variables se pueden escribir con cualquier
combinación de mayúsculas y minúsculas. Se debe incluir un espacio
en blanco entre el carácter \verb+':'+ y el valor de la variable.
No debe de existir ningún espacio en blanco antes del nombre de la
variable. El valor de la variable puede ocupar varias líneas,
todas ellas separadas por la secuencia CRLF, debiendo cumplir que
al inicio de cada una de ellas debe haber al menos un espacio en
blanco o un tabulador.

Existen cuatro tipos de cabeceras: cabeceras generales, cabeceras
de petición, cabeceras de respuesta y cabeceras de entidad.

Las cabeceras generales se pueden incluir tanto en los mensajes de
petición como en los mensajes de respuesta. Algunas de estas
cabeceras son las siguientes:

\begin{itemize}
\item \emph{Date}: Especifica la fecha local de la operación, la
cual debe incluir la zona horaria correspondiente.

\item \emph{Pragma}: Permite incluir información variada
relacionada con el protocolo HTTP en la petición respuesta que se
está realizando. Por ejemplo, un cliente puede incluir la cabecera
\verb+Pragma: no-cache+ para informar de que desea una copia nueva
del recurso especificado, ignorando la \emph{cache} que pueda
existir.

\item \emph{Connection}: Su uso se verá más tarde. Puede ser
empleada tanto como por el cliente como por el servidor para
indicarle el uno al otro que la conexión va a ser cerrada.

\item \emph{Transfer-Encondig}: Indica qué tipo de transformación
ha sido aplicada al cuerpo del mensaje con el fin de transmitirlo
de forma óptima.

\end{itemize}

Las cabeceras de petición sólo pueden ser incluidas en los
mensajes de petición. Algunas de estas cabeceras son las
siguientes:

\begin{itemize}
\item \emph{Accept}: Es un campo opcional que contiene una lista
de tipos MIME aceptados por el cliente.

\item \emph{Authorization}: Define la clave de acceso que envía un
cliente para acceder a un recurso  de uso protegido o limitado. La
información incluye el formato de autorización empleado, seguido
de la clave de acceso propiamente dicha.

\item \emph{From}: Campo opcional que contiene la dirección de
correo electrónico del usuario del cliente.

\item \emph{If-Modified-Since}: Permite realizar operaciones
\emph{GET} condicionales, en función de si la fecha de
modificación del objeto requerido es anterior o posterior a la
fecha proporcionada.

\item \emph{User-agent}: Indica el tipo y la versión del cliente
que realiza la petición.

\item \emph{Range}: Como se verá más adelante, el cliente puede
especificar mediante esta cabecera el rango de bytes que requiere
del recurso solicitado al servidor.

\item \emph{Host}: Especifica la dirección, y opcionalmente, el
puerto, del servidor al cual se le envía la petición. Todas las
peticiones HTTP/1.1 que pasen a través de Internet deben incluir
esta cabecera.

\end{itemize}

Las cabeceras de respuesta sólo pueden ser incluidas en los
mensajes de respuesta. Algunas de estas cabeceras son las
siguientes:

\begin{itemize}

\item \emph{Location}: Informa sobre la dirección exacta del
recurso al que se ha accedido. Cuando el servidor proporciona un
código de respuesta de la serie 3xx, este parámetro contiene la
URL necesaria para accesos posteriores a este recurso.

\item \emph{Server}: Especifica la cadena que identifica el tipo y
la versión del servidor.

\item \emph{WWW-Authenticate}: Cuando se accede a un recurso
protegido o de acceso restringido, el servidor devuelve un código
de estado 401 y utiliza este campo para informar de los modelos de
autentificación válidos para acceder a este recurso.

\item \emph{Accept-Ranges}: Esta cabecera es enviada por el
servidor para notificarle al cliente si acepta o no la posibilidad
de \emph{byte-ranging}.

\end{itemize}

Tanto los mensajes de petición como los de respuesta pueden
incluir datos, es decir, el cuerpo del mensaje. Las cabeceras que
contienen información relacionada con los datos almacenados en el
cuerpo del mensaje son denominadas cabeceras de entidad. Algunas
de las cabeceras de entidad son las siguientes:

\begin{itemize}

\item \emph{Content-Enconding}: Si los datos del cuerpo del
mensaje han sido codificados de alguna forma, por ejemplo, que
hayan sido comprimidos o encriptados, esta cabecera especifica el
tipo de codificación aplicada.

\item \emph{Content-Length}: Define la longitud total del cuerpo
del mensaje.

\item \emph{Content-Range}: Cuando se está leyendo rangos de
bytes, \emph{byte-ranging}, el mensaje de trocea en submensajes.
Cada submensaje posee esta cabecera que especifica de qué rango se
trata.

\item \emph{Content-Type}: Especifica el tipo MIME de los datos
incluidos en el cuerpo del mensaje. Cuando el servidor envía datos
a un cliente, el cliente utiliza el valor de esta cabecera para
saber cual es el tratamiento adecuado a aplicar a dichos datos.

\end{itemize}

\section{Características avanzadas}

\subsection{Mensajes \emph{chunkeados}}

El servidor puede trocear en bloques el mensaje de respuesta, con
el fin de poder transmitir los datos de forma óptima. Esto puede
ocurrir cuando la longitud del mensaje a transmitir sea excesiva o
cuando el servidor no conozca a priori el tamaño total de los
datos. En esta caso, al mensaje se le denomina mensaje
\emph{chunkeado} (\emph{chunked message}).

Imaginemos que realizamos una petición a un cliente HTTP/1.1 como
la siguiente:

\begin{verbatim}
GET /muyGrande.dat HTTP/1.1
Host: www.servidor.com

\end{verbatim}

El servidor decide trocear el mensaje, con lo cual, la respuesta
sería similar a como sigue:

\begin{verbatim}
HTTP/1.1 200 OK
Transfer-Enconding: chunked

3fe
Estos son los datos del bloque 1
y que tienen una longitud de
0x3FE bytes ...
a2
Y estos son los datos del bloque 2,
que tienen una longitud de
0xA2 bytes ...
0

\end{verbatim}

Como se puede apreciar, cuando el servidor decide trocear el
mensaje, incluye la cabecera \emph{Transfer-Encoding} con el valor
\emph{chunked}. En el ejemplo, el cuerpo del mensaje, que comienza
a partir de la línea en blanco situada justo después de las
cabeceras del mensaje, está dividido en dos trozos. Cada trozo
comienza con la longitud de los datos que contiene, expresada en
hexadecimal. Dicha longitud finaliza con la secuencia CRLF, a
partir de la cual comienzan los datos. Después de los datos existe
una secuencia CRLF. Después del último trozo se incluye un cero,
en ASCII, indicando que no existen más trozos. A continuación del
cero se incluye una secuencia CRLF, opcionalmente un conjunto de
cabeceras de entidad, y finalmente, otra secuencia CRLF. En el
ejemplo no se ha incluido ninguna cabecera de entidad, con lo cual
el mensaje de respuesta finaliza con una línea vacía. Las
cabeceras de entidad contendrían información acerca de los datos
de cada trozo.

Todo cliente de HTTP/1.1 debe ser capaz de recibir y decodificar
mensajes \emph{chukeados}.

\subsection{Conexiones persistentes}

En las versiones anteriores del protocolo HTTP, cada vez que un
cliente realizaba una petición a un servidor, éste establecía una
conexión, realizaba la petición, y una vez recibida la respuesta,
la conexión era cerrada. De esta forma, debía abrir y cerrar una
conexión por cada petición, lo que provocaba una sobrecarga de los
servidores y una congestión en Internet.

En la versión 1.1 del protocolo HTTP, las conexiones se vuelven
persistentes, es decir, el cliente puede realizar multitud de
peticiones con la misma conexión. Esto, que es algo disponible en
la mayoría de los protocolos cliente/servidor, no era posible
hasta el momento.

En HTTP/1.1 todas las conexiones son persistentes. El servidor
asume que el cliente desea tener abierta la conexión, a menos que
reciba la cabecera \emph{Connection} con el valor \emph{close}.
Por otra parte, el cliente también asumirá que el servidor
mantendrá abierta la conexión, a menos que reciba la cabecera
\emph{Connection} con el valor \emph{close}. Tanto el cliente como
el servidor, una vez reciben la cabecera \emph{Connection} con el
valor \emph{close}, deben cerrar su conexión.

A pesar de ser conexiones persistentes, muchos servidores
incluirán la cabecera \emph{Connection} con el valor \emph{close}
tras la primera petición, obligando al cliente a cerrar su
conexión. El cliente puede no obstante retrasar esto, incluyendo
en sus peticiones la cabecera \emph{Connection} con el valor
\emph{Keep-Alive}. El servidor mantendrá entonces abierta la
conexión el tiempo que tenga configurado.

El cliente que use conexiones persistentes debe limitar el número
de conexiones simultaneas que mantiene con un servidor determinado
como mucho a 2.

\subsection{\emph{Pipelining}}

Con la inclusión de la posibilidad de crear conexiones HTTP/1.1
persistentes, se añade también la de realizar \emph{pipelining}
con los mensajes. Esto quiere decir que el cliente puede enviar
múltiples peticiones seguidamente, sin tener que esperar, como
ocurría con versiones anteriores, a recibir la respuesta de una
petición para poder realizar otra. El servidor tiene la obligación
de enviar las respuestas en el mismo orden en el que recibió las
peticiones.

Lo único que es preciso tener en cuenta es que, como se comentó
anteriormente, el servidor podría incluir en alguna de sus
respuestas la cabecera \emph{Connection} con el valor
\emph{close}, y posteriormente cerrar la conexión. Esto, si sólo
disponemos de un sólo hilo para realizar todas las peticiones a la
vez, y luego esperar las respuestas, no existe mayor problema, ya
que terminaríamos de leer respuestas en cuanto se recibiera dicha
cabecera. Pero si decidiéramos optimizar aún más la comunicación,
y tuviésemos dos hilos, uno de los cuales fuese el encargado de
enviar todas las peticiones y el otro el encargado de ir
leyéndolas, en cuanto el que las lee recibiera la cabecera que
indica un cierre de la conexión, debería comunicárselo al hilo
encargado de las peticiones, si aún está en ejecución, para que
finalice.

\subsection{\emph{Byte-ranging}}

El protocolo HTTP/1.1 permite solicitar porciones
(\emph{byte-ranges}) de un determinado recurso u objeto del
servidor. Esto es especialmente útil para aplicaciones que no
requieren el contenido entero de un determinado archivo, sino
aquella parte que solicite de forma interactiva el usuario.

Un ejemplo de esta situación lo podemos encontrar en el
\emph{plug-in} de \emph{Acrobat} que es utilizado para visualizar
archivos PDF en los navegadores. De esta forma, el usuario no
tiene que esperar a recibir el documento completo para comenzar a
inspeccionar una parte del mismo.

Un servidor HTTP/1.1 no tiene obligación de ofrecer la posibilidad
de \emph{byte-ranging}. Si un servidor lo soporta, existe la
posibilidad, aunque tampoco es obligatorio, de que envíe la
cabecera \emph{Accept-Ranges} con el valor bytes (el único valor
permitido hasta el momento, y que indica que los rangos son en
unidades de bytes). Si un servidor no lo soporta existe la
posibilidad, aunque tampoco es obligatorio, de que envíe la
cabecera \emph{Accept-Ranges} con el valor \emph{none}. El
problema es que es posible que el servidor soporte
\emph{byte-ranging} pero no lo comunique. Si quisiéramos realizar
\emph{byte-ranging} sobre un servidor, del cual no hemos recibido
la confirmación de que lo soporta, pero tampoco la negación, y
éste no lo soportase, recibiríamos un código de error 501 (``Not
Implemented'').

El rango de bytes que se quiera se especifica en la cabecera
\emph{Range}. En una misma petición se puede especificar uno o más
de un rango. El valor de esta cabecera se forma de la siguiente
forma:

\begin{verbatim}
bytes=<rango1>,<rango2>,...,<rangoN>
\end{verbatim}

Los rangos se separan por comas. No debe existir espacio alguno
entre el carácter \verb+'='+ y la palabra \verb+'bytes'+, así como
entre el carácter \verb+'='+ y el primer rango especificado. Cada
rango de bytes se forma de la siguiente forma:

\begin{verbatim}
[<inicio>]-[<fin>]
\end{verbatim}

Tanto \emph{inicio} como \emph{fin} son números decimales. Si
ambos están presentes, \emph{inicio} representa el \emph{offset}
del primer byte a transmitir, incluido, y \emph{fin} representa el
\emph{offset} del último byte a transmitir, incluido también. Los
\emph{offset} son respecto al inicio del archivo. Si \emph{inicio}
está ausente, \emph{fin} representa el número de bytes del final
del archivo a transmitir. Si \emph{fin} está ausente, se asume que
es el final del archivo.

Algunos ejemplos serían:

\begin{itemize}
\item Los últimos 100 bytes:

\begin{verbatim}
bytes=-100
\end{verbatim}

\item Los primeros 100 bytes:

\begin{verbatim}
bytes=0-99
\end{verbatim}

\item Desde el byte 80 hasta el final del archivo:

\begin{verbatim}
bytes=80-
\end{verbatim}

\item El rango desde el byte 10 hasta el byte 15 y desde el 20 al
25:

\begin{verbatim}
bytes=10-15,20-25
\end{verbatim}

\end{itemize}

Cuando el servidor recibe una petición de uno o más
\emph{byte-ranges} de un archivo determinado, éste, en el caso de
responder satisfactoriamente, devolverá el código 206 (``Partial
Content''). La estructura de la respuesta del servidor es distinta
de si requerimos un sólo \emph{byte-range} o más de uno.

Imaginemos que solicitamos los primeros 100 bytes de un archivo,
de la siguiente forma:

\begin{verbatim}
GET /imagen.jpg HTTP/1.1 Host: www.servidor.com Range: bytes=0-99

\end{verbatim}

El servidor, en el caso de responder satisfactoriamente, enviaría
una respuesta similar a la siguiente:

\begin{verbatim}
HTTP/1.1 206 Partial Content
Server: Apache/1.3.12 (Win32)
ETag: "0-fffe-278427e3"
Accept-Ranges: bytes
Content-Length: 100
Content-Range: bytes=0-99/1024
Content-Type: image/jpeg

(Los 100 bytes iniciales de la imagen...)
\end{verbatim}

En la respuesta vemos que la cabecera \emph{Content-Length}
contiene el tamaño total del rango solicitado, 100 bytes. La
cabecera \emph{Content-Range} contiene una copia del rango
especificado en la petición, \verb+'0-99'+, seguida del carácter
\verb+'/'+ y un número decimal que representa el tamaño total del
archivo. Las demás cabeceras son las típicas de cualquier
respuesta. Nótese que en este ejemplo, el servidor sí nos notifica
que acepta \emph{byte-ranging}, incluyendo la cabecera
\emph{Accept-Ranges} con el valor bytes.

En el ejemplo anterior vemos que cuando la petición se refiere a
un único rango, la respuesta que se devuelve es una respuesta
``típica'', a excepción del código 206, que nos indica que es un
\emph{byte-range}, y de la inclusión de la cabecera
\emph{Content-Range}. Para el caso de las peticiones de varios
\emph{byte-ranges}, la respuesta del servidor es algo más
compleja. Veamos el siguiente ejemplo, en el cual solicitamos los
100 primeros bytes, el rango que va desde el byte 120 al 150 y el
rango que va desde el byte 200 al 230:

\begin{verbatim}
GET /imagen.jpg HTTP/1.1
Host: www.servidor.com
Range: bytes=0-99,120-150,200-230

\end{verbatim}

El servidor, en el caso de responder satisfactoriamente, enviaría
una respuesta similar a la siguiente:

\begin{verbatim}
HTTP/1.1 206 Partial Content
Server: Apache/1.3.12 (Win32)
ETag: "0-55fe-278427e3"
Accept-Ranges: bytes
Content-Length: 100
Content-Type: multipart/byteranges; boundary=cadenadelimitadora


--cadenadelimitadora
Content-Type: image/jpeg
Content-Range: 0-99/1024

(Datos del primer rango...)
--cadenadlimitadora
Content-Type: image/jpeg
Content-Range: 120-150/1024

(Datos del segundo rango...)
--cadenadelimitadora
Content-Type: image/jpeg
Content-Range: 200-230/1024

(Datos del tercer y último rango...)
--cadenadelimitadora--
\end{verbatim}

En la respuesta del servidor vemos como ahora la cabecera
\emph{Content-Length} no especifica el tamaño de ningún rango,
sino del cuerpo del mensaje de respuesta, que incluye tanto la
suma de los rangos solicitados como las subcabeceras de cada
rango. El tipo MIME especificado en la cabecera
\emph{Content-Type} ya no es \emph{image/jpeg}, sino
\emph{multipart/byteranges}. Esta cabecera incluye además una
cadena delimitadora, a continuación de la cadena
\verb+'boundary='+. Esta cadena delimitadora será la empleada para
separar los diferentes rangos en el mensaje. Hay que tener en
cuenta que, a diferencia de lo que ocurre al solicitar un sólo
rango, al solicitar varios rangos no es que el mensaje se
transmita en partes, una por rango, sino que el mensaje es un tipo
de mensaje especial (\emph{multipart/byteranges}), en cuyo cuerpo
están incluidos los rangos requeridos. Esto quiere decir que el
servidor podría enviar el mensaje de respuesta a una petición
multi-rango de forma \emph{chunkeada} si lo considerara
conveniente.

El cuerpo del mensaje comienza, a diferencia del resto de
mensajes, tras dos líneas vacías, y está dividido en tantas
secciones como rangos se haya solicitado. Al inicio de cada
sección se incluye una línea con la cadena \verb+'--'+ seguida de
la cadena delimitadora. A continuación se encuentra un conjunto de
cabeceras relacionadas con el rango asociado a dicha sección. Las
cabeceras suelen ser la cabecera \emph{Content-Range} y la
cabecera \emph{Content-Type}. La primera cabecera, al igual que se
comentó para el caso de peticiones de un único rango, contiene el
rango correspondiente y el tamaño total del archivo. Los datos del
rango de una sección comienzan tras la primera línea vacía. Al
final del mensaje se incluye una línea con la cadena \verb+'--'+
seguida de la cadena delimitadora y \verb+'--'+.
