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.
http://localhost/cgi-bin/localtime.cgi
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 4 using std::cout; 5 6 #include // 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; 11 12 int main() 13 { 14 time_t currentTime; // variable for storing time 15 16 cout << "Content-Type: text/html "; // output HTTP header 17 18 // output XML declaration and DOCTYPE 19 cout << "" 20 << " 21 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 22 23 time( ¤tTime ); // store time in currentTime 24 25 // output html element and some of its contents 26 cout << "" 27 << "Current date and time" 28 << " " << asctime( localtime( ¤tTime ) ) 29 << " "; 30 return 0; 31 } // end main |
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.
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.
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.
Current date and time
Wed Oct 13 10:22:18 2004
|
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. |
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 4 using std::cout; 5 6 #include 7 using std::string; 8 9 #include 10 using std::getenv; 11 12 int main() 13 { 14 string environmentVariables[ 24 ] = { 15 "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", 16 "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", 17 "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", 18 "HTTP_HOST", "HTTP_USER_AGENT", "PATH", 19 "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT", 20 "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", 21 "SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN", 22 "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL", 23 "SERVER_SIGNATURE","SERVER_SOFTWARE" }; 24 25 cout << "Content-Type: text/html "; // output HTTP header 26 27 // output XML declaration and DOCTYPE 28 cout << "" 29 << " 30 << ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">"; 31 32 // output html element and some of its contents 33 cout << "" 34 << "Environment Variables"; 35 36 // begin outputting table 37 cout << ""; 38 39 // iterate through environment variables 40 for ( int i = 0; i < 24; i++ ) 41 { 42 cout << ""; 53 } // end for 54 55 cout << "
|
Lines 4252 output each row of the table. Let us examine each of these lines closely. Line 42 outputs an XHTML (table row) start tag, which indicates the beginning of a new table row. Line 52 outputs a corresponding 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 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 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."