Etiqueta

14 octubre 2015

Uso de comandos HTTP con Omnis

Caso ejemplo


Queremos hacer uso de comandos HTTP, para obtener una imagen ubicada en algún lugar de Internet y guardarla sobre un control JPEG de nuestro propio “remote form”, como por ejemplo la localizada en la dirección de internet: http://www.tigerlogic.com/omnis/images/omnis_studio_box.png.

 

HTTP Request y HTTP Response


Antes de entrar en detalles sobre el uso de comandos HTTP con Omnis, echemos un vistazo a lo que ocurre cuando se solicita una imagen, (o cualquier otro dato) mediante HTTP. Si introducimos la URL de un archivo imagen, (como por ejemplo la indicada en el párrafo anterior) en un navegador ésta será mostrada sobre la ventana del navegador, pero, lo que realmente ha sucedido es que el navegador (como cliente) a enviado un “HTTP Request” al servidor web “www.tigerlogic.com” solicitándole el fichero “/omnis/images/omnis_ studio_box.png” (parte de la URL, denominada URI), como consecuencia de esto, el servidor envía de vuelta un “HTTP Response” al navegador, que contiene, (entre otras cosas) el fichero solicitado. El formato de los paquetes de datos transferidos obedecen al protocolo estándar definido en el RFC 2616, consulte: www.faqs.org/rfcs/rfc2616.html

El “HTTP Request” está compuesto principalmente por una cabecera, que contiene los datos de identificación del cliente,  la información de lo solicitado por éste y su formato, mientras que el servidor responde con un “HTTP Response”, que a su vez consta de una cabecera y un cuerpo con la información requerida.

La cabecera de ambos es transferida en forma de texto ASCII estándar y por lo tanto puede ser “atrapada” mediante el uso de programas para el análisis de paquetes denominados “Sniffer’s”. Véase, por ejemplo: www.wireshark.org

Están compuestos por líneas individuales, cada una de ellas terminada con un retorno de carro (CR = Código ASCII 13) y un salto de línea (LF = Código ASCII 10). En cada línea, se asigna un valor a un campo, su formato es ≤nombre de campo≥":"≤valor≥. Entre la cabecera y el cuerpo hay una línea en blanco. De modo que, delante del cuerpo siempre encontraremos la cadena CR + LF + CR + LF.

 

¿Es Omnis un navegador?


Lo que podemos decir es que Omnis, soporta algunos comandos 4GL para la ejecución del ciclo “HTTP request/response”. Volviendo al caso planteado, podemos hacer uso de éstos comandos para obtener una imagen desde una ubicación remota. En primer lugar, Omnis deberá enviar una petición HTTP al servidor para recuperar o “conseguir” el archivo imagen. A continuación mostramos el código necesario: (“host” y “uri” son las variables locales de tipo “Character”, “socket” es de tipo “Long Integer”)

Calculate host as 'www.tigerlogic.com'
Calculate uri as '/omnis/images/omnis_studio_box.png'
HTTPGet (host,uri) Returns socket

Si la solicitud es aceptada, la variable “socket” contendrá un valor positivo, por su parte, Omnis habrá enviado lo siguiente:

GET /omnis/images/omnis_studio_box.png HTTP/1.1
Host: www.tigerlogic.com
Accept: */*
User-Agent: Raining Data - OMNIS


Si se desea definir parámetros adicionales para incluirlos en la cabecera de la solicitud o bien para nuestra propia versión de la URI utilizada por defecto, disponemos del comando “HTTPGet” el cual permite el uso de parámetros adicionales; en éste caso el código sería algo como lo siguiente:

Do cgiList.$define()
Do cgiList.$cols.$add(‘atributo’,kCharacter,kSimplechar,2000)
Do cgiList.$cols.$add(‘valor’,kCharacter,kSimplechar,2000)
Do cgiList.$add( ... )
Do headerList.$define()
Do headerList.$cols.$add(‘nombre’,kCharacter,kSimplechar,2000)
Do headerList.$cols.$add(‘valor’,kCharacter,kSimplechar,2000)
Do headerList.$add( ... )
HTTPGet (host,uri,cgiList,headerList) Returns socket

Si el “socket” es válido podremos recuperar datos del servidor, e ir guardándolos (en un primer momento) sobre (por ejemplo)  la variable “buffer” (definida como tipo “Character”):

HTTPRead (socket,buffer) Returns charCount

Los datos obtenidos tras el primer “HTTPRead” pueden no ser todos los esperados, por lo que, (como medida de precaución) es mejor crear un bucle (la variable “bufferPart” también es tipo “Character”). Así el código completo para leer una respuesta HTTP sería:

If socket>0
  Calculate buffer as ''
  Repeat
    Calculate bufferPart as ''
    HTTPRead (socket,bufferPart) Returns charCount
    Calculate buffer as con(buffer,bufferPart)
  Until (len(bufferPart)=0)|(charCount=0)
  HTTPClose (socket)
  ...(hacer algo)...
End If

Tras la obtención de todos los datos, será muy conveniente hacer uso del comando “HTTPClose” (socket) y después, comprobar que al inicio de la variable “buffer”; disponemos de algo como  lo siguiente:

HTTP/1.1 200 OK Server: Zeus/3.3
Date: Tue, 08 Dec 2007 12:34:57 GMT Content-Length: 4351
Content-Type: image/jpeg
Last-Modified: Thu, 01 Dec 2007 10:04:25 GMT
 

Tras la cabecera, vendrá una línea en blanco y luego los datos binarios.

Si se envía un “URI” inválido, como por ejemplo, solicitando el archivo “studio4_box.jpg” que no existe en el subdirectorio “/products/studio/” del servidor web, no se nos devolverá el número “2xx”, si no (generalmente) el correspondiente al error 404. De modo que, nuestra aplicación debería comprobar la presencia de este número sobre la primera línea devuelta, comprobando que su primer dígito sea igual a 2. Por ejemplo:

If not(mid(buffer,pos(' ',buffer)+1,1)='2')
  OK message Error {[uri] no localizado.}
  Quit method
End If


Ahora deberemos separar el cuerpo de su cabecera. Recuerde que todo lo que nos llega después de la línea en blanco, son los datos referenciados. Por lo tanto deberemos declarar las siguientes variables locales:

posEmptyLine (Long integer)
bufferStripped (Binary)
picFormat (Character)
 

y las variables-instancia:

iPicture (Binary)

finalmente deberemos añadir el siguiente código antes del comando “End If”:

Calculate posEmptyLine as pos(chr(kCr,kLf,kCr,kLf),buffer)
Calculate bufferStripped as mid(buffer,posEmptyLine+4,len(buffer))
Calculate picFormat as pictformat(bufferStripped)
Calculate iPicture as pictconvfrom(picFormat,bufferStripped)

Ahora podríamos asignar la variable IPicture a la propiedad “$dataname” de un control JPEG para así mostrar la imagen sobre nuestro “remote form”.

No hay comentarios: