Interfaz de puerta de enlace común (CGI)

Los propietarios de tiendas en línea conocen de primera mano el concepto de "comercio electrónico"; ya conocen la respuesta a la pregunta "comercio electrónico: ¿qué es?" Pero si se llega al fondo, surgen muchos matices y este término adquiere un significado más amplio.

Comercio electrónico: ¿qué es?

El concepto general es el siguiente: el comercio electrónico se entiende como un determinado enfoque para hacer negocios, que implica la inclusión de una serie de operaciones que utilizan la transferencia de datos digitales en la provisión de bienes o la prestación de servicios/trabajo, incluido el uso de Internet.

Así, es cualquier transacción comercial que se realice utilizando un medio de comunicación electrónico.

El esquema de trabajo se organiza de la siguiente manera:

  • cualquiera puede ser blogger o cualquier otro propietario de su propia página de Internet) se registra en este sistema;
  • obtiene su propio enlace;
  • coloca un código especial en su página web: aparece un anuncio del socio oficial seleccionado de la Red de Socios de Comercio Electrónico;
  • monitorea la conversión del sitio web;
  • gana un cierto porcentaje por cada compra realizada por un visitante de su sitio web que sigue un enlace de afiliado.

Comercio electrónico de WP

Hoy en día, un gran número de personas se apasionan por el comercio electrónico, principalmente por el deseo de crear su propio sitio web, una tienda online única para vender sus propios productos. Para satisfacer esta creciente demanda, los desarrolladores se han centrado en la creación de plantillas de comercio electrónico. Veamos qué es esto a continuación.

Un ejemplo de plantilla es el comercio electrónico de WordPress. Es un complemento de carrito de compras para WordPress (uno de los sistemas de gestión de recursos web más famosos), destinado principalmente a crear y organizar blogs). Se proporciona de forma totalmente gratuita y permite a los visitantes del sitio realizar compras en el sitio web.

En otras palabras, este complemento te permite crear una tienda en línea (basada en WordPress). Este complemento de comercio electrónico tiene todas las herramientas, configuraciones y opciones necesarias para satisfacer las necesidades modernas.

Una interfaz de usuario interactiva es un sistema que permite la interacción entre el usuario y el programa. Para WWW, una interfaz interactiva se puede definir como una secuencia de documentos HTML que implementan una interfaz de usuario. También puede clasificar condicionalmente los principios de construcción de la interfaz según el tipo de generación del documento HTML:

    estático;

    dinámica.

En el primer caso, la fuente de la interfaz es un documento HTML creado en algún editor de texto o orientado a HTML. En consecuencia, este documento permanece sin cambios durante su uso. En el segundo caso, la fuente de la interfaz es un documento HTML generado por el módulo cgi. En consecuencia, existe cierta flexibilidad a la hora de modificar la interfaz durante su uso.

Por tanto, podemos introducir el concepto de interfaz interactiva para la WWW. Una interfaz interactiva para la WWW es una secuencia de documentos HTML estáticos o generados dinámicamente que implementan la interfaz de usuario.

Casi cualquier tarea que resuelva el problema de recibir datos de un cliente implica construir una interfaz. Lo más interesante es crear interfaces para varias bases de datos, acceder a un servidor SQL, recibir información de dispositivos periféricos y crear estaciones de trabajo cliente. Todo esto es posible a través de CGI (Common Gateway Interface). Common Gateway Interface (CGI) es un estándar para la interfaz de un programa de aplicación externo con un servidor WWW.

La tarea de construir las interfaces anteriores se divide en dos partes (Apéndice 2):

    parte del cliente. Para crear la parte del cliente, necesita crear un documento HTML que implemente la interfaz de usuario. En HTML esto es posible a través de formularios.

2. Parte del servidor. La parte del servidor consta de un módulo ejecutable que resuelve las principales tareas de procesar datos provenientes de la parte del cliente, generar una respuesta en formato HTML, etc. Tal módulo se llama módulo cgi.

especificación cgi

CGI define 4 flujos de información (Apéndice 3):

1) Variables de entorno dividido condicionalmente en dos tipos:

a) común para todo tipo de solicitudes (establecido para todos los tipos);

b) dependiendo del método de solicitud.

2) Flujo de salida estándar

CGI- el módulo envía información al flujo de salida estándar. Esta salida puede ser un documento generado por el módulo cgi o una instrucción al servidor donde obtener el documento requerido. Generalmente cgi-el módulo produce su salida. La ventaja de este enfoque es que cgi-el módulo no debe generar un encabezado HTTP completo para cada solicitud.

3) Flujo de entrada estándar

En caso de método de solicitud CORREO los datos se transmiten como contenido de una solicitud HTTP. Y se enviarán al flujo de entrada estándar. Los datos se pasan al módulo cgi de la siguiente forma: nombre= valor& nombre1= valor1&...& nombreN= valorN,

Dónde nombre- nombre de la variable, valor- valor de la variable, norte- número de variables.

El byte CONTENT_LENGTH se envía al descriptor de archivo de entrada estándar. El servidor también pasa CONTENT_TYPE (tipo de datos) al módulo cgi. El servidor no envía el carácter de fin de archivo después de enviar CONTENT_LENGTH bytes de datos o después de que el módulo cgi los haya leído. Las variables de entorno CONTENT_LENGTH y CONTENT_TYPE se configuran cuando el servidor ejecuta el módulo cgi. Por lo tanto, si como resultado de ejecutar un formulario con el argumento de etiqueta FORM - METHOD="POST" se genera la cadena de datos firm=MMM&price=100023, entonces el servidor establecerá el valor CONTENT_LENGTH en 21 y CONTENT_TYPE en application/x-www. -form-urlencoded, y según el estándar, el flujo de entrada envía un bloque de datos.

En caso de método CONSEGUIR, la cadena de datos se pasa como parte de la URL. Aquellos. por ejemplo, http://host/cgi-bin/script?nombre1=valor1&nombre2=valor2

En este caso, la variable de entorno QUERY_STRING toma el valor nombre1=valor1&nombre2=valor2

4) Argumentos de línea de comando

CGI- el módulo en la línea de comando del servidor recibe: el resto de la URL después del nombre del módulo cgi como primer parámetro (el primer parámetro estará vacío si solo estaba presente el nombre del módulo cgi), y una lista de palabras clave como el resto de la línea de comando para el script de búsqueda, o nombres alternos de campos de formulario con un signo igual agregado y los valores de variable correspondientes. Las palabras clave, los nombres y los valores de los campos de formulario se envían decodificados (desde el formato de codificación de URL HTTP) y se vuelven a codificar de acuerdo con las reglas de codificación del shell Bourne para que el módulo cgi en la línea de comando reciba la información sin necesidad de realizar acciones adicionales. conversiones.

Una vez que se haya formado la estructura "nombre-valor", puede comenzar a resolver los problemas para los cuales se creó realmente el módulo cgi. El siguiente punto importante es la generación dinámica de un documento HTML por parte del módulo cgi (formateando el resultado de la operación del módulo). Por ejemplo, tablas de selección de una base de datos. Para hacer esto, el módulo cgi debe generar un encabezado que consta de la línea al flujo de salida estándar: Tipo de contenido: texto/html y una cadena vacía (dos caracteres CR). Después de este encabezado puedes dar cualquier texto en formato HTML.

Andover, Massachusetts, 19 de noviembre de 2003

El grupo de comercio, Inc. (NYSE: CGI), el mayor emisor de seguros privados para automóviles de pasajeros en Massachusetts y CGI Group Inc. (CGI) (TSX: GIB.A; NYSE: GIB;), un proveedor líder de tecnología de la información y servicios de procesamiento de negocios, anunció hoy la firma de una renovación de contrato de subcontratación de procesos de negocios (BPO) por seis años valorado en US$35 millones. CGI proporcionará servicios completos de procesamiento de pólizas para líneas de automóviles comerciales y de pasajeros privados de Massachusetts, además de proporcionar la herramienta de interfaz de agencia CollaborativeEdge de CGI, soporte y mantenimiento de aplicaciones, soporte regulatorio, consultoría de sistemas y servicios de gestión de documentos.

Gerald Fels, vicepresidente ejecutivo y director financiero de Commerce Group, afirmó: "Como proveedor líder de automóviles privados de pasajeros en Massachusetts, nuestro objetivo es brindar a nuestros agentes y empleados servicios que les ayuden a desempeñarse al más alto nivel. A lo largo de los años, hemos fomentado una sólida relación con CGI. Su sistema es robusto y preciso y su equipo está muy familiarizado con nuestros sistemas de procesamiento interno. Eso es importante para nosotros".

Serge LaPalme, presidente de servicios comerciales de seguros de CGI, agregó: "Estamos muy contentos de continuar nuestra relación con Commerce Group, que se remonta a más de 30 años. Commerce Group continúa siendo uno de nuestros valiosos socios comerciales y es estratégico para nuestro éxito Para ayudar a nuestro cliente a centrarse aún más en su negocio principal, estamos aprovechando las nuevas tecnologías cuando y donde tiene sentido. Nuestro equipo conoce íntimamente la industria de seguros y el entorno regulatorio único del Estado y, como resultado, es rápido. adaptar las soluciones existentes a este sector en constante evolución".

Acerca del grupo de comercio, Inc.

The Commerce Group, Inc., una sociedad holding de seguros, tiene su sede en Webster, Massachusetts. Las subsidiarias de seguros de propiedad y accidentes de Commerce Group incluyen The Commerce Insurance Company y Citation Insurance Company en Massachusetts, Commerce West Insurance Company en California y American Commerce Insurance Company en Ohio. A través de las actividades de seguros combinadas de sus subsidiarias, Commerce Group ocupa el puesto 22. grupo de seguros de automóviles personales más grande del país por A.M. Mejor, basado en información directa sobre primas emitidas en 2002.

Acerca de CGI
Fundada en 1976, CGI es la quinta empresa independiente de servicios de tecnología de la información más grande de América del Norte, según su plantilla. CGI y sus empresas afiliadas emplean a 20.000 profesionales. La tasa de ejecución de ingresos anualizada de CGI es actualmente de 2.800 millones de dólares canadienses (1.900 millones de dólares estadounidenses) y al 30 de septiembre de 2003, la cartera de pedidos de CGI era de 12.300 millones de dólares canadienses (9.100 millones de dólares estadounidenses). CGI brinda servicios integrales de TI y procesos comerciales a clientes de todo el mundo desde oficinas en Canadá, Estados Unidos y Europa. Las acciones de CGI cotizan en la TSX (GIB.A) y la Bolsa de Nueva York (GIB) y están incluidas en el índice compuesto TSX 100, así como en el sitio web de los índices canadienses de tecnología de la información y MidCap de S&P/TSX: .

  • Tutorial

Buenas tardes.
En este artículo me gustaría hablar sobre el protocolo FastCGI y cómo trabajar con él. A pesar de que el protocolo en sí y su implementación aparecieron en 1996, simplemente no existen manuales detallados para este protocolo; los desarrolladores nunca escribieron ayuda para su propia biblioteca. Pero hace dos años, cuando comencé a usar este protocolo, a menudo escuchaba frases como "No entiendo muy bien cómo usar esta biblioteca". Es esta deficiencia la que quiero corregir: escribir una guía detallada sobre el uso de este protocolo en un programa multiproceso y recomendaciones para elegir varios parámetros que cualquiera pueda usar.

La buena noticia es que el método de codificación de datos en FastCGI y en CGI es el mismo, solo cambia el método de transmisión: si un programa CGI usa la interfaz de entrada-salida estándar, entonces un programa FastCGI usa sockets. En otras palabras, solo necesita comprender algunas funciones de la biblioteca para trabajar con FastCGI y luego aprovechar la experiencia de escribir programas CGI, de los cuales, afortunadamente, hay muchos ejemplos.

Entonces, en este artículo veremos:
- ¿Qué es FastCGI y en qué se diferencia del protocolo CGI?
- ¿Por qué necesito FastCGI cuando ya existen muchos lenguajes para el desarrollo web?
- ¿Qué implementaciones del protocolo FastCGI existen?
- ¿Qué son los enchufes?
- Descripción de las funciones de la biblioteca FastCGI
- Un ejemplo simple de un programa FastCGI multiproceso
- Ejemplo de configuración simple de Nginx
Desafortunadamente, es muy difícil escribir un artículo que sea igualmente comprensible para principiantes e interesante para los veteranos experimentados, por lo que intentaré cubrir todos los puntos con el mayor detalle posible y usted simplemente puede omitir las secciones que no sean interesantes. A usted.

¿Qué es FastCGI?

Puede leer sobre FastCGI en Wikipedia. En pocas palabras, es un programa CGI que se ejecuta en bucle. Si se reinicia un programa CGI normal para cada nueva solicitud, entonces un programa FastCGI utiliza una cola de solicitudes que se procesan secuencialmente. Ahora imagine: su servidor de 4 a 8 núcleos recibió entre 300 y 500 solicitudes simultáneas. Un programa CGI típico ejecutará estos mismos 300-500 veces. Obviamente, hay demasiados procesos: su servidor físicamente no puede procesarlos todos a la vez. Esto significa que terminará con una cola de procesos esperando su intervalo de tiempo del procesador. Normalmente, el programador distribuirá el procesador de manera uniforme (por lo que, en este caso, las prioridades de todos los procesos son las mismas), lo que significa que tendrá entre 300 y 500 respuestas "casi listas" a las solicitudes. No suena muy optimista, ¿verdad? En el programa FastCGI, todos estos problemas se resuelven mediante una cola de solicitudes simple (es decir, se utiliza la multiplexación de solicitudes).

¿Por qué necesito FastCGI cuando ya tengo PHP, Ruby, Python, Perl, etc.?

Quizás la razón principal es que un programa compilado se ejecutará más rápido que uno interpretado. Para PHP, por ejemplo, existe toda una línea de aceleradores, incluidos APC, eAccelerator, XCache, que reducen el tiempo de interpretación del código. Pero para C/C++ todo esto simplemente no es necesario.
Lo segundo que debes recordar es que la escritura dinámica y el recolector de basura consumen muchos recursos. A veces, mucho. Por ejemplo, las matrices de enteros en PHP ocupan aproximadamente 18 veces más memoria (hasta 35 veces dependiendo de las diversas opciones de compilación de PHP) que en C/C++ para la misma cantidad de datos, así que piense en la sobrecarga para estructuras de datos relativamente grandes.
En tercer lugar, un programa FastCGI puede almacenar datos comunes a diferentes solicitudes. Por ejemplo, si PHP comienza a procesar una solicitud desde cero cada vez, entonces el programa FastCGI puede realizar una serie de acciones preparatorias incluso antes de que llegue la primera solicitud, por ejemplo, asignar memoria, cargar datos de uso frecuente, etc. - Obviamente, todo esto puede mejorar el rendimiento general del sistema.
El cuarto es la escalabilidad. Si mod_php supone que el servidor web Apache y PHP están en la misma máquina, entonces la aplicación FastCGI puede usar sockets TCP. En otras palabras, puede tener un grupo completo de varias máquinas, cuya comunicación se realiza a través de la red. Al mismo tiempo, FastCGI también admite sockets de dominio Unix, lo que le permite ejecutar de manera eficiente una aplicación FastCGI y un servidor web en la misma máquina si es necesario.
Quinto - seguridad. Lo creas o no, con la configuración predeterminada, Apache te permite hacer todo lo que hay bajo el sol. Por ejemplo, si un atacante carga un script malicioso exploit.php.jpg en un sitio web bajo la apariencia de una "imagen inocente" y luego lo abre en el navegador, Apache ejecutará "honestamente" el código PHP malicioso. Quizás la única solución bastante confiable sea eliminar o cambiar todas las extensiones potencialmente peligrosas de los nombres de los archivos descargados, en este caso: php, php4, php5, phtml, etc. Esta técnica se utiliza, por ejemplo, en Drupal: se agrega un guión bajo a todas las extensiones "adicionales" y el resultado es exploit.php_.jpg. Sin embargo, cabe señalar que un administrador del sistema puede agregar cualquier extensión de archivo adicional como controlador de php, por lo que algunos archivos .html podrían convertirse repentinamente en un terrible agujero de seguridad simplemente porque .php se veía feo, era malo para el SEO o el cliente no. No me gusta. Entonces, ¿qué nos aporta FastCGI en términos de seguridad? En primer lugar, si utiliza el servidor web Nginx en lugar de Apache, simplemente servirá archivos estáticos. Punto. En otras palabras, el archivo exploit.php.jpg se entregará "tal cual", sin ningún procesamiento en el lado del servidor, por lo que simplemente no será posible ejecutar un script malicioso. En segundo lugar, el programa FastCGI y el servidor web pueden funcionar con diferentes usuarios, lo que significa que tendrán diferentes derechos sobre archivos y carpetas. Por ejemplo, un servidor web solo puede leer archivos descargados; esto es suficiente para devolver datos estáticos, y un programa FastCGI solo puede leer y cambiar el contenido de la carpeta con los archivos descargados; esto es suficiente para descargar archivos nuevos y eliminar archivos antiguos, pero El acceso directo a los archivos descargados no lo tendrá, lo que significa que tampoco podrá ejecutar código malicioso. En tercer lugar, un programa FastCGI puede ejecutarse en un chroot diferente del chroot del servidor web. El propio Chroot (cambiar el directorio raíz) le permite limitar en gran medida los derechos de un programa, es decir, aumentar la seguridad general del sistema, porque el programa simplemente no podrá acceder a archivos fuera del directorio especificado.

¿Qué servidor web con soporte FastCGI es mejor elegir?

En resumen, uso Nginx. En general, existen bastantes servidores que admiten FastCGI, incluidos los comerciales, así que consideremos varias alternativas.
Apache es quizás lo primero que nos viene a la cabeza, aunque consume muchos más recursos que Nginx. Por ejemplo, para 10.000 conexiones HTTP keep-alive inactivas, Nginx consume alrededor de 2,5 M de memoria, lo cual es bastante realista incluso para una máquina relativamente débil, y Apache se ve obligado a crear un nuevo hilo para cada nueva conexión, por lo que 10.000 hilos son simplemente fantástico.
Lighttpd: la principal desventaja de este servidor web es que procesa todas las solicitudes en un solo hilo. Esto significa que puede haber problemas con la escalabilidad: simplemente no podrá utilizar los 4 a 8 núcleos de los procesadores modernos. Y en segundo lugar, si por alguna razón el hilo del servidor web se congela (por ejemplo, debido a una larga espera por una respuesta del disco duro), todo el servidor se congelará. En otras palabras, todos los demás clientes dejarán de recibir respuestas debido a una solicitud lenta.
Otro candidato es el Cherokee. Según los desarrolladores, en algunos casos funciona más rápido que Nginx y Lighttpd.

¿Qué implementaciones del protocolo FastCGI existen?

Por el momento, existen dos implementaciones del protocolo FastCGI: la biblioteca libfcgi.lib de los creadores del protocolo FastCGI y Fastcgi++, una biblioteca de clases C++. Libfcgi se ha desarrollado desde 1996 y, según Open Market, es muy estable y está más extendido, por lo que lo utilizaremos en este artículo. Me gustaría señalar que la biblioteca está escrita en C, el "envoltorio" integrado de C++ no se puede llamar de alto nivel, por lo que usaremos la interfaz C.
Creo que no tiene sentido detenerse en la instalación de la biblioteca en sí: tiene un archivo MAKE, por lo que no debería haber problemas. Además, en distribuciones populares esta biblioteca está disponible en paquetes.

¿Qué son los enchufes?

Se puede obtener un concepto general de sockets en Wikipedia. En pocas palabras, los sockets son un método de comunicación entre procesos.
Como recordamos, en todos los sistemas operativos modernos, cada proceso utiliza su propio espacio de direcciones. El kernel del sistema operativo es responsable del acceso directo a la RAM, y si un programa accede a una dirección de memoria que no existe (en el contexto de un programa determinado), el kernel devolverá un error de segmentación y cerrará el programa. Esto es maravilloso: ahora los errores en un programa simplemente no pueden dañar a otros; están, por así decirlo, en otras dimensiones. Pero como los programas tienen diferentes espacios de direcciones, tampoco puede haber datos compartidos ni intercambio de datos. Pero ¿qué pasa si realmente necesitas transferir datos de un programa a otro? En realidad, los sockets se desarrollaron para resolver este problema: dos o más procesos (léase: programas) se conectan al mismo socket y comienzan a intercambiar datos. Resulta ser una especie de "ventana" a otro mundo: a través de ella se pueden recibir y enviar datos a otras transmisiones.
Dependiendo del tipo de conexión utilizada, los enchufes son diferentes. Por ejemplo, existen sockets TCP: utilizan una red normal para intercambiar datos, es decir, los programas pueden ejecutarse en diferentes computadoras. La segunda opción más común, los sockets de dominio Unix, son adecuados para intercambiar datos solo dentro de una máquina y parecen una ruta normal en el sistema de archivos, pero en realidad no se utiliza el disco duro: todo el intercambio de datos se produce en la RAM. Debido al hecho de que no es necesario utilizar una pila de red, son un poco más rápidos (aproximadamente un 10%) que los sockets TCP. Para el sistema operativo Windows, esta opción de socket se denomina canalización con nombre.
En este artículo se pueden encontrar ejemplos del uso de sockets para el sistema operativo GNU/Linux. Si no ha trabajado antes con sockets, le recomendaría que se familiarice con él; no es obligatorio, pero mejorará su comprensión de lo que se presenta aquí.

¿Cómo utilizar la biblioteca Libfcgi?

Entonces, queremos crear una aplicación FastCGI multiproceso, así que permítanme describir algunas de las funciones más importantes.
En primer lugar, es necesario inicializar la biblioteca:
int FCGX_Init(nulo);
¡Atención! Esta función debe llamarse antes que cualquier otra función en esta biblioteca y solo una vez (solo una vez, para cualquier número de subprocesos).

A continuación necesitamos abrir un conector de escucha:
int FCGX_OpenSocket(const char *ruta, int backlog);
La variable de ruta contiene la cadena de conexión del socket. Se admiten tanto los sockets de dominio Unix como los sockets TCP; la biblioteca hará todo el trabajo necesario para preparar los parámetros y llamar a una función.
Ejemplos de cadenas de conexión para sockets de dominio Unix:
"/tmp/fastcgi/mysocket" "/tmp/fcgi_example.bare.sock"
Creo que aquí todo está claro: solo necesita pasar una ruta única como una cadena, y todos los procesos que interactúan con el socket deben tener acceso a ella. Repito una vez más: este método sólo funciona dentro de una computadora, pero es algo más rápido que los sockets TCP.
Ejemplos de cadenas de conexión para sockets TCP:
":5000" ":9000"
En este caso, se abre un socket TCP en el puerto especificado (en este caso, 5000 o 9000, respectivamente) y se aceptarán solicitudes desde cualquier dirección IP. ¡Atención! Este método es potencialmente inseguro: si su servidor está conectado a Internet, su programa FastCGI aceptará solicitudes de cualquier otra computadora. Esto significa que cualquier atacante podrá enviar un "paquete de muerte" a su programa FastCGI. Por supuesto, esto no tiene nada de bueno: en el mejor de los casos, su programa puede simplemente "fallarse" y provocar una denegación de servicio (ataque DoS, si lo desea); en el peor de los casos, la ejecución remota de código (si lo desea). Si eres realmente desafortunado), por lo tanto, siempre limita el acceso a dichos puertos usando un firewall (firewall), y el acceso debe otorgarse solo a aquellas direcciones IP que realmente se usan durante el funcionamiento normal del programa FastCGI (el principio de "todo lo que no es permitido explícitamente está prohibido”).
El siguiente es un ejemplo de cadenas de conexión:
"*:5000" "*:9000"
El método es completamente similar al anterior: se abre un socket TCP para aceptar conexiones desde cualquier dirección IP, por lo que en este caso también es necesario configurar cuidadosamente el firewall. La única ventaja de dicha línea de conexión es puramente administrativa: cualquier programador o administrador del sistema que lea los archivos de configuración comprenderá que su programa acepta conexiones desde cualquier dirección IP, por lo que, en igualdad de condiciones, es mejor preferir esta opción a la el anterior.
Una opción más segura es especificar explícitamente la dirección IP en la cadena de conexión:
"5.5.5.5:5000" "127.0.0.1:9000"
En este caso, las solicitudes se aceptarán solo desde la dirección IP especificada (en este caso, 5.5.5.5 o 127.0.0.1, respectivamente), para todas las demás direcciones IP, este puerto (en este caso, 5000 o 9000, respectivamente) será cerrado. Esto aumenta la seguridad general del sistema, por lo que siempre que sea posible, utilice siempre este formato de cadena de conexión para los sockets TCP. ¿Qué pasa si el administrador del sistema “simplemente se olvida” de configurar el firewall? Preste atención al segundo ejemplo: allí se indica la dirección de la misma máquina (localhost). Esto le permite crear un socket TCP en la misma máquina si por alguna razón no puede usar sockets de dominio Unix (por ejemplo, porque el chroot del servidor web y el chroot del programa FastCGI están en carpetas diferentes y no tienen rutas de archivos comunes). Desafortunadamente, no puede especificar dos o más direcciones IP diferentes, por lo que si realmente necesita aceptar solicitudes de múltiples servidores web ubicados en diferentes computadoras, tendrá que abrir el puerto por completo (consulte el método anterior) y confiar en la configuración de su firewall o use múltiples sockets en diferentes puertos. Además, la biblioteca libfcgi no admite direcciones IPv6; en 1996, este estándar acaba de nacer, por lo que tendrá que limitar su apetito a direcciones IPv4 normales. Es cierto que si realmente necesita compatibilidad con IPv6, es relativamente fácil agregarlo parcheando la función FCGX_OpenSocket; la licencia de la biblioteca lo permite.
¡Atención! Usar la función de especificar una dirección IP al crear un socket no es una protección suficiente: los ataques de suplantación de IP (sustituyendo la dirección IP del remitente del paquete) son posibles, por lo que aún es necesario configurar un firewall. Normalmente, como protección contra la suplantación de IP, el firewall verifica la correspondencia entre la dirección IP del paquete y la dirección MAC de la tarjeta de red para todos los hosts de nuestra red local (más precisamente, para el dominio de transmisión con nuestro host) y descarta todos los paquetes provenientes de Internet cuya dirección de retorno se encuentre en la zona de direcciones IP privadas o host local (máscaras 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7, 127.0.0.0/ 8 y::1/128). Sin embargo, es mejor utilizar esta función de biblioteca: en el caso de un firewall configurado incorrectamente, enviar un "paquete de muerte" desde una dirección IP falsificada es mucho más difícil que desde cualquier otra, ya que el protocolo TCP tiene incorporado protección contra la suplantación de propiedad intelectual.
El último tipo de cadena de conexión es utilizar el nombre de dominio del host:
"ejemplo.com:5000" "localhost:9000"
En este caso, la dirección IP se obtendrá automáticamente en función del nombre de dominio del host que haya especificado. Las restricciones siguen siendo las mismas: el host debe tener una dirección IPv4; de lo contrario, se producirá un error. Sin embargo, dado que el socket se crea una vez al comienzo de trabajar con FastCGI, es poco probable que este método sea muy útil: cambiar dinámicamente la dirección IP aún no funcionará (más precisamente, después de cada cambio de dirección IP tendrá para reiniciar su programa FastCGI). Por otro lado, quizás esto sea útil para una red relativamente grande: recordar un nombre de dominio es aún más fácil que una dirección IP.

El segundo parámetro de la función de trabajo pendiente especifica la longitud de la cola de solicitudes de socket. El valor especial 0 (cero) indica la longitud de cola predeterminada para este sistema operativo.
Cada vez que llega una solicitud del servidor web, se coloca una nueva conexión en esta cola, esperando ser procesada por nuestro programa FastCGI. Si la cola está completamente llena, todas las solicitudes de conexión posteriores fallarán: el servidor web recibirá una respuesta de Conexión rechazada. En principio, no hay nada de malo en esto: el servidor web Nginx tiene su propia cola de solicitudes y, si no hay recursos libres, las nuevas solicitudes esperarán su turno para procesarse ya en la cola del servidor web (al menos hasta que se agote el tiempo de espera). expirar). Además, si tiene varios servidores ejecutando FastCGI, Nginx puede pasar dicha solicitud a un servidor menos cargado.
Entonces, intentemos averiguar cuál será la longitud óptima de la cola. En general, es mejor configurar este parámetro individualmente según los datos de las pruebas de carga, pero intentaremos estimar el rango más adecuado para este valor. Lo primero que debe saber es que la longitud máxima de la cola es limitada (determinada por la configuración del kernel del sistema operativo, generalmente no más de 1024 conexiones). En segundo lugar, la cola consume recursos, baratos, pero aún así recursos, por lo que no deberías alargarla excesivamente. Además, digamos que nuestro programa FastCGI tiene 8 subprocesos de trabajo (bastante realista para procesadores modernos de 4 a 8 núcleos), y cada subproceso necesita su propia conexión: las tareas se procesan en paralelo. Esto significa que, idealmente, ya deberíamos tener 8 solicitudes del servidor web para poder proporcionar trabajo a todos los subprocesos de inmediato, sin demoras innecesarias. En otras palabras, el tamaño mínimo de la cola de solicitudes es la cantidad de subprocesos de trabajo del programa FastCGI. Puede intentar aumentar este valor entre un 50 % y un 100 % para proporcionar algo de margen para la carga, ya que el tiempo de transferencia de datos a través de la red es finito.
Ahora determinemos el límite superior de este valor. Aquí necesitamos saber cuántas solicitudes podemos procesar realmente y limitar la cola de solicitudes a este valor. Imagine que ha hecho esta cola demasiado grande, hasta el punto de que sus clientes simplemente se cansan de esperar su turno y simplemente abandonan su sitio sin esperar una respuesta. Obviamente, esto no tiene nada de bueno: el servidor web tuvo que enviar una solicitud para abrir una conexión, lo que en sí mismo es costoso, y luego cerrar esta conexión solo porque el programa FastCGI no tuvo tiempo suficiente para procesar esta solicitud. En una palabra, solo estamos desperdiciando tiempo del procesador, ¡pero simplemente no tenemos suficiente! Pero esto no es lo peor: es peor cuando el cliente se niega a recibir información de su sitio después de que la solicitud ha comenzado a procesarse. Resulta que tendremos que procesar por completo una solicitud esencialmente inútil, lo que, como ve, solo empeorará la situación. Teóricamente, puede surgir una situación en la que la mayoría de los clientes no esperarán una respuesta cuando su procesador esté 100% cargado. Malo.
Entonces, digamos que podemos procesar una solicitud en 300 milisegundos (es decir, 0,3 segundos). A continuación, sabemos que, en promedio, el 50% de los visitantes abandonan un recurso si una página web tarda más de 30 segundos en cargarse. Evidentemente, el 50% de personas insatisfechas es demasiado, por lo que limitaremos el tiempo máximo de carga de la página a 5 segundos. Esto significa una página web completamente terminada: después de aplicar hojas de estilo en cascada y ejecutar JavaScript, esta etapa en un sitio promedio puede tomar el 70% del tiempo total de carga de una página web, por lo que no quedan más de 5 días para cargar los datos. la red *0,3 = 1,5 segundos A continuación, debe recordar que el código html, las hojas de estilo, los scripts y los gráficos se transfieren en archivos diferentes, y primero, el código html, y luego todo lo demás, sin embargo, después de recibir el código html. el navegador comienza a solicitar los recursos restantes en paralelo, por lo que podemos estimar el tiempo de carga del código html como el 50% del tiempo total para recibir datos. Entonces, no nos quedan más de 1,5 * 0,5 = 0,75 segundos para procesar uno. solicitud. Si en promedio un subproceso procesa una solicitud en 0,3 segundos, entonces debería haber 0,75/0,3 = 2,5 solicitudes por subproceso en la cola. Dado que tenemos 8 subprocesos de trabajo, el tamaño de la cola resultante debería ser 2,5 *8 = 20 solicitudes. Me gustaría señalar que los cálculos anteriores son condicionales: si tiene un sitio específico, los valores utilizados en el cálculo se pueden determinar con mucha más precisión, pero aún proporciona un punto de partida para un ajuste del rendimiento más óptimo.

Entonces, recibimos un descriptor de socket, después del cual necesitamos asignar memoria para la estructura de la solicitud. La descripción de esta estructura es la siguiente:
typedef struct FCGX_Request ( int requestId; int role; FCGX_Stream *in; FCGX_Stream *out; FCGX_Stream *err; char **envp; struct Params *paramsPtr; int ipcFd; int isBeginProcessed; int keepConnection; int appStatus; int nWriters; int flags; int escucha_sock; int separado;) FCGX_Request;
¡Atención! Después de recibir una nueva solicitud, se perderán todos los datos anteriores, por lo que si necesita almacenar datos durante mucho tiempo, utilice la copia profunda (copie los datos en sí, no los punteros a los datos).
Debes saber lo siguiente sobre esta estructura:
- las variables in, out y err desempeñan el papel de flujos de entrada, salida y error, respectivamente. El flujo de entrada contiene los datos de la solicitud POST, la respuesta del programa FastCGI (por ejemplo, encabezados http y código html de la página web) debe enviarse al flujo de salida y el flujo de error simplemente agregará una entrada al servidor web. registro de errores. En este caso, no es necesario utilizar el flujo de errores en absoluto; si realmente necesita registrar errores, entonces quizás sea mejor usar un archivo separado para esto: transferir datos a través de la red y su procesamiento posterior mediante el servidor web consume recursos adicionales.
- la variable envp contiene los valores de las variables de entorno establecidas por el servidor web y los encabezados http, por ejemplo: SERVER_PROTOCOL, REQUEST_METHOD, REQUEST_URI, QUERY_STRING, CONTENT_LENGTH, HTTP_USER_AGENT, HTTP_COOKIE, HTTP_REFERER, etc. Estos encabezados están definidos por los estándares de protocolo CGI y HTTP, respectivamente, se pueden encontrar ejemplos de su uso en cualquier programa CGI. Los datos en sí se almacenan en una matriz de cadenas, y el último elemento de la matriz contiene un puntero nulo (NULL) para indicar el final de la matriz. Cada línea (cada elemento de la matriz de cadenas) contiene un valor de variable en el formato VARIABLE_NAME=VALUE, por ejemplo: CONTENT_LENGTH=0 (en este caso, significa que esta solicitud no tiene datos POST, ya que su longitud es cero). Si la matriz de cadenas envp no contiene el encabezado que necesita, significa que no se transmitió. Si desea pasar todos los valores de las variables al programa FastCGI, simplemente lea todas las líneas de la matriz envp en un bucle hasta que encuentre un puntero a NULL.
En realidad, hemos terminado con la descripción de esta estructura; no necesitarás todas las demás variables.

La memoria ha sido asignada, ahora necesita inicializar la estructura de la solicitud:
int FCGX_InitRequest(FCGX_Request *solicitud, int calcetín, int banderas);
Los parámetros de la función son los siguientes:
solicitud: puntero a la estructura de datos que se inicializará
calcetín es el descriptor de socket que recibimos después de llamar a la función FCGX_OpenSocket. Me gustaría señalar que en lugar de un descriptor listo para usar, puede pasar 0 (cero) y recibir un socket con la configuración predeterminada, pero para nosotros este método no es nada interesante: el socket se abrirá en un puerto libre aleatorio. , lo que significa que no podremos configurar correctamente nuestro servidor web, no sabemos de antemano dónde exactamente se deben enviar los datos.
banderas - banderas. En realidad, solo se puede pasar un indicador a esta función: FCGI_FAIL_ACCEPT_ON_INTR; no llame a FCGX_Accept_r cuando se interrumpa.

Después de esto necesitas recibir una nueva solicitud:
int FCGX_Accept_r(FCGX_Request *solicitud);
Debe pasarle la estructura de solicitud ya inicializada en la etapa anterior. ¡Atención! En un programa multiproceso, debe utilizar la sincronización al llamar a esta función.
En realidad, esta función hace todo el trabajo con los sockets: primero, envía una respuesta al servidor web a la solicitud anterior (si la hubo), cierra el canal de datos anterior y libera todos los recursos asociados con él (incluidas las variables de estructura de la solicitud). , luego recibe una nueva solicitud, abre un nuevo canal de datos y prepara nuevos datos en la estructura de la solicitud para su posterior procesamiento. Si hay un error al recibir una nueva solicitud, la función devuelve un código de error menor que cero.

A continuación, probablemente necesitará obtener variables de entorno. Para ello, puede procesar la matriz request->envp usted mismo o utilizar la función;
char *FCGX_GetParam(const char *nombre, FCGX_ParamArray envp);
donde nombre es una cadena que contiene el nombre de la variable de entorno o encabezado http cuyo valor desea obtener,
envp: una matriz de variables de entorno contenidas en la variable solicitud->envp
La función devuelve el valor de la variable de entorno que necesitamos como una cadena. Que el lector atento no se alarme por la falta de coincidencia de tipos entre char ** y FCGX_ParamArray; estos tipos se declaran sinónimos (typedef char **FCGX_ParamArray).
Además, probablemente necesitarás enviar una respuesta al servidor web. Para hacer esto, necesita usar la solicitud->flujo de salida de salida y la función
int FCGX_PutStr(const char *cadena, int n, FCGX_Stream *flujo);
donde str es un búfer que contiene los datos que se van a generar, sin el nulo final (es decir, el búfer puede contener datos binarios),
n - longitud del búfer en bytes,
flujo: el flujo en el que queremos generar datos (solicitud->salida o solicitud->err).

Si utiliza cadenas C estándar terminadas en nulo, será más conveniente utilizar la función
int FCGX_PutS(const char *cadena, FCGX_Stream *corriente);
que simplemente determinará la longitud de la cadena usando strlen(str) y llamará a la función anterior. Por lo tanto, si conoce la longitud de la cadena de antemano (por ejemplo, usa C++ std::strings), es mejor usar la función anterior por razones de eficiencia.
Me gustaría señalar que estas funciones funcionan perfectamente con cadenas UTF-8, por lo que no debería haber problemas con las aplicaciones web multilingües.
También puede llamar a estas funciones varias veces mientras procesa la misma solicitud; en algunos casos, esto puede mejorar el rendimiento. Por ejemplo, necesita enviar un archivo grande. En lugar de descargar este archivo completo desde su disco duro y luego enviarlo de una sola vez, puede comenzar a enviar datos de inmediato. Como resultado, el cliente, en lugar de una pantalla blanca del navegador, comenzará a recibir los datos que le interesan, lo que, puramente psicológicamente, le obligará a esperar un poco más. En otras palabras, ganas un poco de tiempo para que se cargue la página. También me gustaría señalar que la mayoría de los recursos (hojas de estilo en cascada, JavaScript, etc.) se indican al principio de la página web, es decir, el navegador podrá analizar parte del código html y comenzar a cargar estos recursos antes. - otra razón para mostrar datos en partes.

Lo siguiente que quizás deba hacer es procesar la solicitud POST. Para obtener su valor, necesita leer los datos de la solicitud->en flujo usando la función
int FCGX_GetStr(char * str, int n, FCGX_Stream *flujo);
donde str es un puntero al búfer,
n - tamaño del búfer en bytes,
flujo: el flujo del cual estamos leyendo datos.
El tamaño de los datos transmitidos en una solicitud POST (en bytes) se puede determinar utilizando la variable de entorno CONTENT_LENGTH, cuyo valor, como recordamos, se puede obtener utilizando la función FCGX_GetParam. ¡Atención! Crear un búfer str basado en el valor de la variable CONTENT_LENGTH sin restricciones es una muy mala idea: cualquier atacante puede enviar cualquier solicitud POST, sin importar cuán grande sea, y su servidor simplemente puede quedarse sin RAM libre (esto resultará en un Ataque DoS, si lo desea). En su lugar, es mejor limitar el tamaño del búfer a un valor razonable (desde unos pocos kilobytes hasta varios megabytes) y llamar a la función FCGX_GetStr varias veces.

La última función importante muestra los flujos de salida y de error (envía al cliente los datos aún no enviados que logramos colocar en los flujos de salida y de error) y cierra la conexión:
void FCGX_Finish_r(FCGX_Request *solicitud);
Me gustaría señalar especialmente que esta función es opcional: la función FCGX_Accept_r también envía datos al cliente y cierra la conexión actual antes de recibir una nueva solicitud. Surge la pregunta: entonces, ¿por qué es necesario? Imagine que ya ha enviado al cliente todos los datos necesarios y ahora necesita realizar algunas operaciones finales: escribir estadísticas en la base de datos, errores en el archivo de registro, etc. Obviamente, la conexión con el cliente ya no es necesaria, pero el cliente (es decir, el navegador) todavía está esperando nuestra información: ¿y si enviamos algo más? Al mismo tiempo, es obvio que no podemos llamar a FCGX_Accept_r con anticipación; después de esto, tendremos que comenzar a procesar la siguiente solicitud. Es en este caso que necesitará la función FCGX_Finish_r: le permitirá cerrar la conexión actual antes de recibir una nueva solicitud. Sí, podremos procesar la misma cantidad de solicitudes por unidad de tiempo que sin usar esta función, pero el cliente recibirá una respuesta antes; ya no tendrá que esperar hasta el final de nuestras operaciones finales, y es Precisamente por la mayor velocidad de procesamiento de solicitudes que utilizamos FastCGI.
De hecho, esto finaliza la descripción de las funciones de la biblioteca y comienza el procesamiento de los datos recibidos.

Un ejemplo simple de un programa FastCGI multiproceso

Creo que todo quedará claro en el ejemplo. Lo único es que imprimir mensajes de depuración y "dormir" el hilo de trabajo se realiza únicamente con fines de demostración. Al compilar el programa, no olvide incluir las bibliotecas libfcgi y libpthread (opciones del compilador gcc: -lfcgi y -lpthread).

#incluir #incluir #incluir #include "fcgi_config.h" #include "fcgiapp.h" #define THREAD_COUNT 8 #define SOCKET_PATH "127.0.0.1:9000" //almacena el identificador del socket abierto static int socketId; static void *doit(void *a) ( int rc, i; FCGX_Request request; char *server_name; if(FCGX_InitRequest(&request, socketId, 0) != 0) ( //error al inicializar la estructura de la solicitud printf("No se puede init request\n"); return NULL; ) printf("La solicitud se inicia\n"); for(;;) ( static pthread_mutex_t Accept_mutex = PTHREAD_MUTEX_INITIALIZER; //intenta recibir una nueva solicitud printf("Intenta aceptar una nueva solicitud \n" ); pthread_mutex_lock(&accept_mutex); rc = FCGX_Accept_r(&request);< 0) { //ошибка при получении запроса printf("Can not accept new request\n"); break; } printf("request is accepted\n"); //получить значение переменной server_name = FCGX_GetParam("SERVER_NAME", request.envp); //вывести все HTTP-заголовки (каждый заголовок с новой строки) FCGX_PutS("Content-type: text/html\r\n", request.out); //между заголовками и телом ответа нужно вывести пустую строку FCGX_PutS("\r\n", request.out); //вывести тело ответа (например - html-код веб-страницы) FCGX_PutS("\r\n", solicitud.out); FCGX_PutS(" \r\n", solicitud.out); FCGX_PutS("\r\n", solicitud.out); FCGX_PutS(" \r\n", solicitud.out); FCGX_PutS("

FastCGI ¡Hola! (C multiproceso, biblioteca fcgiapp)

\r\n", solicitud.out); FCGX_PutS("

Solicitud aceptada del anfitrión ", solicitud.out); FCGX_PutS(nombre_servidor? nombre_servidor: "?", solicitud.out); FCGX_PutS("

\r\n", solicitud.out); FCGX_PutS("

\r\n", solicitud.out); FCGX_PutS("\r\n", request.out); //"quedarse dormido" - imitación de un entorno multiproceso sleep(2); //cerrar la conexión actual FCGX_Finish_r(&request); //acciones finales - registrar estadísticas, iniciar sesión errores, etc. ) return NULL; ) int main(void) ( int i; pthread_t id; //inicializa la biblioteca FCGX_Init(); printf("Lib is inited\n"); //abre un nuevo socket socketId = FCGX_OpenSocket (SOCKET_PATH, 20);< 0) { //ошибка при открытии сокета return 1; } printf("Socket is opened\n"); //создаём рабочие потоки for(i = 0; i < THREAD_COUNT; i++) { pthread_create(&id[i], NULL, doit, NULL); } //ждем завершения рабочих потоков for(i = 0; i < THREAD_COUNT; i++) { pthread_join(id[i], NULL); } return 0; }

Ejemplo de configuración simple de Nginx

En realidad, el ejemplo más simple de configuración se ve así:

Servidor ( nombre_servidor localhost; ubicación / ( fastcgi_pass 127.0.0.1:9000; #fastcgi_pass unix:/tmp/fastcgi/mysocket; #fastcgi_pass localhost:9000; incluye fastcgi_params; ) )

En este caso, esta configuración es suficiente para que nuestro programa FastCGI funcione correctamente. Las líneas comentadas son un ejemplo de cómo trabajar con sockets de dominio Unix y especificar un nombre de host de dominio en lugar de una dirección IP.
Después de compilar y ejecutar el programa y configurar Nginx, recibí una inscripción de orgullo en la dirección del host local:
FastCGI ¡Hola! (C multiproceso, biblioteca fcgiapp)

Gracias a todos los que leyeron hasta el final.

Gracias a la World Wide Web, casi cualquier persona puede proporcionar información en línea en un formato agradable a la vista y que pueda difundirse ampliamente. Sin duda, ha navegado por Internet y visto otros sitios, y ahora probablemente sepa que acrónimos aterradores como "HTTP" y "HTML" son simplemente una abreviatura de "Web" y "la forma en que se expresa la información en Internet". Es posible que ya tenga cierta experiencia presentando información en Internet.

Internet ha demostrado ser un medio ideal para distribuir información, como lo demuestra su enorme popularidad y su amplio desarrollo. Aunque algunos han cuestionado la utilidad de Internet y atribuyen su amplio desarrollo y popularidad principalmente a la publicidad intrusiva, es innegable que Internet es un medio importante para presentar todo tipo de información. No sólo hay muchos servicios disponibles para proporcionar información actualizada (noticias, clima, eventos deportivos en vivo) y materiales de referencia electrónicamente, sino que también hay cantidades significativas de otros tipos de datos disponibles. El IRS, que distribuyó todos sus formularios de declaración de impuestos de 1995 y otra información a través de la World Wide Web, admitió recientemente haber recibido correo de fans de su sitio Web. ¿Quién hubiera pensado que el IRS recibiría alguna vez cartas de fans? Esto no se debió a que su sitio estuviera bien diseñado, sino a que había demostrado ser una herramienta verdaderamente útil para miles, tal vez millones, de personas.

¿Qué hace que la Web sea un servicio de información único y tan atractivo? En primer lugar, proporciona una interfaz hipermedia para los datos. Piense en el disco duro de su computadora. Normalmente, los datos se expresan de forma lineal, similar a un sistema de archivos. Por ejemplo, tiene varias carpetas y dentro de cada carpeta hay documentos u otras carpetas. La web utiliza un paradigma diferente para expresar información llamado hipermedia. Una interfaz de hipertexto consta de un documento y enlaces. Los enlaces son palabras en las que se hace clic para ver otros documentos o encontrar otro tipo de información. La Web amplía el concepto de hipertexto para incluir otros tipos de medios, como gráficos, sonidos y vídeos (de ahí el nombre "hipermedios"). Seleccionar texto o gráficos en un documento le permite ver información relacionada sobre el elemento seleccionado en cualquier cantidad de formas.

Casi todo el mundo puede beneficiarse de esta forma sencilla y única de presentar y distribuir información, desde académicos que quieren utilizar datos inmediatamente con sus colegas hasta empresarios que comparten información sobre su empresa con todo el mundo. Sin embargo, aunque dar información es extremadamente importante, en los últimos años muchos han sentido que recibir información es un proceso igualmente importante.

Aunque la Web proporciona una interfaz hipermedia única para la información, existen muchas otras formas efectivas de distribuir datos. Por ejemplo, los servicios de red como el Protocolo de transferencia de archivos (FTP) y el grupo de noticias Gopher existieron mucho antes que la World Wide Web. El correo electrónico ha sido el principal medio de comunicación e intercambio de información en Internet y en la mayoría de las demás redes casi desde el comienzo de estas redes. ¿Por qué Internet se ha convertido en una forma tan popular de distribuir información? El aspecto multimedia de Internet ha contribuido significativamente a su éxito sin precedentes, pero para que Internet sea más eficaz debe ser interactivo.

Sin la capacidad de recibir comentarios de los usuarios y proporcionar información, la Web sería un entorno completamente estático. La información sólo estaría disponible en el formato especificado por el autor. Esto socavaría una de las capacidades de la informática en general: la información interactiva. Por ejemplo, en lugar de obligar al usuario a ver varios documentos como si estuviera mirando un libro o un diccionario, sería mejor permitirle identificar palabras clave sobre un tema de interés. Los usuarios pueden personalizar la presentación de los datos en lugar de depender de una estructura rígida definida por el proveedor de contenido.

El término "servidor web" puede resultar engañoso porque puede referirse tanto a la máquina física como al software que utiliza para comunicarse con los navegadores de Internet. Cuando un navegador solicita una dirección web determinada, primero se conecta a la máquina a través de Internet y envía al software del servidor web una solicitud del documento. Este software se ejecuta continuamente, esperando que lleguen dichas solicitudes y respondiendo en consecuencia.

Aunque los servidores pueden enviar y recibir datos, el servidor en sí tiene una funcionalidad limitada. Por ejemplo, el servidor más primitivo sólo puede enviar el archivo requerido al navegador. El servidor normalmente no sabe qué hacer con tal o cual entrada adicional. Si el ISP no le dice al servidor cómo manejar esta información adicional, lo más probable es que el servidor ignore la entrada.

Para que el servidor pueda realizar otras operaciones además de buscar y enviar archivos al navegador de Internet, es necesario saber cómo ampliar la funcionalidad del servidor. Por ejemplo, un servidor web no puede buscar en una base de datos basándose en una palabra clave ingresada por un usuario y devolver múltiples documentos coincidentes a menos que dicha capacidad haya sido programada en el servidor de alguna manera.

¿Qué es el CGI?

La interfaz de puerta de enlace común (CGI) es una interfaz para el servidor que le permite ampliar la funcionalidad del servidor. Usando CGI, puede interactuar interactivamente con los usuarios que acceden a su sitio. A nivel teórico, CGI permite que el servidor pueda analizar (interpretar) la entrada del navegador y devolver información basada en la entrada del usuario. A nivel práctico, CGI es una interfaz que permite a un programador escribir programas que se comunican fácilmente con un servidor.

Normalmente, para ampliar las capacidades del servidor, deberá modificarlo usted mismo. Esta solución no es deseable porque requiere comprender la capa inferior de la programación de la red del Protocolo de Internet. Esto también requeriría editar y recompilar el código fuente del servidor o escribir un servidor personalizado para cada tarea. Supongamos que desea ampliar las capacidades del servidor para que actúe como una puerta de enlace de Web a correo electrónico, tomando la información ingresada por el usuario desde el navegador y enviándola por correo electrónico a otro usuario. El servidor tendría que insertar un código para analizar la entrada del navegador, reenviarla por correo electrónico al otro usuario y reenviar la respuesta al navegador a través de la conexión de red.

En primer lugar, dicha tarea requiere acceso al código del servidor, lo que no siempre es posible.

En segundo lugar, es difícil y requiere amplios conocimientos técnicos.

En tercer lugar, esto sólo se aplica a un servidor específico. Si necesita mover su servidor a otra plataforma, tendrá que ejecutarlo o al menos dedicar mucho tiempo a migrar el código a esa plataforma.

¿Por qué CGI?

CGI ofrece una solución portátil y sencilla a estos problemas. El protocolo CGI define una forma estándar para que los programas se comuniquen con un servidor web. Sin ningún conocimiento especial, puede escribir un programa en cualquier lenguaje de máquina que interactúe y se comunique con el servidor web. Este programa funcionará con todos los servidores web que comprendan el protocolo CGI.

La comunicación CGI se realiza mediante entrada y salida estándar, lo que significa que si sabe cómo imprimir y leer datos utilizando su lenguaje de programación, puede escribir una aplicación de servidor web. Además de analizar la entrada y la salida, programar aplicaciones CGI es casi equivalente a programar cualquier otra aplicación. Por ejemplo, para programar el programa "¡Hola mundo!", utiliza las funciones de impresión de su idioma y el formato definido para los programas CGI para imprimir el mensaje apropiado.

Seleccionar un lenguaje de programación

Debido a que CGI es una interfaz universal, no está limitado a ningún lenguaje de máquina específico. Una pregunta importante que se hace a menudo es: ¿qué lenguajes de programación se pueden utilizar para la programación CGI? Puede utilizar cualquier idioma que le permita hacer lo siguiente:

  • Imprimir en salida estándar
  • Leer desde la entrada estándar
  • Leer desde modos variables

Casi todos los lenguajes de programación y muchos lenguajes de scripting hacen estas tres cosas y usted puede usar cualquiera de ellas.

Los idiomas se clasifican en una de las dos clases siguientes: traducidos e interpretados. Un lenguaje traducido como C o C++ suele ser más pequeño y más rápido, mientras que los lenguajes interpretados como Perl o Rexx a veces requieren que se cargue un intérprete grande al inicio. Además, puede distribuir códigos binarios (código que se traduce al lenguaje de máquina) sin código fuente si su idioma es traducible. Distribuir scripts interpretables normalmente significa distribuir código fuente.

Antes de elegir un idioma, primero debes considerar tus prioridades. Debe sopesar los beneficios de la velocidad y eficiencia de un lenguaje de programación frente a la facilidad de programación de otro. Si desea aprender otro idioma, en lugar de utilizar el que ya conoce, sopese cuidadosamente las ventajas y desventajas de ambos idiomas.

Los dos lenguajes más utilizados para la programación CGI son C y Perl (ambos se tratan en este libro). Ambos tienen claras ventajas y desventajas. Perl es un lenguaje de muy alto nivel y, al mismo tiempo, un lenguaje potente, especialmente adecuado para analizar texto. Aunque su facilidad de uso, flexibilidad y potencia lo convierten en un lenguaje atractivo para la programación CGI, su tamaño relativamente grande y su funcionamiento más lento a veces lo hacen inadecuado para algunas aplicaciones. Los programas C son más pequeños, más eficientes y proporcionan control del sistema de nivel inferior, pero son más complejos de programar, no tienen rutinas de procesamiento de texto integradas livianas y son más difíciles de depurar.

¿Qué lenguaje es el más adecuado para la programación CGI? El que consideres más conveniente desde el punto de vista de la programación. Ambos son igualmente efectivos para programar aplicaciones CGI y, con las bibliotecas adecuadas, ambos tienen capacidades similares. Sin embargo, si tiene un servidor de difícil acceso, puede utilizar programas C traducidos más pequeños. Si necesita escribir rápidamente una aplicación que requiera mucho procesamiento de texto, puede utilizar Perl.

Precauciones

Existen algunas alternativas importantes a las aplicaciones CGI. Muchos servidores ahora incluyen programación API, lo que facilita la programación de extensiones directas de servidor en lugar de aplicaciones CGI independientes. Los servidores API son generalmente más eficientes que los programas CGI. Otros servidores incluyen funciones integradas que pueden manejar elementos especiales que no son CGI, como enlaces de bases de datos. Finalmente, algunas aplicaciones pueden manejarse mediante nuevas tecnologías del lado del cliente (en lugar de del lado del servidor), como Java. Con cambios tecnológicos tan rápidos, ¿el CGI se volverá obsoleto rápidamente?

Difícilmente. CGI tiene varias ventajas sobre las tecnologías más nuevas.

  • Es versátil y portátil. Puede escribir una aplicación CGI utilizando casi cualquier lenguaje de programación en cualquier plataforma. Algunas de las alternativas, como la API del servidor, te limitan a ciertos idiomas y son mucho más difíciles de aprender.
  • Es poco probable que las tecnologías del lado del cliente, como Java, reemplacen a CGI, porque hay algunas aplicaciones para las que las aplicaciones del lado del servidor son mucho más adecuadas para ejecutar.
  • Muchas de las limitaciones de CGI son limitaciones de HTML o HTTP. A medida que evolucionan los estándares de Internet en su conjunto, también lo hacen las capacidades CGI.

Reanudar

La interfaz de puerta de enlace común es el protocolo mediante el cual los programas interactúan con los servidores web. La versatilidad de CGI brinda a los programadores la capacidad de escribir programas de entrada en casi cualquier idioma, aunque existen muchas compensaciones asociadas con los diferentes idiomas. Sin esta capacidad, la creación de páginas web interactivas sería difícil; en el mejor de los casos requeriría modificaciones en el servidor, y la interactividad no estaría disponible para la mayoría de los usuarios que no sean administradores de sitios.

Capítulo 2: Conceptos básicos

Hace varios años, creé una página para una universidad de Harvard donde la gente podía enviar comentarios sobre ellos. En aquel momento, Internet era joven y la documentación escasa. Yo, como muchos otros, dependí de documentación breve y sistemas de programación creados por otros para aprender a programar CGI. Aunque este método de estudio requirió algunas búsquedas, muchos experimentos y generó muchas preguntas, fue muy efectivo. Este capítulo es el resultado de mis primeros trabajos con CGI (con algunos ajustes, por supuesto).

Aunque lleva algún tiempo comprender y dominar completamente la interfaz de puerta de enlace común, el protocolo en sí es bastante simple. Cualquiera que tenga algunas habilidades básicas de programación y esté familiarizado con la Web puede aprender rápidamente a programar aplicaciones CGI bastante complejas tal como yo y otros aprendimos a hacer hace varios años.

El propósito de este capítulo es presentar los conceptos básicos de CGI de una manera integral, aunque condensada. Cada concepto discutido aquí se presenta en detalle en los capítulos siguientes. Sin embargo, después de completar este capítulo, podrá comenzar inmediatamente a programar aplicaciones CGI. Una vez que alcance este nivel, podrá aprender las complejidades de CGI, ya sea leyendo el resto de este libro o simplemente experimentando por su cuenta.

Puede reducir la programación CGI a dos tareas: recibir información desde el navegador web y enviar información de regreso al navegador. Esto se hace de forma bastante intuitiva una vez que se familiariza con el uso normal de las aplicaciones CGI. A menudo se le pide al usuario que complete algún formulario, por ejemplo, que inserte su nombre. Una vez que el usuario completa el formulario y presiona Enter, esta información se envía al programa CGI. Luego, el programa CGI debe convertir esta información en algo que comprenda, procesarla en consecuencia y luego enviarla de regreso al navegador, ya sea una simple confirmación o el resultado de una búsqueda en una base de datos multipropósito.

En otras palabras, la programación CGI requiere comprender cómo recibir información del navegador de Internet y cómo enviar la salida. Lo que sucede entre las etapas de entrada y salida de un programa CGI depende del objetivo del desarrollador. Descubrirá que la principal dificultad en la programación CGI reside en esta etapa intermedia; Una vez que aprenda a trabajar con entrada y salida, será suficiente para convertirse en desarrollador CGI.

En este capítulo, aprenderá los principios detrás de la entrada y salida CGI, así como otras habilidades básicas que necesitará para escribir y usar CGI, incluidas cosas como crear formularios HTML y nombrar sus programas CGI. Este capítulo cubre los siguientes temas:

  • Programa tradicional "¡Hola Mundo!";
  • Salida CGI: envío de información para mostrarla en un navegador de Internet;
  • Configurar, instalar y ejecutar la aplicación. Aprenderás sobre diferentes plataformas y servidores Web;
  • Entrada CGI: Interpretación de la información enviada por el navegador web. Introducción a algunas bibliotecas de programación útiles para analizar dicha entrada;
  • Un ejemplo sencillo: cubre todas las lecciones de un capítulo determinado;
  • Estrategia de programación.

Debido a la naturaleza de este capítulo, sólo toco ligeramente algunos temas. No te preocupes; Todos estos temas se tratan con mucha más profundidad en otros capítulos.

¡Hola Mundo!

Comienzas con un problema de programación introductorio tradicional. Escribirás un programa que muestre "¡Hola, mundo!" en su navegador web. Antes de escribir este programa, debe comprender qué información espera recibir el navegador web de los programas CGI. También necesita saber cómo ejecutar este programa para poder verlo en acción.

CGI es independiente del idioma, por lo que puedes implementar este programa en cualquier idioma. Aquí se utilizan varios idiomas diferentes para demostrar la independencia de cada idioma. En Perl, el programa "¡Hola mundo!" se muestra en el Listado 2.1.

Listado 2.1. ¡Hola Mundo! en Perl. #!/usr/local/bin/perl # Hola.cgi - Mi primer programa CGI imprime "Tipo de contenido: texto/html\n\n"; imprimir " \n"; imprimir " ¡Hola Mundo!"; imprimir "\n"; imprimir " \n"; imprimir "

¡Hola Mundo!

\n"; imprimir "

\norte";

Guarde este programa como hello.cgi e instálelo en la ubicación adecuada. (Si no está seguro de dónde está, no se preocupe; lo descubrirá en la sección "Instalación y ejecución de un programa CGI" más adelante en este capítulo). Para la mayoría de los servidores, el directorio que necesita es cgi-bin . Ahora, llame al programa desde su navegador web. Para la mayoría, esto significa abrir el siguiente localizador uniforme de recursos (URL):

http://nombre de host/nombre de directorio/hola.cgi

Nombre de host es el nombre de su servidor web y nombre de directorio es el directorio donde coloca hello.cgi (probablemente cgi-bin).

Dividiendo hola.cgi

Hay algunas cosas a tener en cuenta sobre hello.cgi.

Primero, utiliza comandos de impresión simples. Los programas CGI no requieren descriptores de archivos ni descriptores de salida especiales. Para enviar resultados al navegador, simplemente imprima en stdout.

En segundo lugar, tenga en cuenta que el contenido de la primera declaración impresa (Tipo de contenido: texto/html) no aparece en su navegador web. Puede enviar cualquier información que desee al navegador (página HTML, gráficos o sonido), pero primero debe decirle al navegador qué tipo de datos le está enviando. Esta línea le dice al navegador qué tipo de información esperar; en este caso, una página HTML.

En tercer lugar, el programa se llama hello.cgi. No siempre es necesario utilizar la extensión .cgi con el nombre de su programa CGI. Aunque el código fuente de muchos idiomas también usa la extensión .cgi, no se usa para indicar el tipo de idioma, sino que es una forma para que el servidor identifique el archivo como un archivo ejecutable en lugar de un archivo de gráficos, un archivo HTML o archivo de texto. Los servidores a menudo están configurados para intentar ejecutar solo aquellos archivos que tienen esta extensión, mostrando el contenido de todos los demás. Aunque no es necesario utilizar la extensión .cgi, se considera una buena práctica.

En general, hello.cgi consta de dos partes principales:

  • le dice al navegador qué información esperar (Tipo de contenido: texto/html)
  • le dice al navegador qué mostrar (¡Hola, mundo!)

¡Hola Mundo! Cª

Para mostrar la independencia del lenguaje de los programas CGI, el Listado 2.2 muestra el equivalente del programa hello.cgi escrito en C.

Listado 2.2. ¡Hola Mundo! en C. /* hello.cgi.c - Hola, mundo CGI */ #include int main() ( printf("Tipo de contenido: texto/html\r\n\r\n"); printf(" \n"); printf(" ¡Hola Mundo!\n"); printf("\n"); printf(" \n"); printf("

¡Hola Mundo!

\n"); printf("

\n"); )

Nota

Tenga en cuenta que la versión Perl de hello.cgi utiliza el tipo de contenido print ": text/html\n\n "; Mientras que la versión C usa Printf("Content-Type: text/html\r\n\r\n");

¿Por qué Perl imprime el operador y termina con dos nuevas líneas (\n) mientras que C printf termina con dos retornos de carro y nuevas líneas (\r\n)?

Técnicamente, se espera que los encabezados (todos los resultados antes de la línea en blanco) estén separados por retornos de carro y nuevas líneas. Desafortunadamente, en máquinas DOS y Windows, Perl traduce \r como otra nueva línea en lugar de como un retorno de carro.

Aunque la excepción \rs de Perl es técnicamente incorrecta, funcionará en casi todos los protocolos y es igualmente portátil en todas las plataformas. Por lo tanto, en todos los ejemplos de Perl en este libro, utilizo encabezados de separación de nueva línea en lugar de retornos de carro y nuevas líneas.

Una solución adecuada a este problema se presenta en el Capítulo 4, Conclusión.

Ni al servidor web ni al navegador les importa qué idioma se utiliza para escribir el programa. Aunque cada lenguaje tiene ventajas y desventajas como lenguaje de programación CGI, es mejor utilizar el lenguaje con el que se sienta más cómodo trabajando. (La elección del lenguaje de programación se analiza con más detalle en el Capítulo 1, “Interfaz de puerta de enlace común (CGI)”).

renderizado CGI

Ahora puede examinar más de cerca la cuestión del envío de información al navegador web. En el ejemplo de Hola mundo, puede ver que los navegadores web esperan dos conjuntos de datos: un encabezado, que contiene información como qué información mostrar (por ejemplo, tipo de contenido: línea) e información real (lo que muestra el navegador web). . Estos dos datos están separados por una línea en blanco.

El encabezado se llama encabezado HTTP. Da información importante sobre la información que va a recibir el navegador. Hay varios tipos diferentes de encabezados HTTP y el más común es el que ha usado antes: Tipo de contenido: encabezado. Puede utilizar diferentes combinaciones de encabezados HTTP, separados por retornos de carro y nuevas líneas (\r\n). La línea en blanco que separa el encabezado de los datos también consta de un retorno de carro y una nueva línea (el motivo por el que ambos son necesarios se analiza brevemente en la nota anterior y se detalla en el Capítulo 4). Aprenderá sobre otros encabezados HTTP en el Capítulo 4; Actualmente estás tratando con el tipo de contenido: encabezado.

Tipo de contenido: el encabezado describe el tipo de datos que devuelve el CGI. El formato apropiado para este encabezado es:

Tipo de contenido: subtipo/tipo

Donde subtipo/tipo es el tipo correcto de Extensiones multipropósito de correo de Internet (MIME). El tipo MIME más común es el tipo HTML: texto/html. La Tabla 2.1 enumera algunos tipos MIME más comunes que se analizarán; En el Capítulo 4 se proporciona una lista y un análisis más completos de los tipos MIME.

Nota

MIME se inventó originalmente para describir el contenido de los cuerpos de los mensajes de correo. Se ha convertido en una forma bastante común de representar información de tipo de contenido. Puede leer más sobre MIME en RFC1521. Los RFC en Internet significan Solicitudes de comentarios, que son resúmenes de decisiones tomadas por grupos en Internet que intentan establecer estándares. Puede ver los resultados del RFC1521 en la siguiente dirección: http://andrew2.andrew.cmu.edu/rfc/rfc1521.html

Tabla 2.1. Algunos tipos MIME comunes. Tipo MIME Descripción Texto/html Lenguaje de marcado de hipertexto (HTML) Texto/sin formato Archivos de texto sin formato Imagen/gif Archivos gráficos GIF Imagen/jpeg Archivos gráficos comprimidos JPEG Audio/archivos de audio básicos Sun *.au Audio/x-wav Archivos de Windows *.

Después del encabezado y una línea vacía, simplemente imprime los datos en el formulario que necesita. Si está enviando HTML, imprima las etiquetas HTML y los datos en la salida estándar después del encabezado. También puede enviar gráficos, sonido y otros archivos binarios simplemente imprimiendo el contenido del archivo en la salida estándar. En el Capítulo 4 se dan varios ejemplos de esto.

Instalación y ejecución de un programa CGI

Esta sección se desvía un poco de la programación CGI y habla sobre cómo configurar su servidor web para usar CGI, instalar y ejecutar programas. Se le presentarán diferentes servidores para diferentes plataformas con más o menos detalle, pero tendrá que profundizar en la documentación de su servidor para encontrar la mejor opción.

Todos los servidores requieren espacio para archivos de servidor y espacio para documentos HTML. En este libro, el área del servidor se llama ServerRoot y el área de documentos se llama DocumentRoot. En máquinas UNIX, ServerRoot suele estar en /usr/local/etc/httpd/ y DocumentRoot suele estar en /usr/local/etc/httpd/htdocs/. Sin embargo, esto no hará ninguna diferencia en su sistema, así que reemplace todas las referencias a ServerRoot y DocumentRoot con sus propios ServerRoot y DocumentRoot.

Cuando accede a archivos utilizando su navegador web, especifica el archivo en la URL relativa a DocumentRoot. Por ejemplo, si la dirección de su servidor es mimáquina.org, acceda a este archivo con la siguiente URL: http://mimáquina.org/index.html

Configurando el servidor para CGI

La mayoría de los servidores web están preconfigurados para permitir el uso de programas CGI. Normalmente, dos parámetros indican al servidor si el archivo es una aplicación CGI o no:

  • Directorio designado. Algunos servidores le permiten determinar que todos los archivos en un directorio designado (generalmente llamado cgi-bin de forma predeterminada) son CGI.
  • Extensiones de nombre de archivo. Muchos servidores tienen esta preconfiguración que permite definir como CGI todos los archivos que terminan en .cgi.

El método del directorio designado es una especie de reliquia del pasado (los primeros servidores lo utilizaron como único método para determinar qué archivos eran programas CGI), pero tiene varias ventajas.

  • Mantiene centralizados los programas CGI, evitando que otros directorios se saturan.
  • No estás limitado a ninguna extensión de nombre de archivo específica, por lo que puedes nombrar tus archivos como quieras. Algunos servidores le permiten designar varios directorios diferentes como directorios CGI.
  • También te da más control sobre quién puede grabar CGI. Por ejemplo, si tiene un servidor y admite un sistema con múltiples usuarios y no desea que utilicen sus propios scripts CGI sin auditar primero el programa por razones de seguridad, puede designar solo esos archivos en un directorio centralizado limitado como CGI. . Luego, los usuarios tendrán que proporcionarle programas CGI para instalar y usted primero podrá auditar el código para asegurarse de que el programa no tenga problemas de seguridad importantes.

La notación CGI mediante extensión de nombre de archivo puede resultar útil debido a su flexibilidad. No está limitado a un único directorio para programas CGI. La mayoría de los servidores se pueden configurar para reconocer CGI a través de la extensión del nombre de archivo, aunque no todos están configurados de esta manera de forma predeterminada.

Advertencia

Recuerde la importancia de los problemas de seguridad cuando configure su servidor para CGI. Aquí se cubrirán algunos consejos y el Capítulo 9, Protección de CGI, cubre estos aspectos con más detalle.

Instalación de CGI en servidores UNIX

Independientemente de cómo esté configurado su servidor UNIX, hay varios pasos que debe seguir para asegurarse de que sus aplicaciones CGI se ejecuten como se espera. Su servidor web normalmente se ejecutará como un usuario inexistente (es decir, el usuario de UNIX nadie, una cuenta que no tiene permisos de archivos y no puede iniciar sesión). Los scripts CGI (escritos en Perl, Bourne Shell u otro lenguaje de scripting) deben ser ejecutables y legibles en todo el mundo.

Clave

Para que sus archivos sean legibles y ejecutables en todo el mundo, utilice el siguiente comando de permisos UNIX: chmod 755 filename.

Si está utilizando un lenguaje de secuencias de comandos como Perl o Tcl, proporcione la ruta completa de su intérprete en la primera línea de su secuencia de comandos. Por ejemplo, un script Perl que utilice perl en el directorio /usr/local/bin comenzaría con la siguiente línea:

#!/usr/local/bin/perl

Advertencia

Nunca coloque el intérprete (perl o el binario Tcl Wish) en el directorio /cgi-bin. Esto crea un riesgo de seguridad en su sistema. Esto se analiza con más detalle en el Capítulo 9.

Algunos servidores UNIX genéricos

Los servidores NCSA y Apache tienen archivos de configuración similares porque el servidor Apache se basó originalmente en el código NCSA. De forma predeterminada, están configurados para que cualquier archivo en el directorio cgi-bin (ubicado de manera predeterminada en ServerRoot) sea un programa CGI. Para cambiar la ubicación del directorio cgi-bin, puede editar el archivo de configuración conf/srm.conf. El formato para configurar este directorio es

ScriptAlias ​​nombredirectoriofalso nombredirectorioreal

donde fakedirectoryname es el nombre del pseudodirectorio (/cgi-bin) y realdirectoryname es la ruta completa donde realmente se almacenan los programas CGI. Puede configurar más de un ScriptAlias ​​agregando más líneas de ScriptAlias.

La configuración predeterminada es suficiente para las necesidades de la mayoría de los usuarios. Debe editar la línea en el archivo srm.conf en cualquier caso para determinar el nombre del directorio real correcto. Si, por ejemplo, sus programas CGI están ubicados en /usr/local/etc/httpd/cgi-bin, la línea ScriptAlias ​​​​en su archivo srm.conf debería ser algo como esto:

ScriptAlias ​​/cgi-bin/ /usr/local/etc/httpd/cgi-bin/

Para acceder o vincular programas CGI ubicados en este directorio, utilice la siguiente URL:

Http://nombredehost/cgi-bin/nombredeprograma

Donde nombre de host es el nombre del host de su servidor web y nombre de programa es el nombre de su CGI.

Por ejemplo, digamos que copia el programa hello.cgi a su directorio cgi-bin (por ejemplo, /usr/local/etc/httpd/cgi-bin) en su servidor web llamado www.company.com. Para acceder a su CGI, utilice la siguiente URL: http://www.company.com/cgi-bin/hello.cgi

Si desea configurar su servidor NCSA o Apache para reconocer cualquier archivo con extensión .cgi como CGI, debe editar dos archivos de configuración. Primero, en el archivo srm.conf, descomente la siguiente línea:

Aplicación AddType/x-httpd-cgi .cgi

Esto asociará el tipo MIME CGI con la extensión .cgi. Ahora, necesitamos cambiar el archivo access.conf para poder ejecutar CGI en cualquier directorio. Para hacer esto, agregue la opción ExecCGI a la línea Opción. Se verá algo así como la siguiente línea:

Índices de opciones FollowSymLinks ExecCGI

Ahora, cualquier archivo con extensión .cgi se considera CGI; acceda a él como lo haría con cualquier archivo en su servidor.

El servidor CERN está configurado de la misma manera que los servidores Apache y NCSA. En lugar de ScriptAlias, el servidor CERN utiliza el comando Exec. Por ejemplo, en el archivo httpd.conf, verá la siguiente línea:

Ejecutivo /cgi-bin/* /usr/local/etc/httpd/cgi-bin/*

Otros servidores UNIX se pueden configurar de la misma manera; Esto se describe con más detalle en la documentación del servidor.

Instalación de CGI en Windows

La mayoría de los servidores disponibles para Windows 3.1, Windows 95 y Windows NT están configurados utilizando el método de "extensión de nombre de archivo" para el reconocimiento CGI. En general, cambiar la configuración de un servidor basado en Windows simplemente requiere ejecutar el programa de configuración del servidor y realizar los cambios apropiados.

A veces, configurar un servidor para ejecutar un script (como Perl) correctamente puede resultar complicado. En DOS o Windows, no podrá especificar el intérprete en la primera línea del script, como es el caso de UNIX. Algunos servidores tienen una configuración predefinida para asociar algunas extensiones de nombre de archivo con el intérprete. Por ejemplo, muchos servidores web de Windows suponen que los archivos que terminan en .pl son secuencias de comandos Perl.

Si el servidor no realiza este tipo de asociación de archivos, puede definir un archivo por lotes del empaquetador que llame tanto al intérprete como al script. Al igual que con el servidor UNIX, no instale el intérprete ni en el directorio cgi-bin ni en ningún directorio accesible desde la Web.

Instalación de CGI en Macintosh

Las dos opciones de servidor más conocidas para Macintosh son WebStar StarNine y su predecesor MacHTTP. Ambos reconocen CGI por su extensión de nombre de archivo.

MacHTTP comprende dos extensiones diferentes: .cgi y .acgi, que significa CGI asíncrono. Los programas CGI normales instalados en un Macintosh (con una extensión .cgi) mantendrán el servidor web ocupado hasta que el CGI termine de ejecutarse, lo que provocará que el servidor suspenda todas las demás solicitudes. CGI asíncrono, por otro lado, permite que el servidor acepte solicitudes incluso mientras se está ejecutando.

Un desarrollador CGI Macintosh que utilice cualquiera de estos servidores web debería, si es posible, utilizar sólo la extensión .acgi en lugar de la extensión .cgi. Debería funcionar con la mayoría de los programas CGI; Si no funciona, cambie el nombre del programa a .cgi.

Ejecutando CGI

Una vez que haya instalado CGI, hay varias formas de ejecutarlo. Si su programa CGI es un programa de sólo salida, como el programa Hello,World, entonces puede ejecutarlo simplemente accediendo a su URL.

La mayoría de los programas se ejecutan como una aplicación de servidor en un formulario HTML. Antes de aprender cómo obtener información de estos formularios, primero lea una breve introducción sobre cómo crear dichos formularios.

Un tutorial rápido sobre formularios HTML

Las dos etiquetas más importantes en un formulario HTML son las

Y . Puede crear la mayoría de los formularios HTML utilizando sólo estas dos etiquetas. En este capítulo, explorará estas etiquetas y un pequeño subconjunto de posibles tipos o atributos. . En el Capítulo 3, HTML y formularios, encontrará una guía completa y un enlace a los formularios HTML.

Etiqueta

Etiqueta se utiliza para determinar qué parte del archivo HTML debe usarse para la información ingresada por el usuario. Esto se refiere a cómo la mayoría de las páginas HTML llaman a un programa CGI. Los atributos de etiqueta especifican el nombre y la ubicación del programa, ya sea localmente o como una URL completa, el tipo de codificación utilizada y el método de movimiento de datos utilizado por el programa.

La siguiente línea muestra las especificaciones de la etiqueta. :

< ACTION FORM = "url" METHOD = ENCTYPE = "..." >

El atributo ENCTYPE no juega un papel especial y normalmente no se incluye con la etiqueta. . En el Capítulo 3 se proporciona información detallada sobre la etiqueta ENCTYPE. En el Capítulo 14, "Extensiones de marca", se muestra una forma de utilizar ENCTYPE.

El atributo ACCIÓN se refiere a la URL del programa CGI. Una vez que el usuario completa el formulario y proporciona información, toda la información se codifica y se transfiere al programa CGI. El propio programa CGI resuelve el problema de decodificar y procesar información; Este aspecto se analiza en "Aceptar entradas del navegador", más adelante en este capítulo.

Finalmente, el atributo MÉTODO describe cómo el programa CGI debe recibir información. Los dos métodos, GET y POST, difieren en cómo pasan información al programa CGI. Ambos se analizan en "Aceptar entradas del navegador".

Para que el navegador permita la entrada del usuario, todas las etiquetas y la información del formulario deben estar rodeadas por la etiqueta . No olvides la etiqueta de cierre.

para indicar el final del formulario. No puedes tener un formulario dentro de un formulario, aunque puedes configurar un formulario que te permita presentar información en diferentes lugares; Este aspecto se analiza ampliamente en el Capítulo 3.

Etiqueta

Puede crear barras de entrada de texto, botones de radio, casillas de verificación y otros medios para aceptar entradas usando la etiqueta . Esta sección cubre sólo los campos de entrada de texto. Para implementar este campo, use la etiqueta con los siguientes atributos:

< INPUT TYPE=text NAME = "... " VALUE = "... " SIZE = MAXLENGTH = >

NOMBRE es el nombre simbólico de la variable que contiene el valor ingresado por el usuario. Si incluye texto en el atributo VALOR, ese texto se colocará de forma predeterminada en el campo de entrada de texto. El atributo TAMAÑO le permite especificar la longitud horizontal del campo de entrada tal como aparecerá en la ventana del navegador. Finalmente, MAXLENGTH especifica la cantidad máxima de caracteres que el usuario puede ingresar en el campo. Tenga en cuenta que los atributos VALOR, TAMAÑO y MAXLENGTH son opcionales.

Envío de formulario

Si solo tiene un campo de texto dentro de un formulario, el usuario puede enviar el formulario simplemente escribiendo información en el teclado y presionando Enter. De lo contrario, debe existir alguna otra forma para que el usuario presente la información. El usuario envía información mediante un botón de envío con la siguiente etiqueta:

< Input type=submit >

Esta etiqueta crea un botón Enviar dentro de su formulario. Cuando el usuario termina de completar el formulario, puede enviar su contenido a la URL especificada por el atributo ACCIÓN del formulario haciendo clic en el botón Enviar.

Aceptar entradas del navegador

Arriba se muestran ejemplos de grabación de un programa CGI que envía información desde el servidor al navegador. En realidad, un programa CGI que sólo genera datos no tiene muchas aplicaciones (algunos ejemplos se dan en el Capítulo 4). La capacidad más importante de CGI es recibir información del navegador, la característica que le da a la Web su carácter interactivo.

El programa CGI recibe dos tipos de información del navegador.

  • Primero, obtiene varios datos sobre el navegador (su tipo, lo que puede ver, el host, etc.), el servidor (su nombre y versión, su puerto de ejecución, etc.) y el programa CGI. sí mismo (nombre del programa y dónde se encuentra). El servidor proporciona toda esta información al programa CGI a través de variables de entorno.
  • En segundo lugar, el programa CGI puede recibir información del usuario. Esta información, después de ser codificada por el navegador, se envía a través de una variable de entorno (método GET) o mediante una entrada estándar (stdin - método POST).

Variables de entorno

Es útil saber qué variables de entorno están disponibles para un programa CGI, tanto durante el entrenamiento como para la depuración. La Tabla 2.2 enumera algunas de las variables de entorno CGI disponibles. También puede escribir un programa CGI que envíe variables de entorno y sus valores a un navegador web.

Tabla 2.2. Algunas variables de entorno CGI importantes Variable de entorno Propósito REMOTE_ADDR Dirección IP de la máquina cliente. REMOTE_HOST El host de la máquina cliente. HTTP _ACCEPT Enumera los tipos de datos MIME que el navegador puede interpretar. HTTP _USER_AGENT Información del navegador (tipo de navegador, número de versión, sistema operativo, etc.). REQUEST_METHOD OBTENER o PUBLICAR. CONTENT_LENGTH El tamaño de la entrada si se envía mediante POST.

Si no hay entrada o si se utiliza el método GET, este parámetro no está definido. QUERY_STRING Contiene la información de entrada cuando se pasa mediante el método GET. PATH_INFO Permite al usuario especificar una ruta desde la línea de comando CGI (por ejemplo, http://hostname/cgi-bin/programname/path). PATH_TRANSLATED Traduce la ruta relativa en PATH_INFO a una ruta real en el sistema.

  • Para escribir una aplicación CGI que muestre variables de entorno, necesita saber cómo hacer dos cosas:
  • Defina todas las variables de entorno y sus valores correspondientes.

Imprime los resultados en el navegador.

Ya sabes cómo realizar la última operación. En Perl, las variables de entorno se almacenan en la matriz asociativa %ENV, que se introduce con el nombre de la variable de entorno. El Listado 2.3 contiene env.cgi, un programa Perl que logra nuestro objetivo.

Listado 2.3. Un programa Perl, env.cgi, que imprime todas las variables de entorno CGI. \n"; imprimir " #!/usr/local/bin/perl print "Tipo de contenido: texto/html\n\n"; imprimir "\n"; imprimir "\n"; imprimir " \n"; imprimir "

#!/usr/local/bin/perl print "Tipo de contenido: texto/html\n\n"; imprimir "

Entorno CGI \n"; foreach $env_var (claves %ENV) ( imprimir "$env_var
= $ENV($env_var)

\norte";

\n"; ) imprimir "

Se podría escribir un programa similar en C; el código completo está en el Listado 2.4. Listado 2.4. env.cgi.c en C. /* env.cgi.c */ #include \n"); printf(" #!/usr/local/bin/perl print "Tipo de contenido: texto/html\n\n"; imprimir "\n"); printf("\n"); printf(" \n"); printf("

#!/usr/local/bin/perl print "Tipo de contenido: texto/html\n\n"; imprimir "

carácter externo **entorno; int main() ( char **p = entorno; printf("Tipo de contenido: texto/html\r\n\r\n"); printf("
\n"); mientras(*p != NULL) printf("%s

\n"); )

\n",*p++); printf("

OBTENER o PUBLICAR?

Para determinar qué método se utiliza, el programa CGI verifica la variable de entorno REQUEST_METHOD, que se establecerá en GET o POST. Si se establece en POST, la longitud de la información codificada se almacena en la variable de entorno CONTENT_LENGTH.

Entrada codificada

Cuando un usuario envía un formulario, el navegador primero codifica la información antes de enviarla al servidor y luego a la aplicación CGI. Cuando usas la etiqueta , cada campo recibe un nombre simbólico. El valor ingresado por el usuario se representa como el valor de la variable.

Para determinar esto, el navegador utiliza una especificación de codificación de URL, que se puede describir de la siguiente manera:

  • Separa diferentes campos con un signo comercial (&).
  • Separa el nombre y los valores con signos iguales (=), con el nombre a la izquierda y el valor a la derecha.
  • Reemplaza espacios con signos más (+).
  • Reemplaza todos los caracteres "anormales" con un signo de porcentaje (%) seguido de un código hexadecimal de dos dígitos para el carácter.

Su cadena codificada final será similar a la siguiente:

Nombre1=valor1&nombre2=valor2&nombre3=valor3...

Nota: Las especificaciones para la codificación de URL se encuentran en RFC1738.

Por ejemplo, digamos que tiene un formulario que solicita nombre y edad. El código HTML que se utilizó para mostrar este formulario se muestra en el Listado 2.5.

Listado 2.5. Código HTML para mostrar el formulario de nombre y edad.

Nombre y Edad

Introduce tu nombre:

Introduce tu edad:



Digamos que el usuario ingresa Joe Schmoe en el campo de nombre y 20 en el campo de edad. La entrada se codificará en la cadena de entrada.

Nombre=Joe+Schmoe&edad=20

Analizando la entrada

Para que esta información sea útil, necesita usar la información en algo que pueda ser usado por sus programas CGI. Las estrategias para analizar la entrada se tratan en el Capítulo 5. En la práctica, nunca tendrá que pensar en cómo analizar la entrada, porque varios expertos ya han escrito bibliotecas que realizan el análisis, accesibles para todos. Dos de estas bibliotecas se presentan en este capítulo en las siguientes secciones: cgi -lib.pl para Perl (escrito por Steve Brenner) y cgihtml para C (escrito por mí).

El objetivo general de la mayoría de las bibliotecas escritas en varios idiomas es analizar una cadena codificada y colocar pares de nombre y valor en una estructura de datos. Existe una ventaja obvia al utilizar un lenguaje que tiene estructuras de datos integradas como Perl; sin embargo, la mayoría de las bibliotecas para lenguajes de bajo nivel como C y C++ incluyen estructura de datos y ejecución de subrutinas.

No es necesario alcanzar una comprensión completa de las bibliotecas; es más importante aprender a utilizarlos como herramientas para facilitar el trabajo del programador CGI.

Cgi-lib.pl

Cgi-lib.pl utiliza matrices asociativas de Perl. La función &ReadParse analiza la cadena de entrada e ingresa cada par de nombre/valor por nombre. Por ejemplo, las cadenas Perl correspondientes necesarias para decodificar la cadena de entrada "nombre/edad" que se acaba de presentar serían

&ReadParse(*entrada);

Ahora, para ver el valor ingresado para "nombre", puede acceder a la matriz asociativa $input("nombre"). De manera similar, para acceder al valor de "edad", es necesario mirar la variable $input ("edad").

cgihtml

C no tiene estructuras de datos integradas, por lo que cgihtml implementa su propia lista de enlaces para usar con sus rutinas de análisis CGI. Esto define la estructura del tipo de entrada de la siguiente manera:

Estructura Typedef ( Char *nombre; Char *valor; ) Tipo de entrada;

Para analizar la cadena de entrada "nombre/edad" en C usando cgihtml, se utiliza lo siguiente:

/* declarar una lista enlazada llamada entrada */ Llist entrada; /* analiza la entrada y la ubicación en la lista vinculada */ read_cgi_input(&input);

Para acceder a la información de edad, puede analizar la lista manualmente o utilizar la función cgi _val() disponible.

#incluir #incluir Char *edad = malloc(sizeof(char)*strlen(cgi_val(input, "edad")) + 1); Strcpy(edad, cgi_val(entrada, "edad"));

El valor de "edad" ahora está almacenado en la cadena de edad.

Nota: En lugar de utilizar una matriz simple (como char age;), estoy asignando dinámicamente espacio de memoria para la cadena age. Aunque esto dificulta la programación, es importante desde el punto de vista de la seguridad. Esto se analiza con más detalle en el Capítulo 9.

Un programa CGI sencillo

Vas a escribir un programa CGI llamado nameage.cgi que maneja el formulario nombre/edad. El procesamiento de datos (lo que suelo llamar "cosas intermedias") es mínimo. Nameage.cgi simplemente decodifica la entrada y muestra el nombre y la edad del usuario. Si bien esta herramienta no tiene mucha utilidad, demuestra el aspecto más crítico de la programación CGI: entrada y salida.

Utilice el mismo formulario que el anterior, llamando a los campos "nombre y edad". No se preocupe todavía por la solidez y la eficiencia; resolver el problema existente de la forma más sencilla. Las soluciones de Perl y C se muestran en los Listados 2.6 y 2.7, respectivamente.

Listado 2.6. Nombre.cgi en Perl

#!/usr/local/bin/perl # nameage.cgi requiere "cgi-lib.pl" &ReadParse(*input); print "Tipo de contenido: texto/html\r\n\r\n"; imprimir " \n"; imprimir " Nombre y Edad\n"; imprimir "\n"; imprimir " \n"; print "Hola, " . $entrada("nombre") . ". Tienes\n"; print $input("edad") . " años.

\n"; imprimir "

\norte";

Listado 2.7. nombreage.cgi en C

/* nombreage.cgi.c */ #include #include "cgi-lib.h" int main() ( lista de entrada; read_cgi_input(&input); printf("Tipo de contenido: texto/html\r\n\r\n"); printf(" \n"); printf(" Nombre y Edad\n"); printf("\n"); printf(" \n"); printf("Hola, %s. Eres\n",cgi_val(input,"nombre")); printf("%s años.

\n",cgi_val(entrada,"edad")); printf("

\n"); )

Tenga en cuenta que estos dos programas son casi equivalentes. Ambos contienen rutinas de análisis que ocupan solo una línea y procesan toda la entrada (gracias a las rutinas de biblioteca correspondientes). El resultado es esencialmente una versión modificada de su programa principal Hello, World!

Intente ejecutar el programa completando el formulario y haciendo clic en el botón Enviar.

Estrategia general de programación

Ahora conoce todos los principios básicos necesarios para la programación CGI. Una vez que comprenda cómo CGI recibe información y cómo la envía de regreso al navegador, la calidad real de su producto final depende de sus habilidades generales de programación. Es decir, cuando programes CGI (o cualquier cosa, de hecho), ten en cuenta las siguientes cualidades:

  • Sencillez
  • Eficiencia
  • Versatilidad

Las dos primeras cualidades son bastante comunes: intenta que tu código sea lo más legible y eficiente posible. La versatilidad se aplica más a los programas CGI que a otras aplicaciones. Cuando empiece a desarrollar sus propios programas CGI, aprenderá que existen varias aplicaciones básicas que todo el mundo quiere crear. Por ejemplo, una de las tareas más comunes y obvias de un programa CGI es procesar un formulario y enviar los resultados por correo electrónico a un destinatario específico. Podría procesar varios formularios separados, cada uno con un destinatario diferente. En lugar de escribir un programa CGI para cada formulario individual, puede ahorrar tiempo escribiendo un programa CGI más general que se aplique a todos los formularios.

Al cubrir todos los aspectos básicos de CGI, le proporcioné suficiente información para comenzar con la programación CGI. Sin embargo, para convertirse en un desarrollador CGI eficaz, es necesario tener un conocimiento más profundo de cómo se comunica CGI con el servidor y el navegador. El resto de este libro cubre en detalle los temas que se mencionaron brevemente en este capítulo, así como la estrategia de desarrollo de aplicaciones y las ventajas y limitaciones del protocolo.

Reanudar

Este capítulo presentó brevemente los conceptos básicos de la programación CGI. Usted crea resultados formateando sus datos correctamente e imprimiendo en stdout. Recibir entrada CGI es un poco más complejo porque debe analizarse antes de poder usarse. Afortunadamente, ya existen varias bibliotecas que realizan análisis.

A estas alturas deberías poder programar aplicaciones CGI con bastante facilidad. El resto de este libro profundiza en especificaciones, consejos y estrategias de programación para aplicaciones más avanzadas y complejas.




Arriba