C++ Web Programming
What is CGI?
The Common Gateway Interface (CGI), is a set of standards that define how information is exchanged between the web server and a client script.
The CGI specification is currently maintained by NCSA, which defines CGI as follows:
The Common Gateway Interface (CGI) is an interface standard for external gateway programs to interface with information servers such as HTTP servers.
The current version is CGI/1.1, with CGI/1.2 being developed.
Web Browsing
To better understand the concept of CGI, let's click on a hyperlink, browse to a specific web page or URL, and see what happens.
Your browser contacts the HTTP web server and requests the URL, which is the file name.
The web server parses the URL and looks for the file name. If it finds the requested file, the web server sends the file back to the browser; otherwise, it sends an error message indicating that you requested a wrong file.
The web browser receives the response from the web server and displays the file or error message based on the received response.
However, in this setup, whenever a file in the directory is requested, instead of sending the file back, the HTTP server executes it as a program and sends the output generated by the execution back to the browser for display.
The Common Gateway Interface (CGI) is a standard protocol that allows applications (called CGI programs or CGI scripts) to interact with the web server and the client. These CGI programs can be written in Python, PERL, Shell, C, or C++.
CGI Architecture Diagram
The diagram below demonstrates the architecture of CGI:
Web Server Configuration
Before you start CGI programming, ensure that your web server supports CGI and is configured to handle CGI programs. All CGI programs executed by the HTTP server must be in a pre-configured directory. This directory is called the CGI directory and is conventionally named /var/www/cgi-bin. Although CGI files are C++ executables, by convention, their extension is .cgi.
By default, the Apache web server is configured to run CGI programs in /var/www/cgi-bin. If you want to specify another directory to run CGI scripts, you can modify the following section in the httpd.conf file:
<Directory "/var/www/cgi-bin">
AllowOverride None
Options ExecCGI
Order allow,deny
Allow from all
</Directory>
<Directory "/var/www/cgi-bin">
Options All
</Directory>
Here, we assume that the web server is configured and running successfully, allowing you to run any CGI program, such as Perl or Shell.
First CGI Program
Consider the following C++ program:
Example
#include <iostream>
using namespace std;
int main ()
{
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Hello World - First CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<h2>Hello World! This is my first CGI program</h2>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Compile the above code, name the executable file cplusplus.cgi, and save it in the /var/www/cgi-bin directory. Before running the CGI program, use the chmod 755 cplusplus.cgi UNIX command to modify the file mode, ensuring the file is executable. Accessing the executable file will display the following output:
Hello World! This is my first CGI program
The above C++ program is a simple program that writes its output to the STDOUT file, which is displayed on the screen. It is important to note that the first line of output Content-type:text/html\r\n\r\n is sent back to the browser and specifies the content type to be displayed in the browser window. Understanding the basic concepts of CGI is essential for writing more complex CGI programs in Python. C++ CGI programs can interact with any external system, such as RDBMS.
HTTP Headers
This is an HTTP header part, which is sent to the browser to better understand the page content. The format of HTTP header information is as follows:
HTTP Field Name: Field Content
For example:
Content-type: text/html\r\n\r\n
There are also other important HTTP headers that are frequently used in your CGI programming.
Header | Description |
---|---|
Content-type: | MIME string, defining the format of the returned file. For example, Content-type:text/html. |
Expires: Date | The date when the information becomes invalid. The browser uses it to determine when a page needs to be refreshed. A valid date string should be in the format 01 Jan 1998 12:00:00 GMT. |
Location: URL | This URL is the one that should be returned, not the requested URL. You can use it to redirect a request to any file. |
Last-modified: Date | The last modification date of the resource. |
Content-length: N | The length of the data to be returned, in bytes. The browser uses this value to indicate the estimated download time of a file. |
Set-Cookie: String | Sets a cookie via string. |
CGI Environment Variables
All CGI programs can access the following environment variables. These variables play a very important role when writing CGI programs.
Variable Name | Description |
---|---|
CONTENT_TYPE | The data type of the content. Used when the client sends additional content to the server, such as file upload functionality. |
CONTENT_LENGTH | The length of the query information. Only available for POST requests. |
HTTP_COOKIE | Returns the set cookies in key & value pairs. |
HTTP_USER_AGENT | The user agent request header field, which provides information about the user who initiated the request, including the browser's name, version, and additional platform-specific information. |
PATH_INFO | The path of the CGI script. |
QUERY_STRING | The URL-encoded information sent with the GET method, including parameters after the question mark in the URL. |
REMOTE_ADDR | The IP address of the remote host making the request. This is useful for logging and authentication. |
REMOTE_HOST | The fully qualified name of the host making the request. If this information is not available, you can use REMOTE_ADDR to get the IP address. |
REQUEST_METHOD | The method used to make the request. The most common methods are GET and POST. |
SCRIPT_FILENAME | The full path of the CGI script. |
SCRIPT_NAME | The name of the CGI script. |
SERVER_NAME | The hostname or IP address of the server. |
SERVER_SOFTWARE | The name and version of the software running on the server. |
The following CGI program lists all CGI variables.
Example
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
const string ENV[ 24 ] = {
"COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",
"HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",
"HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",
"HTTP_HOST", "HTTP_USER_AGENT", "PATH",
"QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",
"REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME",
"SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",
"SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",
"SERVER_SIGNATURE","SERVER_SOFTWARE" };
int main ()
{
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>CGI Environment Variables</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<table border = \"0\" cellspacing = \"2\">";
for ( int i = 0; i < 24; i++ )
{
cout << "<tr><td>" << ENV[ i ] << "</td><td>";
// Attempt to retrieve the value of the environment variable
char *value = getenv( ENV[ i ].c_str() );
if ( value != 0 ){
cout << value;
}else{
cout << "Environment variable does not exist.";
}
cout << "</td></tr>\n";
}
cout << "</table><\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
C++ CGI Library
In real-world scenarios, you need to perform many operations through a CGI program. Here is a CGI library specifically written for C++ programs, which we can download from ftp://ftp.gnu.org/gnu/cgicc/ and install following these steps:
$ tar xzf cgicc-X.X.X.tar.gz
$ cd cgicc-X.X.X/
$ ./configure --prefix=/usr
$ make
$ make install
Note: The libcgicc.so and libcgicc.a libraries will be installed in the /usr/lib directory, and you need to execute the following copy command:
$ sudo cp /usr/lib/libcgicc.* /usr/lib64/
to ensure that the CGI program can automatically find the libcgicc.so dynamic link library.
You can click C++ CGI Lib Documentation to view the related library documentation.
GET and POST Methods
You may have encountered situations where you need to pass some information from the browser to the web server, and finally to the CGI program. Typically, the browser uses two methods to pass this information to the web server, which are GET and POST methods.
Using GET Method to Pass Information
The GET method sends the encoded user information appended to the page request. The page and the encoded information are separated by the ? character, as shown below:
http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2
The GET method is the default method for passing information from the browser to the web server, and it generates a very long string in the browser's address bar. Do not use the GET method when passing passwords or other sensitive information. The GET method has a size limit, with a maximum of 1024 characters in a request string.
When using the GET method, the information is passed using the QUERY_STRING http header, which can be accessed in the CGI program using the QUERY_STRING environment variable.
You can pass information by simply concatenating key-value pairs after the URL, or by using the GET method of the HTML <FORM> tag.
Simple URL Example: GET Method
Here is a simple URL that uses the GET method to pass two values to the cpp_get.cgi program.
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
The following example generates the cpp_get.cgi CGI program, which processes the input provided by the web browser. Accessing the passed information is easy using the C++ CGI library:
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Using GET and POST Methods</title>\n";
cout << "</head>\n";
cout << "<body>\n";
form_iterator fi = formData.getElement("first_name");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "First Name: " << **fi << endl;
}else{
cout << "No text entered for first name" << endl;
}
cout << "<br/>\n";
fi = formData.getElement("last_name");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Last Name: " << **fi << endl;
}else{
cout << "No text entered for last name" << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Now, compile the above program as follows:
$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc
This will generate cpp_get.cgi, and place it in your CGI directory and try to access it using the following link:
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
This will produce the following result:
First Name: ZARA
Last Name: ALI
Simple Form Example: GET Method
Here is a simple example that uses an HTML form and a submit button to pass two values. We will use the same CGI script, cpp_get.cgi, to process this input.
<form action="/cgi-bin/cpp_get.cgi" method="get">
First Name: <input type="text" name="first_name"> <br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
Here is the actual output of the above form, please enter the first name and last name, then click the submit button to see the result.
Passing Information Using POST Method
A more reliable way to pass information to a CGI program is the POST method. This method packages the information in exactly the same way as the GET method, but instead of sending it as a text string after a ? in the URL, it sends it as a separate message. This message is sent to the CGI script in the form of standard input.
We will use the same cpp_get.cgi script to process the POST method. Let's take the same example as above, using an HTML form and a submit button to pass two values, but this time using the POST method instead of GET, as shown below:
<form action="/cgi-bin/cpp_get.cgi" method="post">
First Name: <input type="text" name="first_name"><br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
Passing Checkbox Data to CGI Program
Checkboxes are used when more than one option is required to be selected.
Here is an example HTML code for a form with two checkboxes:
<form action="/cgi-bin/cpp_checkbox.cgi"
method="POST"
target="_blank">
<input type="checkbox" name="maths" value="on" /> Maths
<input type="checkbox" name="physics" value="on" /> Physics
<input type="submit" value="Select Subject" />
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
bool maths_flag, physics_flag;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Checkbox Data to CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
maths_flag = formData.queryCheckbox("maths");
if( maths_flag ) {
cout << "Maths Flag: ON " << endl;
}else{
cout << "Maths Flag: OFF " << endl;
}
cout << "<br/>\n";
physics_flag = formData.queryCheckbox("physics");
if( physics_flag ) {
cout << "Physics Flag: ON " << endl;
}else{
cout << "Physics Flag: OFF " << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Passing Radio Button Data to CGI Program
When only one option needs to be selected, we use radio buttons.
The following HTML code example is a form with two radio buttons:
<form action="/cgi-bin/cpp_radiobutton.cgi"
method="post"
target="_blank">
<input type="radio" name="subject" value="maths"
checked="checked"/> Maths
<input type="radio" name="subject" value="physics" /> Physics
<input type="submit" value="Select Subject" />
</form>
The following C++ program generates the cpp_radiobutton.cgi script, which processes the input given by the web browser through radio buttons.
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Radio Button Data to CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
form_iterator fi = formData.getElement("subject");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Subject: " << **fi << endl;
}else{
cout << "No subject selected" << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
form_iterator fi = formData.getElement("subject");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Radio box selected: " << **fi << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Passing Text Area Data to CGI Program
When you need to pass multi-line text to a CGI program, we use the TEXTAREA element.
The following HTML code example is a form with a TEXTAREA box:
<form action="/cgi-bin/cpp_textarea.cgi"
method="post"
target="_blank">
<textarea name="textcontent" cols="40" rows="4">
Please enter text here...
</textarea>
<input type="submit" value="Submit" />
</form>
The following C++ program generates the cpp_textarea.cgi script, which processes the input given by the web browser through the text area.
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Passing Text Area Data to CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
form_iterator fi = formData.getElement("textcontent");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Text Content: " << **fi << endl;
}else{
cout << "No text entered" << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Passing Drop-Down Box Data to CGI Program
When there are multiple options available but only one or two can be selected, we use drop-down boxes.
The following HTML code example is a form with a drop-down box:
<form action="/cgi-bin/cpp_dropdown.cgi"
method="post" target="_blank">
<select name="dropdown">
<option value="Maths" selected>Math</option>
<option value="Physics">Physics</option>
</select>
<input type="submit" value="Submit"/>
</form>
The following C++ program generates the cpp_dropdown.cgi script, which processes the input given by the web browser through the drop-down box.
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Passing Drop-Down Box Data to CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
form_iterator fi = formData.getElement("dropdown");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Selected: " << **fi << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
#include <iostream>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc formData;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Passing Drop-Down Box Data to CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
form_iterator fi = formData.getElement("dropdown");
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Value Selected: " << **fi << endl;
}
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Using Cookies in CGI
HTTP is a stateless protocol. However, for a commercial website, it needs to maintain session information among different pages. For example, a user id is registered and remains the same for the entire session. How can we maintain the user's session information across all web pages?
In many instances, using cookies is the most efficient method for remembering and tracking preferences, purchases, commissions, and other information required for better visitor experience or site statistics.
How It Works
The server sends some data to the visitor's browser in the form of a cookie. If the browser accepts the cookie, it is stored as a plain text record on the visitor's hard drive. Now, when the visitor arrives at another page on the site, the cookie is available for retrieval. Once a cookie has been retrieved, the server can read the information stored in it.
A cookie is a plain text data record of 5 variable-length fields:
Expires: The date the cookie will expire. If this is blank, the cookie will expire when the visitor quits the browser.
Domain: The domain name of the site.
Path: The path to the directory or web page that sets the cookie. This may be blank if you want to retrieve the cookie from any directory or page.
Secure: If this field contains the word "secure", then the cookie may only be retrieved with a secure server. If this field is blank, no such restriction exists.
Name=Value: Cookies are set and retrieved in the form of key-value pairs.
Setting Cookies
Sending cookies to the browser is very simple. These cookies are sent along with the HTTP headers before the Content-type field. Suppose you want to set UserID and Password as cookies, the steps to set cookies are as follows:
Example
#include <iostream>
using namespace std;
int main ()
{
cout << "Set-Cookie:UserID=XYZ;\r\n";
cout << "Set-Cookie:Password=XYZ123;\r\n";
cout << "Set-Cookie:Domain=www.w3cschool.cc;\r\n";
cout << "Set-Cookie:Path=/perl;\n";
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Cookies in CGI</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "Setting cookies" << endl;
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
From this example, we learned how to set cookies. We use the Set-Cookie HTTP header to set cookies.
Here, some attributes of setting cookies are optional, such as Expires, Domain, and Path. It is important to note that cookies are set before the line "Content-type:text/html\r\n\r\n" is sent. Compile the above program to generate setcookies.cgi, and try setting cookies using the following link. It will set four cookies on your computer:
/cgi-bin/setcookies.cgi
Retrieving Cookies
Retrieving all set cookies is quite simple. Cookies are stored in the CGI environment variable HTTP_COOKIE, and they are in the following format:
key1=value1;key2=value2;key3=value3....
The following example demonstrates how to retrieve cookies.
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc cgi;
const_cookie_iterator cci;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Cookies in CGI</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<table border = \"0\" cellspacing = \"2\">";
// Get environment variables
const CgiEnvironment& env = cgi.getEnvironment();
for( cci = env.getCookieList().begin();
cci != env.getCookieList().end();
++cci )
{
cout << "<tr><td>" << cci->getName() << "</td><td>";
cout << cci->getValue();
cout << "</td></tr>\n";
}
cout << "</table><\n";
cout << "<br/>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
Now, compile the above program to generate getcookies.cgi, and try using the following link to retrieve all available cookies on your computer:
/cgi-bin/getcookies.cgi
This will produce a list showing the four cookies set in the previous section as well as any other cookies on your computer:
UserID XYZ
Password XYZ123
Domain www.w3cschool.cc
Path /perl
File Upload Example
To upload a file, the HTML form must set the enctype attribute to multipart/form-data. The input tag with the file type creates a "Browse" button.
<html>
<body>
<form enctype="multipart/form-data"
action="/cgi-bin/cpp_uploadfile.cgi"
method="post">
<p>File: <input type="file" name="userfile" /></p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
This code results in the following form:
File:
Note: The above example intentionally disables saving the uploaded file on our server. You can try the above code on your own server.
Below is the script cpp_uploadfile.cpp for handling file uploads:
Example
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>
using namespace std;
using namespace cgicc;
int main ()
{
Cgicc cgi;
cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>File Upload in CGI</title>\n";
cout << "</head>\n";
cout << "<body>\n";
// Get the list of files to be uploaded
const_file_iterator file = cgi.getFile("userfile");
if(file != cgi.getFiles().end()) {
// Send the data type in cout
cout << HTTPContentHeader(file->getDataType());
// Write the content in cout
file->writeToStream(cout);
}
cout << "<File upload successful>\n";
cout << "</body>\n";
cout << "</html>\n";
return 0;
}
The above example writes the content to the cout stream, but you can open a file stream and save the uploaded file content to a file at the target location.