Secciones: 1. Principios básicos | 2. Devolviendo páginas Web | 3. Variables de Entorno | 4. Formularios y comunicación con los programas CGI |

Ejemplos: MIME en formato texto | MIME en formato HTML | HolaText | HolaHtml | Vars | getEnvSafe | getUrl | Formulario simple |

PLF - Programación de CGI's en Haskell

1. Principios básicos

Internet se basa en el protocolo TCP/IP

La world wide web se basa en el protocolo HTTP (Hypertext Transfer Protocol), un protocolo cliente/servidor que funciona por encima del protocolo TCP/IP

El funcionamiento básico de HTTP es el siguiente:

Las respuestas del servidor se envían en formato MIME (Multipurpose Internet Mail Extensions). Este protocolo define las cabeceras y los contenidos de varios tipos de mensajes que pueden enviarse por correo electrónico

Ejemplo (MIME en formato texto)

El tipo básico de mensaje es texto sin más, el cual se denota como text/plain. Un posible mensaje de saludo en formato MIME sería:

content-type: text/plain

Hola en texto
NOTA: El formato MIME comienza con una línea en la que se especifica el tipo de contenido, seguida de un salto de línea obligatorio y del contenido propiamente dicho
Ejemplo (MIME en formato HTML)

Un tipo de contenido muy habitual en la Web es texto en formato HTML, el cual se denota como text/html. Un posible mensaje de saludo sería:



content-type: text/html

<html>
<head><title>Saludo</title>
<body>
<h1>P&aacute;gina de saludo</h1>
<p> Hola en HTML </p>
</body>


En una operación cliente/servidor habitual, el cliente solicita una dirección URL al servidor y éste devuelve el contenido. Dicho contenido suele ser un texto en formato HTML

Mediante el protocolo CGI ó Common Gateway Interface es posible crear contenido dinámico en Internet. Cuando el servidor reconoce que una dirección es un CGI, en lugar de devolver su contenido, ejecuta dicho CGI y devuelve al cliente el resultado en formato MIME (habitualmente text/html).

Para que el servidor reconozca que la dirección es un programa CGI, existen diversas técnicas dependiendo de la configuración del servidor. En algunos servidores, los CGI's se identifican por la extensión .cgi. En otras ocasiones, los programas CGI's residen en un directorio determinado (normalmente /cgi-bin).

Para implementar un programa ejecutable en Haskell, es necesario definir una función main::IO() que debe exportarse. Para ello, se define la siguiente línea

> module Main(main) where
> import System (getEnv) -- Para usar la función (getEnv)
>
> main :: IO ()
> -- main = ... programa que corresponda

Ejemplo (HolaText) El siguiente CGI devuelve la cadena de texto "Hola"
> mainHola = 
>     do { putStrLn "content-type: text/plain"
>        ; putStrLn ""
>        ; putStrLn "Hola"
>        }

Para que el programa anterior pueda ejecutarse como un CGI existen 2 posibilidades

NOTA:

Un truco habitual cuando no se dispone de un servidor Web en el cual instalar los programas CGI's es hacer que nuestro propio ordenador sea el servidor. Para ello, se debe instalar el software que implemente el protocolo HTTP servidor en nuestro ordenador. Entre las múltiples opciones, Apache da buenos resultados en Linux, mientras Xitami hace lo propio en Windows.

Una vez que nuestro ordenador tiene el software servidor funcionando, la dirección 127.0.0.1 permite hacer referencia a la dirección IP de nuestro propio ordenador. De esta forma, no es necesario tener activada una conexión Internet al exterior para poder practicar a realizar programas CGI.

2. Devolviendo páginas Web

Habitualmente, los programas CGI devuelven código HTML que corresponde con una página Web

Ejemplo (HolaHtml) El siguiente CGI devuelve una página Web con un saludo
> mainHtml = 
>     do { putHeaderHtml
>        ; putStrLn "<html><head><title>Saludo</title>"
>        ; putStrLn "<body><h1>P&aacute;gina de saludo</h1>"
>        ; putStrLn "<p> Hola en HTML </p></body></html>"
>        }
>
> putHeaderHtml = 
>     do { putStrLn "content-type: text/html"
>        ; putStrLn ""
>        }


El formato HTML consiste en una serie de marcas predefinidas. Algunas de estas marcas son:

3. Variables de Entorno

La comunicación entre el servidor y el programa CGI se realiza mediante una serie de variables de entorno. Las principales son:

Ejemplo (Vars) El siguiente CGI muestra el valor de las variables del entorno
> mainVars = 
>     do { putHeaderHtml
>        ; putStrLn "<html><head><title>Vars</title>"
>        ; putStrLn "<body><h1>Variables de Entorno</h1>"
>        ; putVarsHtml
>        ; putStrLn "</body>"
>        }
>
> putVarsHtml =
>     do { putStrLn "<ul>"
>	 ; vs <- cgiEnv
>	 ; putStrLn $ concat ["<li>" ++ v ++ " = " ++ n ++ "</li>\n" | (v,n) <- vs]
>	 ; putStrLn "</ul>"
>        }
>
> cgiEnv :: IO [(String,String)]
> cgiEnv = do { cgiValues <- mapM getEnvSafe cgiVars
>             ; return (zip cgiVars cgiValues)
>             }
>
> cgiVars = [ "SERVER_SOFTWARE", "SERVER_NAME", "SERVER_PROTOCOL", "SERVER_PORT"
>           , "REQUEST_METHOD",  "PATH_INFO",   "PATH_TRANSLATED", "SCRIPT_NAME"
>           , "QUERY_STRING",    "REMOTE_HOST", "REMOTE_ADDR",     "AUTH_TYPE"
>	    , "REMOTE_USER",     "CONTENT_TYPE", "CONTENT_LENGTH"
>           , "HTTP_ACCEPT",     "HTTP_USER_AGENT" ]
>


Ejemplo (getEnvSafe)

En la definición anterior se utiliza la función getEnvSafe que actúa de forma similar a la función getEnv de la librería System. La única diferencia es que cuando no encuentra el valor de una variable, en lugar de lanzar una excepción, devuelve la cadena vacía ""

> getEnvSafe :: String -> IO String
> getEnvSafe var = catch (getEnv var) (\e -> return "")


4. Formularios y comunicación con los programas CGI

Una aplicación habitual de los programas CGI es la búsqueda de información en una base de datos. Este tipo de aplicaciones solicitan una información al usuario y cuando el usuario introduce dicha información enlazan con otro programa que muestra el resultado

Una técnica habitual es que la acción consista en ejecutar el mismo programa CGI

Ejemplo (getUrl)

La función getUrl permite obtener la dirección del CGI actual

> getUrl :: IO String
> getUrl = do { host   <- getEnv "SERVER_NAME"
>             ; script <- getEnv "SCRIPT_NAME"
>             ; return $ "http://" ++ host ++ script
>             }


Existen dos métodos para realizar programas interactivos que contengan formularios.