CGI

作者: wayyyy | 来源:发表于2020-11-01 21:28 被阅读0次

CGI 即 Common Gateway Interface,译作“通用网关接口”,为了理解它,我们需要首先知道:静态网页和动态网页。

  • 静态网页是指内容固定的网页,通常是事先写好的html文档,每次访问得到的都是相同的内容。
  • 而动态网页是指多次访问可以得到不同内容的网页,现在流行的动态网页技术有PHP、JSP、ASP等。

CGI规定了外部应用程序(CGI程序)如何与Web服务器交换信息,但由于有许多缺点,现在几乎已经被淘汰。

CGI 如何工作

http://guodongxiaren.me/cgi-bin/helloworld.cgi为例子

输入
  • Web 服务器在调用 helloworld.cgi 之前,会把各类HTTP请求中的信息以环境变量的方式写入OS。CGI程序本质是OS上一个普通的可执行程序,它通过语言本身库函数来获取环境变量,从而获得数据输入。

  • 除环境变量外,另外一个CGI程序获取数据的方式就是标准输入(stdin)。如post请求一个CGI的URL,那么POST的数据,CGI是通过标准输入来获取到的。

输出

而CGI如何构造出数据(比如HTML页面)返回给浏览器呢?其实CGI本身只要向标准输出去写入数据即可。比如printf、cout等。因为Web服务器已经做了重定向,将标准输出重定向给Web服务器的与浏览器连接的socket。

实例

《深入理解计算机系统》中有一个简单的C语言Web 服务器实例,里面有一个简单CGI例子。

image.png
关键代码分析
  • main
    ...
    listenfd = Open_listenfd(argv[1]);
    while (1) {
        clientlen = sizeof(clientaddr); 
        connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); 
        Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINE, 
                      port, MAXLINE, 0);
        printf("Accepted connection from (%s, %s)\n", hostname, port);
        doit(connfd);                                             
        Close(connfd);                                          
    }
    
  • doit
    Rio_readinitb(&rio, fd);
    // 读取请求行
    if (!Rio_readlineb(&rio, buf, MAXLINE)) 
          return;
    printf("%s", buf);
    sscanf(buf, "%s %s %s", method, uri, version);       
    ... 
    // parse_uri 里面查找"cgi-bin",判断是静态请求还是动态请求。
    is_static = parse_uri(uri, filename, cgiargs);  
    if (is_static) { /* Serve static content */          
    ...
    }
    else { /* Dynamic content */
        if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode)) { 
          clienterror(fd, filename, "403", "Forbidden", "Tiny couldn't run the CGI program");
          return;
        }
        serve_dynamic(fd, filename, cgiargs);            
    }
    
  • serve_dynamic
    void serve_dynamic(int fd, char *filename, char *cgiargs) 
    {
        char buf[MAXLINE], *emptylist[] = { NULL };
    
        /* Return first part of HTTP response */
        sprintf(buf, "HTTP/1.0 200 OK\r\n"); 
        Rio_writen(fd, buf, strlen(buf));
        sprintf(buf, "Server: Tiny Web Server\r\n");
        Rio_writen(fd, buf, strlen(buf));
    
        if (Fork() == 0) { /* Child */
            /* Real server would set all CGI vars here */
            setenv("QUERY_STRING", cgiargs, 1);     // 将参数通过系统的环境变量的方式设置
            Dup2(fd, STDOUT_FILENO);    // 将标准输出重定向到连接套接字
            Execve(filename, emptylist, environ); /* Run CGI program */
        }
        Wait(NULL); /* Parent waits for and reaps child */ //line:netp:servedynamic:wait
    }
    
    • cgi 程序
      int main(void) {
          char *buf, *p;
          char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE];
          int n1=0, n2=0;
      
          /* Extract the two arguments 从系统换进变量中取出参数 */
          if ((buf = getenv("QUERY_STRING")) != NULL) {
              p = strchr(buf, '&');
              *p = '\0';
              strcpy(arg1, buf);
              strcpy(arg2, p+1);
              n1 = atoi(arg1);
              n2 = atoi(arg2);
          }
      
          /* Make the response body */
          sprintf(content, "Welcome to add.com: ");
          sprintf(content, "%sTHE Internet addition portal.\r\n<p>", content);
          sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>", 
          content, n1, n2, n1 + n2);
          sprintf(content, "%sThanks for visiting!\r\n", content);
      
          /* Generate the HTTP response 标准输出已经重定向 */
          printf("Connection: close\r\n");
          printf("Content-length: %d\r\n", (int)strlen(content));
          printf("Content-type: text/html\r\n\r\n");
          printf("%s", content);
          flush(stdout);
      
          exit(0);
      }
      

setenv/getenv
dup2
mmap

缺点

  • 每次HTTP请求CGI时,Web服务器都有启动一个新的进程去执行这个CGI程序。当用户请求量大的时候,这个拉起一个新进程的操作会严重拖慢Web服务器的性能。

  • 缺乏URL路由的功能,基本上一个CGI都是独立提供给外界访问,一个CGI就是独立的可执行程序。因此 不仅CGI的URL比较丑陋,而且容易暴露真实路径。


参考资料
1、https://www.jianshu.com/p/dd580395bf11
2、《深入理解计算机系统》
3、https://zhuanlan.zhihu.com/p/25013398

相关文章

网友评论

      本文标题:CGI

      本文链接:https://www.haomeiwen.com/subject/obehmktx.html