// 静态网页 文本等的处理 static void echo_www(int sock,const char* path, ssize_t size) { int fd = open(path, O_RDONLY); if (fd < 0) { echo_errno(sock); return; } printf("get a new client: %d -> %s \n", sock, path); char status_line[_SIZE_]; sprintf(status_line, "HTTP/1.0 200 OK\r\n\r\n");// 发送 回应行 和 空行 之间GET没有参数 参数 在url中 send(sock, status_line, strlen(status_line), 0); ///////////////////////////////////////////////////// // sendfile 将fd拷贝到 sock 直接在内核态完成 不许要经历用户态 切换 【高效】 if (sendfile(sock, fd, NULL, size) < 0) // 发送文件内容 回应内容 { echo_errno(sock); return; } close(fd); close(sock); }
static void echo_www(int sock, const char *path, ssize_t size) { int fd = open(path, O_RDONLY); //index.html and ....... //fcntl if(fd < 0) { echo_errno(sock); return; } printf("get a new client %d\n %s\n", sock, path); char status_line[SIZE]; sprintf(status_line, "HTTP/1.0 200 OK\r\n\r\n"); send(sock, status_line, strlen(status_line), 0); if( sendfile(sock, fd, NULL, size) < 0 ) { echo_errno(sock); return; } close(fd); }
static void echo_www(int sock,const char* path,ssize_t size) { int fd = open(path,O_RDONLY); if(fd < 0) { echo_errno(sock,1);// return ; } printf("get a new client: %d -> %s\n",sock,path); char buf[SIZE]; sprintf(buf,"HTTP/1.0 200 OK\r\n\r\n"); send(sock,buf,strlen(buf),0); if(sendfile(sock,fd,NULL,size) < 0)//sendfile 提高效率 { echo_errno(sock,1); return ; } close(fd); }
static void * accept_request(void *arg) { int sock = (int)arg; char buf[_SIZE_]; char method[_SIZE_/10]; char url[_SIZE_]; char path[_SIZE_]; memset(buf, '\0', sizeof(buf)); memset(buf, '\0', sizeof(method)); memset(buf, '\0', sizeof(url)); memset(buf, '\0', sizeof(path)); int cgi = 0; int ret = -1; char *query_string = NULL; // 数据参数 int len = sizeof(buf) / sizeof(buf[0]); #ifdef _DEBUG_ do { // http 请求 报文 按行存储 ret = get_line(sock, buf, len); printf("%s", buf); fflush(stdout); } while (ret > 0 && strcmp(buf, "\n") != 0); #endif ret = get_line(sock, buf, len); // 获取请求行 printf("line: %s\n", buf); if (ret < 0) { echo_errno(sock); return (void*)1; } // GET / HTTP/1.0 int i = 0; // method index int j = 0; // buf index // 请求行 包括 【方法(GET/POST)】【url】【HTTP/1.0(1.1)】 // 获取方法 GET/POST while ((i < sizeof(method) - 1) && (j < sizeof(buf)) && (!isspace(buf[j]))) { method[i] = buf[j]; ++i; ++j; } method[i] = '\0'; // strcasecmp 忽略大小写的比较 if (strcasecmp(method, "GET") != 0 && strcasecmp(method, "POST") != 0) { echo_errno(sock); return (void*)2; } // 跳过空格 while (j < sizeof(buf) && isspace(buf[j])) { j++; } i = 0; // 获取url url是除了域名 端口号之后的 /。。。 while ((i < sizeof(url) - 1) && (j < sizeof(buf)) && (!isspace(buf[j]))) { url[i++] = buf[j++]; } url[i] = '\0'; //GET 所传递的参数 在URL中, 从server的QUERY_STRING 中获取 //POST 所传递的参数 在 数据包中 从server环境变量中CONTENT_LENGTH 环境变量中获取参数 数据的长度 if (strcasecmp(method, "POST") == 0) { cgi = 1; } if (strcasecmp(method, "GET") == 0) { query_string = url; // 路径和数据参数 以?分隔 如 http:// baidu.com /s ? k = v while (*query_string != '\0' && *query_string != '?') { ++query_string; } if(*query_string == '?') // GET 带参数 需要进一步处理参数 { cgi = 1; *query_string++ = '\0'; } } // 没指定具体网页 加默认网页 和 根文件夹(安全考虑) sprintf(path, "httpdoc%s", url); if (path[strlen(path) - 1] == '/') { strcat(path, "index.html"); } // method , query_string, cgi, path struct stat st; if (stat(path, &st) < 0) // 测文件在不在 { echo_errno(sock); return (void*)3; } else { if (S_ISDIR(st.st_mode))// 测是不是 文件夹 { strcat(path, "/index.html"); } else if( (st.st_mode & S_IXUSR) ||\ (st.st_mode & S_IXGRP) ||\ (st.st_mode & S_IXOTH)) // 查看cgi执行权限 { cgi = 1; } else {} if (cgi) { exec_cgi(sock, method, path, query_string); } else { clear_header(sock); // echo_www(sock, path, st.st_size); } } }
static void exec_cgi(int sock, const char *method, const char *path, const char *query_string ) { char buf[_SIZE_]; int content_length = -1;// 内容长度 方便获取内容 int ret = -1; int cgi_input[2]; int cgi_output[2]; char method_env[_SIZE_]; char query_string_env[_SIZE_]; char content_length_env[_SIZE_]; printf("[exec_cgi ]method : %s \n", method); if (strcasecmp(method, "GET") == 0) { clear_header(sock); } else // POST { do { ret = get_line(sock, buf, sizeof(buf)); if (strncasecmp(buf, "Content-Length: ", 16) == 0) { content_length = atoi(&buf[16]); // break 不用 break 即把参数Content-Length获取 又把 空行删除 } }while ((ret > 0) && strcmp(buf, "\n") != 0); if (content_length == -1) { echo_errno(sock); return; } } sprintf(buf, "HTTP/1.0 200 OK\r\n\r\n"); send(sock, buf, strlen(buf), 0); // 创建 父子进程之间的 通信管道 cgi_input子进程的读 cgi_output子进程的写 if (pipe(cgi_input) < 0) { echo_errno(sock); return; } if (pipe(cgi_output) < 0) { echo_errno(sock); return; } pid_t id = fork(); if (id < 0) { echo_errno(sock); return ; } if (id == 0)// child { close(cgi_input[1]); close(cgi_output[0]); // //////////////// // 重定向 管道到 标准输入 和 输出 这样以后 printf()直接打到管道 dup2(cgi_input[0], 0); dup2(cgi_output[1], 1); sprintf(method_env, "REQUEST_METHOD=%s", method); putenv(method_env);// 注册环境变量 这样 execl 执行二进制程序时时 获取这些参数方便getenv // GET 要得 参数 在请求字段 中 环境变量注册 quer_string_env // post 要的参数在 内容中 所以要知道 内容什么时候截至(内容长度)所以 只要知道content_length_env 就可以了 if (strcasecmp(method, "GET") == 0) { sprintf(query_string_env, "QUERY_STRING=%s", query_string); putenv(query_string_env); } else // post { sprintf(content_length_env, "CONTENT_LENGTH=%d", content_length); putenv(content_length_env); printf("%d-----------env\n", content_length); } // 执行 二进制 程序 execl(path,path,NULL); exit(1); } else // father { close(cgi_input[0]); close(cgi_output[1]); char c = '\0'; int i = 0; printf("%s --fmethod\n", method); if (strcasecmp(method, "POST") == 0) { printf("--father here %d\n", content_length); for (; i < content_length; i++) { recv(sock, &c, 1, 0); printf("--%c ", c); fflush(stdout); write(cgi_input[1], &c, 1);// 给子进程 发过去 } } printf("\n"); int ret = 0; while ((ret = read(cgi_output[0], &c, 1)) > 0)// 子进程退出 文件符号关闭 read读完文件结尾 返回0 { send(sock, &c, 1, 0);// 父进程 负责向sock发送子进程的数据 } waitpid(id, NULL, 0); close(sock); } }
static void * accept_request(void* arg) { int sock = (int)arg; printf("%d\n",sock); char buf[SIZE]; int ret = 0; #ifdef _DEBUG_ do { ret = get_line(sock,buf,size); printf("%s",buf); fflush(stdout); }while(ret > 0 && strcmp(buf,'\n')); #endif char method[SIZE / 10]; char url[SIZE]; char* query_string = NULL; int cgi = 0; char path[SIZE]; memset(method,'\0',sizeof(method)); memset(url,'\0',sizeof(url)); ret = get_line(sock,buf,sizeof(buf)); if(ret < 0) { echo_errno(sock,1); return (void*)1; } printf("%s\n",buf); //1 get method //GET //xx//yy HTTP/1.1 int i = 0; int j =0; while(i< sizeof(method) - 1 && !isspace(buf[j]) && j < sizeof(buf) ) { method[i]=buf[j]; ++i; ++j; } method[i] = '\0'; //2 check method if(strcasecmp(method,"GET")!=0 && strcasecmp(method,"POST") != 0) { echo_errno(sock,1); return (void*)2; } //3 get url first step space while(isspace(buf[j])) { ++j; } i=0; while(!isspace(buf[j])&& (i < sizeof(url)-1) && j < sizeof(buf)) { url[i] = buf [j]; ++i; ++j; } if(strcasecmp(method,"POST") == 0) { cgi = 1; } printf("method: %s,url_path :%s\n ",method,url); if(strcasecmp(method,"GET") == 0) { query_string = url; } char *start = url; while( *start != '\0') { if( *start == '?') { cgi = 1; *start = '\0'; query_string = start+1; break; } ++start; } sprintf(path,"htdoc%s",url); if(path[strlen(path)-1] == '/') { strcat(path,"index.html"); } // printf("path:%s\n",path); printf("cgi:%d\n",cgi); //method,query_string,cgi,path struct stat st; if(stat(path,&st) < 0)//default -> htdoc/index.html { printf("stat error\n"); echo_errno(sock,1); return (void*)-3; } else { if(S_ISDIR(st.st_mode)) { strcpy(path,"htdoc/index.html"); } if(( st.st_mode & S_IXGRP)||\ ( st.st_mode & S_IXGRP)||\ st.st_mode & S_IXOTH) { cgi = 1; } else {} //path cgi if(cgi) { printf("cgi mode\n"); execut_cgi(sock,path,method,query_string); } else// 请求首页内容 { clear_head(sock); echo_www(sock,path,st.st_size); } } close(sock); //no face link return (void*) 0; }
static void execut_cgi(int sock,const char* path,const char* method,const char* query_string) { int content_len = -1; char buf[SIZE]; memset(buf,'\0',sizeof(buf)); int cgi_input[2]; int cgi_output[2]; printf("method: %s\n",method); if(strcasecmp(method,"GET") == 0) { clear_head(sock); }else //POST { printf("aaaaaaaaaaaaaaaa\n"); int ret = 0; do{ ret = get_line(sock,buf,sizeof(buf)); if(strncasecmp(buf,"Content-Length: ",16) == 0) { content_len = atoi(&buf[16]); } }while((ret > 0) && strcmp(buf,"\n") != 0); printf("contlen:%d\n",content_len); if(content_len == -1) { echo_errno(sock,1); return ; } } if(pipe(cgi_output) < 0) { echo_errno(sock,1); return ; } if(pipe(cgi_input) < 0) { echo_errno(sock,1); return ; } sprintf(buf,"HTTP/1.0 200 OK\r\n\r\n"); send(sock,buf,strlen(buf),0); pid_t id = fork(); // 处理客户端请求 if(id == 0)//child { close(cgi_input[1]); close(cgi_output[0]); dup2(cgi_input[0],0); dup2(cgi_output[1],1); sprintf(buf,"REQUEST_METHOD=%s",method); putenv(buf); if(strcasecmp(method,"GET") == 0) { sprintf(buf,"QUERY_STRING=%s",query_string); putenv(buf); }else { sprintf(buf,"CONTENT_LENGTH=%d",content_len); putenv(buf); } execl(path,path,NULL); exit(1); }else //father { close(cgi_input[0]); close(cgi_output[1]); int i=0; char c = '\0'; if(strcasecmp(method,"POST")==0) { printf("cccccccccccc\n"); for(;i < content_len;++i) { recv(sock,&c,1,0); write(cgi_input[1],&c,1); } } printf("\n"); while(read(cgi_output[0],&c,1) > 0) { send(sock,&c,1,0); } waitpid(id,NULL,0); close(cgi_input[1]); close(cgi_output[0]); } }
void* accept_request(void* arg) { pthread_detach(pthread_self()); int sock = (int)arg; char buf[_SIZE_]; char method[_SIZE_]; char url[_SIZE_]; char path[_SIZE_]; memset(buf, '\0', sizeof(buf)); memset(method, '\0', sizeof(method)); memset(url, '\0', sizeof(url)); memset(path, '\0', sizeof(path)); int cgi = 0; int ret = -1; char* query_string = NULL; #ifdef _DEBUG_ do{ ret = get_line(sock, buf, sizeof(buf)); printf("%s", buf); fflush(stdout); } while((ret > 0) && (strcmp(buf, "\n") != 0)); #endif ret = get_line(sock, buf, sizeof(buf)); if(ret < 0) { echo_errno(sock); return (void *)1; } //GET /HTTP/1.1 int i = 0; // method index int j = 0; // buf index while( (i < sizeof(method)-1) && (j < sizeof(buf)) && (!isspace(buf[j]))) { method[i] = buf[j]; i++, j++; } method[i] = '\0'; while( isspace(buf[j]) ) { j++; } if(strcasecmp(method, "GET") != 0 && strcasecmp(method, "POST") != 0) { echo_errno(sock); return (void*)2; } if(strcasecmp(method, "POST") == 0) { cgi = 1; } i = 0; // url index while( (i<sizeof(url)-1) && (j < sizeof(buf)) && (!isspace(buf[j]))) { url[i] = buf[j]; i++, j++; } if(strcasecmp(method, "GET") == 0) { query_string = url; while(*query_string != '\0' && *query_string != '?' ) { query_string++; } if(*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } // / /aa/bb/cc sprintf(path, "htdoc%s", url); // htdoc/ if(path[strlen(path) - 1] == '/') { strcat(path, "index.html"); } printf("method: %s\n", method); printf("path: %s\n", path); printf("query_string: %s\n", query_string); struct stat st; if(stat(path, &st) < 0) { echo_errno(sock); return (void*)3; } else { if(S_ISDIR(st.st_mode)) { strcpy(path, "htdoc/index.html"); } else if( (st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) { cgi = 1; } else {} if(cgi) { exec_cgi(sock, path, method, query_string); } else { clear_header(sock); echo_html(sock, path, st.st_size); } } close(sock); return (void*)0; }
static void* accept_request(void *arg) //static { int sock = (int)arg; char buf[SIZE]; int len = sizeof(buf)/sizeof(*buf); char method[SIZE/10]; char url[SIZE]; char path[SIZE]; int ret = -1; int i = 0; int j = 0; char *query_string = NULL; //aim at val(can shu) int cgi = 0; #ifdef _DEBUG_ // do // { // ret = get_line(sock, buf, len); // printf("%s", buf); // fflush(stdout); // }while(ret > 0 && (strcmp(buf, "\n") != 0) ); #endif memset(buf, '\0', sizeof(buf)); memset(method, '\0', sizeof(method)); memset(url, '\0', sizeof(url)); memset(path, '\0', sizeof(buf)); //Request Line ret = get_line(sock, buf, len); if(ret <= 0) { echo_errno(sock); return (void*)1; } i = 0; //method index j = 0; //buf index while((i < (sizeof(method)/sizeof(*method) - 1)) && (j < sizeof(buf)/sizeof(*buf) - 1) && (!isspace(buf[j]) ) ) { method[i] = buf[j]; ++i; ++j; } method[i] = '\0'; if((strcasecmp(method, "GET") != 0) && (strcasecmp(method, "POST")) ) { //echo_errno(sock); return (void*)2; } //URL while(isspace(buf[j])) //Remove Space { ++j; } i = 0; while( ( i < sizeof(url)/sizeof(*url)-1 ) && (j < sizeof(buf)/sizeof(*buf)) && (!isspace(buf[j])) ) { url[i] = buf[j]; ++i; ++j; } url[i] = '\0'; if( strcasecmp(method, "POST") == 0 ) { cgi = 1; sprintf(path, "%s", url+1); } if( strcasecmp(method, "GET") == 0 ) { query_string = url; while( *query_string != '\0' && *query_string != '?' ) { query_string++; } if(*query_string == '?') { cgi = 1; *query_string = '\0'; ++query_string; } } if( strcasecmp(method, "GET") == 0 ) { sprintf(path, "htdoc%s", url); if( path[strlen(path)-1] == '/' ) { strcat(path, "index.html"); } } struct stat st; if( stat(path, &st) < 0 ) { //echo_errno(); //404 return (void*)3; } else //case : DIR { if( S_ISDIR(st.st_mode) ) { strcat(path, "index.html"); } else if( (st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) //bin(binary file) { cgi = 1; } else {} //noting to do } printf("!@!#%@^ %s !@%@^%\n", buf); if(cgi) // u+x file { printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!cgi\n"); exe_cgi(sock, method, path, query_string); //cgi mode } else //.jpg .html ... { printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!www\n"); clear_header(sock); //! important! echo_www(sock, path, st.st_size); } close(sock); return 0; }
static void exe_cgi( int sock, const char *method, const char *path, const char *query_string ) { char buf[SIZE]; int content_length = -1; //pipe named by child side int cgi_input[2]; int cgi_output[2]; char method_env[SIZE]; char query_string_env[SIZE]; char content_length_env[SIZE]; char tmpc; memset(buf, '\0', sizeof(buf)); // ! ! ! ! ! M U S T I N I T A R R A Y ! ! ! memset(method_env, '\0', sizeof(method_env)); memset(query_string_env, '\0', sizeof(query_string)); memset(content_length_env, '\0', sizeof(content_length_env)); if(strcasecmp(method, "GET") == 0 ) { clear_header(sock); //"GET" send val by url ,already get } int ret = 0; if(strcasecmp(method, "POST") == 0 ) //different { do { memset(buf, '\0', sizeof(buf)); ret = get_line(sock, buf, sizeof(buf)); if( strncasecmp(buf, "Content-Length: ", 16) == 0) { content_length = atoi(&buf[16]); } }while( (ret > 0) && strcmp(buf, "\n") != 0 ); printf("content_length = %d\n", content_length); if( content_length == -1 ) { echo_errno(sock); return; } } ///////////// (8.11) ///////////////////////////// sprintf(buf, "HTTP/1.0 200 OK\r\n\r\n"); send(sock, buf, strlen(buf), 0); if( pipe(cgi_input) < 0 ) { echo_errno(sock); return; } if( pipe(cgi_output) < 0 ) { echo_errno(sock); return; } pid_t id = fork(); if(id == 0) //child { close(cgi_input[1]); close(cgi_output[0]); dup2(cgi_input[0], 0); dup2(cgi_output[1], 1); sprintf(method_env, "REQUEST_METHOD=%s", method); putenv(method_env); if( strcasecmp(method, "GET") == 0 ) //GET { sprintf(query_string_env, "QUERY_STRING=%s", query_string); putenv(query_string_env); } else //POST { sprintf(content_length_env, "CONTENT_LENGTH=%d", content_length); putenv(content_length_env); } execl(path, path, NULL); //run here , execl wrong exit(1); } else //father { close(cgi_input[0]); close(cgi_output[1]); // dup2(cgi_input[1], 1); // dup2(cgi_output[0], 0); char c = '\0'; int i =0; if( strcasecmp(method, "POST") == 0 ) { for(; i < content_length; ++i) { recv(sock, &c, 1, 0); printf("%c", c); write(cgi_input[1], &c, 1); } } int ret = 0; while( read(cgi_output[0], &c, 1) > 0) { send(sock, &c, 1, 0); } waitpid(id, NULL, 0); } }