Main Page

Previous Page
Next Page

[Page 920 (continued)]

19.9. Simple CGI Scripts

As long as an XHTML file on the server remains unchanged, its associated URL will display the same content in clients' browsers each time the file is accessed. To change the content of the XHTML file (e.g., to include new links or the latest company news), someone must alter the file manually on the server, probably with a text editor or Web-page-design software.

This need for manual change is a problem for Web page authors who want to create interesting and dynamic Web pages. To have a person continually alter a Web page is tedious. For example, if you want your Web page always to display the current date or weather conditions, the page will require continuous updating.

First CGI Script

Figure 19.5 shows our first CGI script. Note that the program consists mainly of cout statements (lines 1629). Until now, the output of cout always has been displayed on the screen. However, technically speaking, the default target for cout is standard output. When a C++ program is executed as a CGI script, the standard output is redirected by the Web server to the client Web browser. To execute the program as a CGI script, we placed the compiled C++ executable file in the Web server's cgi-bin directory. For the purpose of this chapter, we have changed the executable file extension from .exe to .cgi.[4] Assuming that the Web server is on your local computer, you can execute the script by typing

[4] On a server running Microsoft Windows, the executable may be run directly in .exe form.

[Page 921]


in your browser's Address or Location field. If you are requesting this script from a remote Web server, you will need to replace localhost with the server's machine name or IP address.

Figure 19.5. First CGI script.

 1  // Fig. 19.5: localtime.cpp
 2  // Displays the current date and time in a Web browser.
 3  #include <iostream>
 4  using std::cout;
 6  #include <ctime> // definitions of time_t, time, localtime and asctime
 7  using std::time_t;
 8  using std::time;
 9  using std::localtime;
10  using std::asctime;
12  int main()
13  {
14     time_t currentTime; // variable for storing time
16     cout << "Content-Type: text/html\n\n"; // output HTTP header
18     // output XML declaration and DOCTYPE                       
19     cout << "<?xml version = \"1.0\"?>"                         
20        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
21        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";  
23     time( &currentTime ); // store time in currentTime
25     // output html element and some of its contents          
26     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
27        << "<head><title>Current date and time</title></head>"
28        << "<body><p>" << asctime( localtime( &currentTime ) )
29        << "</p></body></html>";                              
30     return 0;
31  } // end main

[Page 922]

The notion of standard output is similar to that of standard input, which we have seen associated with cin. Just as standard input refers to the standard source of input into a program (normally, the keyboard), standard output refers to the standard destination of output from a program (normally, the screen). It is possible to redirect (or pipe) standard output to another destination. Thus, in our CGI script, when we output an HTTP header (line 16) or XHTML elements (lines 1921 and 2629), the output is sent to the Web server, as opposed to the screen. The server sends that output to the client over HTTP, which interprets the headers and elements as if they were part of a normal server response to an XHTML document request.

It is fairly straightforward to write a C++ program that outputs the current time and date (to the monitor of the local computer). In fact, this requires only a few lines of code (lines 14, 23 and 28). Line 14 declares currentTime as a variable of type time_t. Function time (line 23) gets the current time, which is represented as the number of seconds elapsed since midnight January 1, 1970, and stores the retrieved value to the location specified by the parameter (in this case, currentTime). C++ library function localtime (line 28), when passed a time_t variable (e.g., currentTime), returns a pointer to an object containing the "broken-down" local time (i.e., days, hours, etc. are placed in individual member variables). Function asctime (line 28), which takes a pointer to an object containing "broken-down" time, returns a string such as

     Wed Oct 31 13:10:37 2004

What if we wish to send the current time to a client's browser window for display (rather than outputting it to the screen)? CGI makes this possible by redirecting the output of a program to the Web server itself, which then sends the output to a client's browser.

How Web Server Redirects the Output

Figure 19.6 illustrates this process in more detail. In Step 1, the client requests the resource named localtime.cgi from the server, just as it requested downloads.html in the previous example (Fig. 19.4). If the server was not configured to handle CGI scripts, it might just return the contents of the C++ executable file to the client, as if it were any other document. However, based on the Web server configuration, the server executes localtime.cgi (implemented using C++) and sends the CGI script's output to the Web browser.

Figure 19.6. Step 1: The get request, GET /cgi-bin/localtime.cgi HTTP/1.1.
(This item is displayed on page 923 in the print version)

Figure 19.6. Step 2: The Web server starts the CGI script.
(This item is displayed on page 923 in the print version)

Figure 19.6. Step 3: The script output is sent to the Web server.
(This item is displayed on page 923 in the print version)

Figure 19.6. Step 4: The HTTP response, HTTP/1.1 200 OK.
(This item is displayed on page 924 in the print version)

A properly configured Web server, however, will recognize that different types of resources should be handled differently. For example, when the resource is a CGI script, the script must be executed by the server before it is sent. A CGI script is designated in one of two ways: either it has a special filename extension (such as .cgi or .exe) or it is located in a specific directory (often cgi-bin). In addition, the server administrator must give permission explicitly for remote clients to be able to access and execute CGI scripts.[5]

[5] If you are using the Apache HTTP Server and would like more information on configuration, consult the Apache home page at httpd.apache.org/docs-2.0/.

In Step 2 of Fig. 19.6, the server recognizes that the resource is a CGI script and executes the script. In Step 3, the output produced by the script's three cout statements (lines 16, 1921 and 2629 of Fig. 19.5) is sent to the standard output and is returned to the Web server. Finally, in Step 4, the Web server adds a message to the output that indicates the status of the HTTP transaction (such as HTTP/1.1 200 OK, for success) and sends the entire output from the CGI program to the client.

[Page 923]

The client-side browser then processes the XHTML document and displays the results. It is important to note that the browser is unaware of what has transpired on the server. In other words, as far as the browser is concerned, it requests a resource like any other and receives a response like any other. The browser receives and interprets the script's output just as if it were a simple, static XHTML document.

[Page 924]

In fact, you can view the content that the browser receives by executing localtime.cgi from the command line, as we normally would execute any of the programs from the previous chapters. [Note: The filename extension must be changed to .exe prior to executing it from the command line on a system running Windows.] Figure 19.7 shows the output. For the purpose of this chapter, we formatted the output for human readability. Notice that, with the CGI script, we must output the Content-Type header, whereas, for an XHTML document, the Web server would include the header.

Figure 19.7. Output of localtime.cgi when executed from the command line.

  Content-Type: text/html

  <?xml version = "1.0"?>
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"

  <html xmlns = "http://www.w3.org/1999/xhtml">
        <title>Current date and time</title>

        <p>Wed Oct 13 10:22:18 2004</p>

The CGI script prints the Content-Type header, a blank line and the data (XHTML, plain text, etc.) to standard output. When the CGI script is executed on the Web server, the Web server retrieves the script's output, inserts the HTTP response to the beginning and delivers the content to the client. Later we will see other content types that may be used in this manner, as well as other headers that may be used in addition to Content-Type.

Common Programming Error 19.1

Forgetting to place a blank line after a header is a syntax error.

[Page 925]

Displaying Environment Variables

The program of Fig. 19.8 outputs the environment variables that the Apache HTTP Server sets for CGI scripts. These variables contain information about the client and server environment, such as the type of Web browser being used and the location of a document on the server. Lines 1423 initialize an array of string objects with the names of the CGI environment variables. [Note: Environment variables are server-specific. Servers other than Apache HTTP Server may not provide all of these environment variables.] Line 37 begins the XHTML table in which the data will be displayed.

Figure 19.8. Retrieving environment variables via function getenv.
(This item is displayed on pages 925 - 927 in the print version)

 1  // Fig. 19.8: environment.cpp
 2  // Program to display CGI environment variables.
 3  #include <iostream>
 4  using std::cout;
 6  #include <string>
 7  using std::string;
 9  #include <cstdlib>
10  using std::getenv;
12  int main()
13  {
14     string environmentVariables[ 24 ] = {                 
16        "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             
18        "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            
23        "SERVER_SIGNATURE","SERVER_SOFTWARE" };            
25     cout << "Content-Type: text/html\n\n"; // output HTTP header
27     // output XML declaration and DOCTYPE                       
28     cout << "<?xml version = \"1.0\"?>"                         
29        << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
30        << "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">";  
32     // output html element and some of its contents
33     cout << "<html xmlns = \"http://www.w3.org/1999/xhtml\">"
34        << "<head><title>Environment Variables</title></head><body>";
36     // begin outputting table
37     cout << "<table border = \"0\" cellspacing = \"2\">";
39     // iterate through environment variables
40     for ( int i = 0; i < 24; i++ )
41     {
42        cout << "<tr><td>" << environmentVariables[ i ] << "</td><td>";
44        // attempt to retrieve value of current environment variable
45        char *value = getenv( environmentVariables[ i ].c_str() );  
47        if ( value != 0 ) // environment variable exists  
48           cout << value;                                 
49        else                                              
50           cout << "Environment variable does not exist.";
52        cout << "</td></tr>";
53     } // end for
55     cout << "</table></body></html>";
56     return 0;
57  } // end main

[Page 927]

Lines 4252 output each row of the table. Let us examine each of these lines closely. Line 42 outputs an XHTML <tr> (table row) start tag, which indicates the beginning of a new table row. Line 52 outputs a corresponding </tr> end tag, which indicates the end of the row. Each row of the table contains two table cellsthe name of an environment variable and the data associated with that variable (if the variable exists). The <td> start tag (line 42) begins a new table cell. The for loop (lines 4053) iterates through each of the 24 string objects. Each environment variable's name is output in the left table cell (line 42). Line 45 attempts to retrieve the value associated with the environment variable by calling function getenv of <cstdlib> and passing it the string value returned from the function call environmentVariables[ i ].c_str(). Function c_str returns a C-style char * string containing the contents of the environmentVariables[ i ] string. Function getenv returns a char * string containing the value of a specified environment variable or a null pointer if the environment variable does not exist.

Lines 4750 output the contents of the right table cell. If the current environment variable exists (i.e., getenv did not return a null pointer), line 48 outputs the value returned by function getenv. If the environment variable does not exist on the server executing the script, line 50 outputs an appropriate message. The sample execution shown in Fig. 19.8 was produced by running this example on Apache HTTP Server, so the output contains data associated with each of the environment variables. The results on other servers may vary. For example, if you were to run this example on Microsoft Internet Information Services (IIS), several of the table cells in the right column would display the message "Environment variable does not exist."

[Page 928]

Previous Page
Next Page