/* Execute script in /cgi-bin*/ void execute_script(int socket) { /* Currently unsupported, return error code to client*/ cannot_execute(socket); return; }
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) while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { numchars = get_line(client, buf, sizeof(buf)); while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } if (content_length == -1) { bad_request(client); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); 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; } if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; dup2(cgi_output[1], 1); dup2(cgi_input[0], 0); close(cgi_output[0]); close(cgi_input[1]); sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } execl(path, path, NULL); exit(0); } else { /* parent */ close(cgi_output[1]); close(cgi_input[0]); if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); } while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); close(cgi_output[0]); close(cgi_input[1]); waitpid(pid, &status, 0); } }
void editrule(nunetwork_socket client, char *path, char *method, char *query_string) { char buf[1024], tmpbuf[255]; int cgi_output[2]; int cgi_input[2]; pid_t pid; int status; char c; char *param[64]; char *tempstr; char *ruleno; char *chain; int pos = 0; buf[0] = 'A'; buf[1] = '\0'; /* if (strcasecmp(method, "GET") == 0) nunetwork_discardheaders(client); else { / * POST * / unimplemented(client); return; } */ if (strlen(query_string) < 13) { unimplemented(client); return; } snprintf(buf, sizeof (buf)-1, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"); nunetwork_send(client, buf, strlen(buf), 0); param[pos++] = (char *)strdup(path); param[pos++] = "-R"; tempstr = (char *)strdup(query_string); ruleno = (char *)strdup(strtok(tempstr, "@\n")); chain = (char *)strdup(strtok(NULL, "@\n")); param[pos++] = (char *)strdup(chain); param[pos] = (char *)strdup(ruleno); while (param[pos++] != NULL) { param[pos] = strtok(NULL, "@\n"); } /* Replacing Rule */ 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; } if (pid == 0) { /* child: Add new rule */ dup2(cgi_output[1], 1); dup2(cgi_input[0], 0); close(cgi_output[0]); close(cgi_input[1]); execv(path, param); exit(0); } else { /* parent */ close(cgi_output[1]); close(cgi_input[0]); pos = 0; while (read(cgi_output[0], &c, 1) > 0) tmpbuf[pos++] = c; tmpbuf[pos] = '\0'; close(cgi_output[0]); close(cgi_input[1]); waitpid(pid, &status, 0); /* Log Request */ snprintf(log_msg_text, sizeof (log_msg_text)-1, "IP: %s %s: %s:%s %s:%s %s %s\n", (char *) inet_ntoa(client_name.sin_addr), (char *) gettext("Edit Rule"), (char *) gettext("Chain"), (char *) chain, (char *) gettext("Rule"), (char *) ruleno, (char *) gettext("Replaced with"), (char *) tmpbuf); log_msg(logfile, log_msg_text, 1); snprintf(buf, sizeof (buf)-1, "<html>\n<head>\n<meta http-equiv='Refresh' content='2; URL=/$%s'>\n\ <meta http-equiv='Pragma' content='no-cache'>\n\ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n\ <title>netUstad</title></head>\n", server_sid, (char *) gettext("charset")); nunetwork_send(client, buf, strlen(buf), 0); snprintf(buf, sizeof (buf)-1, "<link rel='stylesheet' type='text/css' href='/netustad.css'>\n"); nunetwork_send(client, buf, strlen(buf), 0); snprintf(buf, sizeof (buf)-1, "<body><center>\n<br><b>%s<b><br>%s</body></html>\n", (char *) gettext("Edit Complete"), (char *) gettext("Redirecting to Rule List")); nunetwork_send(client, buf, strlen(buf), 0); } }
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) /*把所有的 HTTP header 读取并丢弃*/ while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { /* 对 POST 的 HTTP 请求中找出 content_length */ numchars = get_line(client, buf, sizeof(buf)); while ((numchars > 0) && strcmp("\n", buf)) { /*利用 \0 进行分隔 */ buf[15] = '\0'; /* HTTP 请求的特点*/ if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } /*没有找到 content_length */ if (content_length == -1) { /*错误请求*/ bad_request(client); return; } } /* 正确,HTTP 状态码 200 */ sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); /* 建立管道*/ 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; } if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; /* 把 STDOUT 重定向到 cgi_output 的写入端 */ dup2(cgi_output[1], 1); /* 把 STDIN 重定向到 cgi_input 的读取端 */ dup2(cgi_input[0], 0); /* 关闭 cgi_input 的写入端 和 cgi_output 的读取端 */ close(cgi_output[0]); close(cgi_input[1]); /*设置 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); } /*用 execl 运行 cgi 程序*/ execl(path, path, NULL); exit(0); } else { /* parent */ /* 关闭 cgi_input 的读取端 和 cgi_output 的写入端 */ close(cgi_output[1]); close(cgi_input[0]); if (strcasecmp(method, "POST") == 0) /*接收 POST 过来的数据*/ for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); /*把 POST 数据写入 cgi_input,现在重定向到 STDIN */ write(cgi_input[1], &c, 1); } /*读取 cgi_output 的管道输出到客户端,该管道输入是 STDOUT */ while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); /*关闭管道*/ close(cgi_output[0]); close(cgi_input[1]); /*等待子进程*/ waitpid(pid, &status, 0); } }
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 中填东西以保证能进入下面的 while buf[0] = 'A'; buf[1] = '\0'; //如果是 http 请求是 GET 方法的话读取并忽略请求剩下的内容 if (strcasecmp(method, "GET") == 0) while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); else /* POST */ { //只有 POST 方法才继续读内容 numchars = get_line(client, buf, sizeof(buf)); //这个循环的目的是读出指示 body 长度大小的参数,并记录 body 的长度大小。其余的 header 里面的参数一律忽略 //注意这里只读完 header 的内容,body 的内容没有读 while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) content_length = atoi(&(buf[16])); //记录 body 的长度大小 numchars = get_line(client, buf, sizeof(buf)); } //如果 http 请求的 header 没有指示 body 长度大小的参数,则报错返回 if (content_length == -1) { bad_request(client); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); //下面这里创建两个管道,用于两个进程间通信 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; } //子进程用来执行 cgi 脚本 if (pid == 0) /* child: CGI script */ { char meth_env[255]; char query_env[255]; char length_env[255]; //dup2()包含<unistd.h>中,参读《TLPI》P97 //将子进程的输出由标准输出重定向到 cgi_ouput 的管道写端上 dup2(cgi_output[1], 1); //将子进程的输出由标准输入重定向到 cgi_ouput 的管道读端上 dup2(cgi_input[0], 0); //关闭 cgi_ouput 管道的读端与cgi_input 管道的写端 close(cgi_output[0]); close(cgi_input[1]); //构造一个环境变量 sprintf(meth_env, "REQUEST_METHOD=%s", method); //putenv()包含于<stdlib.h>中,参读《TLPI》P128 //将这个环境变量加进子进程的运行环境中 putenv(meth_env); //根据http 请求的不同方法,构造并存储不同的环境变量 if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } //execl()包含于<unistd.h>中,参读《TLPI》P567 //最后将子进程替换成另一个进程并执行 cgi 脚本 execl(path, path, NULL); exit(0); } else { /* parent */ //父进程则关闭了 cgi_output管道的写端和 cgi_input 管道的读端 close(cgi_output[1]); close(cgi_input[0]); //如果是 POST 方法的话就继续读 body 的内容,并写到 cgi_input 管道里让子进程去读 if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); } //然后从 cgi_output 管道中读子进程的输出,并发送到客户端去 while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); //关闭管道 close(cgi_output[0]); close(cgi_input[1]); //等待子进程的退出 waitpid(pid, &status, 0); } }
void serve_led_request(int client, char *query) { char buf[1024]; int numchars = 1; char *token; char *split; int r = -1; int g = -1; int b = -1; int pattern = 0; int option = 0; buf[0] = 'A'; buf[1] = '\0'; while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ { numchars = get_line(client, buf, sizeof(buf)); } token = strtok(query, "&"); while( token != NULL ) { split=strchr(token,'='); switch(token[0]) { case 'r': r = toRGB(split+1); break; case 'g': g = toRGB(split+1); break; case 'b': b = toRGB(split+1); break; case 'p': pattern = toRGB(split+1); break; case 'o': option = toRGB(split+1); break; } token = strtok(NULL, "&"); } if ( (r == -1 || g == -1 || b == -1) && pattern == 0) { logMessage (LOG_DEBUG,"Received BAD LED query:- Red=%d Green=%d, Blue=%d\n",r,g,b); cannot_execute(client); return; } else { int index = 0; lpd8806worker(&_gpioconfig_.lpd8806cfg[index], (uint8_t*)&pattern, (uint8_t*)&option, (uint8_t*)&r, (uint8_t*)&g, (uint8_t*)&b ); sprintf(buf, "{ \"title\" : \"%s\",\r\n\"name\" : \"%s\",\r\n", _gpioconfig_.name, _gpioconfig_.name); send(client, buf, strlen(buf), 0); sprintf(buf, "\"led\" : {\"r\" : %d, \"g\" : %d, \"b\" : %d, \"p\" : %d}\r\n}\r\n", r,g,b,pattern); /* This one is more accurate and should be used over the above next debug session */ /* sprintf(buf, "\"led\" : {\"name\" : \"%s\", \"r\" : %d, \"g\" : %d, \"b\" : %d, \"p\" : %d}\r\n}\r\n", _gpioconfig_.lpd8806cfg[index].name, _gpioconfig_.lpd8806cfg[index].red, _gpioconfig_.lpd8806cfg[index].green, _gpioconfig_.lpd8806cfg[index].blue, _gpioconfig_.lpd8806cfg[index].pattern);*/ send(client, buf, strlen(buf), 0); } }
void deleterule(nunetwork_socket client, char *path, char *method, char *query_string) { char buf [1024]; int cgi_output [2]; int cgi_input [2]; pid_t pid; int status; /* char c; */ buf[0] = 'A'; buf[1] = '\0'; if (strlen(query_string) != 5) { unimplemented(client); return; } snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\nContent-Type: text/html\n\n"); nunetwork_send(client, buf, strlen(buf), 0); 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; } if (pid == 0) { /* child: Delete rule */ dup2(cgi_output[1], 1); dup2(cgi_input[0], 0); close(cgi_output[0]); close(cgi_input[1]); execl(path, path, "delete", query_string, NULL); exit(0); } else { /* parent */ close(cgi_output[1]); close(cgi_input[0]); snprintf(log_msg_text, sizeof(log_msg_text), "IP: %s %s %s\n", \ (char *)inet_ntoa(client_name.sin_addr), \ gettext("Delete Rule:"), \ (char *)query_string); log_msg(logfile, log_msg_text, 1); snprintf(buf, sizeof (buf)-1, "<html>\n<head>\n<meta http-equiv='Refresh' content='2; URL=/$%s'>\n\ <meta http-equiv='Pragma' content='no-cache'>\n\ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n\ <title>netUstad</title></head>\n", server_sid, (char *) gettext("charset")); nunetwork_send(client, buf, strlen(buf), 0); snprintf(buf, sizeof (buf)-1, "<link rel='stylesheet' type='text/css' href='/netustad.css'>\n"); nunetwork_send(client, buf, strlen(buf), 0); snprintf(buf, sizeof(buf), \ "</style>\n<body><center>\n<br><b>%s %s %s<b><br>%s</body></html>", \ gettext("Rule"), \ query_string, \ gettext("is deleted"), \ gettext("Redirecting to Rule List")); nunetwork_send(client, buf, strlen(buf), 0); close(cgi_output[0]); close(cgi_input[1]); waitpid(pid, &status, 0); } }
// 配置环境变量,创建子进程,执行cgi程序 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)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); // 只处理了请求首行,忽略后面的请求头 else /* POST */ { numchars = get_line(client, buf, sizeof(buf)); // 读取请求头中的header属性 while ((numchars > 0) && strcmp("\n", buf)) { buf[15] = '\0'; if (strcasecmp(buf, "Content-Length:") == 0) // Content-Length:后面的数字切出来 content_length = atoi(&(buf[16])); numchars = get_line(client, buf, sizeof(buf)); } if (content_length == -1) { // Content-Length获取失败,该请求有问题 bad_request(client); // 400 return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n"); // 响应首行 send(client, buf, strlen(buf), 0); 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; } if (pid == 0) /* child: CGI script */ { // 子进程开始执行 char meth_env[255]; char query_env[255]; char length_env[255]; dup2(cgi_output[1], 1); // 复制到标准输出 dup2(cgi_input[0], 0); // 复制到标准输入 close(cgi_output[0]); close(cgi_input[1]); // 关闭不需要的描述符 // 添加几个环境变量 sprintf(meth_env, "REQUEST_METHOD=%s", method); putenv(meth_env); if (strcasecmp(method, "GET") == 0) { sprintf(query_env, "QUERY_STRING=%s", query_string); putenv(query_env); } else { /* POST */ sprintf(length_env, "CONTENT_LENGTH=%d", content_length); putenv(length_env); } // 准备工作完毕,开始执行cgi程序 execl(path, path, NULL); exit(0); } else { /* parent */ // 父进程代码 close(cgi_output[1]); close(cgi_input[0]); // 关闭不需要的描述符 if (strcasecmp(method, "POST") == 0) for (i = 0; i < content_length; i++) { recv(client, &c, 1, 0); write(cgi_input[1], &c, 1); // 读取剩下的请求头写给子进程的cgi程序 } while (read(cgi_output[0], &c, 1) > 0) send(client, &c, 1, 0); // 读取cgi程序的输出发送给客户端 close(cgi_output[0]); close(cgi_input[1]); // 使用完毕,关闭描述符 waitpid(pid, &status, 0); // 等待子进程退出 } }