// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x628, %rsp            # imm = 0x628
movq %rcx, -0x48(%rbp)
movq %rsi, -0x50(%rbp)
movl %edi, %ebx
movw $0x41, -0x550(%rbp)
leaq 0x2ffa(%rip), %rsi      # 0x7014
movq %rdx, -0x40(%rbp)
movq %rdx, %rdi
callq 0x3370
testl %eax, %eax
je 0x40c6
leaq -0x550(%rbp), %rsi
movl %ebx, %edi
movl $0x400, %edx            # imm = 0x400
callq 0x3b2b
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
testl %eax, %eax
jle 0x40a8
cmpw $0xa, -0x550(%rbp)
je 0x40a8
leaq -0x540(%rbp), %r14
leaq 0x309e(%rip), %r12      # 0x7101
leaq -0x550(%rbp), %r13
movb $0x0, -0x541(%rbp)
movq %r13, %rdi
movq %r12, %rsi
callq 0x3370
testl %eax, %eax
jne 0x408b
movq %r14, %rdi
callq 0x34a0
movl %eax, %r15d
movl %ebx, %edi
movq %r13, %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x3b2b
testl %eax, %eax
jle 0x40a8
cmpw $0xa, -0x550(%rbp)
jne 0x406a
cmpl $-0x1, %r15d
jne 0x40fa
movl %ebx, %edi
addq $0x628, %rsp            # imm = 0x628
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x42f3
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
cmpw $0xa, -0x550(%rbp)
je 0x40fa
leaq -0x550(%rbp), %r14
movl %ebx, %edi
movq %r14, %rsi
movl $0x400, %edx            # imm = 0x400
callq 0x3b2b
testl %eax, %eax
jle 0x40fa
cmpw $0xa, -0x550(%rbp)
jne 0x40dd
movups 0x3010(%rip), %xmm0     # 0x7111
leaq -0x550(%rbp), %r14
movaps %xmm0, (%r14)
movw $0xa, 0x10(%r14)
movq %r14, %rdi
callq 0x3150
movl %ebx, %edi
movq %r14, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x31b0
leaq -0x30(%rbp), %rdi
callq 0x3400
testl %eax, %eax
js 0x4221
leaq -0x38(%rbp), %rdi
callq 0x3400
testl %eax, %eax
js 0x4221
callq 0x30a0
testl %eax, %eax
js 0x4221
je 0x423a
movl %eax, %r14d
movl -0x2c(%rbp), %edi
callq 0x3570
movl -0x38(%rbp), %edi
callq 0x3570
leaq 0x2e9f(%rip), %rsi      # 0x7018
movq -0x40(%rbp), %rdi
callq 0x3370
testl %eax, %eax
jne 0x41b8
testl %r15d, %r15d
jle 0x41b8
leaq -0x150(%rbp), %r12
movl $0x1, %edx
movl %ebx, %edi
movq %r12, %rsi
xorl %ecx, %ecx
callq 0x30f0
movl -0x34(%rbp), %edi
movl $0x1, %edx
movq %r12, %rsi
callq 0x3100
decl %r15d
jne 0x4192
movl -0x30(%rbp), %edi
leaq -0x150(%rbp), %rsi
movl $0x1, %edx
callq 0x3440
testq %rax, %rax
jle 0x41fe
leaq -0x150(%rbp), %r15
movl $0x1, %edx
movl %ebx, %edi
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x31b0
movl -0x30(%rbp), %edi
movl $0x1, %edx
movq %r15, %rsi
callq 0x3440
testq %rax, %rax
jg 0x41d8
movl -0x30(%rbp), %edi
callq 0x3570
movl -0x34(%rbp), %edi
callq 0x3570
leaq -0x650(%rbp), %rsi
movl %r14d, %edi
xorl %edx, %edx
callq 0x3260
jmp 0x4228
movl %ebx, %edi
callq 0x4469
addq $0x628, %rsp            # imm = 0x628
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl -0x2c(%rbp), %edi
movl $0x1, %esi
callq 0x3300
movl -0x38(%rbp), %edi
xorl %esi, %esi
callq 0x3300
movl -0x30(%rbp), %edi
callq 0x3570
movl -0x34(%rbp), %edi
callq 0x3570
leaq 0x2ebb(%rip), %rsi      # 0x7123
leaq -0x650(%rbp), %rbx
movq %rbx, %rdi
movq -0x40(%rbp), %r14
movq %r14, %rdx
xorl %eax, %eax
callq 0x3070
movq %rbx, %rdi
callq 0x3360
leaq 0x2d85(%rip), %rsi      # 0x7014
movq %r14, %rdi
callq 0x3370
testl %eax, %eax
jne 0x42b9
leaq 0x2e93(%rip), %rsi      # 0x7135
leaq -0x150(%rbp), %rbx
movq %rbx, %rdi
movq -0x48(%rbp), %rdx
xorl %eax, %eax
callq 0x3070
jmp 0x42d4
leaq 0x2e85(%rip), %rsi      # 0x7145
leaq -0x150(%rbp), %rbx
movq %rbx, %rdi
movl %r15d, %edx
xorl %eax, %eax
callq 0x3070
movq %rbx, %rdi
callq 0x3360
movq -0x50(%rbp), %rdi
movq %rdi, %rsi
xorl %edx, %edx
xorl %eax, %eax
callq 0x33e0
xorl %edi, %edi
callq 0x33d0