El primer paso obligado dentro de Wininet es abrir una instancia del API. Esta apertura de instancia, lo que hace es crearnos un objeto que representará a la aplicación que hace uso de Wininet, identificada por un descriptor. Este objeto funcionará como descriptor raíz, a partir del cual iremos creando otros descriptores (por ejemplo: de conexión, de petición, etc.).
Dentro del API Wininet, cualquier descriptor que creemos será de tipo HINTERNET. Este tipo de dato nos obliga a que estos descriptores sean utilizados solamente con las funciones propias del API Wininet, por lo que no podremos utilizarlos como parámetros de las funciones básicas del API Win32, como CloseHandle, DuplicateHandle, etc. Ni que decir tiene que al contrario tampoco será posible: no podemos crear un descriptor con CreateFile y utilizarlo en una función de Wininet como InternetReadFile.
La función para la apertura del API es InternetOpen, y la situación más normal es que sea llamada una única vez por una aplicación, aunque si queremos definir distintos modos de comportamiento en la conexión (por ejemplo, acceso a través de distintos servidores proxy), debemos llamar a esta función una vez por cada tipo de comportamiento que queramos utilizar.
Vamos a ver cómo se llama a la función InternetOpen:
HINTERNET InternetOpen(
LPCTSTR lpszAplicación,
DWORD dwTipoAcceso,
LPCTSTR lpszProxy,
LPCTSTR lpszExcepciónProxy,
DWORD dwOpciones
);
Los parámetros son los siguientes:
- lpszAplicación: un puntero a cadena que contiene el nombre de la aplicación (en inglés: user-agent) que va a enviar las peticiones. Este nombre será el utilizado en la llamada HTTP que haga el cliente, concretamente en la clave "User-Agent" de la cabecera, y sirve para identificar a un cliente frente al servidor que reciba las peticiones HTTP. Estableciendo un "agente" especial, podemos hacer que nuestro servidor HTTP responda de un modo diferente a ciertas llamadas, por ejemplo, las que llegan desde una aplicación concreta. Un ejemplo práctico de esto son las estadísticas sobre el tipo de navegador o sistema operativo que utilizamos los usuarios a la hora de navegar por internet. Es sencillo imaginarse que cada navegador (que no es más que un cliente HTTP) utilizará un "user-agent" distinto, por lo que un servidor web sólo tendrá que registrar el número de accesos de cada tipo, y calcular estadísticas a partir de este dato. A modo de curiosidad: podemos ver fácilmente el "user-agent" que envía nuestro navegador, utilizando JavaScript, en esta web.
- dwTipoAcceso: indica el tipo de acceso que se va utilizar en la conexión:
- INTERNET_OPEN_TYPE_DIRECT: hace una conexión directa a internet, sin utilizar servidores proxy ni corta-fuegos entre nuestro equipo y los recursos remotos. Esta configuración es válida para conexiones permanentes, como ADSL, cable, etc.
- INTERNET_OPEN_TYPE_PRECONFIG: lee del registro el tipo de conexión que hayamos configurado en "Panel de Control - Opciones de Internet - Conexiones - Configuración LAN". Este modo es el más recomendable para asegurarnos de que vamos a utilizar el tipo de conexión que esté utilizando el usuario desde Internet Explorer.
- INTERNET_OPEN_TYPE_PROXY: se utiliza un proxy para realizar la conexión, a no ser que la conexión se haga a un host que se encuentre en la lista de "excepciones" (en el parámetro lpszExcepciónProxy).
- lpszProxy: una cadena que contiene el nombre de el(los) servidor(es) proxy a utilizar en la conexión. Si en el parámetro dwTipoAcceso se ha indicado un valor distinto de INTERNET_OPEN_TYPE_PROXY, este parámetro debe ser nulo (nunca una cadena vacía). En caso contrario, debe pasarse una cadena que puede indicar símplemente un nombre de host (o dirección IP) que se utilizará como proxy, de este modo:
"servidor_proxy" ó "127.100.100.1"
Aunque con el nombre de host es suficiente, esta función permite una sintaxis más compleja, definiendo un proxy para cada uno de los protocolos soportados por Wininet. La sintaxis es la siguiente:
"[prot=][prot://]host[:puerto]"---Las opciones encerradas entre corchetes indican que son opcionales.
"prot" indica el tipo de protocolo para el que estamos definiendo un proxy, es decir: si queremos especificar un protocolo especial para una conexión por FTP, debemos pasar la siguiente cadena:
"ftp=ftp://servidor_proxy"---"host" indica el nombre o dirección IP del servidor que se utilizará como proxy.
"puerto" indica el número de puerto al que se accederá. Si se omite, se utilizará el puerto por defecto para cada uno de los protocolos (21 para FTP, 70 para Gopher, 80 para HTTP y 443 para HTTPS).
Para definir otros servidores proxy, basta con separar las distintas cadenas por un espacio, por ejemplo:
"ftp=ftp://servidor_proxy_1:21 http=http://10.10.10.1:80"---De este modo se indica que se utilice el "servidor_proxy_1" para conexiones FTP y el "10.10.10.1" para conexiones HTTP.
También es posible indicar un servidor proxy para un protocolo en particular, y otro servidor para el resto de protocolos, del siguiente modo:
"ftp=ftp://servidor_proxy_1:21 servidor_el_resto"
- lpszExcepciónProxy: este parámetro sirve para indicar una serie de direcciones que serán accedidas directamente, sin utilizar el proxy. Normalmente, esta lista es configurable por el usuario, a través de la opción "Panel de control - Opciones de Internet - Conexiones - Configuración LAN - Avanzadas - Excepciones", aunque utilizando el API Wininet podemos definir nuestra propia lista de excepciones.
La cadena de excepciones también sigue una sintaxis especial, pudiendo utilizar el carácter comodín "*", o incluír varios servidores separándolos por un espacio.
Existe una cadena especial, , que indica que todas las direcciones que no contengan un punto (locales), se accederán sin utilizar un proxy.
Por ejemplo, podemos indicar una cadena como la siguiente, separando las distintas excepciones por espacio:
" 127.*.100.* 128.*.*.* 192.1.45.12"
- dwOpciones: un valor que combina las opciones de comportamiento. Se puede incluír cualquiera de los siguientes valores:
- INTERNET_FLAG_ASYNC: indica que las llamadas se harán de forma asíncrona, esto es, cada función que llamemos retornará antes de que termine su ejecución. Posteriormente, cuando la ejecución haya terminado, se notificará al programador a través de una función de retrollamada (callback). Esta bandera afecta a las llamadas hechas a través del descriptor retornado por InternetOpen, como las hechas con cualquier descriptor descendiente de este. Trataremos el tema de las funciones asíncronas en el próximo artículo.
- INTERNET_FLAG_FROM_CACHE: cuando se tenga que recuperar algún dato de la red, se intentará buscar esta información en el caché que mantiene Internet Explorer, y si existe y es correcto, lo retornará. En caso de que el caché no contenga esta información, la función correspondiente retornará un error, normalmente el valor de la constante ERROR_FILE_NOT_FOUND. Esta bandera debe establecerse cuando una aplicación funcione en modo "Trabajar sin conexión".
- INTERNET_FLAG_OFFLINE: funciona del mismo modo que el modo anterior, INTERNET_FLAG_FROM_CACHE, intentarndo resolver todas las peticiones contra el caché, sin hacer ningún acceso remoto.
Esta función retornará NULL si ha ocurrido algún error o un descriptor válido si todo ha ido bien. Debemos almacenar en una variable el descriptor retornado ya que lo necesitaremos para crear el resto de descriptores. En caso de error, se puede llamar a la función GetLastError para averiguar el código de error.