CGI解析

原博地址:

https://blog.csdn.net/hzhxxx/article/details/37909253

https://blog.csdn.net/hzhxxx/article/details/37908613

https://blog.csdn.net/liunian_siyu/article/details/60964966

关于CGI:

主要问题在于用户将请求发至web服务器端,web服务器将请求设置为一系列环境变量的值,将这些环境变量一并发给对应的CGI程序,即可使用CGI对用户请求进行相关处理,CGI将结果返回至web服务器,web服务器再将结果传回至客户端。

有很多个不同的CGI程序分别对应处理不同的请求。

CGI如何获取web服务器数据:

//gcc get_post.c -o get_post.ums;



#include <stdio.h>

#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[]) 
{ 
    size_t i = 0,n = 0;
    printf("Content-Type:text/plain\n\n"); 
    char * method = NULL;
    //获取HTTP请求方法(POST/GET)
    if(NULL == (method = getenv("REQUEST_METHOD")))
    {
        return 0;
    }

    
    if(getenv("CONTENT_LENGTH") && strcmp(method,"POST") == 0)
    { 
        //POST 方法解析,从 STDIN_FILENO 动态获取数据
        n = atoi(getenv("CONTENT_LENGTH"));
        size_t length = n * sizeof(char) + 1;
        char * inputdata = (char *)malloc(length);
        if(inputdata)
        {
            memset((void*)inputdata,0,length);
            if(n != read(STDIN_FILENO,inputdata,n));
            {
                //
            }
            printf("hello %s,cgi post call.\n",inputdata);
            free(inputdata);
        }
    }
    else if(getenv("QUERY_STRING") && strcmp(method,"GET") == 0)
    {
        //环境变量的长度有限,导致GET方法传送数据被限制
        char * inputdata = getenv("QUERY_STRING");
        printf("hello %s,get call.\n",inputdata);
    }
    else
    {
        printf("%s\n","bad request!");
    }
    fprintf(stdout,"finish,data length %d\n",n);
    return 0;    

} 

WEB服务与CGI交互数据

扫描二维码关注公众号,回复: 2478795 查看本文章

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

#define    CGI_NAME "get_post.ums"
#define    REQUEST_METHOD "REQUEST_METHOD=POST"
#define REQUEST_PARAMETER "myname=huangzhihui"

int main(int argc, char *argv[])
{
    int fd[2];
    if (pipe(fd) < 0)
    {
        printf("create pipe fail.\n");
    }

    pid_t pid;
    if ((pid = fork()) < 0)
    {
        printf("fork fail.\n");
    }
    else if (pid > 0)
    {
        /* parent */                
        //模拟向 CGI 传送数据
        ssize_t length = strlen(REQUEST_PARAMETER);
        if (write(fd[1], REQUEST_PARAMETER, length) != length)
        {
            printf("write error to pipe\n");
        }
        close(fd[1]);
        
        //等待CGI子进程完全把数据读取后写入,
        //实际情况应该是使用select 或者 epoll 监听
        usleep(1000);

        //模拟接收 CGI 应答的数据        
        char buff[256] = { 0 };
        length = read(fd[0], buff, sizeof(buff));
        if (length <= 0)
        {
            printf("read error from pipe\n");
        }
        else
        {
            printf("pid %d read data=%u,%s\n",getpid(),length, buff);
        }
        close(fd[0]);

        if (waitpid(pid, NULL, 0) < 0)
        {
            printf("waitpid error\n");
        }
        exit(0);
    }
    else
    {
        /* child */
       //重定向管道的输入端到标准输入
        if (fd[0] != STDIN_FILENO)
        {
            if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
            {
                printf("dup2 error to stdin");
            }
            close(fd[0]);
        }

        //重定向管道的输出端到标准输出
        if (fd[1] != STDOUT_FILENO)
        {
            if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
            {
                printf("dup2 error to stdout");
            }
            close(fd[1]);
        }

        //覆盖进程空间,设置CGI环境变量
        char content_length[128] = { 0 };
        sprintf(content_length, "CONTENT_LENGTH=%u", strlen(REQUEST_PARAMETER));
        char *exec_argv[3] = { REQUEST_METHOD, content_length };
        if (execve(CGI_NAME,argv,exec_argv) < 0)
        {
            printf("execl error for %s", CGI_NAME);
        }
        exit(0);
    }
    exit(0);
}

web服务器收到CGI标准输入输出流传来的结果返回至服务器端就ok了。

一个CGI一次只能处理一个进程,因此对于CGI内部需要用到文件锁。避免程序时间片用完挂起时内存值被其他程序修改。

猜你喜欢

转载自blog.csdn.net/parallel2333/article/details/81152362
CGI