Скрипты CGI: когда можно вернуть документ вместо HTTP-ответа?

Скрипты CGI: когда можно вернуть документ вместо HTTP-ответа?

Скрипт 1 ниже — это bash, и находится в https://example.com/cgi-bin/test. При извлечении он выводит сообщение «В разработке». Он выводит Statusи Content-typeзаголовки, и немного HTML. Если вместо этого я попытаюсь вывести весь HTML-документ, Apache просто выдаст сообщение о недопустимом заголовке.

Скрипт 2 ниже — это php, и находится в https://example.com/cgi-bin/test2.php. В отличие от скрипта bash, этот возвращает HTML-документ.

Почему скрипт 2 может отправить целый HTML-документ, а скрипт 1 — нет?

Сценарий 1

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

<p>Under construction.</p>
EOF

Сценарий 2

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

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

РЕДАКТИРОВАТЬ

phpпоставляется в 2 вариантах: CLI и CGI версии. Если вы просто запустите Script 2 из командной строки, php test2.phpтотолькоВывод, произведенный командой, php— это именно то, что вы видите: HTML-документ php-cgi— это версия CGI (устанавливается в Ubuntu/Deb как apt install php-cgi). Apache (фактически) запускает версию CGI (в реальной жизни он делает это немного иначе, но с теми же результатами):

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

<!DOCTYPE html>
...rest of doc

Скрипты CGI должны возвращать как минимум Content-typeApache (но могут возвращать больше заголовков, включая Status). Так что ответ таков:обаСкрипты работают, потому что Скрипт 1 явно возвращает Content-type, в то время как внутренняя CGI-версия phpделает то же самое.

Скрипт bash может вернуть весь HTML-документ, если он также возвращает расширение Content-type.

решение1

В CGI вам нужно отправить Content-Type. PHP сгенерирует его для вас. (проверьте вывод через браузер, вы увидите его, даже если не видите его в своем коде.)

У меня есть CGI, который я сделал на языке C, и вам действительно нужен content-type;

В моем случае, например;

printf("Тип содержимого: text/html;charset=us-ascii\n\n");

Если вам нужно изменить заголовок в php, вам нужно вызвать header в начале вашего скрипта.

то есть;

header('Тип содержимого: application/json');

решение2

В этом контексте PHP и CGI — это две разные вещи.

CGI — это интерфейс между программой (в данном случае скриптом bash) и веб-сервером. Этот интерфейс определяет связь между веб-сервером и программой.

Этот стандарт требует, чтобы программа возвращалавсезаголовки, включая заголовки статуса, перед фактическим содержанием. В HTTP заголовки и тело разделяются одной строкой - таким образом, формат, в котором вы имеете

Header
Header

Content

После заголовков вы можете включить полный HTML-документ или любые другие данные, соответствующие отправляемым вами заголовкам.

PHP делает несколько предположений за вас, и если вы их не переопределите, он автоматически устанавливает тип контента, код состояния и т. д.

решение3

Вам нужно включить допустимый ответ заголовка CGI, а не ответ HTTP, если вы вызываете скрипт через CGI через Apache. Я думаю, что по сути (подробности ниже) вам нужно удалить "Status: 200 OK" из вашего файла, и это может сработать.

Есть хорошая статья от самих Apache (https://httpd.apache.org/docs/2.2/howto/cgi.html), который показывает вам минимум для получения допустимого ответа.

Пример заголовка, полученного клиентом, может быть следующим:

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>

Но ваш CGI должен отправлять только данные из «Content-Type: text/html; charset=UTF-8» и ниже.

Довольно хорошую статью с объяснением заголовков можно найти здесь: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

Что касается обслуживаемого PHP-файла через Apache, существует несколько уровней взаимодействия:

  • Запрос Apache выполняется на порт TCP. Это включает заголовок запроса, если через HTTP.
  • Apache запускает все необходимые правила (например, mod_rewrite) и обрабатывает все необходимые SSL-соединения/рукопожатия.
  • Затем Apache определяет расширение файла как PHP и вызывает PHP-скрипт через интерпретатор PHP.
  • PHP-код интерпретируется и преобразуется в статическую строку (надеюсь :-), которая возвращается Apache и содержит HTML-код.
  • Затем Apache добавляет информацию заголовка на HTML-страницу вместе с любой другой исходящей обработкой.
  • Данные сериализуются и передаются обратно клиенту по TCP-соединению.

Другой хороший способ изучить заголовки — использовать Firefox / Chrome Developer Tools (нажатие F12 в Firefox открывает их). Перейдите на вкладку Network, как только Developer Tools будут открыты, и перезагрузите страницу (Ctrl + R в Windows/Linux). Есть опция «Raw», где вы можете увидеть точные данные, которые были отправлены и получены.

Наконец, если вы обнаружите веб-сайт или даже то, что ваш CGI обслуживается по протоколу http, а не https, вы можете установить Wireshark (https://www.wireshark.org) и легко отслеживать трафик разговоров, чтобы узнать разницу между тем, что вы отправляете и что неправильно понимается, и тем, как выглядит обычный статический HTML-диалог, обслуживаемый Apache.

P.S. (В 2022 году) Если вы действительно используете Apache 2.2:

Связанный контент