15 - Rangos en HTTP

[editar]
Tutorial creado por Juan Manuel. Extraido de: http://www.lawebdejm.com
30 de Noviembre de 1999
Con lo que sabemos hasta ahora, es fácil hacer un programa que descargue un recurso de internet, sin embargo, no sabemos como trocear nuestro recurso para ir descargando por separado cada una de las partes. Para ello tenemos que utilizar una nueva característica de HTTP, introducida en la versión 1.1 del protocolo.

Esta característica consiste en informar al servidor de que no queremos descargar el recurso completo, sino un rango de byte de él. De este modo, conseguimos ir descargando el recurso por rangos. Por ejemplo, imaginemos un archivo que ocupa 2 KB. (2048 bytes). Podemos dividirlo en los siguientes 4 segmentos:

  1. Segmento 1: desde el byte 0 al 511 (ambos inclusive).
  2. Segmento 2: desde el byte 512 al 1023 (ambos inclusive)
  3. Segmento 3: desde el byte 1024 al 1535 (ambos inclusive)
  4. Segmento 4: desde el byte 1536 al 2047 (ambos inclusive)

Como vemos, hemos dividido el tamaño total en cuatro partes iguales, de 512 bytes cada una de ellas, marcando las fronteras de bytes entre unas y otras partes. El segmento final no llega hasta el byte 2048, sino uno menos, ya que como empezamos a contar en el byte 0, el último byte será el tamaño menos 1 (n-1).

El modo de informar al servidor del rango que queremos descargar, es a través de una cabecera adicional al comando GET, que como sabemos, podemos enviar a través de la función HttpAddRequestHeaders.
Esta petición, con la cabecera, tiene el siguiente aspecto:

|| GET /recurso.zip HTTP/1.1 ||
|| Accept: text/html ||
|| Range: bytes=512-1023 ||
||   ||

Enviando esta cabecera, indicamos al servidor que queremos descargar los bytes comprendidos entre el 512 y el 1023.

Adicionalmente, podemos indicar que queremos descargar los bytes desde una posición determinada, hasta el final del recurso, utilizando una cabecera como la siguiente:

|| GET /recurso.zip HTTP/1.1 ||
|| Accept: text/html ||
|| Range: bytes=1536- ||
||   ||

De este modo, indicamos que descargaremos desde el byte 1536, hasta el final del recurso. Esta misma sintaxis, nos permite definir un único rango, para descargar el recurso por completo, como hemos hecho hasta ahora:

|| GET /recurso.zip HTTP/1.1 ||
|| Accept: text/html ||
|| Range: bytes=0- ||
||   ||

Esto indicará que se descargue desde el byte 0 (el primero) hasta el final del recurso, o dicho de otro modo: se descargará el recurso completo, en un único segmento.

Si nos fijamos en la línea de la petición GET de todos estos ejemplos, veremos que la versión que se utiliza del protocolo es la 1.1. Esto es debido a que, como ya he dicho, los rangos de descarga sólo se soportan a partir de esta versión. En el mundo WinInet, si utilizamos el método directo (con la función InternetOpenUrl), no será necesario indicar la versión del protocolo. Sin embargo, si utilizamos el método detallado, os recuerdo que indicamos la versión a utilizar del protocolo a través del parámetro lpszVersion de la función HttpOpenRequest. Si olvidamos indicar la versión 1.1, e intentamos utilizar este tipo de cabecera, recibiremos un error de tipo ERROR_HTTP_HEADER_NOT_FOUND.


Y ahora que sabemos cómo se forma la cabecera que definen nuestros rangos, lo único que tenemos que hacer es añadir esta cabecera a nuestra petición, utilizando los mecanismos que nos ofrece WinInet para ello:

  • Con el parámetro "lpszCabeceras" de la función InternetOpenUrl: consiste en enviar las cabeceras adicionales a través de la función utilizada en el método directo: InternetOpenUrl. No es necesario indicar la versión del protoco, ya que se seleccionará automaticamente.
{ se abre la instancia de internet HINTERNET hInet = ::InternetOpen(...); almacenamos en variables los límites del rango DWORD byteIni = 512; DWORD byteFin = 1023; se compone la cabecera con su sintaxis char* cabecera; wsprintf(cabecera, "Range: bytes=%d-%d", byteIni, byteFin); se abre la URL, enviando también las cabeceras adicionales HINTERNET hReq = ::InternetOpenUrl(hInet, "http://www.servidor.com/recurso.zip", cabecera, strlen(cabecera), INTERNET_FLAG_RELOAD, ); ... lectura del recurso con InternetReadFile y cierre de descriptores }
  • Con el parámetro "lpszCabeceras" de la función HttpSendRequest: utilizando el método detallado, podemos enviar cabeceras adicionales de la petición a través del segundo parámetro en la función HttpSendRequest. En este caso, debemos indicar la versión del protocolo (1.1) en la llamada a la función HttpOpenRequest:
{ se abre la instancia de internet HINTERNET hInet = ::InternetOpen(...); se conecta al servidor HINTERNET hConn = ::InternetConnect(hInet, "servidor.com", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, , ); se crea la petición GET. Ojo a la versión HINTERNET hReq = ::HttpOpenRequest(hConn, "GET", "/recurso.zip", "HTTP/1.1", NULL, NULL, , ); almacenamos en variables los límites del rango DWORD byteIni = 512; DWORD byteFin = 1023; se compone la cabecera con su sintaxis char* cabecera; wsprintf(cabecera, "Range: bytes=%d-%d", byteIni, byteFin); se manda la URL, enviando también las cabeceras adicionales int len = sizeof(cabecera); if ( !::HttpSendRequest(hReq, cabecera, len, NULL, 0) ) { Se ha producido un error. Si no se admite la cabecera, al llamar al GetLastError obtendremos el error ERROR_HTTP_HEADER_NOT_FOUND. } ... lectura del recurso con InternetReadFile y cierre de descriptores }
  • Con la función HttpAddRequestHeaders: otra opción si utilizamos el método detallado es añadir la cabecera a la petición, utilizando HttpAddRequestHeaders. Esto nos permite, no solo añadir, sino eliminar, cambiar o reemplazar las cabeceras a enviar junto con la petición.
{
se abre la instancia de internet HINTERNET hInet = ::InternetOpen(...); se conecta al servidor HINTERNET hConn = ::InternetConnect(...); se crea la petición GET. Ojo a la versión HINTERNET hReq = ::HttpOpenRequest(...); almacenamos en variables los límites del rango DWORD byteIni = 512; DWORD byteFin = 1023; se compone la cabecera con su sintaxis char* cabecera; wsprintf(cabecera, "Range: bytes=%d-%d", byteIni, byteFin); se añade la nueva cabecera a la petición if ( !::HttpAddRequestHeaders(hReq, cabecera, sizeof(cabecera), HTTP_ADDREQ_FLAG_ADD) ) { Se ha producido un error. } se manda la petción if ( !::HttpSendRequest(hReq, NULL, 0, NULL, 0) ) { Se ha producido un error. } ... lectura del recurso con InternetReadFile y cierre de descriptores }
[editar]

1 opinión

esta chido

esta de poca aunke no le entendi jajajajaja

Tutoriales relacionados con 'Los rincones del API Win32: Más sobre WinInet y HTTP'

El protocolo FTP desde el API WinInet. Con este curso aprenderás a hacer un pequeño... Más »

Autor y licencia de 'Los rincones del API Win32: Más sobre WinInet y HTTP'


Tutorial de Juan Manuel. Extraido de: http://www.lawebdejm.com CopyLeft
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.