Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Web programming


May 11, 2021 C++


Table of contents


Web programming in C+

What is CGI?

  • Public Gateway Interface (CGI), a set of standards that defines how information is exchanged between Web servers and client scripts.
  • The CGI specification is currently maintained by the NCSA, which defines CGI as follows:
  • Public Gateway Interface (CGI), an interface standard for docking external gateway programs with information servers, such as HTTP servers.
  • The current version is CGI/1.1, and the CGI/1.2 version is in progress.

Web browsing

To better understand the concept of CGI, let's click on a hyperlink and browse a particular page or URL to see what happens.

  • Your browser contacts the HTTP web server and requests the URL, which is the file name.
  • The Web server resolves 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 an error message is sent indicating that you requested an incorrect file.
  • The web browser gets a response from the web server and displays a file or error message based on the response received.

However, the HTTP server is built in this way, and whenever a file in the directory is requested, the HTTP server sends back not the file, but as a program and sends the output generated by the execution back to the browser for display.

A public 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 with Python, PERL, Shell, C, C, C, and so on.

CGI architecture diagram

The following illustration illustrates the architecture of CGI:

Web programming

Web server configuration

Before you program CGI, make sure that your web server supports CGI and is configured to handle CGI programs. A ll CGI programs performed by http servers must be in a preconfigured directory. T he directory is called the CGI directory and is customaryly named /var/www/cgi-bin. Although the CGI file is an executable file for C++, its extension by convention is .cgi.

By default, the Apache Web server is configured to run CGI programs in /var/www/cgi-bin. If you want to specify a different directory to run CGI scripts, you can modify the following sections 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, let's assume that the Web server is configured and running successfully, and that you can run any CGI program, such as Perl or Shell.

The first CGI program

Take a look at the following C++ program:

#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 - 第一个 CGI 程序</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<h2>Hello World! 这是我的第一个 CGI 程序</h2>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

Compile the code above, name the executable cplusplus .cgi, and save the file in the /var/www/cgi-bin directory. B efore you run the CGI program, use the chmod 755 cplusplus.cgi UNIX command to modify the file mode to ensure that the file is executable. Access the executable and you'll see the following output:

Hello World! This is my first CGI program

The above program is a simple program that writes its output on the STDOUT file, which is displayed on the screen. H ere, it's worth noting that the first line outputs Content-type:text/html\n\n?. T his line is sent back to the browser and specifies the type of content to display on the browser window. Y ou must understand the basic concepts of CGI in order to further write more complex CGI programs using Python. The C?CGI program can interact with any other external system, such as RDBMS.

HTTP header information

Line Content-type:text/html\n is part of the HTTP header information, which is sent to the browser to better understand the content of the page. Http header information takes the form of:

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

There are some other important HTTP header information that is often used in your CGI programming.

Head information describe
Content-type: MIME string, define the returned file format.For example, Content-Type: Text / HTML.
Expires: Date The information becomes an invalid date.The browser uses it to determine when a page needs to be refreshed.The format of an effective date string should be 01 Jan 1998 12:00:00 GMT.
Location: URL This URL refers to the URL that should be returned instead of the requested URL.You can use it to redirect a request to any file.
Last-modified: Date The final modification date of the resource.
Content-length: N The length of the data to be returned, in bytes.The browser uses this value to represent the expected download time of a file.
Set-Cookie: String pass through string Set the cookie.

CGI environment variables

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

variable name describe
CONTENT_TYPE The data type of the content.Use when the client sends additional content to the server.For example, file upload function.
CONTENT_LENGTH The information length of the query.Only available for POST requests.
HTTP_COOKIE Returns the set cookies in the form of a key & value.
HTTP_USER_AGENT The user agent requests the header field, submits the information of the user initiated the request, contains additional information of the browser name, version, and other platform sex.
PATH_INFO The path of the CGI script.
QUERY_STRING The URL encoded information is sent when the request is sent through the GET method, contains the parameters behind the URL symbol.
REMOTE_ADDR Send the IP address of the requested remote host.This is very useful when logging and authentication.
REMOTE_HOST A fully qualified name for issuing the requested host.If this information is not available, remove_addr can be used to get the IP address.
REQUEST_METHOD Method for issuing a request.The most common method is GET and POST.
SCRIPT_FILENAME The full path to 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 CGI variables.

#include <iostream>
#include <stdlib.h>
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 环境变量</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>";
       // 尝试检索环境变量的值
       char *value = getenv( ENV[ i ].c_str() );  
       if ( value != 0 ){
         cout << value;                                 
       }else{
         cout << "环境变量不存在。";
       }
       cout << "</td></tr>\n";
   }
   cout << "</table><\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

The C?CGI library

In a real instance, you need to do a lot through the CGI program. Here's a CGI library written specifically for the C++ program, which we can download from ftp://ftp.gnu.org/gnu/cgicc/ and follow these steps to install the library:

$tar xzf cgicc-X.X.X.tar.gz 
$cd cgicc-X.X.X/ 
$./configure --prefix=/usr 
$make
$make install

You can view the relevant library documentation by clicking on the CGI Lib Documentation.

GET and POST methods

You may have experienced situations where you need to pass some information from your browser to the Web server and finally to a CGI program. Typically, browsers use two methods to pass this information to the Web server, the GET and POST methods.

Use the GET method to pass information

The GET method sends encoded user information appended to the page request. P ages and encoded information pass through ? Characters are separated as follows:

http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2

The GET method is the default way to pass information from the browser to the web server, and it generates a long string in the browser's address bar. D o not use the GET method when you pass passwords or other sensitive information to the server. T he GET method has a size limit and can pass up to 1024 characters in a request string.

When using the GET method, the QUERY_STRING http header is used to pass information, which can be accessed in CGI programs using QUERY_STRING environment variables.

You can pass information by following the key-value pair of a simple connection after the URL, or by using the GET method of the HTML-lt;FORM-gt; tag.

Simple URL instance: Get method

Here's a simple URL that uses the GET method to pass two values to hello_get.py program.

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

The following example cpp_get.cgi CGI program that handles input from a web browser. The information that is passed can be easily accessed by using the C?CGI library:

#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>使用 GET 和 POST 方法</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   form_iterator fi = formData.getElement("first_name");  
   if( !fi->isEmpty() && fi != (*formData).end()) {  
      cout << "名:" << **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 << "姓:" << **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 program above, as follows:

$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc

Build cpp_get.cgi, put it in the CGI directory, and try to access it using the link below:

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

This results in the following:

名:ZARA 
姓:ALI 

Simple form example: GET method

Here's a simple example of using an HTML form and a submit button to pass two values. We'll use the same CGI script cpp_get.cgi process the input.

<form action="/cgi-bin/cpp_get.cgi" method="get">
名:<input type="text" name="first_name">  <br />
 
姓:<input type="text" name="last_name" />
<input type="submit" value="提交" />
</form>

Here's the actual output of the form above, enter your first and last name, and then click the Submit button to see the results.

Use the POST method to pass information

A more reliable way to pass information to CGI programs is the POST method. T his approach packages information in the same way as the GET method, unlike putting information in a URL as a text string? I t is then passed, but 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 to pass two values by using HTML forms and submit buttons, except this time we're not using the GET method, but the POST method, as follows:

<form action="/cgi-bin/cpp_get.cgi" method="post">
名:<input type="text" name="first_name"><br />
姓:<input type="text" name="last_name" />
 
<input type="submit" value="提交" />
</form>

Pass check box data to the CGI program

We use check boxes when multiple options need to be selected.

The following instance of HTML code is a form with two check boxes:

<form action="/cgi-bin/cpp_checkbox.cgi" 
         method="POST" 
         target="_blank">
<input type="checkbox" name="maths" value="on" /> 数学
<input type="checkbox" name="physics" value="on" /> 物理
<input type="submit" value="选择学科" />
</form>

The following C++ program generates cpp_checkbox.cgi script that handles the input given by the Web browser through the check box.

#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>向 CGI 程序传递复选框数据</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;
}

Pass the turntr button data to the CGI program

We use a turn button when only one option needs to be selected.

The following instance of HTML code is a form with two turntable buttons:

<form action="/cgi-bin/cpp_radiobutton.cgi" 
         method="post" 
         target="_blank">
<input type="radio" name="subject" value="maths" 
                                    checked="checked"/> 数学 
<input type="radio" name="subject" value="physics" /> 物理
<input type="submit" value="选择学科" />
</form>

The following C++ program generates cpp_radiobutton.cgi script that handles input given by a Web browser through a single button.

#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>向 CGI 程序传递单选按钮数据</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;
}

Pass text area data to the CGI program

We use the TEXTAREA element when we need to pass multiple lines of text to a CGI program.

The following example of HTML code 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">
请在这里输入文本...
</textarea>
<input type="submit" value="提交" />
</form>

The following C++ program generates a cpp_textarea.cgi that handles input given by a Web browser through a text area.


#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>向 CGI 程序传递文本区域数据</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;
}

Pass the pull-down box data to the CGI program

We use a pull-down box when more than one option is available, but only one or two options can be selected.

The following example of HTML code is a form with a pull-down box:

<form action="/cgi-bin/cpp_dropdown.cgi" 
                       method="post" target="_blank">
<select name="dropdown">
<option value="Maths" selected>数学</option>
<option value="Physics">物理</option>
</select>
<input type="submit" value="提交"/>
</form>

The following C++ program generates cpp_dropdown.cgi script that handles the input given by the web browser through the pull-down box.

#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>向 CGI 程序传递下拉框数据</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;
}

Use cookies in CGI

The HTTP protocol is a stateless protocol. B ut for a business website, it needs to keep session information between pages. F or example, a user ends registration after completing steps on multiple pages. However, how to keep the user's session information in all web pages.

In many cases, the use of cookies is the most effective way to remember and track 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. I f the browser accepts the cookie, the cookie is stored on the visitor's hard drive as a plain text record. C ookies are now retrieved when a visitor visits another page on the website. Once the cookie is found, the server knows what is stored.

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

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

Set cookies

Sending cookies to your browser is very simple. T hese cookies are sent with the HTTP header before the Content-type field. Assuming you want to set UserID and Password as cookies, the steps for setting cookies are as follows:

#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.cn;\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>CGI 中的 Cookies</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   cout << "设置 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, there are some properties that set cookies that are optional, such as Expires, Domain, and Path. It is worth noting that cookies were set before the line "Content-type:text/html\n\n?n" was sent.

Compile the above program, generate a setcookies .cgi, and try setting cookies using the link below. It sets four cookies on your computer:

/cgi-bin/setcookies.cgi

Get cookies

Retrieving all settings of cookies is very simple. Cookies are stored in the CGI environment HTTP_COOKIE in the following form:

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

The following example shows how to get cookies.

#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>CGI 中的 Cookies</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";
   cout << "<table border = \"0\" cellspacing = \"2\">";
   
   // 获取环境变量
   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, generate a getcookies .cgi, and try using the link below to get all the available cookies on your computer:

/cgi-bin/getcookies.cgi

This results in a list of the four cookies set in the last section and all other cookies on your computer:

UserID XYZ 
Password XYZ123 
Domain www.w3cschool.cn 
Path /perl 

File upload instance

In order to upload a file, the HTML form must set the enctype property to multipart/form-data. The input label with file type creates a "Browse" button.

<html>
<body>
   <form enctype="multipart/form-data" 
            action="/cgi-bin/cpp_uploadfile.cgi" 
            method="post">
   <p>文件:<input type="file" name="userfile" /></p>
   <p><input type="submit" value="上传" /></p>
   </form>
</body>
</html>

You can try the code above on your own server.


Here are the scripts used to handle file uploads cpp_uploadfile.cpp:

#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>CGI 中的文件上传</title>\n";
   cout << "</head>\n";
   cout << "<body>\n";

   // 获取要被上传的文件列表
   const_file_iterator file = cgi.getFile("userfile");
   if(file != cgi.getFiles().end()) {
      // 在 cout 中发送数据类型
      cout << HTTPContentHeader(file->getDataType());
      // 在 cout 中写入内容
      file->writeToStream(cout);
   }
   cout << "<文件上传成功>\n";
   cout << "</body>\n";
   cout << "</html>\n";
   
   return 0;
}

The above example is written in a cout stream, but you can open the file stream and save the uploaded file content in a file at the destination location.