Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4462997
  • 博文数量: 1148
  • 博客积分: 25453
  • 博客等级: 上将
  • 技术积分: 11949
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-06 21:14
文章分类

全部博文(1148)

文章存档

2012年(15)

2011年(1078)

2010年(58)

分类: 嵌入式

2011-03-25 16:16:49

9.处理GET方法的 CGI请求
    当前面的 parse_uri 返回1时,将转到 exec_cgi函数处理,看看 exec_cgi 函数的实现


  1. ### 运行CGI程序

  2. void exec_cgi(int fd, char *method, int content_length, char *filename, char *cgiargs)
  3. {
  4.     char buf[MAXLINE], *emptylist[] = { NULL };

  5. #### 发送 HTTP相依的第一部分

  6.     sprintf(buf, "HTTP/1.1 200 OK\r\n");
  7.     write(fd, buf, strlen(buf));
  8.     sprintf(buf, "Server: Mini Web Server\r\n");
  9.     write(fd, buf, strlen(buf));
  10.   
  11.     if (fork() == 0) { ##返回是0,表示是在子进程中运行,处理POST 方式
  12.        ### 子进程 处理POST 方法
  13.         if (strcasecmp(method, "POST") == 0) {
  14.             int pfd[2];
  15.             int rc = pipe(pfd);
  16.             if (rc < 0) {
  17.                 perror("pipe in POST failed");
  18.                 exit(1);
  19.             }
  20.             int post_pid = fork();
  21.             if (post_pid == 0) {
  22.                 close(pfd[0]);
  23.                 int n = 0, bytes_read = 0;
  24.                 /*only read length of "content_length"*/
  25.                 while (n < content_length) {
  26.                     bytes_read = read(fd, buf, sizeof(buf)-1);
  27.                     printf("content read: %s \n", buf);
  28.                     if (bytes_read > 0) {
  29.                         write(pfd[1], buf, bytes_read);
  30.                         n += bytes_read;
  31.                     }
  32.                 }
  33.                 exit(0);
  34.             }
  35.                 
  36.             close(pfd[1]);
  37.             /*redirect to STDIN*/
  38.             dup2(pfd[0],STDIN_FILENO);
  39. ### POST  处理结束
  40.         }

  41.   
    ### 设置 CGI 环境变量,本程序中仅支持 “QUERY_STRING”和“content_length”
  42.      setenv("QUERY_STRING", cgiargs, 1);
  43.         sprintf(buf, "%d", content_length);
  44.         setenv("CONTENT_LENGTH", buf);
  45.      dup2(fd, STDOUT_FILENO);    # 重定向stdout 到客户端
  46.      execve(filename, emptylist, environ);   # 运行 CGI 程序
  47.     }
  48.     wait(NULL);   #父进程等待 子进程结束并收回
  49. }


   函数体中比较长的部分是处理POST方法,我们先忽略这段逻辑,来看看相对简单的GET方法怎么处理。
  1. sprintf(buf, "HTTP/1.1 200 OK\r\n");
  2.     write(fd, buf, strlen(buf));
  3.     sprintf(buf, "Server: Mini Web Server\r\n");
  4.     write(fd, buf, strlen(buf));
按照上面的代码按照HTTP规范返回HTTP响应行即部分响应报头之后,在下面通过fork 调用来复制一个子进程。在子进程的处理中,忽略POST处理逻辑。
  1. setenv("QUERY_STRING", cgiargs, 1);
  2.         sprintf(buf, "%d", content_length);
  3.         setenv("CONTENT_LENGTH", buf);
  4. 设置环境变量“QUERY_STRING” 和“CONTENT_LENGTH”,这是 CGI规范中规定的WEB 服务器向CGI程序传递参数的方式之一,CGI规范所定义的环境变量除了“QUERY_STRING”和“CONTENT_LENGTH”之外,还有“SERVER_PORT”,“REMOTE_HOST”
  5. 等很多,这里我们仅仅支持了最常用的两个,实际应用中可能是需要增加的。   

     dup2(fd, STDOUT_FILENO);    # 重定向stdout 到客户端
     execve(filename, emptylist, environ);   # 运行 CGI 程序
通过dup2函数将子进程的标准输出stdout重定向到fd,接着通过execve加载并运行CGI程序,并通过glibc中的全局变量 environ 来传递环境变量,这样程序运行时,就可以通过环境变量来接收服务器传递过来的参数,并将结果通过标准输出stdout返回给客户端浏览器。

      wait(NULL);   #父进程等待 子进程结束并收回

   
     我们可以利用后面的测试程序来理解服务器对 CGI的支持。在测试程序中我们提供了用来测试GET 和 POST 的HTML表单,分别对应 get.html 和 post.html 两个文件。

get.html 的 内容如下:



test of "GET"

Test GET Form



Input your test strings:


ID:

Name:














阅读(881) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~