Scripts CGI: ¿cuándo se puede devolver un documento, en lugar de una respuesta HTTP?

Scripts CGI: ¿cuándo se puede devolver un documento, en lugar de una respuesta HTTP?

El script 1 a continuación es bash y está en https://example.com/cgi-bin/test. Produce el resultado 'En construcción' cuando se recupera. Tiene ecos Statusy Content-typeencabezados, y algo de HTML. Si, en cambio, intento hacer eco de un documento HTML completo, Apache simplemente se queja de un encabezado no válido.

El script 2 a continuación es php y está en https://example.com/cgi-bin/test2.php. A diferencia del script bash, éste devuelve un documento HTML.

¿Cómo es que el script 2 puede enviar un documento HTML completo, pero el script 1 no?

Guión 1

#!/bin/bash
cat <<'EOF'
Status: 200 OK
Content-type: text/html

<p>Under construction.</p>
EOF

Guión 2

<?php
print <<<EOF  
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    ...etc
  </head>

  <body>
  ...etc
  </body>
</html>
EOF;
?>

EDITAR

phpViene en 2 versiones: las versiones CLI y CGI. Si simplemente ejecuta el Script 2 desde la línea de comando, php test2.phpentonces elsoloEl resultado producido por phpes exactamente lo que ve: el documento HTML. php-cgies la versión CGI (instalar en Ubuntu/Deb como apt install php-cgi). Apache (efectivamente) ejecuta la versión CGI (en la vida real, lo hace de manera ligeramente diferente, pero con los mismos resultados):

 $ php-cgi test2.php
Content-type: text/html; charset=UTF-8

<!DOCTYPE html>
...rest of doc

Los scripts CGI deben regresar al menos Content-typea Apache (pero pueden devolver más encabezados, incluido Status). Entonces la respuesta es queambosLos scripts funcionan porque el script 1 devuelve explícitamente Content-type, mientras que la versión CGI interna de phphace lo mismo.

El script bash puede devolver el documento HTML completo, siempre que también devuelva el archivo Content-type.

Respuesta1

En CGI necesitas enviar el tipo de contenido. PHP lo genera por ti. (verifique el resultado a través de un navegador, lo verá incluso si no lo ve en su código.

Tengo un CGI que hice en C y realmente necesitas el tipo de contenido;

En mi caso por ejemplo;

printf("Tipo de contenido: texto/html;charset=us-ascii\n\n");

Si necesita cambiar el encabezado en php, debe llamar al encabezado al comienzo de su secuencia de comandos.

es decir;

header('Tipo de contenido: aplicación/json');

Respuesta2

PHP y CGI son dos cosas diferentes en este contexto.

CGI es una interfaz entre un programa (en este caso un script bash) y el servidor web. Esta interfaz especifica la comunicación entre el servidor web y el programa.

Este estándar requiere que el programa devuelvatodoencabezados, incluidos los encabezados de estado, antes del contenido real. En HTTP, los encabezados y el cuerpo están separados por una sola línea; de ahí el formato en el que tiene

Header
Header

Content

Después de los encabezados, puedes incluir un documento HTML completo o cualquier otro tipo de datos que coincidan con los encabezados que envías.

PHP hace algunas suposiciones por usted y, a menos que las anule, establece el tipo de contenido, el código de estado, etc., automáticamente.

Respuesta3

Debe incluir una respuesta de encabezado CGI válida, no una respuesta HTTP, si llama a un script mediante CGI a través de Apache. Creo que, en esencia (detallado a continuación), debes eliminar "Estado: 200 OK" de tu archivo y podría funcionar.

Hay un buen artículo escrito por los propios Apache (https://httpd.apache.org/docs/2.2/howto/cgi.html) que le muestra el mínimo para lograr una respuesta válida.

Un encabezado de ejemplo recibido por el cliente podría ser el siguiente:

HTTP/1.x 200 OK
Transfer-Encoding: chunked
Date: Tue, 06 Dec 2021 19:58:00 GMT
Server: My_Bash_Script
Connection: close
X-Powered-By: My_Bash_Script
Pragma: public
Expires: Tue, 06 Dec 2021 20:58:00 GMT
Cache-Control: max-age=3600, public
Last-Modified: Tue, 06 Dec 2021 20:58:00 GMT
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
Content-Type: text/html; charset=UTF-8
 
<!DOCTYPE html>
<head><title>Under construction</title>
<body><p>Under construction.</p></body>
</html>

Pero su CGI solo necesita enviarse desde "Tipo de contenido: texto/html; charset=UTF-8" hacia abajo.

Puede encontrar un artículo bastante bueno aquí que explica los encabezados: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

Con respecto a un archivo PHP servido a través de Apache, existen varias capas de comunicación:

  • Se realiza una solicitud a Apache en un puerto TCP. Esto incluye un encabezado de solicitud si se realiza a través de HTTP.
  • Apache ejecuta todas las reglas (por ejemplo, mod_rewrite) y maneja las conexiones/apretones de manos SSL necesarios.
  • Luego, Apache detecta la extensión del archivo como PHP y llama al script PHP a través del intérprete PHP.
  • El código PHP se interpreta y se convierte en una cadena estática (con suerte :-) que se devuelve a Apache y contiene el código HTML.
  • Luego, Apache agrega la información del encabezado a la página HTML, junto con cualquier otro procesamiento saliente.
  • Esto se serializa y se canaliza de regreso a través de la conexión TCP al cliente.

Otra buena forma de explorar los encabezados es utilizar las herramientas de desarrollo de Firefox/Chrome (al presionar F12 en Firefox se abren). Vaya a la pestaña Red una vez que las Herramientas de desarrollo estén abiertas y vuelva a cargar la página (Ctrl + R en Windows/Linux). Hay una opción "Sin procesar" donde puede ver los datos exactos que se enviaron y recibieron.

Finalmente, si encuentra un sitio web, o incluso si su CGI se sirve a través de http en lugar de https, puede instalar Wireshark (https://www.wireshark.org) y monitoree fácilmente las conversaciones de tráfico para conocer la diferencia entre lo que envía y que no se entiende bien y cómo se ve una conversación normal en una página HTML estática servida por Apache.

PD (en 2022) Si realmente está ejecutando Apache 2.2:

información relacionada