// File: fltflt[P]Tinyhttpd_with_threadpool_epoll/httpd.cpp
// Function: execute_cgi(int, char const*, char const*, char const*)
void execute_cgi(int client, const char *path,
                 const char *method, const char *query_string)
{
	char buf[1024];
 int cgi_output[2];//声明的读写管道，切莫被名称给忽悠，会给出图进行说明
 int cgi_input[2];//
 pid_t pid;
 int status;
 int i;
 char c;
 int numchars = 1;
 int content_length = -1;

 buf[0] = 'A'; buf[1] = '\0';
 if (strcasecmp(method, "GET") == 0)
 //如果是GET请求
 //读取并且丢弃头信息
 	while ((numchars > 0) && strcmp("\n", buf)) 
 		numchars = get_line(client, buf, sizeof(buf));
 	else    
 	{
 //处理的请求为POST
 		numchars = get_line(client, buf, sizeof(buf));
 		while ((numchars > 0) && strcmp("\n", buf))
  {//循环读取头信息找到Content-Length字段的值
   buf[15] = '\0';//目的是为了截取Content-Length:
   
   if (strcasecmp(buf, "Content-Length:") == 0)
    //"Content-Length: 15"
    content_length = atoi(&(buf[16]));//获取Content-Length的值
numchars = get_line(client, buf, sizeof(buf));
}
if (content_length == -1) {
  //错误请求
	bad_request(client);
	return;
}
}
//返回正确响应码200
sprintf(buf, "HTTP/1.0 200 OK\r\n");
send(client, buf, strlen(buf), 0);
//#include<unistd.h>
//int pipe(int filedes[2]);
//返回值：成功，返回0，否则返回-1。参数数组包含pipe使用的两个文件的描述符。fd[0]:读管道，fd[1]:写管道。
//必须在fork()中调用pipe()，否则子进程不会继承文件描述符。
//两个进程不共享祖先进程，就不能使用pipe。但是可以使用命名管道。
//pipe(cgi_output)执行成功后，cgi_output[0]:读通道 cgi_output[1]:写通道，这就是为什么说不要被名称所迷惑
if (pipe(cgi_output) < 0) {
	cannot_execute(client);
	return;
}
if (pipe(cgi_input) < 0) {
	cannot_execute(client);
	return;
}

if ( (pid = fork()) < 0 ) {
	cannot_execute(client);
	return;
}
 //fork出一个子进程运行cgi脚本
 if (pid == 0)  /* 子进程: 运行CGI 脚本 */
{
	char meth_env[255];
	char query_env[255];
	char length_env[255];

  dup2(cgi_output[1], 1);//1代表着stdout，0代表着stdin，将系统标准输出重定向为cgi_output[1]
  dup2(cgi_input[0], 0);//将系统标准输入重定向为cgi_input[0]，这一点非常关键，
                        //cgi程序中用的是标准输入输出进行交互
  close(cgi_output[0]);//关闭了cgi_output中的读通道
  close(cgi_input[1]);//关闭了cgi_input中的写通道
  //CGI标准需要将请求的方法存储环境变量中，然后和cgi脚本进行交互
  //存储REQUEST_METHOD
  sprintf(meth_env, "REQUEST_METHOD=%s", method);
  putenv(meth_env);
  if (strcasecmp(method, "GET") == 0) {
  //存储QUERY_STRING
  	sprintf(query_env, "QUERY_STRING=%s", query_string);
  	putenv(query_env);
  }
  else {   /* POST */
    //存储CONTENT_LENGTH
  sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
  putenv(length_env);
}
 // 表头文件#include<unistd.h>
 // 定义函数
 // int execl(const char * path,const char * arg,....);
 // 函数说明
 // execl()用来执行参数path字符串所代表的文件路径，接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]……，最后一个参数必须用空指针(NULL)作结束。
 // 返回值
 // 如果执行成功则函数不会返回，执行失败则直接返回-1，失败原因存于errno中。
  execl(path, path, NULL);//执行CGI脚本
  exit(0);
 } else {    /* 父进程 */
  close(cgi_output[1]);//关闭了cgi_output中的写通道，注意这是父进程中cgi_output变量和子进程要区分开
  close(cgi_input[0]);//关闭了cgi_input中的读通道
  if (strcasecmp(method, "POST") == 0)
  	for (i = 0; i < content_length; i++) {
    //开始读取POST中的内容
  		recv(client, &c, 1, 0);
    //将数据发送给cgi脚本
  		write(cgi_input[1], &c, 1);
  	}
   //读取cgi脚本返回数据
  	while (read(cgi_output[0], &c, 1) > 0)
    //发送给浏览器
  		send(client, &c, 1, 0);
//运行结束关闭
  	close(cgi_output[0]);
  	close(cgi_input[1]);
//定义函数：pid_t waitpid(pid_t pid, int * status, int options);
//函数说明：waitpid()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 
//如果在调用wait()时子进程已经结束, 则wait()会立即返回子进程结束状态值. 子进程的结束状态值会由参数status 返回, 
//而子进程的进程识别码也会一快返回. 
//如果不在意结束状态值, 则参数status 可以设成NULL. 参数pid 为欲等待的子进程识别码, 其他数值意义如下：
//1、pid<-1 等待进程组识别码为pid 绝对值的任何子进程.
//2、pid=-1 等待任何子进程, 相当于wait().
//3、pid=0 等待进程组识别码与目前进程相同的任何子进程.
//4、pid>0 等待任何子进程识别码为pid 的子进程.
  	waitpid(pid, &status, 0);
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x770, %rsp            # imm = 0x770
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movl $0x1, -0x444(%rbp)
movl $0xffffffff, -0x448(%rbp) # imm = 0xFFFFFFFF
movb $0x41, -0x420(%rbp)
movb $0x0, -0x41f(%rbp)
movq -0x18(%rbp), %rdi
leaq 0xad49(%rip), %rsi      # 0xf070
callq 0x33d0
cmpl $0x0, %eax
jne 0x4390
jmp 0x4333
xorl %eax, %eax
cmpl $0x0, -0x444(%rbp)
movb %al, -0x751(%rbp)
jle 0x4363
leaq -0x420(%rbp), %rsi
leaq 0xb007(%rip), %rdi      # 0xf359
callq 0x3460
cmpl $0x0, %eax
setne %al
movb %al, -0x751(%rbp)
movb -0x751(%rbp), %al
testb $0x1, %al
jne 0x436f
jmp 0x438b
movl -0x4(%rbp), %edi
leaq -0x420(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x3bb0
movl %eax, -0x444(%rbp)
jmp 0x4333
jmp 0x4452
movl -0x4(%rbp), %edi
leaq -0x420(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x3bb0
movl %eax, -0x444(%rbp)
xorl %eax, %eax
cmpl $0x0, -0x444(%rbp)
movb %al, -0x752(%rbp)
jle 0x43da
leaq -0x420(%rbp), %rsi
leaq 0xaf90(%rip), %rdi      # 0xf359
callq 0x3460
cmpl $0x0, %eax
setne %al
movb %al, -0x752(%rbp)
movb -0x752(%rbp), %al
testb $0x1, %al
jne 0x43e6
jmp 0x443a
movb $0x0, -0x411(%rbp)
leaq -0x420(%rbp), %rdi
leaq 0xad62(%rip), %rsi      # 0xf15d
callq 0x33d0
cmpl $0x0, %eax
jne 0x441b
leaq -0x420(%rbp), %rdi
addq $0x10, %rdi
callq 0x34d0
movl %eax, -0x448(%rbp)
movl -0x4(%rbp), %edi
leaq -0x420(%rbp), %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x3bb0
movl %eax, -0x444(%rbp)
jmp 0x43aa
cmpl $-0x1, -0x448(%rbp)
jne 0x4450
movl -0x4(%rbp), %edi
callq 0x46d0
jmp 0x46c0
jmp 0x4452
leaq -0x420(%rbp), %rdi
leaq 0xad0d(%rip), %rsi      # 0xf16d
movb $0x0, %al
callq 0x3070
movl -0x4(%rbp), %eax
movl %eax, -0x764(%rbp)
leaq -0x420(%rbp), %rax
movq %rax, -0x760(%rbp)
leaq -0x420(%rbp), %rdi
callq 0x3170
movl -0x764(%rbp), %edi
movq -0x760(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x31d0
leaq -0x428(%rbp), %rdi
callq 0x3440
cmpl $0x0, %eax
jge 0x44bf
movl -0x4(%rbp), %edi
callq 0x4860
jmp 0x46c0
leaq -0x430(%rbp), %rdi
callq 0x3440
cmpl $0x0, %eax
jge 0x44dd
movl -0x4(%rbp), %edi
callq 0x4860
jmp 0x46c0
callq 0x30c0
movl %eax, -0x434(%rbp)
cmpl $0x0, %eax
jge 0x44fa
movl -0x4(%rbp), %edi
callq 0x4860
jmp 0x46c0
cmpl $0x0, -0x434(%rbp)
jne 0x45dc
movl -0x424(%rbp), %edi
movl $0x1, %esi
callq 0x3340
movl -0x430(%rbp), %edi
xorl %esi, %esi
callq 0x3340
movl -0x428(%rbp), %edi
callq 0x35b0
movl -0x42c(%rbp), %edi
callq 0x35b0
leaq -0x550(%rbp), %rdi
movq -0x18(%rbp), %rdx
leaq 0xac33(%rip), %rsi      # 0xf17f
movb $0x0, %al
callq 0x3070
leaq -0x550(%rbp), %rdi
callq 0x33c0
movq -0x18(%rbp), %rdi
leaq 0xab06(%rip), %rsi      # 0xf070
callq 0x33d0
cmpl $0x0, %eax
jne 0x459b
leaq -0x650(%rbp), %rdi
movq -0x20(%rbp), %rdx
leaq 0xac0b(%rip), %rsi      # 0xf191
movb $0x0, %al
callq 0x3070
leaq -0x650(%rbp), %rdi
callq 0x33c0
jmp 0x45c2
leaq -0x750(%rbp), %rdi
movl -0x448(%rbp), %edx
leaq 0xabf2(%rip), %rsi      # 0xf1a1
movb $0x0, %al
callq 0x3070
leaq -0x750(%rbp), %rdi
callq 0x33c0
movq -0x10(%rbp), %rdi
movq -0x10(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
movb $0x0, %al
callq 0x3420
xorl %edi, %edi
callq 0x3410
movl -0x424(%rbp), %edi
callq 0x35b0
movl -0x430(%rbp), %edi
callq 0x35b0
movq -0x18(%rbp), %rdi
leaq 0xaa77(%rip), %rsi      # 0xf074
callq 0x33d0
cmpl $0x0, %eax
jne 0x465f
movl $0x0, -0x43c(%rbp)
movl -0x43c(%rbp), %eax
cmpl -0x448(%rbp), %eax
jge 0x465d
movl -0x4(%rbp), %edi
leaq -0x43d(%rbp), %rsi
movl $0x1, %edx
xorl %ecx, %ecx
callq 0x3110
movl -0x42c(%rbp), %edi
leaq -0x43d(%rbp), %rsi
movl $0x1, %edx
callq 0x3120
movl -0x43c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x43c(%rbp)
jmp 0x4611
jmp 0x465f
jmp 0x4661
movl -0x428(%rbp), %edi
leaq -0x43d(%rbp), %rsi
movl $0x1, %edx
callq 0x3480
cmpq $0x0, %rax
jle 0x4696
movl -0x4(%rbp), %edi
leaq -0x43d(%rbp), %rsi
movl $0x1, %edx
xorl %ecx, %ecx
callq 0x31d0
jmp 0x4661
movl -0x428(%rbp), %edi
callq 0x35b0
movl -0x42c(%rbp), %edi
callq 0x35b0
movl -0x434(%rbp), %edi
leaq -0x438(%rbp), %rsi
xorl %edx, %edx
callq 0x32a0
addq $0x770, %rsp            # imm = 0x770
popq %rbp
retq
nopl (%rax)