├── pic ├── 1.png ├── 2.png └── 3.png ├── Makefile ├── htdocs ├── index.html ├── color.cgi └── easycgi.py ├── README.md └── httpd.c /pic/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hunterzhao/EasyHttp/HEAD/pic/1.png -------------------------------------------------------------------------------- /pic/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hunterzhao/EasyHttp/HEAD/pic/2.png -------------------------------------------------------------------------------- /pic/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hunterzhao/EasyHttp/HEAD/pic/3.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | httpd : httpd.o 2 | cc -o -pthread httpd httpd.o 3 | httpd.o: httpd.c 4 | cc -c httpd.c 5 | -------------------------------------------------------------------------------- /htdocs/index.html: -------------------------------------------------------------------------------- 1 | 2 |
welcome to EasyHttp
5 |your browser send a bad request, "); 145 | send(client,buf,strlen(buf),0); 146 | sprintf(buf,"such as a POST without a content-Length.\r\n"); 147 | send(client,buf,strlen(buf),0); 148 | } 149 | 150 | /*put the entire content of a file out on a socket 151 | * parameters: the client socket descriper 152 | * FILE pointer for the file to cat 153 | * FILE pointer for the file to cat 154 | */ 155 | 156 | void cat(int client ,FILE *resource) 157 | { 158 | char buf[1024]; 159 | 160 | //read the content of file into socket 161 | fgets(buf,sizeof(buf),resource); 162 | while(!feof(resource)) 163 | { 164 | send(client,buf,strlen(buf),0); 165 | fgets(buf,sizeof(buf),resource); 166 | } 167 | printf("send index.html\n"); 168 | } 169 | 170 | /* 171 | * inform the client cgi could not run 172 | */ 173 | 174 | void cannot_execute(int client) 175 | { 176 | char buf[1024]; 177 | 178 | sprintf(buf,"HTTP/1.0 500 Internal Server Error\r\n"); 179 | send(client,buf,strlen(buf),0); 180 | sprintf(buf,"Content-type: text/html\r\n"); 181 | send(client,buf,strlen(buf),0); 182 | sprintf(buf,"\r\n"); 183 | send(client,buf,strlen(buf),0); 184 | sprintf(buf,"
Error prohibited CGI execution
\r\n"); 185 | send(client,buf,strlen(buf),0); 186 | } 187 | 188 | /* 189 | * print out the error message whith perror() 190 | */ 191 | 192 | void error_die(const char *sc) 193 | { 194 | perror(sc); 195 | exit(1); 196 | } 197 | 198 | /* 199 | *execute the CGI script will need ro set environment variable as appropriate 200 | Parameters:client socket descriptor 201 | path to the CGI script 202 | */ 203 | void execute_cgi(int client,const char *path,const char *method,const char *query_string) 204 | { 205 | char buf[1024]; 206 | int cgi_output[2]; 207 | int cgi_input[2]; 208 | // int cgi_pip[2]; 209 | pid_t pid; 210 | int status; 211 | int i; 212 | char c; 213 | int numchars=1; 214 | int content_length=-1; 215 | 216 | buf[0]='A';buf[1]='\0'; 217 | if(strcasecmp(method,"GET")==0) 218 | //将所有的http header 读取并丢弃 219 | while((numchars>0) && strcmp("\n",buf)){ 220 | //memset( buf, 0, strlen( buf ) ); 221 | numchars=get_line(client,buf,strlen(buf)); 222 | } 223 | else 224 | { 225 | //post 找出content-length 226 | numchars=get_line(client,buf,strlen(buf)); 227 | while((numchars >0) && strcmp("\n",buf)) 228 | { 229 | //利用\0进行分割 获取15个字符长度的字符串 230 | buf[15]='\0'; 231 | if(strcasecmp(buf,"Content-Length:")==0){ 232 | content_length=atoi(&buf[16]); 233 | } 234 | numchars =get_line(client,buf,strlen(buf)); 235 | } 236 | //没有找到content_length 237 | if(content_length==-1){ 238 | bad_request(client); 239 | return; 240 | } 241 | } 242 | 243 | //correct 244 | sprintf(buf,"HTTP/1.0 200 OK\r\n");//已经清空了buf的内容 245 | send(client,buf,strlen(buf),0); 246 | // sprintf(buf,"Content-type: text/html\r\n"); 247 | // send(client,buf,strlen(buf),0); 248 | // sprintf(buf,"\r\n"); 249 | // send(client,buf,strlen(buf),0); 250 | 251 | //传送系统的缓冲区空间不够保存需传送的数据,除非套接口处于非阻塞I/O方式,否则send()将阻塞 所以导致一直处于pending的状态 252 | 253 | //close(client); 关闭了连接 导致发出reset信号 254 | //建立管道 255 | if(pipe(cgi_output)<0){ 256 | cannot_execute(client); 257 | return; 258 | } 259 | 260 | if(pipe(cgi_input)<0){ 261 | cannot_execute(client); 262 | return; 263 | } 264 | 265 | if((pid=fork())<0){ 266 | cannot_execute(client); 267 | return; 268 | } 269 | 270 | if(pid==0) //子进程 271 | { 272 | char meth_env[255]; 273 | char query_env[255]; 274 | char length_env[255]; 275 | 276 | dup2(cgi_output[1],1);//stdout 重定向到cgi_out的写入端 277 | dup2(cgi_input[0],0);//stdin 重定向到cgi_input的读取端 278 | close(cgi_output[0]); 279 | close(cgi_input[1]); 280 | sprintf(meth_env,"REQUEST_METHOD=%s",method); 281 | putenv(meth_env); 282 | if(strcasecmp(method,"GET")==0){ 283 | snprintf(query_env,"QUERY_STRING=%s",query_string); 284 | putenv(query_env); 285 | } 286 | else{ //post 287 | sprintf(length_env,"CONTENT_LENGTH=%d",content_length); 288 | } 289 | if(execl(path,path,NULL)<0) 290 | { 291 | printf("execl error\n"); 292 | } 293 | printf("come on cgi
\n"); 294 | exit(0); 295 | }else{ //父进程 296 | // close(cgi_output[1]); 297 | // close(cgi_input[0]); 298 | if(strcasecmp(method,"POST")==0) 299 | //接受post过来的数据 300 | for(i=0;iThe server could not fulfill\r\n"); 331 | send(client, buf, strlen(buf), 0); 332 | sprintf(buf, "your request because the resource specified\r\n"); 333 | send(client, buf, strlen(buf), 0); 334 | sprintf(buf, "is unavailable or nonexistent.\r\n"); 335 | send(client, buf, strlen(buf), 0); 336 | sprintf(buf, "\r\n"); 337 | send(client, buf, strlen(buf), 0); 338 | } 339 | 340 | int get_line(int sock, char *buf, int size) 341 | { 342 | int i = 0; 343 | char c = '\0'; 344 | int n; 345 | 346 | while ((i < size - 1) && (c != '\n')) 347 | { 348 | n = recv(sock, &c, 1, 0); 349 | /* DEBUG printf("%02X\n", c); */ 350 | if (n > 0) 351 | { 352 | if (c == '\r') 353 | { 354 | n = recv(sock, &c, 1, MSG_PEEK); 355 | /* DEBUG printf("%02X\n", c); */ 356 | if ((n > 0) && (c == '\n')) 357 | recv(sock, &c, 1, 0); 358 | else 359 | c = '\n'; 360 | } 361 | buf[i] = c; 362 | i++; 363 | } 364 | else 365 | c = '\n'; 366 | } 367 | buf[i] = '\0'; 368 | 369 | return(i); 370 | } 371 | 372 | void header(int client,const char *filename) 373 | { 374 | char buf[1024]; 375 | (void)filename; 376 | 377 | strcpy(buf,"HTTP/1.0 200 OK\r\n"); 378 | send(client,buf,strlen(buf),0); 379 | //服务器信息 380 | strcpy(buf,SERVER_STRING); 381 | send(client,buf,strlen(buf),0); 382 | strcpy(buf,"Content-Type: text/html\r\n"); 383 | send(client,buf,strlen(buf),0); 384 | strcpy(buf,"\r\n"); 385 | send(client,buf,strlen(buf),0); 386 | printf("send head\n"); 387 | } 388 | 389 | void server_file(int client,const char *filename) 390 | { 391 | FILE *resource =NULL; 392 | int numchars= 1; 393 | char buf[1024]; 394 | 395 | //丢弃header 396 | buf[0]='A'; buf[1]='\0'; 397 | while((numchars >0) && strcmp("\n", buf) ) 398 | numchars=get_line(client,buf,sizeof(buf)); 399 | //打开server的文件 400 | resource = fopen(filename,"r"); 401 | if(resource ==NULL) 402 | not_found(client); 403 | else 404 | { 405 | header(client,filename); 406 | cat(client,resource); 407 | 408 | } 409 | fclose(resource); 410 | } 411 | 412 | int startup(u_short *port) 413 | { 414 | int httpd = 0; 415 | struct sockaddr_in name; 416 | 417 | httpd=socket(PF_INET,SOCK_STREAM,0); 418 | if(httpd== -1) 419 | error_die("socket"); 420 | memset(&name,0,sizeof(name)); 421 | name.sin_family =AF_INET; 422 | name.sin_port = htons(*port); 423 | name.sin_addr.s_addr=htonl(INADDR_ANY); 424 | if(bind(httpd,(struct sockaddr *)&name,sizeof(name))<0) 425 | error_die("bind"); 426 | 427 | if(*port ==0 ) 428 | { 429 | int namelen=sizeof(name); 430 | if(getsockname(httpd,(struct sockaddr*)& name , &namelen)==-1) 431 | error_die("getsockname"); 432 | *port=ntohs(name.sin_port); 433 | } 434 | 435 | if(listen(httpd,5)<0) 436 | error_die("listen"); 437 | return(httpd); 438 | } 439 | 440 | void unimplemented(int client) 441 | { 442 | char buf[1024]; 443 | sprintf(buf,"HTTP/1.0 501 Method Not Implemented\r\n"); 444 | send(client,buf,strlen(buf),0); 445 | 446 | sprintf(buf,SERVER_STRING); 447 | send(client,buf,strlen(buf),0); 448 | sprintf(buf,"Content-Type: Text/html\r\n"); 449 | send(client,buf,strlen(buf),0); 450 | sprintf(buf,"\r\n"); 451 | send(client,buf,strlen(buf),0); 452 | sprintf(buf,"
HTTP request method not supported.\r\n"); 457 | send(client,buf,strlen(buf),0); 458 | sprintf(buf,"\r\n"); 459 | send(client,buf,strlen(buf),0); 460 | } 461 | 462 | int main(void) 463 | { 464 | int server_sock =-1; 465 | u_short port=0; 466 | int client_sock=-1; 467 | struct sockaddr_in client_name; 468 | int client_name_len=sizeof(client_name); 469 | pthread_t newthread; 470 | 471 | server_sock =startup(&port); 472 | printf("http running on port %d\n",port); 473 | 474 | while(1) 475 | { 476 | client_sock =accept(server_sock,(struct sockaddr *)&client_name,&client_name_len); 477 | if(client_sock ==-1) 478 | error_die("accept"); 479 | // accept_request(client_sock); 480 | if(pthread_create(&newthread,NULL,accept_request,client_sock)!=0) 481 | perror("pthread_create"); 482 | //close(client_sock); 483 | } 484 | 485 | close(server_sock); 486 | return(0); 487 | } 488 | --------------------------------------------------------------------------------