bool XDataAllocator::Alloc(ULONG_PTR functionStart, DWORD functionSize, ushort pdataCount, ushort xdataSize, SecondaryAllocation* allocation) { XDataAllocation* xdata = static_cast<XDataAllocation*>(allocation); Assert(start != nullptr); Assert(current != nullptr); Assert(current >= start); Assert(xdataSize <= XDATA_SIZE); Assert(pdataCount == 1); // Allocate a new xdata entry if((End() - current) >= XDATA_SIZE) { xdata->address = current; current += XDATA_SIZE; } // try allocating from the free list else if(freeList) { auto entry = freeList; xdata->address = entry->address; this->freeList = entry->next; HeapDelete(entry); } else { xdata->address = nullptr; OUTPUT_TRACE(Js::XDataAllocatorPhase, _u("No space for XDATA.\n")); } #ifndef _WIN32 if (xdata->address) { ClearHead(xdata->address); // mark empty .eh_frame } #endif return xdata->address != nullptr; }
//一个线程处理一个http的请求 void* HandlerRequest(void* arg) { int fd = (int)arg; char buf[SIZE]; int ret = -1; // //测试Getline()函数 // do // { // ret = GetLine(fd, buf, sizeof(buf)); // printf("%s", buf); // }while(ret > 0 && strcmp(buf, "\n") != 0); int nums = -1;//错误码 char method[SIZE/10];//获取请求方法 char url[SIZE]; //比如一个请求行是GET /a/b/index.html http/1.0,那么这个url存储的就是/a/b/index.html if(GetLine(fd, buf, sizeof(buf)) <= 0) { //获取请求行,如果进到这个循环中则错误退出 ret = -1; nums = -1;//错误码 goto end; } int i = 0; int j = 0;//保存buf的下标 //获取请求方法 while(i < sizeof(method)-1 && j < sizeof(buf) && !isspace(buf[j])) { method[i++] = buf[j++]; } method[i] = 0; printf("method = %s\n", method); //过滤掉请求方法和请求资源中间的所有空格 while(j < sizeof(buf) && !isspace(buf[j])) { j++; } i = 0; //获取请求资源 while(i < sizeof(url)-1 && j < sizeof(buf) && !isspace(buf[j])) { url[i++] = buf[j++]; } url[i] = 0; printf("url = %s\n", url); //这个小型的web服务器只处理GET方法和POST方法,对其他方法均不做处理 if(strcasecmp(method, "GET")&& strcasecmp(method, "POST")) { //strcasecmp()函数不分大小写比较 ret = -2; nums = -1; goto end; } //这里区分哪些请求要使用cgi的程序,哪些返回默认程序 //0->非cgi 1->cgi //GET方法无参非cgi,GET方法带参和POST方法都是CGI int cgi = 0;//默认为非CGI方法 char* query_string = NULL;//指向GET方法带参以后的参数部分 if(strcasecmp(method, "POST") == 0) { //只要是POST方法cgi就等于1 cgi = 1; } else { query_string = url; while(*query_string != '\0') { if(*query_string == '?') { *query_string = '\0'; query_string++;//这时候query_string指向?后面的参数部分 cgi = 1; break; } else { query_string++; } } } char path[SIZE]; sprintf(path, "wwwroot%s", url);//sprintf()格式化输出到指定的字符串中 if(path[strlen(path) - 1] == '/') { //如果path现在只是一个路径的话,给他拼上一个默认页面 strcat(path, "index.html");//strcat()字符串拼接 } //判断资源路径是否合法 //Linux下一切皆文件,判断这个路径下的文件是否存在就可以证明这个资源路径是否合法 struct stat st; if(stat(path, &st) != 0) { //文件不存在 ret = -3; nums = -1; goto end; } 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) { //执行cgi程序 ExecCgi(fd, path, method, query_string); } else { ClearHead(fd);//清除头部信息,调用函数完了以后请求行,请求报头,还有空行都全部被清除 EchoWww(fd, path, st.st_size); } end: EchoClient(nums); close(fd); return (void*)ret;//返回退出码 }
void ExecCgi(int fd, const char* path, const char* method, const char*query_string) { int content_lenght = -1;//用于存放POST方法Content-Lenght的长度(参数的长度) //POST和GET方法均要清空头部信息,POST在清空头部信息的时候还要获取参数的长度 if(strcasecmp(method, "GET") == 0) { ClearHead(fd); } else { //POST方法 char buf[SIZE]; int ret = -1; do{ ret = GetLine(fd, buf, sizeof(buf)); if(strncasecmp(buf, "Content-Lenght: ", 16) == 0) { content_lenght = atoi(buf+16);//提取POST方法的参数的长度 } }while(ret > 0 && strcmp(buf, "\n")); if(content_lenght <= 0) { return; } } //将响应行,空行写回去 const char* statusline = "HTTP/1.0 200 OK\r\n";//响应行 const char* blankline = "\r\n";//空行 send(fd, statusline, strlen(statusline), 0); send(fd, blankline, strlen(blankline), 0); //为父子进程之间创建管道进行通信 int input[2]; int output[2]; if(pipe(input) < 0) { return; } if(pipe(output) < 0) { return; } pid_t id = fork(); if(id == 0) { //子进程 close(input[1]); close(output[0]); dup2(input[0], 0);//将标准输入重定向到input[0]中 dup2(output[1], 1);//将标准输出重定向到output[1]中 char method_env[SIZE/10]; char query_string_env[SIZE]; char content_lenght_env[SIZE]; //putenv()函数可以设置环境变量,环境变量是可以被子进程继承的 sprintf(method_env, "METHOD = %s", method); putenv(method_env); if(strcasecmp(method, "GET") == 0) { sprintf(query_string_env, "QUERY_STRING = %s", query_string); putenv(query_string_env); } else { sprintf(content_lenght_env, "CONTENT_LENGHT = %s", content_lenght); putenv(content_lenght_env); } execl(path, path, NULL);//第一个参数表示资源路径在哪里,第二个参数表示命令行应该怎么执行他 //execl函数程序替换成功没有返回值,一旦返回,必定失败 exit(1); } else if(id > 0) { //父进程 close(input[0]); close(output[1]); char c = '\0'; if(strcasecmp(method, "POST") == 0) { //如果是POST方法,我们需要将参数传给子进程,让子进程来处理 int i = 0; for(;i < content_lenght;i++) { recv(fd, &c, 1, 0); write(input[1], &c, 1); } } //子进程处理响应,并将结果写回父进程,父进程需要从管道中取读取数据 while(read(output[0], &c, 1) > 0) { send(fd, &c, 1, 0); } waitpid(id, NULL, 0); close(input[1]); close(output[0]); } else { perror("fork"); return; } }