Problemas tí­picos de la programación Web

Formularios y CGI

HTTP, como hemos visto anteriormente, se caracteriza por ser un protocolo stateless, es decir, en el cual no se mantiene información de estado. Las transacciones se ejecutan con un requerimiento de un lado y una respuesta del otro. Esta aproximación puede parecer bastante simplista en el terreno de las aplicaciones cliente-servidor. Ninguna de las aplicaciones anteriores (FTP, Telnet) es stateless, con la posible excepción de NFS.

De hecho, NFS se implementa sobre el protocolo UDP, ni siquiera TCP. Esto porque está en mente principalmente el objetivo de conseguir buenos tiempos de respuesta, a costo de todo lo demás. Por otra parte, por la implementación en múltiples procesos de la mayorí­a de los servidores, es raro que dos requests consecutivos del mismo cliente sean atendidos por el mismo proceso.

En el caso de HTTP, esto puede llegar a ser un problema mayor. La forma en que CGI+HTML resuelven el tema de las aplicaciones Web es realmente muy limitada:
El usuario llena un formulario HTML y presiona «submit»
El servidor recibe el formulario HTML, lee las variables que hay en él, ejecuta algún efecto colateral y despliega otra página (posiblemente con un formulario también).

Formularios

Un formulario es un diálogo que forma parte de una página Web. Este diálogo está construí­do con un conjunto de elementos como:
Campos de texto de una o varias lí­neas
Checkboxes (opciones no excluyentes)
Radio buttons (opciones múltiples excluyentes)
Pull-down menus
Botones

Algunos de estos elementos tienen un nombre. Este nombre indica que el valor actual del elemento debe ser codificado y enviado al servidor en el momento del enví­o del formulario. Más información en WDVL – Forms.

Precálculos y Validación en el lado del cliente

Es algo estándar actualmente que antes de enviar el formulario, un programa corriendo en un lenguaje embebido en el browser del cliente (tí­picamente Javascript) realice algunos cálculos. En la práctica esos cálculos significan detener el proceso de enví­o al servidor, bajo ciertas condiciones, generando una alerta al usuario. En otras ocasiones significan que algunos elementos del formulario adquieren nuevos valores que son calculados automáticamente en base a otros.

El ejemplo más típico de precálculo son los formularios que validan dí­gitos verificadores antes de que el usuario enví­e la página.

El proceso de prevalidación tiene las siguientes ventajas:
Más rápido detectar errores
Menos carga del servidor

Notar que la prevalidación puede simplificar la programación de los scripts en el lado del servidor, pero eso no implica dejar de hacer ciertas aserciones para evitar uso malicioso (ej.: ingreso de una URL con variables directamente).

Proceso del formulario en el lado del servidor

El servidor recibe sólo pares del tipo nombre=valor. Normalmente el sofware en el lado del servidor tiene acceso a todos los recursos de esa máquina y por lo tanto puede ejecutar cualquier programa, conectarse a otros servidores, y producir cualquier tipo de efecto colateral que desee.

Desde el punto de vista funcional, este programa recibe entradas y genera una salida. Esta salida puede ser de cualquier tipo MIME aceptado por el browser que enviá el formulario. Lo más tí­pico es HTML pero no es raro ver imágenes generadas también (esto se usa en los ad-servers y todas las herramientas de user-tracking para estudiar patrones de navegación).

Hay varios problemas aquí­:
¿Qué pasa cuando no necesito desarrollar algo más complejo?
¿Qué pasa si necesito varios pasos?
En particular, ¿quá pasa si hay un paso previo de autentificación?

Estas preguntas tienen todas una respuesta afirmativa, es decir, siempre hay solución. Pero contestar eso es lo mismo que decirle a alguien que es perfectamente posible hacer un programa que simplifique expresiones de algebra simbólica usando máquinas de Turing: se necesita en la práctica una forma de más alto nivel de describir el problema.

Lo extraño de todo esto es que normalmente no se busca tal forma, sino que simplemente se intenta parchar con las herramientas disponibles. Veremos una situación intermedia en que la aplicación es complementada por ciertos módulos de nivel medio.

Sesiones

El problema de la persistencia es central al comenzar a pensar en este problema en un nivel un poco más alto. Por persistente significa que la aplicación requiere del envío y respuesta de múltiples formularios, y que esta secuencia de envíos y recepciones requiere cierta coherencia.

Esta coherencia se logra permitiendo que en algún nivel los programas trabajen con los datos como si el proceso de enviar y recibir datos fuera algo continuo. Por lo mismo, en algún nivel inferior la aplicación debe transformar los envíos de datos de formulario entre browser y servidor en alguna estructura más coherente. Estos envíos de datos constituirán una sesión.

La solución consiste en mantener en el lado del servidor un conjunto de datos correspondientes al cliente. Estos datos van más allá de su identificador como usuario, sino que pueden involucrar también sus respuestas en formularios anteriores, patrones navigacionales, etc. Estos datos son almacenados normalmente en una base de datos relacional o en un área de datos compartida entre los procesos de atención del servidor web.

Para conectar estos datos con el usuario, se utiliza por lo general una cookie. Esta cookie incluye un identificador de sesión (session-id) generado aleatoriamente y que por motivos de seguridad puede codificar entre otras cosas la IP del browser, fecha hora actual, etc.

Las sesiones se pueden implementar tanto a nivel del servidor como de la aplicación, con o sin bases de datos y con o sin cookies (a veces se emplean URLs codificadas y métodos de reinterpretación de URLs en el lado del servidor).

Persistencia de datos

Prácticamente todos los sistemas transaccionales en Internet tienen alguna forma de guardar lo realizado durante la sesión, esto es, de hacer los cambios permanentes. Lo típico es utilizar algún SABD y comunicarse con él en SQL. Secundariamente se realizan modificaciones a archivos en el filesystem o conecciones a otros servidores.

Una buena idea es utilizar algún tipo de puente objeto-relacional en este caso. Esto es, la aplicación se construye en algún lenguaje con soporte para objetos persistentes.
virtual class Persistent_Object {
public result_code store();
public static Persistent_Object Retrieve(query); // puede ser SQL, QBE, by_oid, etc.
}

La implementación de la clase base Persistent_Object excede el á¡mbito de este documento, pero pueden consultar más información en ODMG – Object Data Managment Group.

Seguridad
Confidencialidad

Las características de Internet que le son más propias son las mismas que generan una serie de problemas al momento de crear una aplicación en el Web. Un paquete de información puede pasar por varias manos antes de llegar a destino por lo que no es fácil asegurar que no sea examinado o modificado.

Para conseguirlo normalmente se utilizan sistemas de llaves asimétricas, siendo lo más común HTTPS que es HTTP sobre SSL.

SSL (secure socket layer) es un estándar desarrollado por Netscape que permite una transmisión segura de datos.

Como en todo sistema de llaves públicas, es deseable que existan entidades certificadoras que permiten crear un web of trust apropiado.

Autentificación

La autentificación puede llevarse a cabo con o sin SSL. Sin SSL es imposible asegurar demasiada seguridad, siempre alguien podrá suplantar a menos que se use un esquema de tipo challenge en que el servidor genera un token que debe ser transformado por el cliente antes de responder.

Sin embargo a la larga esto ya es suficientemente complicado como para que sea preferible usar SSL, que además de autentificación provee de confidencialidad.

Organización del código

El problema de organizar el código no es menor; debido a las circunstancias/estilo deprogramación hay varias decisiones que tomar:
Todo en un archivo
Varios archivos, uno por cada acción (ti­pico)
Varios archivos, uno por cada clase
Archivos de interfaz y bibliotecas por cada grupo de acciones

Una organización de código inteligente tiene que ver con conocer:
¿Cuáles son las facilidades que da el servidor para precompilar código?
¿Cómo convierto strings en llamadas a funciones?

Respecto a lo primero, es importante saber y determinar cuáles son las partes más variables del código, para ponerlas directamente en los CGI, e ir estabilizando bibliotecas más permanentes que son precompiladas.

Respecto a la segundo, la mejor solución es crear tablas de hashing que permiten convertir en forma más segura la petición del usuario en una llamada a función.

Via: Tejedores del Web