【澳门京葡网站】1.3.09_C++ Web 编制程序

目录显示等功能,协议的详细内容,  HTTP协议是应用层的面向对象的协议,Web 服务器将解析 URL,服务器会把文件发送回浏览器,服务器和CGI程序之间的通讯才是我们关注的,我们只需要知道浏览器请求执行服务器上哪个CGI程序就可以了

澳门京葡网站 17

本条主若是在CSAPP底子上做的,增加了POST,SSL,目录突显等效果。

2)GET方法

  在该措施下,CGI程序无法直接从服务器的正规输入(客商发送的音信正文)中获取数据,因为服务器把它从正式输入选取到得数据编码四处境变量QUEPRADOY_STRING(或PATH_INFO)。

  接纳GET方法提交HTML表单数据的时候,客商机将把那些数量附加到由ACTION标识命名的UGL450L的结尾,用一个席卷把经过U帕杰罗L编码后的消息与CGI程序的名字分别:?name=hgq$id=1,QUERY_STENVISIONING的值为name=hgq&id=1(?左边为要呼吁的财富,侧面为参数,参数形式平日为name=value情势,以“&”连接)。或许使用nomal情势的GET方法,无参数,不带正文,独有伏乞行+音讯报头+空行。有个别技术员不情愿利用GET方法,因为在她们看来,把动态新闻附加在UPAJEROL的尾声有违U讴歌MDXL的视角:UENCOREL作为风度翩翩种规范用语,经常是用作互连网资源的独一无二定位标示。

CGI 架构图

下图演示了 CGI 的构造:

澳门京葡网站 1

CGI 架构

1.POST方法

倘诺利用POST方法,那么客商带给的客户数据将贮存在在CGI进度的正儿八经输入中,同一时候将客户数据的长短付与际遇变量中的CONTENT_LENGTH。顾客端用POST情势发送数占领三个对应的MIME类型(通用Internet邮件扩张服务:Multi-purpose
Internet Mail
Extensions)。近期,MIME类型经常是:application/x-wwww-form-urlencoded,该项目表示数据来源于HTML表单。该品种记录在景况变量CONTENT_TYPE中,CGI程序应该检查该变量的值。

二、设计原理

先是介绍一些HTTP协议基本知识。

#1.GET/POST

本实现协理GET/POST方法,都以HTTP合同需求援救的行业内部方法。

GET方法重借使透过UTucsonL发送哀告和传送数据,而POST方法在伸手头空意气风发格之后传送数据,所以POST方法比GET方法安全性高,因为GET方法能够一直看出传送的多寡。此外叁个分别就是GET方法传输的数据很小,而POST方法一点都不小。所以日常表单,登入页面等都以经过POST方法。

#2.MIME类型

当服务器获取顾客端的呼吁的文书名,将深入分析文件的MIME类型,然后告诉浏览器改文件的MIME类型,浏览器通过MIME类型深入剖判传送过来的多寡。具体来讲,浏览器央求四个主页面,该页面是一个HTML文件,那么服务器将”text/html”类型发给浏览器,浏览器通过HTML深入分析器度和胆识别发送过来的开始和结果并出示。

下边将陈诉二个实际情状。

客商端应用浏览器通过UTiguanL发送诉求,服务器获取央求。

如浏览器UEvoqueL为:127.0.0.1/postAuth.html,

那正是说服务器获取到的呼吁为:GET  /postAuth.html  HTTP/1.1

意思是急需根目录下postAuth.html文件的内容,通过GET方法,使用HTTP/1.1争辩(1.1是HTTP的版本号State of Qatar。那是服务器将解析文件名,获悉postAuth.html是一个HTML文件,所以将”text/html”发送给浏览器,然后读取postAuth.html内容发给浏览器。

落到实处轻巧的MIME类型识别代码如下:

要害正是通过文件后缀获取文件类型。

static void get_filetype(const char *filename, char *filetype)   
{  
    if (strstr(filename, ".html"))  
        strcpy(filetype, "text/html");  
    else if (strstr(filename, ".gif"))  
        strcpy(filetype, "image/gif");  
    else if (strstr(filename, ".jpg"))  
        strcpy(filetype, "image/jpeg");  
    else if (strstr(filename, ".png"))  
        strcpy(filetype, "image/png");  
    else  
    strcpy(filetype, "text/plain");  
}

万意气风发帮衬HTTPS的话,那么大家就#define HTTPS,那根本透过gcc
的D选项达成的,具体细节可参照man手册。

静态内容呈现实现如下:

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

#3.CGI规范

假定不能不显示页面那么可信缺少动态人机联作工夫,于是CGI产生了。CGI是公家网关接口(Common
Gateway
Interface卡塔尔(قطر‎,是在CGI程序和Web服务器之间传递音信的准则。CGI允许Web服务器施行外界程序,并将它们的出口发送给浏览器。那样就提供了动态人机联作技巧。

那正是说服务器是如何分开管理静态页面和动态CGI程序的啊?这关键是通过深入解析U悍马H2L的情势。大家得以定义CGI程序的目录,如cgi-bin,那么生龙活虎旦UENCOREL包涵”cgi-bin”字符串则那是动态程序,且将UCR-VL的参数给cgiargs。要是是静态页面,parse_uri再次来到1,反正重返0。所以大家得以经过重临值分化分歧的服务类型。

切实深入深入分析UENCOREL格局如下:

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

GET方式的CGI标准落实原理:

服务器通过U君越L获取传给CGI程序的参数,设置意况变量QUEHighlanderY_ST福特ExplorerING,并将标准输出重定向到文件描述符,然后通过EXEC函数簇试行外界CGI程序。外界CGI程序获得QUE纳瓦拉Y_STGL450ING并管理,管理完后输出结果。由于那时候专门的学业输出已重定向到文件描述符,即发送给了浏览器。

得以完毕细节如下:由于涉及到HTTPS,所以某些有一点复杂。

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

POST情势的CGI标准落实原理:

是因为POST格局不是由此U讴歌RDXL传递参数,所以达成情势与GET方式不相像。

POST格局获取浏览器发送过来的参数长度设置为条件变量CONTENT-LENGTH。并将参数重定向到CGI的正统输入,那至关首要透过pipe管道达成的。CGI程序从专门的学业输入读取CONTENT-LENGTH个字符就得到了浏览器传送的参数,并将管理结果输出到正规输出,同理标准输出已重定向到文件描述符,所以浏览器就能够吸收接纳管理的响应。

具体达成细节如下:

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

目录显示效果原理:

首假诺透过UENVISIONL获取所需目录,然后拿走该目录下有所文件,并发送相应音讯,满含文件格式对应图片,文件名,文件大小,最终改过时间等。由于我们发送的公文名是通过超链接的情势,所以大家可以点击文件名接续浏览新闻。

现实实现细节如下:

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

HTTPS的实现:

HTTPS首要依照openssl的开源库达成。若无安装,那么大家就不#define
HTTPS。
HTTPS的效果与利益主要正是提供安全的接连,服务器和浏览器之间传递的数码是因而加密的,加密方式可以和煦选定。

发端接二连三时,服务器供给发送CA,由于大家的CA是友好签发的,所以须求大家和好增加为可相信。

访谈调节功用:

关键是经过拿到客商端IP地址,并转移为整数,与上配置文件中定义的掩码,假使符合布局文件中允许的网段,那么能够访谈,不然不得以。

具体落到实处如下。

static void serve_static(int fd, char *filename, int filesize) 
{
    int srcfd;
    char *srcp, filetype[MAXLINE], buf[MAXBUF];

    /* Send response headers to client */
    get_filetype(filename, filetype);
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n", buf);
    sprintf(buf, "%sContent-length: %d\r\n", buf, filesize);
    sprintf(buf, "%sContent-type: %s\r\n\r\n", buf, filetype);

    /* Send response body to client */
    srcfd = Open(filename, O_RDONLY, 0);
    srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);
    Close(srcfd);

    #ifdef HTTPS 
    if(ishttps)
    {
        SSL_write(ssl, buf, strlen(buf));
    SSL_write(ssl, srcp, filesize);
    }
    else
    #endif
    {
    Rio_writen(fd, buf, strlen(buf));
    Rio_writen(fd, srcp, filesize);
    }
    Munmap(srcp, filesize);
}

配备文件的读取:

着重筛选音信都定义与结构文件中。

格式比如如下;

#HTTP PORT
PORT = 8888

于是读取配置文件函数具体如下:

static char* getconfig(char* name)  
{  
/* 
pointer meaning: 

...port...=...8000... 
   |  |   |   |  | 
  *fs |   |   |  *be    f->forward  b-> back 
      *fe |   *bs       s->start    e-> end 
          *equal 
*/  
    static char info[64];  
    int find=0;  
    char tmp[256],fore[64],back[64],tmpcwd[MAXLINE];  
    char *fs,*fe,*equal,*bs,*be,*start;  

    strcpy(tmpcwd,cwd);  
    strcat(tmpcwd,"/");  
    FILE *fp=getfp(strcat(tmpcwd,"config.ini"));  
    while(fgets(tmp,255,fp)!=NULL)  
    {  
        start=tmp;  
        equal=strchr(tmp,'=');  

        while(isblank(*start))  
            ++start;  
        fs=start;  

        if(*fs=='#')  
            continue;  
        while(isalpha(*start))  
            ++start;  
        fe=start-1;  

        strncpy(fore,fs,fe-fs+1);  
        fore[fe-fs+1]='\0';  
        if(strcmp(fore,name)!=0)  
            continue;  
        find=1;  

        start=equal+1;  
        while(isblank(*start))  
            ++start;  
        bs=start;  

        while(!isblank(*start)&&*start!='\n')  
            ++start;  
        be=start-1;  

        strncpy(back,bs,be-bs+1);  
        back[be-bs+1]='\0';  
        strcpy(info,back);  
        break;  
    }  
    if(find)  
        return info;  
    else  
        return NULL;  
}

3)POST与GET的区别

      

GET形式采纳的数额是有长度约束,而用
POST方式选择的多寡是还未长度限定的。并且,以 GET方式发送数据,能够透过 U奥德赛L的花样来发送,但 POST方式发送的数目一定要通过
Form才到发送。

CGI程序示例 mathcgi.h

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void mymath(char *arg)
 5 {
 6     //data1=1000&data2=2000
 7     char *argv[3];
 8     int i = 0;
 9     char *start = arg;
10     while(*start){
11         if(*start == '='){
12             start++;
13             argv[i++] = start;
14             continue;
15         }
16         if(*start== '&'){
17             *start = '\0';
18         }
19         start++;
20     }
21     argv[i] = NULL;
22     int data1 = atoi(argv[0]);
23     int data2 = atoi(argv[1]);
24     printf("<html><body><h1>");
25     printf("%d + %d = %d<br/>", data1, data2, data1 + data2);
26     printf("%d - %d = %d<br/>", data1, data2, data1 - data2);
27     printf("%d * %d = %d<br/>", data1, data2, data1 * data2);
28     printf("%d / %d = %d<br/>", data1, data2, data2==0? 0 : data1 / data2);
29     printf("%d %% %d = %d<br/>", data1, data2, data2==0? 0 : data1 % data2);
30     printf("</h1></body></html>");
31 }
32 
33 int main()
34 {
35     char *method = NULL;
36     char *query_string = NULL;
37     char *string_arg = NULL;
38     int content_len = -1;
39     char buf[1024];
40     if((method=getenv("METHOD"))){
41         if(strcasecmp(method, "GET") == 0){
42             if((query_string=getenv("QUERY_STRING"))){
43                 string_arg = query_string;
44             }
45         }else{
46             if(getenv("CONTENT_LENGTH")){
47                 content_len = atoi(getenv("CONTENT_LENGTH"));
48                 int i = 0;
49                 for(; i < content_len; i++){
50                     read(0, &buf[i], 1);
51                 }
52                 buf[i] = '\0';
53                 string_arg = buf;
54             }
55         }
56     }
57 
58     mymath(string_arg);
59     return 0;
60 }

 (2)HTML

本项目中只是选拔了部分为主的HTML知识,下边是简单的 index.html :

 1 <html>
 2     <head>hello http</head>
 3     <body>
 4         <h1>Hello My Web!</h1>
 5         <img src="imag/mgh.jpg" alt="default" width="100" height="100">
 6         <a href="cgi-bin/select_cgi">select</a>
 7         <!--<form action="/cgi-bin/math_cgi" method="POST">
 8         First data:<br>
 9         <input type="text" name="data1" value="0">
10         <br>
11         second data:<br>
12         <input type="text" name="data2" value="1">
13         <br><br>
14         <input type="submit" value="Submit">
15         </form>--!>
16     </body>
17 </html>

到此处就核心得以访谈网页音信了:

4、本机实行环回测验,用的IP是127.0.0.1,Http公约的TCP连接私下认可端口号为80:

澳门京葡网站 2

 图片本人筛选,此页面完结的是八个数的加减乘除,当点击submit时跳转页面如下:

澳门京葡网站 3

那儿跳转到cgi_bin目录下的可实行文件debug_cgi,显示加减乘除的结果。

二个简陋的http服务器就达成了。后边还索要有些其它的恢宏,再立异……

获取 Cookies

搜寻全部安装的 cookies 是特轻易的。cookies 被积攒在 CGI 情况变量
HTTP_CEOKIE 中,且它们的款型如下:

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

下边的实例演示了什么得到 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;
}

现今,编写翻译上边包车型大巴前后相继,生成
getcookies.cgi,并尝试利用上面包车型地铁链接获取你的微计算机上具备可用的 cookies:

/cgi-bin/getcookies.cgi

这会发出一个列表,展现了上生机勃勃节中设置的多个 cookies
以至你的微型机上具备别的的 cookies:

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

二.境况变量

      
对于CGI程序来讲,它继续了系统的情况变量。CGI景况变量在CGI程序运行时开首化,在告竣作时间销毁。

      
当贰个CGI程序不是被HTTP服务器调用时,它的碰着变量差不离是系统遭逢变量的复制。

当以此CGI程序被HTTP服务器调用时,它的蒙受变量就能够多了以下关于HTTP服务器、顾客端、CGI传输进度等门类。

 

与央浼相关的情况变量

REQUEST_METHOD

服务器与CGI程序之间的新闻传输情势

QUERY_STRING

动用GET时所传输的音信

CONTENT_LENGTH

STDIO中的有效消息长度

CONTENT_TYPE

指令所盛传的音讯的MIME类型

CONTENT_FILE

行使Windows HTTPd/WinCGI标定期,用来传送数据的文本名

PATH_INFO

渠道信息

PATH_TRANSLATED

CGI程序的完全路线名

SCRIPT_NAME

所调用的CGI程序的名字

与服务器相关的情状变量

GATEWAY_INTERFACE

服务器所完毕的CGI版本

SERVER_NAME

服务器的IP或名字

SERVER_PORT

长机的端口号

SERVER_SOFTWARE

调用CGI程序的HTTP服务器的名号和版本号

与客商端相关的情状变量

REMOTE_ADDR

客户机的主机名

REMOTE_HOST

客商机的IP地址

ACCEPT

例出能被次号召选取的答疑情势

ACCEPT_ENCODING

列出顾客机帮忙的编码方式

ACCEPT_LANGUAGE

标记顾客机可选择语言的ISO代码

AUTORIZATION

标记被注脚了的客户

FORM

列出顾客机的EMAIL地址

IF_MODIFIED_SINGCE

当用get情势倡议况且独有当文书档案比钦赐日期更早时才回去数据

PRAGMA

设定未来要用到的服务器代理

REFFERER

提议连接到当下文书档案的文书档案的UOdysseyL

USER_AGENT

顾客端浏览器的音讯

      
CONTENT_TYPE:如application/x-www-form-urlencoded,表示数据来源于HTML表单,並且通过了UENVISIONL编码。

ACCEPT:客商机所帮忙的MIME类型清单,内容如:”image/gif,image/jpeg”

      

 

 

REQUEST_METHOD:它的值常常富含三种:POST和GET,但我们写CGI程序时,最终还要思考别的的动静。

三、 测试

这次测量试验

利用了两台机器。一台Ubuntu的浏览器作为客户端,风流罗曼蒂克台Redhat作为劳动器端,个中Redhat是Ubuntu上依据VirtualBox的风度翩翩台设想机。

IP地址新闻如下:Ubuntu的vboxnet0:

<img src="http://jbcdn2.b0.upaiyun.com/2016/11/73d81eee84e5fe07de8e076ee6b5d25a.jpg" alt="澳门京葡网站 4" />

RedHateth0:

澳门京葡网站 5

RedHat主机编写翻译项目:

澳门京葡网站 6

鉴于我们同事监听了8000和4444,所以有八个经过运行。

HTTP的首页:

澳门京葡网站 7

目录突显效果:

澳门京葡网站 8

HTTP GET页面:

澳门京葡网站 9

HTTPGET响应:

澳门京葡网站 10

从HTTP GET响应中大家观望UPAJEROL,参数实乃经过U哈弗L传送过去的。

其中getAuth.c如下:

#include "wrap.h"  
#include "parse.h"  

int main(void) {  
    char *buf, *p;  
    char name[MAXLINE], passwd[MAXLINE],content[MAXLINE];  

    /* Extract the two arguments */  
    if ((buf = getenv("QUERY_STRING")) != NULL) {  
    p = strchr(buf, '&');  
    *p = '\0';  
    strcpy(name, buf);  
    strcpy(passwd, p+1);  
    }  

    /* Make the response body */  
    sprintf(content, "Welcome to auth.com:%s and %s\r\n<p>",name,passwd);  
    sprintf(content, "%s\r\n", content);  

    sprintf(content, "%sThanks for visiting!\r\n", content);  

    /* Generate the HTTP response */  
    printf("Content-length: %d\r\n", strlen(content));  
    printf("Content-type: text/html\r\n\r\n");  
    printf("%s", content);  
    fflush(stdout);  
    exit(0);  
}

HTTPS的首页:由于大家的CA不可信赖,所以需求大家认可

澳门京葡网站 11

认可后HTTPS首页:

澳门京葡网站 12

HTTPS POST页面:

澳门京葡网站 13

HTTPS POST响应:

澳门京葡网站 14

从上大家得以看见,POST提交的参数的确不是透过U帕杰罗L传送的。

3、相关本领解释:

(1)CGI:通用网关接口

  基本原理:通用网关接口是贰个Web服务器主机提供音讯服务的规范接口。通过CGI接口,Web服务器依据客户端提交的能源乞求音信,转交给服务器端对应的CGI程序开展管理,最终回来结果给客户端。简单的话便是HTTP服务器与顾客端进行“交谈”的风流倜傥种工具,其程序须运营在互联网服务器上。

  组成CGI通讯系统的是两部分:风流洒脱部分是html页面,正是在顾客端浏览器上海展览中心示的页面。另风度翩翩有的则是运作在服务器上的Cgi程序。绝大好多的CGI程序被用来分解管理来自表单的输入消息,并在服务器发生相应的管理,或将相应的消息陈说给浏览器。CGI程序使网页具有人机联作功能。

  CGI在客商端与服务器通信中的管理步骤:

  1)通过Internet把客商恳求送到服务器;

  2)服务器收到顾客乞请并提交相应CGI程序管理;

  3)CGI程序把管理结果传送给服务器;

  4)服务器把结果重返给客商。

  前边早就介绍过服务器和客商端之间的通讯,实际上是客户端的浏览器和服务器端的http服务器之间的HTTP通讯,大家只须要精晓浏览器诉求施行服务器上哪些CGI程序就足以了,别的不必深究细节,因为那个进度无需程序员去操作。服务器和CGI程序之间的简报才是大家关切的。日常景色下,服务器和CGI程序之间是通过标准输入输出来拓宽多少传递的,而以此历程需求碰到变量的搭档方可完结。在劳动器端实行步骤:1)服务器将UHavalL指向贰个应用程序 
2)服务器为应用程序施行做筹算  3)应用程序施行,读取标准输入和关于情形变量 
4)应用程序进行标准输出。

(2)CGI关于意况变量

对此CGI程序来讲,它继续了系统的景况变量。CGI遭遇变量在CGI程序运维时开端化,在甘休时销毁。

       当三个CGI程序不是被HTTP服务器调用时,它的意况变量差异常少是系统意况变量的复制。

当那几个CGI程序被HTTP服务器调用时,它的情形变量就能够多了以下关于HTTP服务器、客商端、CGI传输进程等体系。

澳门京葡网站 15

CONTENT_TYPE:如application/x-www-form-urlencoded,表示数据来源于HTML表单,何况经过了U智跑L编码。

ACCEPT:客商机所支持的MIME类型清单,内容如:”image/gif,image/jpeg”

REQUEST_METHOD:本项目事关经常见到的二种艺术:POST和GET,但大家写CGI程序时,最后还要思量别的的事态。

  情状变量是二个保留顾客消息的内部存储器区。当顾客端的客户通过浏览器发出CGI乞求时,服务器就查究本地的对应CGI程序并试行它。在实施CGI程序的同临时间,服务器把该客户的消息保存到处境变量里。接下来,CGI程序的实施流程是那样的:查询与该CGI程序进度相应的情形变量:第一步是request_method,假若是POST,就从景况变量的len,然后到该进程相应的正规输入抽出len长的多少。要是是GET,则客户数量就在情形变量的QUE奥德赛Y_STRING里。

 (3)POST/GET传输方式详细解释

向 CGI 程序传递单选按键数据

当只必要选用三个增选时,我们选拔单选按键。

下边包车型大巴 HTML 代码实例是二个饱含四个单选开关的表单:

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

下边包车型地铁 C++ 程序会生成 cpp_radiobutton.cgi 脚本,用于拍卖 Web
浏览器通过单选开关给出的输入。

#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;
}

3.POST与GET的区别

       以 GET 方式接收的数目是有长度节制,而用 POST
方式收受的数码是绝非长度节制的。并且,以 GET 情势发送数据,能够经过 ULANDL
的情势来发送,但 POST形式发送的多寡必须求因此 Form 才到发送。

豆蔻梢头、 实现效果与利益:

1.支持GET/POST方法

2.支撑SSL安全连接即HTTPS

3.支持CGI

4.基于IP地址和掩码的表达

5.目录呈现

6.日记作用

7.不当提醒页面

github地址:

源代码下载地址:点击张开链接

1、项目介绍

  HTTP合计是应用层的面向对象的情商,由于其简捷、快捷的法子,适用于分布式超媒体音讯种类。公约的详尽内容,前不熟悉机勃勃篇HTTP公约详整业已详细介绍了,这里不再赘述。

   项目完全描述:HTTP辅助客商端/服务器格局,终端顾客可透过浏览器或互连网爬虫与服务器创设连接,所以率先须要自己作主完毕服务器Server端,具体由头文件httpd.h、main函数文件httpd.c、模块功效函数文件httpd.c组成,重要完成客商端与服务器通过socket创建通讯机制。首先由顾客积极发起五个到服务器上内定端口(暗中同意端口为80)的央求,服务器则在老大端口监听客商端发送过来的伸手。服务器意气风发行生机勃勃行读取必要,通过诉求新闻决断顾客恳求财富的法子和门路,若方法和路线没不符合规律,则方法和路径通过CGI格局或非CGI向客商提供分歧的HTML网页音讯。管理完要求客户端向顾客发送响应,满含气象行如:“HTTP/1.1
200 OK”、响应报头、音信正文,消息体即为服务器上的财富。

贯彻效果与利益风流倜傥:静态首页展现(图片、文字文字新闻);

落到实处二:援助表单提交,能够凭仗浏览器或telnet工具使用GET、POST方法访问服务器,完结多少的轻松总括功用;

完毕三:引进MYSQL,顾客可透过页面表单实行多少操作,服务器获得顾客提交的数量后,会把数量存入到远端数据库,客商端也可伸手查看数据库音讯。

后生可畏体项指标文件目录:

澳门京葡网站 16

目录:
conf:配置文件,寄存供给绑定的服务器的ip和port ;
log:shell的日记文件以致http错误处理的日志文件 ;
sql_client:mysql部分的API及CGI实现;
thread_pool:线程池完成;
wwwroot:web服务器职业的根目录,包罗种种资源页面(举例私下认可的index.html页面,差错管理的404页面),以致实践cgi的可执路程序。上面还应该有多个 cgi-bin目录,是存放CGI脚本的地点。这几个本子使WWW服务器和浏览器能运作外界程序,而不须求运维另叁个顺序。它是运作在Web服务器上的八个前后相继,并由来自于浏览者的输入触发。

全体项目标框架图:

 澳门京葡网站 17

文件上传实例

为了上传贰个文书,HTML 表单必得把 enctype 属性设置为
multipart/form-data。带有文件类型的 input 标签会创设二个 “Browse” 按键。

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

这段代码的结果是上边的表单:
文件:选用文件
上传

留心:上面的实例已经故意禁止使用了保留上传的文书在大家的服务器上。您可以在融洽的服务器上尝试上边的代码。

下边是用以拍卖公事上传的本子 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;
}

地方的实例是在 cout
流中写入内容,但你能够展开文件流,并把上传的文书内容保留在对象地方的有个别文件中。

代码链接:https://github.com/karst87/cpp/tree/master/learning/com.runoob

2.GET方法

在该方法下,CGI程序不可能直接从服务器的正经输入中获取数据,因为服务器把它从标

准输入接受到得数据编码到条件变量QUEEnclaveY_STRING(或PATH_INFO)。

GET与POST的差异:选择GET方法提交HTML表单数据的时候,客商机将把那些数

据附加到由ACTION标志命名的UCRUISERL的末段,用多少个包含把通过USportageL编码后的音信与CGI程序的名字分别:?name=hgq$id=1,QUERY_STRING的值为name=hgq&id=1

有一些程序猿不情愿利用GET方法,因为在他们看来,把动态新闻附加在U智跑L的末段有

违U宝马7系L的出发点:U景逸SUVL作为生龙活虎种标准用语,日常是用作网络能源的独一定位标示。

 

碰着变量是叁个封存用户消息的内部存款和储蓄器区。当顾客端的客商通过浏览器发出CGI诉求时,服务器就搜索本地的相应CGI程序并实行它。在执行CGI程序的同一时间,服务器把该顾客的新闻保存到碰到变量里。接下来,CGI程序的实行流程是这么的:查询与该CGI程序进程相应的景况变量:第一步是request_method,假使是POST,就从情形变量的len,然后到该进程相应的专门的学问输入抽取len长的数码。即便是GET,则顾客数量就在处境变量的QUETiggoY_STRING里。

2、各模块成效介绍

头文件httpd.h,包涵该类型代码所接收的全套函数的头文件以致宏定义,和函数注脚;

 1 #ifndef _HTTPD_
 2 #define _HTTPD_
 3 
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6 #include <sys/socket.h>
 7 #include <sys/types.h>
 8 #include <netinet/in.h>
 9 #include <arpa/inet.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16 
17 #define SUCCESS 0 
18 #define NOTICE  1
19 #define WARNING 2
20 #define ERROR   3
21 #define FATAL   4
22 
23 #define SIZE 1024
24 
25 void print_log(char *msg, int level); //打印日志
26 int startup(const char *ip, int  port); //创建监听套接字
27 void *handler_request(void *arg);  //处理请求
28 
29 #endif

main函数文件main.c完成入眼通讯逻辑,通过socket建设构造连接的,监听和选用套接字,然后创造新线程管理诉求。

 1 #include <pthread.h>
 2 #include "httpd.h"
 3 
 4 static void usage(const char *proc)
 5 {
 6     printf("Usage: %s [local_ip] [local_port]\n", proc);
 7 }
 8 
 9 int main(int argc, char *argv[])
10 {
11     if(argc != 3){
12         usage(argv[0]);
13         return 1;
14     }
15 
16     int listen_sock = startup(argv[1], atoi(argv[2]));//监听套接字
17     //daemon(0, 0);
18     while(1){
19         struct sockaddr_in client;
20         socklen_t len = sizeof(client);
21         int new_sock = accept(listen_sock, (struct sockaddr*)&client, &len);//接收套接字
22         if(new_sock < 0){
23             print_log(strerror(errno), NOTICE);
24             continue;
25         }
26 
27         printf("get client [%s:%d]\n",\
28                 inet_ntoa(client.sin_addr),\
29                 ntohs(client.sin_port)); //链接到一个客户端之后打印其IP及端口号
30 
31         pthread_t id;
32         int ret = pthread_create(&id, NULL,\ //创建新线程
33                 handler_request, (void *)new_sock);
34         if(ret != 0){
35             print_log(strerror(errno), WARNING);
36             close(new_sock);
37         }else{
38             pthread_detach(id); //将子线程分离,该线程结束后会自动释放所有资源
39         }
40     }
41     close(listen_sock);
42     return 0;
43 }

模块效能函数在httpd.c文件

  1 #include "httpd.h"
  2 
  3 void print_log(char *msg, int level)
  4 {
  5 #ifdef _STDOUT_
  6     const char * const level_msg[]={
  7         "SUCCESS",
  8         "NOTICE",
  9         "WARNING",
 10         "ERROR",
 11         "FATAL",
 12     };
 13     printf("[%s][%s]\n", msg, level_msg[level%5]);
 14 #endif
 15 }
 16 
 17 int startup(const char *ip, int  port)  //
 18 {
 19     int sock = socket(AF_INET, SOCK_STREAM, 0);  //创建套接字
 20     if(sock < 0){
 21         print_log(strerror(errno), FATAL); //strerror()将错误码转换为对应的错误码描述
 22         exit(2);
 23     }
 24 
 25     int opt = 1;
 26     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  //将该套接字设置为地址复用状态,若服务器挂掉可实现立即重启
 27 
 28     struct sockaddr_in local;
 29     local.sin_family = AF_INET;
 30     local.sin_port = htons(port);  //端口号转换
 31     local.sin_addr.s_addr = inet_addr(ip);  //ip转换
 32     if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){  //绑定
 33         print_log(strerror(errno), FATAL);
 34         exit(3);
 35     }
 36     if(listen(sock, 10) < 0){  //监听
 37         print_log(strerror(errno), FATAL);
 38         exit(4);
 39     }
 40     return sock;
 41 }
 42 
 43 //ret > 1, line != '\0'读成功,正常字符; ret=1&line='\n'  ret<=0&&line=='\0'
 44 static int get_line(int sock, char line[], int size)  //得到一行请求内容
 45 {
 46     // read 1 char , one by one
 47     char c = '\0'; 
 48     int len = 0;
 49     while( c != '\n' && len < size-1){  
 50         int r = recv(sock, &c, 1, 0);  
 51         if(r > 0){                      
 52            if(c == '\r'){
 53                //窥探,只把缓冲区的东西拿出来看看
 54                int ret = recv(sock, &c, 1, MSG_PEEK);
 55                if(ret > 0){
 56                    if(c == '\n'){
 57                        recv(sock, &c, 1, 0);
 58                    }else{
 59                        c = '\n'; 
 60                    }
 61                }
 62            }// \r->\n \r\n -> \n
 63            line[len++] = c;
 64         }else{
 65             c = '\n';
 66         }
 67     }
 68     line[len]='\0';
 69     return len;
 70 }
 71 //不同平台下\n、\r、\n+\r,意义不同,这里将其统一成\n
 72 
 73 static void echo_string(int sock)
 74 {}
 75 
 76 static int echo_www(int sock, char *path, int size)
 77 {
 78     int fd = open(path, O_RDONLY);
 79     if(fd < 0){
 80         echo_string(sock);
 81         print_log(strerror(errno), FATAL);
 82         return 8;
 83     }
 84 
 85     const char *echo_line="HTTP/1.0 200 OK\r\n";   //状态行
 86     send(sock, echo_line, strlen(echo_line), 0);
 87     const char *null_line="\r\n";
 88     send(sock, null_line, strlen(null_line), 0); //空行
 89 
 90     if(sendfile(sock, fd, NULL, size) < 0){//在内核区实现两个文件描述符的拷贝,不用定义临时变量,省略两次数据拷贝,效率提高
 91         echo_string(sock);
 92         print_log(strerror(errno), FATAL);
 93         return 9;
 94     }
 95 
 96     close(fd);
 97     return 0;
 98 }
 99 
100 static void drop_header(int sock)
101 {
102     char line[1024];
103     int ret = -1;
104     do{
105         ret = get_line(sock, line, sizeof(line));
106     }while(ret>0 && strcmp(line, "\n"));
107 }
108 
109 static int exe_cgi(int sock, char *method, \
110         char *path, char *query_string)
111 {
112     int content_len = -1;
113     char method_env[SIZE/10];
114     char query_string_env[SIZE];
115     char content_len_env[SIZE/10];
116 
117     if( strcasecmp(method, "GET") == 0 ){//忽略大小写的字符比较,此处为判断请求资源的方法是否为GET方法
118         drop_header(sock);//如果是GET方法则已从URL中知道用户请求资源所传参数
119     }else{//POST
120         char line[1024];
121         int ret = -1;
122         do{
123             ret = get_line(sock, line, sizeof(line));
124             if(ret > 0 &&\
125                strncasecmp(line,"Content-Length: ", 16)== 0){
126                 content_len = atoi(&line[16]);//消息正文字长描述
127             }
128         }while(ret>0 && strcmp(line, "\n"));
129         if(content_len == -1){
130             echo_string(sock);
131             return 10;
132         }
133     }
134     const char *echo_line="HTTP/1.0 200 OK\r\n";  //状态行
135     send(sock, echo_line, strlen(echo_line), 0);  
136     const char *type="Content-Type:text/html;charset=ISO-8859-1\r\n";
137     send(sock, type, strlen(type), 0);
138     const char *null_line="\r\n";  
139     send(sock, null_line, strlen(null_line), 0);  //空行
140 
141     printf("query_string: %s\n", query_string);
142     //path-> exe
143     int input[2];
144     int output[2];
145     if(pipe(input) < 0 || pipe(output) < 0){
146         echo_string(sock);
147         return 11;
148     }
149     pid_t id = fork();
150     if(id < 0){
151         echo_string(sock);
152         return 12;
153     }else if(id == 0){//child
154         close(input[1]);
155         close(output[0]);
156         sprintf(method_env, "METHOD=%s", method);
157         putenv(method_env);
158 
159         if(strcasecmp(method, "GET") == 0){
160             sprintf(query_string_env, "QUERY_STRING=%s", query_string);
161             putenv(query_string_env);
162         }else{ // POST
163             sprintf(content_len_env, "CONTENT_LENGTH=%d", content_len);
164             putenv(content_len_env);
165         }
166         dup2(input[0], 0);//重定向
167         dup2(output[1], 1);
168         execl(path, path, NULL);  //第一个参数:路径及名字,第二个参数:怎么执行,传什么参数
169         printf("execl error!\n");
170         exit(1);
171     }else{
172         close(input[0]);
173         close(output[1]);
174 
175         int i = 0;
176         char c = '\0';
177         if(strcasecmp(method, "POST") == 0){
178             for( ; i < content_len; i++ ){
179                 recv(sock, &c, 1, 0);
180                 write(input[1], &c, 1);
181             }
182         }
183 
184         c='\0';
185         while(read(output[0], &c, 1) > 0){
186             send(sock, &c, 1, 0);
187         }
188 
189         waitpid(id, NULL, 0);
190         close(input[1]);
191         close(output[0]);
192     }
193 }
194 
195 //thread 
196 void *handler_request(void *arg) 
197 {
198     int sock = (int)arg;
199 #ifdef _DEBUG_  //测试代码
200     char line[1024];  
201     do{
202         int ret = get_line(sock, line, sizeof(line));
203         if(ret > 0){
204             printf("%s", line);
205         }else{
206             printf("request ...... done!\n");
207             break;
208         }
209     }while(1);
210 #else
211     int ret = 0;
212     char buf[SIZE];  //读到的请求内容
213     char method[SIZE/10];  //请求资源的方法
214     char url[SIZE];  //统一资源标识符
215     char path[SIZE];  //有效资源路径
216     int i, j;
217     int cgi = 0; //设置CGI模式
218     char *query_string = NULL;  //请求资源字符串(URL中问号后的内容)
219     if(get_line(sock, buf, sizeof(buf)) <= 0){ //获得一行请求内容
220         echo_string(sock);
221         ret = 5;
222         goto end;
223     }
224     i=0;//method ->index
225     j=0;//buf -> index
226 
227     while( !isspace(buf[j]) &&\
228             j < sizeof(buf) &&\
229             i < sizeof(method)-1){
230         method[i]=buf[j];
231         i++, j++;
232     }
233     method[i] = 0;
234     if(strcasecmp(method, "GET") &&\  //忽略大小写的字符比较,此处为判断请求资源的方法是否为GET方法或POST方法
235             strcasecmp(method, "POST") ){
236         echo_string(sock);
237         ret = 6;
238         goto end;
239     }
240     if(strcasecmp(method, "POST") == 0){  //如果使用POST方法必定是CGI模式
241         cgi = 1;
242     }
243     //buf -> "GET          /      http/1.0"
244     while(isspace(buf[j]) && j < sizeof(buf)){
245         j++;
246     }
247     i=0;
248     while(!isspace(buf[j]) && j < sizeof(buf) && i < sizeof(url)-1){
249         url[i] = buf[j];
250         i++, j++;
251     }
252     url[i] = 0;
253     printf("method: %s, url: %s\n", method, url);
254     query_string = url;
255     while(*query_string != '\0'){
256         if(*query_string == '?'){//如果是GET方法且传参,必定是CGI模式
257             *query_string = '\0';
258             query_string++;
259             cgi = 1;
260             break;
261         }
262         query_string++;
263     }
264     sprintf(path, "wwwroot%s", url);
265     //method, url, query_string, cgi
266     if(path[strlen(path)-1] == '/'){ // '/'
267         strcat(path, "index.html");//如果是GET方法且无参,拼接上首页信息
268     }
269     struct stat st;
270     if(stat(path, &st) != 0){
271         echo_string(sock);
272         ret = 7;
273         goto end;
274     }else{
275         if(S_ISDIR(st.st_mode)){  //如果是目录,则拼接上首页信息,默认任何目录下都可以访问首页
276             strcat(path, "/index.html");
277         }else if( (st.st_mode & S_IXUSR) || \  //如果是二进制文件
278                   (st.st_mode & S_IXGRP) || \
279                   (st.st_mode & S_IXOTH) ){
280             cgi=1;
281         }else{
282         }
283         //ok->cgi=?, path, query_string, method
284         if(cgi){
285             printf("enter CGI\n");  //进入CGI模式处理
286             exe_cgi(sock, method, path, query_string);
287         }else{//非CGI处理
288             printf("method: %s, url: %s, path: %s, cgi: %d, query_string: %s\n", method, url, path, cgi, query_string);
289             drop_header(sock); //!!!!!!!!!!!!!!清除信息(不关心的内容)
290             echo_www(sock, path, st.st_size);//非CGI模式时的响应
291         }
292     }
293 
294 end:
295     printf("quit client...\n");  //出错退出
296     close(sock);
297     return (void*)ret;
298 #endif
299 }

CGI 情状变量

不无的 CGI 程序都能够访谈下列的景况变量。这几个变量在编写 CGI
程序时扮演了非常重大的剧中人物。

变量名 描述
CONTENT_TYPE

剧情的数据类型。当客商端向服务器发送附加内容时选取。例如,文件上传等效用。
CONTENT_LENGTH | 查询的音讯长度。只对 POST 央求可用。
HTTP_CEOKIE | 以键 & 值对的款式重回设置的 cookies。
HTTP_USER_AGENT |
顾客代理诉求标头字段,递交客户发起号召的有关消息,富含了浏览器的称呼、版本和任何平台性的增大新闻。
PATH_INFO | CGI 脚本的门径。
QUERY_ST奥德赛ING | 通过 GET 方法发送央求时的 UHighlanderL 编码新闻,包含 U奥迪Q5L
中问号后边的参数。
REMOTE_ADDOdyssey | 发出乞请的长途主机的 IP
地址。那在日记记录和表明时是那一个有效的。
REMOTE_HOST | 发出必要的主机的一心节制名称。倘使此消息不可用,则能够用
REMOTE_ADDR来获取 IP 地址。
REQUEST_METHOD | 用于发出央浼的章程。最遍布的措施是 GET 和 POST。
SCRIPT_FILENAME | CGI 脚本的完好路线。
SCRIPT_NAME | CGI 脚本的名目。
SERVER_NAME | 服务器的主机名或 IP 地址。
SERVER_SOFTWARE | 服务器上运维的软件的名目和本子。

上面包车型大巴 CGI 程系列出了具有的 CGI 变量。

#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;
}

三.CGI程序完毕步骤

1)POST方法

  纵然运用POST方法,那么客商端发送的客户数据将存放在CGI进度的科公输盘入中,即音讯正文内,较为隐讳,且经常未有上限。相同的时候将顾客数据的长度授予情状变量中的CONTENT_LENGTH。顾客端用POST格局发送数据有四个八方呼应的MIME类型(通用Internet邮件增添服务:Multi-purpose Internet Mail Extensions)。最近,MIME类型常常是:application/x-wwww-form-urlencoded,该品种表示数据来自HTML表单。该类型记录在条件变量CONTENT_TYPE中,CGI程序应该检查该变量的值。

向 CGI 程序传递复选框数据

当须求选用五个选用时,大家选用复选框。

下边包车型大巴 HTML 代码实例是三个含有八个复选框的表单:

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

上面包车型地铁 C++ 程序会生成 cpp_checkbox.cgi 脚本,用于拍卖 Web
浏览器通过复选框给出的输入。

#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;
}

1.从服务器获取数据

C语言实今世码:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

int get_inputs()

{

int length;

char *method;

char *inputstring;

 

method = getenv(“REQUEST_METHOD”); //将返回结果赋予指针

if(method == NULL)

    return 1;       //找不到环境变量REQUEST_METHOD

if(!strcmp(method, ”POST”))  // POST方法

{

    length = atoi(getenv(“CONTENT_LENGTH”)); //结果是字符,需要转换

    if(length != 0)

    {

        inputstring = malloc(sizeof(char)*length + 1) //必须申请缓存,因为stdin是不带缓存的。

        fread(inputstring, sizeof(char), length, stdin); //从标准输入读取一定数据

}

}

else if(!strcmp(method, “GET”))

{

    Inputstring = getenv(“QUERY_STRING”);   

    length = strlen(inputstring);

}

if(length == 0)

return 0;

}

Perl实今世码:

$method = $ENV{‘REQUEST_METHOD’};

if($method eq ‘POST’)

{

    Read(STDIN, $input, $ENV{‘CONTENT_LENGTH’});

}

if($method eq ‘GET’ || $method eq ‘HEAD’)

{

    $input = $ENV{‘QUERY_STRING’};

}

if($input eq “”)

{

&print_form;

exit;

}

       PYTHON代码完成

#!/usr/local/bin/python

import cgi

def main():

form = cgi.FieldStorage()

 

Python代码实现更简单,cgi.FieldStorage()返回一个字典,字典的每一个key就是变量名,key对应的值就是变量名的值,更本无需用户再去进行数据解码!

 

      
获取意况变量的时候,如果先推断“REQUEST_METHOD”是还是不是留存,程序会更健康,否则在某个景况下大概会产生程序崩溃。因为若是CGI程序不是由服务器调用的,那么碰着变量集里就从未与CGI相关的景况变量(如REQUEST_METHOD,REMOTE_ADDPAJERO等)加多进去,也正是说“getenv(“REQUEST_METHOD”)”将返回NULL!