Score:0

CGI scripts: when can you return a document, instead of an HTTP response?

gu flag
QF0

Script 1 below is bash, and is at https://example.com/cgi-bin/test. It produces the output 'Under construction' when fetched. It echos Status and Content-type headers, and some HTML. If I instead try to echo an entire HTML doc Apache just complains about an invalid header.

Script 2 below is php, and is at https://example.com/cgi-bin/test2.php. Unlike the bash script, this one returns an HTML document.

How is it that script 2 can send an entire HTML doc, but script 1 can't?

Script 1

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

<p>Under construction.</p>
EOF

Script 2

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

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

EDIT

php comes in 2 flavours: the CLI and CGI versions. If you just run Script 2 from the command line as php test2.php then the only output produced by php is exactly what you see: the HTML doc. php-cgi is the CGI version (install on Ubuntu/Deb as apt install php-cgi). Apache (effectively) runs the CGI version (in real life, it does this slightly differently, but with the same results):

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

<!DOCTYPE html>
...rest of doc

CGI scripts have to return at least Content-type to Apache (but can return more headers, including Status). So the answer is that both scripts work because Script 1 explicitly returns Content-type, while the under-the-hood CGI version of php does the same.

The bash script can return the entire HTML document, as long as it also returns the Content-type.

Score:0
mh flag

You need to include a valid CGI header response, not an HTTP response, if calling a script via CGI through Apache. I think in essence (detail below) you need to remove "Status: 200 OK" from your file, and it might work.

There is a good article by Apache themselves (https://httpd.apache.org/docs/2.2/howto/cgi.html) which shows you the minimum to achive a valid response.

An example header received by the client might be as follows:

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>

But your CGI, only needs to send from "Content-Type: text/html; charset=UTF-8" down.

A rather good article can be found here explaining the headers: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

With regards to a served PHP file via Apache, there are several layers of communication:

  • A request is made of Apache on a TCP port. This includes a request header if via HTTP.
  • Apache runs any rules (e.g. mod_rewrite) and handles any SSL connections / handshakes required.
  • Apache then detects the file extension as PHP and calls the PHP script through the PHP interpreter.
  • The PHP code is interpreted, and turned into a static string (hopefully :-) which is returned to Apache and contains the HTML code.
  • Apache then adds the header information to the HTML page, along with any other outbound processing.
  • This is serialised and piped back over the TCP connection to the client.

Another good way to explore the headers is to use Firefox / Chrome Developer Tools (pressing F12 in Firefox opens them). Goto the Network Tab once Developer Tools are open and reload the page (Ctrl + R on Windows/Linux). There is a "Raw" option where you can see the exact data that was send and received.

Finally, if you find a website, or even that your CGI is being served over http rather than https, you can install Wireshark (https://www.wireshark.org) and easily monitor the traffic conversations to learn the differential between what you are sending that is being misunderstood and what a normal static html page conversatin looks like served by Apache.

P.S. (In 2022,) If you are indeed running Apache 2.2:

QF0 avatar
gu flag
QF0
Sorry, think you might have misunderstood. *Both* scripts already work, and I've got a bucket load of C++ that does exactly the same as the bash script. My problem was understanding how the php also manages to work. The other 2 answers indicate that php *does* actually return the 'missing' headers to Apache, which makes sense. I'll check later.
Score:0
cn flag

In CGI you need to send the Content-Type. PHP generate it for you. (check the output via a browser, you will see it even if you dont see it in your code.

I have a CGI that I did in C, and you realy need the content-type;

In my case for exemple;

printf("Content-Type: text/html;charset=us-ascii\n\n");

If you need to change the header in php you have to call header at the start of your script.

ie;

header('Content-Type: application/json');

QF0 avatar
gu flag
QF0
This is basically correct, so I've accepted it, but see my edit for clarification.
Score:0
ar flag

PHP and CGI is two different things in this context.

CGI is a interface between a program - in this case a bash script - and the web server. This interface specifies communication between the web server and the program.

This standard requires that the program returns all headers, including status headers, before the actual content. In HTTP, headers and body is separated by a single line - thus the format where you have

Header
Header

Content

After the headers, you're free to include a full HTML document - or any other kind of data matching the headers you send.

PHP makes a few assumptions for you, and unless you override it, it sets content type, status code and so forth automatically.

I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.