本帖最后由 席萌0209 于 2018-1-12 15:36 编辑
47.2 CGI函数 CGI脚本涉及到以下5个函数: (1)cgi_func (2)cgi_process_data (3)cgi_process_var (4)http_accept_host (5)cgx_content_type 关于这5个函数的讲解及其使用方法可以看教程第 3 章 3.4 小节里面说的参考资料 rlarm.chm 文件: 本章节除了讲解以上5个函数外,还需要讲解下面这个函数:http_get_var (这个函数在HTTP函数部分) 关于这些函数注意以下两点: 1、CGI的所有函数都不支持重入,也就是不支持多任务调用。 2、通过CGI脚本就可以实现动态HTML网页了。
47.2.1 函数cgi_func函数原型: - U16 cgi_func (
- U8* env, /* 输入字符串地址 */
- U8* buf, /* 输出缓冲区地址 */
- U16 buflen, /* 输出缓冲区大小,单位字节*/
- U32* pcgi ); /* 指针变量,指向一个不会被改变的变量 */
复制代码函数描述: 函数cgi_func由RL-TCPnet脚本解析器调用,当解析RL-TCPnet的脚本时(以cgi结尾的脚本文件),输出HTTP响应的动态部分。脚本文件每个以命令c开头的语句,脚本解析器都会调用函数cgi_func。所以用户必须要编写此函数,以便解析和使用脚本文件中的输入字符。 1、第1个参数是CGI脚本的输入字符串地址,函数cgi_func需要这个参数创建动态响应。这个字符串就是CGI脚本文件中以命令c开头的语句中的字符串,字节数是相同的(不含控制字符,仅HTTP代码部分)。 2、第2个参数是输出缓冲区地址,用于写入HTTP响应字符串。 3、第3个参数是输出缓冲区大小,单位字节。 4、第4个参数是指向不会被HTTP服务器更改的变量,因此,用户可以用它存储函数cgi_func连续调用的参数,比如循环计数器、发送字节数、状态缓冲区地址等,亦或者任何其它应用均可。 5、返回值,返回写入到输出缓冲区的字节数。返回值是U16类型的,其中bit15和bit14还可以作为其它用途,而剩余的bit0-bit13表示的最大值是16383,足够表示TCP Socket的MSS最大报文段大小的1460字节。 (1)bit15作为函数cgi_func是否重复调用的标志,如果此位设置为1,表示退出函数后,依然保持参数env, buflen和 pcgi的数值,并再次调用函数cgi_func,而参数buf会根据用户写入到输出缓冲区的字节数进行自动调整。如果此位设置为0,将不再重复调用。 (2)如果bit14设置为1,取消数据包优化(见下面注意事项4),当前数据包立即被发送。如果bit14为0,不执行此操作。 使用这个函数要注意以下问题: 1. 写入到输出缓冲区的代码必须是HTML格式。 2. CGI脚本中的c命令才会触发此函数。 3. 输出缓冲区的大小buflen会有所不同,因为输出缓冲区的大小是由TCP Socket的MSS最大报文段大小协商决定,局域网中一般是1400字节左右,但是也可减小到500字节,甚至更小。 4. 输出缓冲区的不同大小还有一个原因是HTTP Server会尝试优化生成的TCP数据包数,并将再次调用函数cgi_func来使用所有可用的缓冲区。当缓冲区中只有240个或更少的字节空闲时,将停止调用函数cgi_func,然后生成并发送数据包。如果要强制HTTP Server发送数据包,则此函数的返回值bit14置1。 5. 写到输出缓冲区的数据,不可以超过第三个参数buflen的大小,否则会造成内存指针链表的损坏,从而很容易造成系统崩溃。 6. 第1个参数的输入字符串可能包含单字符子命令,以此来告诉cgi_func如何正确的处理脚本。这些子命令没有规则,因此用户可以创建和使用自己的命令。 7. 对于每个HTTP会话,*pcgi(注意,这里是指的指针变量pcgi所指向的存储单元)变量都是独立的,也就是说新创建一个会话,都会有一个独立的*pvar变量。另外,每个会话首次调用函数cgi_func之前都会将变量*pcgi清零(注意,这里是指的指针变量pvar所指向的存储单元清零)。 8. 每次调用函数cgi_func必须更新*pcgi(注意,这里是指的指针变量pcgi所指向的存储单元)的内容,用户可以使用这个4字节变量存储任何格式的数据(官方手册中说的是必须更新,实际上,用不上的话,不用管)。 使用举例: - U16 cgi_func (U8 *env, U8 *buf, U16 buflen, U32 *pcgi) {
- U16 len = 0;
-
- switch (env[0]) {
- /* Analyze the environment string. It is the script 'c' line starting */
- /* at position 2. What you write to the script file is returned here. */
- case 'a' :
- /* Network parameters - file 'network.cgi' */
- ..
- break;
-
- case 'b':
- /* LED control - file 'led.cgi' */
- ..
- break;
-
- case 'c':
- /* TCP status - file 'tcp.cgi' */
- ..
- break;
-
- case 'd':
- /* System password - file 'system.cgi' */
- switch (env[2]) {
- case '1':
- len = sprintf(buf,&env[4],http_EnAuth ? "Enabled" : "Disabled");
- break;
- case '2':
- len = sprintf(buf,&env[4],http_auth_passw);
- break;
- }
- break;
- }
- return (len);
- }
复制代码
47.2.2 函数cgi_process_data函数原型: - void cgi_process_data (
- U8 code, /* 接收数据缓冲区中的数据类型 */
- U8* dat, /* 来自POST方式的字符串地址 */
- U16 len ); /* 字符串的字节数 */
复制代码函数描述: 函数cgi_process_data处理CGI POST方式返回的数据。当用户使用Web浏览器操作POST方式的HTTP表时(如单选按钮、复选框、选择列表等),HTTP服务器会调用此函数。 1、函数cgi_process_data的三个参数与下表的对应关系: “代码”对应第1个参数code。 “dat指针变量含义”对应第2个参数dat。 “变量len的含义”对应第3个参数len。 使用这个函数要注意以下问题: 1. 仅POST方式才会触发HTTP服务器调用此函数,即METHOD = POST。 - <FORM ACTION=index.htm METHOD=POST NAME=CGI>
- ..
- </FORM>
复制代码2. Web浏览器提供HTTP上传文件的文件名及其路径,而删除文件名中的路径信息是用户的责任。 3. 对于大文件,文件数据将分多次数据包进行接收。数据包的大小取决于TCP的MSS最大报文段大小,一般是1460字节。 4. XML-POST是由webservice application生成的,例如微软的Silverlight。 使用举例: - void cgi_process_data (U8 code, U8 *dat, U16 len) {
- /* This function is called by HTTP server to process the returned Data */
- /* for the CGI Form POST method. It is called on SUBMIT from the browser. */
- /* Parameters: */
- /* code - callback context code */
- /* 0 = www-url-encoded form data */
- /* 1 = filename for file upload (0-terminated string) */
- /* 2 = file upload raw data */
- /* 3 = end of file upload (file close requested) */
- /* 4 = any xml encoded POST data (single or last stream) */
- /* 5 = the same as 4, but with more xml data to follow */
- /* Use http_get_content_type() to check the content type */
- /* dat - pointer to POST received data */
- /* len - received data length */
- U8 *var;
-
- switch (code) {
- case 0:
- /* Url encoded form data received. */
- break;
-
- case 1:
- /* Filename for file upload received as encoded by the browser. */
- /* It might contain an absolute path to a file from the sending */
- /* host. Open a file for writing. */
- return;
-
- case 2:
- /* File content data received. Write data to a file. */
- /* This function will be called several times with */
- /* code 2 when a big file is being uploaded. */
- return;
-
- case 3:
- /* File upload finished. Close a file. */
- return;
-
- case 4:
- /* XML encoded content type, last packet. */
- // pType = http_get_content_type ();
- /* check the content type for CGX file request. */
- /* pType is a pointer to a 0-terminated string */
- /* For example: text/xml; charset=utf-8 */
- return;
-
- case 5:
- /* XML encoded as under 4, but with more to follow. */
- return;
-
- default:
- /* Ignore all other codes. */
- return;
- }
-
- if (len == 0) {
- /* No data or all items (radio, checkbox) are off. */
- return;
- }
-
- var = (U8 *)alloc_mem (40);
-
- do {
- /* Parse all returned parameters. */
- dat = http_get_var (dat, var, 40);
- if (var[0] != 0) {
- if (str_scomp (var, "TICK1=") == __TRUE || str_scomp (var, "pg=") == __TRUE)
- {
- if (str_scomp (var, "pg=") == __TRUE)
- {
- LEDControl = 0;
- }
-
- if(*(var+9) =='1')
- {
- LEDControl |= 0x01;
- }
- else if(*(var+9) =='2')
- {
- LEDControl |= 0x02;
- }
- else if(*(var+9) =='3')
- {
- LEDControl |= 0x04;
- }
- }
- }
- }while (dat);
- free_mem ((OS_FRAME *)var);
-
-
- if(LEDControl & 0x01)
- {
- bsp_LedOn(1);
- }
- else
- {
- bsp_LedOff(1);
- }
-
- if(LEDControl & 0x02)
- {
- bsp_LedOn(2);
- }
- else
- {
- bsp_LedOff(2);
- }
-
- if(LEDControl & 0x04)
- {
- bsp_LedOn(3);
- }
- else
- {
- bsp_LedOff(3);
- }
-
- }
复制代码
47.2.3 函数cgi_process_var函数原型: - void cgi_process_var (
- U8* qs ); /* Pointer to QUERY_STRING returned from the GET method. */
复制代码函数描述: 函数cgi_process_var处理从CGI GET方式返回的环境变量QUERY_STRING(就是个字符串),当用户使用Web浏览器操作GET方式的HTTP表单时(如单选按钮、复选框、选择列表等),HTTP服务器会调用此函数。 1、第1个参数是环境变量QUERY_STRING的地址,实际就是个字符串地址。 使用这个函数要注意以下问题: 1. 环境变量QUERY_STRING以空格结尾,即此字符串以空格结尾。 2. 仅GET方式才会触发HTTP服务器调用此函数,即METHOD = GET。 - <FORM ACTION=index.htm METHOD=GET NAME=CGI>
- ..
- </FORM>
复制代码使用举例: - void cgi_process_var (U8 *qs) {
- /* This function is called by HTTP server to process the Querry_String */
- /* for the CGI Form GET method. It is called on SUBMIT from the browser. */
- /*.The Querry_String.is SPACE terminated. */
- U8 *var;
- int s[4];
-
- var = (U8 *)alloc_mem (40);
- do {
- /* Loop through all the parameters. */
- qs = http_get_var (qs, var, 40);
- /* Check the returned string, 'qs' now points to the next. */
- if (var[0] != 0) {
- /* Returned string is non 0-length. */
- if (str_scomp (var, "ip=") == __TRUE) {
- /* My IP address parameter. */
- sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.IpAdr[0] = s[0];
- LocM.IpAdr[1] = s[1];
- LocM.IpAdr[2] = s[2];
- LocM.IpAdr[3] = s[3];
- }
- else if (str_scomp (var, "msk=") == __TRUE) {
- /* Net mask parameter. */
- sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.NetMask[0] = s[0];
- LocM.NetMask[1] = s[1];
- LocM.NetMask[2] = s[2];
- LocM.NetMask[3] = s[3];
- }
- else if (str_scomp (var, "gw=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.DefGW[0] = s[0];
- LocM.DefGW[1] = s[1];
- LocM.DefGW[2] = s[2];
- LocM.DefGW[3] = s[3];
- }
- else if (str_scomp (var, "pdns=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.PriDNS[0] = s[0];
- LocM.PriDNS[1] = s[1];
- LocM.PriDNS[2] = s[2];
- LocM.PriDNS[3] = s[3];
- }
- else if (str_scomp (var, "sdns=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.SecDNS[0] = s[0];
- LocM.SecDNS[1] = s[1];
- LocM.SecDNS[2] = s[2];
- LocM.SecDNS[3] = s[3];
- }
- }
- }while (qs);
- free_mem ((OS_FRAME *)var);
- }
复制代码
47.2.4 函数http_accept_host函数原型: - BOOL http_accept_host (
- U8* rem_ip, /* 远程设备IP地址 */
- U16 rem_port ); /* 远程设备端口号 */
复制代码函数描述: 函数http_accept_host用于设置是否接受远程连接,用户可以通过此函数选择允许哪些设备可以连接,哪些不可以连接。 1、第1个参数是远程设备的IP地址。 2、第2个参数是远程设备的端口号。 3、返回值,返回__TRUE表示允许此远程连接,返回__FALSE表示不允许此远程连接。 使用这个函数要注意以下问题: 1. 此函数是可选的,如果大家在工程中没有写这个函数,RL-TCPnet库会调用默认的函数,允许所有的连接请求,如果在工程中写了此函数,会执行新写的这个函数。 使用举例: - BOOL http_accept_host (U8 *rem_ip, U16 rem_port) {
-
- if (rem_ip[0] == 192 &&
- rem_ip[1] == 168 &&
- rem_ip[2] == 1 &&
- rem_ip[3] == 1) {
- /* 接受此连接. */
- return (__TRUE);
- }
- /* 拒绝此连接 */
- return (__FALSE);
- }
复制代码
47.2.5 函数cgx_content_type函数原型: - U8 *cgx_content_type (void);
复制代码函数描述: 函数cgx_content_type允许用户对Silverlight Web serviceapplication请求的响应中更改Content-Type HTML头。该函数返回一个指向新的Content-Type HTML头的指针。使用了此函数,将覆盖RL-TCPnet库中的默认Content-Type头。这个Content-Type头用于cgx脚本响应,默认的响应如下: - Content-Type: text/xml\r\n
复制代码如果大家在工程中没有写函数cgx_content_type,RL-TCPnet库会调用上面默认的响应,如果在工程中写了此函数,会执行新写的这个函数。另外,如果这个函数返回值为空指针的话,也是执行默认的响应。 使用这个函数要注意以下问题: 1. 如果大家在工程中没有写函数cgx_content_type,RL-TCPnet库会调用上面默认的响应。 使用举例: - U8 *cgx_content_type (void) {
- /* User configurable Content-type for CGX script files. If this function */
- /* is missing, or returns a NULL pointer, the default 'text/xml' content */
- /* type from the library is used for xml-script file types. */
- return ("text/xml; charset=utf-8");
- }
复制代码
47.2.6 函数http_get_var函数原型: - U8* http_get_var (
- U8* env, /* 环境变量字符串地址 */
- void* ansi, /* 存储环境字符串的缓冲地址 */
- U16 maxlen ); /* 存储环境变量字符串的缓冲区大小,单位字节 */
复制代码函数描述: 函数http_get_var处理包含环境变量的字符串env,并标识第一个变量的结尾。函数获取第一个变量及其数值后以ANSI格式存储到指针变量ansi所指向的存储单元中。 1、第1个参数是环境变量字符串地址。 2、第2个参数存储环境变量字符串的缓冲地址。 3、第3个参数指定存储环境变量字符串的缓冲大小,如果解析的环境变量字符串超过此大小,则该函数会仅存储maxlen大小的字符串。 4、返回值,返回环境变量字符串中下一个变量的地址,如果没有要处理的环境变量了,则返回NULL。 使用这个函数要注意以下问题: 1. 函数http_get_var可以处理GET和POST方式的环境变量。 2. 此函数在HTTP_CGI.c文件中调用。 3. Web浏览器使用环境变量来返回HTTP输入表单(如单选按钮、复选框、选择列表等)中用户输入的信息给Web服务器。 使用举例: - void cgi_process_var (U8 *qs) {
- /* This function is called by HTTP server to process the Querry_String */
- /* for the CGI Form GET method. It is called on SUBMIT from the browser. */
- /*.The Querry_String.is SPACE terminated. */
- U8 *var;
- int s[4];
-
- var = (U8 *)alloc_mem (40);
- do {
- /* Loop through all the parameters. */
- qs = http_get_var (qs, var, 40);
- /* Check the returned string, 'qs' now points to the next. */
- if (var[0] != 0) {
- /* Returned string is non 0-length. */
- if (str_scomp (var, "ip=") == __TRUE) {
- /* My IP address parameter. */
- sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.IpAdr[0] = s[0];
- LocM.IpAdr[1] = s[1];
- LocM.IpAdr[2] = s[2];
- LocM.IpAdr[3] = s[3];
- }
- else if (str_scomp (var, "msk=") == __TRUE) {
- /* Net mask parameter. */
- sscanf ((const char *)&var[4], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.NetMask[0] = s[0];
- LocM.NetMask[1] = s[1];
- LocM.NetMask[2] = s[2];
- LocM.NetMask[3] = s[3];
- }
- else if (str_scomp (var, "gw=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[3], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.DefGW[0] = s[0];
- LocM.DefGW[1] = s[1];
- LocM.DefGW[2] = s[2];
- LocM.DefGW[3] = s[3];
- }
- else if (str_scomp (var, "pdns=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.PriDNS[0] = s[0];
- LocM.PriDNS[1] = s[1];
- LocM.PriDNS[2] = s[2];
- LocM.PriDNS[3] = s[3];
- }
- else if (str_scomp (var, "sdns=") == __TRUE) {
- /* Default gateway parameter. */
- sscanf ((const char *)&var[5], "%d.%d.%d.%d",&s[0],&s[1],&s[2],&s[3]);
- LocM.SecDNS[0] = s[0];
- LocM.SecDNS[1] = s[1];
- LocM.SecDNS[2] = s[2];
- LocM.SecDNS[3] = s[3];
- }
- }
- }while (qs);
- free_mem ((OS_FRAME *)var);
- }
复制代码
|