C++ Web programming

What is CGI?

  • The Common Gateway Interface (CGI) is a standard that defines how information is exchanged between web servers and client scripts.
  • 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, and CGI/1.2 is being developed.

Web browsing

To better understand the concept of CGI, let's click a hyperlink, browse a specific webpage or URL, and see what happens.

  • Your browser contacts the HTTP web server and requests the URL, that is, the file name.
  • The web server parses the URL and looks for the file name. If the requested file is found, the web server sends the file back to the browser; otherwise, it sends an error message indicating that you requested an incorrect file.
  • The web browser receives the response from the web server and displays the file or error message based on the received response.

However, with an HTTP server built in this way, whenever a file in a directory is requested, the HTTP server does not send back the file itself, but executes it as a program and sends the output produced by that execution back to the browser for display.

The Common Gateway Interface (CGI) is a standard protocol that enables applications (called CGI programs or CGI scripts) to interact with web servers and clients. These CGI programs can be written in Python, PERL, Shell, C, or C++, etc.

CGI architecture diagram

The following diagram demonstrates the CGI architecture:

CGI 架构

Web Server Configuration

Before you do CGI programming, make sure your web server supports CGI and has been configured to handle CGI programs. All CGI programs executed by the HTTP server must be placed in a preconfigured directory. This directory is called the CGI directory and, by convention, is 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 has been configured and can run successfully, and you can run any CGI program, such as Perl or Shell, and so on.

First CGI Program

Please look at 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 cplusplus.cgi, and save this file in the /var/www/cgi-bin directory. Before running the CGI program, please usechmod 755 cplusplus.cgiUse a UNIX command to modify the file mode and ensure the file is executable. Access the executable file and you will see 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, that is, displays it on the screen. Here, it is worth noting that the first line of outputContent-type:text/html\r\n\r\nis sent back to the browser and specifies the content type to be displayed in the browser window. You must understand the basic concepts of CGI in order to further use Python to write more complex CGI programs. C++ CGI programs can interact with any other external system (such as RDBMS).

HTTP header information

lineContent-type:text/html\r\n\r\nIt is part of the HTTP header information, which is sent to the browser to better understand the page content. The HTTP header information has the following format:

HTTP 字段名称: 字段内容
 
例如
Content-type: text/html\r\n\r\n

There are also some other important HTTP headers, which are frequently used in your CGI programming.

Header information Description
Content-type: MIME string, defines the format of the returned file. For example Content-type:text/html.
Expires: Date The date on which the information becomes invalid. The browser uses it to determine when a page needs to be refreshed. A valid date string should have the format 01 Jan 1998 12:00:00 GMT.
Location: URL This URL refers to the URL that should be returned, not the requested URL. You can use it to redirect a request to any file.
Last-modified: Date The last modified 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 for a file.
Set-Cookie: String ThroughstringSet cookie.

CGI Environment Variables

All CGI programs can access the following environment variables. These variables play a very important role in writing CGI programs.

Variable Name Description
CONTENT_TYPE The data type of the content. Used when the client sends additional content to the server. For example, features such as file upload.
CONTENT_LENGTH The length of the query information. Only available for POST requests.
HTTP_COOKIE Returns the set cookies in the form of key & value pairs.
HTTP_USER_AGENT The user agent request header field delivers information about the user's request, including the browser name, version, and other platform-specific additional information.
PATH_INFO The path of the CGI script.
QUERY_STRING The URL-encoded information when sending a request via the GET method, containing the parameters after the question mark in the URL.
REMOTE_ADDR The IP address of the remote host making the request. This is very useful for logging and authentication.
REMOTE_HOST The fully qualified name of the host making the request. If this information is not available, REMOTE_ADDR can be used 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 host name 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 the 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>"; // Try to retrieve the value of the environment variable char *value = getenv( ENV[ i ].c_str() ); if ( value != 0 ){ cout << value; }else{ cout << "The 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 examples, you need to perform many operations through the CGI program. Here is a CGI library written specifically for C++ programs, which we can get fromftp://ftp.gnu.org/gnu/cgicc/Download this CGI library and install the library according to the following 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 to the /usr/lib directory; execute the copy command:

$ sudo cp /usr/lib/libcgicc.* /usr/lib64/

So that CGI programs can automatically find the libcgicc.so dynamic link library.

You can clickC++ CGI Lib Documentation, refer to the relevant 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 then to the CGI program. Usually the browser uses two methods to pass this information to the web server: GET and POST.

Passing Information Using the GET Method

The GET method appends the encoded user information to the page request. The page and the encoded information are separated by the ? character, as follows:

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. It generates a long string in the browser's address bar. When you pass passwords or other sensitive information to the server, do not use the GET method. The GET method has a size limit, allowing a maximum of 1024 characters in a request string.

When using the GET method, information is passed using the QUERY_STRING http header, which can be accessed in CGI programs using the QUERY_STRING environment variable.

You can pass information by appending simple concatenated key-value pairs to the URL, or by using the GET method of the HTML <FORM> tag.

Simple URL Example: Get Method

The following is a simple URL that passes two values to the cpp_get.cgi program using the GET method.

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

The following example generatescpp_get.cgiThe CGI program is used to process input from the web browser. By using the C++ CGI library, the passed information can be easily accessed:

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

Generate cpp_get.cgi, place it in the CGI directory, and try accessing it with the following link:

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

This produces the following result:

名:ZARA 
姓:ALI 

Simple form example: GET method

The following 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 handle the 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>

The following is the actual output of the above form. Please enter your first name and last name, then click the submit button to see the result.

Passing Information Using the POST Method

A more reliable method for passing information to CGI programs is the POST method. This method packages information in the same way as the GET method, except that instead of passing the information as a text string after the ? in the URL, it passes it as a separate message. The message is passed to the CGI script as standard input.

We also use the cpp_get.cgi program to handle the POST method. Let's use the same example, passing two values with an HTML form and a submit button, except this time we use the POST method instead of the GET method, as follows:

<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 Programs

When multiple options need to be selected, we use checkboxes.

The following HTML code example is a form with two checkboxes:

<form action="/cgi-bin/cpp_checkbox.cgi" method="POST" target="_blank"> <input type="checkbox" name="maths" value="on" />Mathematics<input type="checkbox" name="physics" value="on" />Physics<input type="submit" value="Select subject" /> </form>

The following C++ program generates the cpp_checkbox.cgi script, which processes input given by the web browser through checkboxes.

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; bool maths_flag, physics_flag; cout << "Content-type:text/html\r\n\r\n"; cout << "<html>\n"; cout << "<head>\n"; cout << "<title>Passing 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 Programs

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"/>Mathematics<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 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>Passing 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 << "Radio box selected: " << **fi << endl; } cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return 0; }

Passing Textarea Data to CGI Programs

When multi-line text needs to be passed 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 input given by the web browser through a textarea.

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 Textarea 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 Dropdown Box Data to CGI Programs

When multiple options are available but only one or two options can be selected, we use a dropdown box.

The following HTML code example is a form with a dropdown box:

<form action="/cgi-bin/cpp_dropdown.cgi" method="post" target="_blank"> <select name="dropdown"> <option value="Maths" selected>Mathematics</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 input given by the web browser through a dropdown 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 Dropdown 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

The HTTP protocol is a stateless protocol. But for a commercial website, it needs to maintain session information between different pages. For example, a user completes registration after finishing steps across multiple pages. However, how can the user's session information be maintained across all web pages?

In many cases, using cookies is the most effective way to remember and track information about user preferences, purchases, commissions, and other information needed for a better visitor experience or website 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 on the visitor's hard drive as a plain text record. Now, when the visitor visits another page on the website, the cookie is retrieved. Once the cookie is found, the server knows what was stored.

A cookie is a plain text data record with 5 variable-length fields:

  • Expires :The expiration date of the cookie. If this field is left blank, the cookie will expire when the visitor exits the browser.
  • Domain :The domain name of the website.
  • Path :The directory or page path where the cookie is set. If you want to retrieve the cookie from any directory or page, this field can be left blank.
  • Secure :If this field contains the word "secure", the cookie can only be retrieved through a secure server. If this field is left blank, this restriction does not exist.
  • Name=Value :Cookies are set and retrieved in the form of key-value pairs.

Set 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 << "Set cookies" << endl; cout << "<br/>\n"; cout << "</body>\n"; cout << "</html>\n"; return 0; }

From this example, we learned how to set cookies. We useSet-CookieHTTP headers to set cookies.

Here, some attributes for setting cookies are optional, such as Expires, Domain, and Path. It is worth noting that cookies are in the sending line"Content-type:text/html\r\n\r\nIt was set previously.

Compile the above program to generate setcookies.cgi, and try using the following link to set cookies. It will set four cookies on your computer:

/cgi-bin/setcookies.cgi

Get Cookies

Retrieving all set cookies is very simple. The cookies are stored in the CGI environment variable HTTP_COOKIE, and their format is as follows:

key1=value1;key2=value2;key3=value3....

The following example demonstrates how to get 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 get all available cookies on your computer:

/cgi-bin/getcookies.cgi

This produces a list showing the four cookies set in the previous section as well as all 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 tomultipart/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>

The result of this code is the following form:

File:

Note:The above example has intentionally disabled saving the uploaded file on our server. You can try the above code on your own server.

The following is a script for handling file uploads.cpp_uploadfile.cpp:

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 data type in cout cout << HTTPContentHeader(file->getDataType()); // Write content in cout file->writeToStream(cout); } cout << "<File uploaded successfully>\n"; cout << "</body>\n"; cout << "</html>\n"; return 0; }

The above example is incoutWrite content to the stream, but you can open a file stream and save the uploaded file content in a certain file at the target location.

other extensions