簡易httpサーバです.


コードロジックから,簡単なhttpサーバロックに従うフレームワークと,バックグラウンド呼び出しのプロセスを明確に見ることができ,ここで,マルチプロセス,プロセス間通信のパイプ,およびネットワーク通信socketの知識を応用した.
/*************************************************************************
    > File Name: httpd.c
    > Author:Victor Qi 
    > Mail:[email protected] 
    > Created Time: Fri 25 Mar 2016 12:30:13 AM CST
 ************************************************************************/

#include//      
#include//socket.h
#include//   linux                   ,                      
#include//            ,                    
#include
#include//          ,       ,        
#include//      
#include//    ,           ,      pid
#include//      
#include//          
#include//  posix  ,          
#include//        
#include//string.h   


#define  ISspace(x)  isspace((int)(x))
#define  SEVER_SIRING "sever:jdbhttpd/0.1.0\r
"
// void accept_request(int);// http , void bad_request(int);// ,http 400 void cat(int,FILE*);// socket void cannot_execute(int);// cgi 。 void error_die(const char *);// perror 。 void execute_cgi(int ,const char * ,const char * , const char *);// cgi , int get_line(int ,char *,int );// , void headers(int ,const char *);// http void not_found(int);// void sever_file(int ,const char *);// cat 。 int startup(u_short *);// httpd , , , 。 void unimplemented(int);// http method // main -> startup -> accept_request -> execute_cgi. // main() int main(int argc ,char ** argv) { int sever_sock =-1; u_short port =0; int client_sock =-1; struct sockaddr_in client_name; int client_name_len =sizeof(client_name); pthread_t newpthread;// sever_sock = startup(&port);// httpd , print("httpd runing on port %d
"
,port); for(;;) { // client_sock=accept(sever_sock,(struct sockaddr *)&client_name,&client_name_len);// (struct sockaddr *) if(client_sock==-1) { error_die("accept"); } if(pthread_create(&newpthread,NULL,accept_request,client_sock)!=0) perror("pthread_create failed"); } close(sever_sock); return 0; } // 。 void error_die(const char * error) { perror(error); exit(1); } int startup(u_short *port) { int httpd=0; struct sockaddr_in name; if(httpd== -1) { error_die("socket error"); } memset(&name,0,sizeof(name)); name.sin_family =AF_INET; name.sin_port=htons(*port); name.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(httpd,(struct sockaddr*)&name,sizeof(name))<0) error_die("bind error"); if(*port==0) { int namelen=sizeof(name); if(getsockname(httpd,(struct sockaddr *)&name,&namelen))// { error_die("getsockname error"); } *port=ntons(name.sin_port); } if(listen(httpd,5)<0) error_die("listen"); return httpd; } void accept_request(int client) { char buf[1024]; int numchar; char method[255]; char url[255]; cahr path[512]; size_t i,j; int cgi=0; char *query_string=NULL; // numchar=get_line(client,buf,sizeof(buf)); i=0;j=0; while(!ISspace(buf[j])&&(i<sizeof(method)-1)) { method[i]=buf[j]; ++i; ++j; } method[i]='\0'; // if(strcasecmp(method,"GET")&&strcasecmp(method,"POST")) { unimplemented(client); return ; } if(strcasecmp(method,"POST")==0) { cgi=1;// cgi } i=0while(ISspace(buf[j])&&(j<sizeof(buf))) j++; while(!ISspace(buf[j])&&(i<sizeof(url)-1)&&j<sizeof(buf)) { // URL url[i]=buf[j]; i++; j++; } url[i]='\0';// // get if(strcasecmp(method,"GET")==0) { query_string=url; // get ? while((*query_string!='?')&&(*query_string!='\0')) { query_string++; } sprintf(path,"htdocs%s",url);// html htdocs if(path[strlen(path)-1]=='/') strcat(path,"index.html"); if(stat(path,&st)==-1) { // headers while((numchar>0)&&strcmp("
"
,buf)) numchar=get_line(client,buf,sizeof(buf)); not_found(client);// } else { if((st.st_mode&S_IFMT)==S_IFDIR) strcat(path,"index.html"); if((st.st_mode&S_IFUSR)||(st.s_mode&S_IXGRP)||(st.st_mode&S_IXOTH)) cgi=1; // cgi, , cgi if(!cgi) { sever_file(client,path); } else execute_cgi(client,path,method,query_string); } close(client);//http : } } void bad_request(int client) { char buf[1024]; // http sprintf(buf,"HTTP/1.1 400 BAD REQUEST\r
"
); send(client,buf,sizeof(buf),0); sprintf(buf,"Content-type:text/html\r
"
); send(client,buf,sizeof(buf),0); sprintf(buf,"\r
"
); send(client,buf,sizeof(buf),0); sprintf(buf,"

your brower send a bad request,"

); send(client,buf,sizeof(buf),0); sprintf(buf,"such as a POST without a Content-length.\t
"
); send(client,buf,sizeof(buf),0); } void cat(int client,FILE*resourse) { char buf[1024]; // socket fgets(buf,sizeof(buf),strlen(buf),0); while(!feof(resourse)) { // send(client,buf,sizeof(buf),0); fgets(buf,sizeof(buf),resourse); } } void cannot_execute(int client) { // sprintf(buf,"HTTP/1.1 500 Internal Sever Error\r
"
); send(client,buf,strlen(buf),0); sprintf(buf,"Content-type:text/html\r
"
); send(client,buf,strlen(buf),0); sprintf(buf,"\r
"
); send(client,buf,strlen(buf),0); sprintf(buf,"

Error prohibited CGI execution.\r
"

); 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];//pipe , int cgi_input[2]; pid_t pid; int status; int i; char c; int numchar =1; int content_length=-1; buf[0]='A'; buf[1]='\0' // header if(strcasecmp(method,"GET")==0)// strcasecmp , while((numchar>0)&&strcmp("
"
buf)) numchar=get_line(client,buf,sizeof(buf));// else { // numchar=get_line(client,buf,sizeof(buf)); { buf[15]='\0'; if(strcasecmp(buf,"content_length:")==0) content_length=atoi(&(buf[16])); numchar=get_line(client,buf,sizeof(buf)); } if(content_length==-1) { bad_request(client); return;// } } sprintf(buf,"HTTP/1.1 200 OK\r
"
); 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) { char meth_env[255]; char querry_env[255]; char length_env[255]; dup2(cgi_input[0],0);// dup2(cgi_output[1],1);// close(cgi_input[1]); close(cgi_output[0]); // request_method sprintf(meth_env,"REQUEST_METHOD=%s",method); putenv(meth_env); if(strcasecmp(method="GET")==0) { sprintf(querry_env,"QUERRY_STRING=%s",query_string); putenv(querry_env); } else { sprintf(length_env,"Content-type=%d",content_length); putenv(length_env); } execl(path,path,NULL);// execl cgi exit(0); } else { close(cgi_output[1]); close(cgi_input[0]); // if(strcasecmp(method,"POST")==0) for(i=0;i1,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);// , } } int get_line(int sock,cahr*buf,int size) { int i=0; char c='\0'; int n; // buf while((i1)&&(c!='
'
)) { n=recv(sock,&c,1,0); if(n>0) { if(c=='\r') { n=recv(sock,&c,1,MSG_PEEK); if((n>0)&&(c=='
'
)) recv(sock,&c,1,0); else c='
'
; } buf[i]=c; i++; } else c='
'
; } buf[i]='\0'; return i; } void headers(int client ,const char * filename) { char buf[1024]; (void)filename;// strcpy(buf,"HTTP/1.1 200OK\r
"
); send(client,buf,strlen(buf),0); strcpy(buf,SEVER_SIRING); send(client,buf,strlen(buf),0); sprintf(buf,"Content-type:text/html\r
"
); send(client,buf,strlen(buf),0); strcpy(buf,"\r
"
); send(client,buf,strlen(buf),0); } void not_found(int client) { // http 404 char buf[1024]; // http sprintf(buf, "HTTP/1.0 404 NOT FOUND\r
"
); send(client, buf, strlen(buf), 0); // serverName sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); // Content-Type sprintf(buf, "Content-Type: text/html\r
"
); send(client, buf, strlen(buf), 0); // sprintf(buf, "\r
"
); send(client, buf, strlen(buf), 0); // html sprintf(buf, "Not Found\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "

The server could not fulfill\r
"

); send(client, buf, strlen(buf), 0); sprintf(buf, "your request because the resource specified\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "is unavailable or nonexistent.\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "\r
"
); send(client, buf, strlen(buf), 0); } void sever_file(int client,const char * filename) { // FILE *resource = NULL; int numchars = 1; char buf[1024]; buf[0] = 'A'; buf[1] = '\0'; while ((numchars > 0) && strcmp("
"
, buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof (buf)); resource = fopen(filename, "r"); if (resource == NULL) not_found(client); else { // headers(client, filename); cat(client, resource); } fclose(resource); } void unimplemented(int client) { char buf[1024]; sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "Method Not Implemented\r<br>"); send(client, buf, strlen(buf), 0); sprintf(buf, "\r
"
); send(client, buf, strlen(buf), 0); sprintf(buf, "

HTTP request method not supported.\r
"

); send(client, buf, strlen(buf), 0); sprintf(buf, "\r
"
); send(client, buf, strlen(buf), 0); } void PrintSocketAddress(const struct sockaddr *address, FILE *stream) { // Test for address and stream if (address == NULL || stream == NULL) return; void *numericAddress; // Pointer to binary address // Buffer to contain result (IPv6 sufficient to hold IPv4) char addrBuffer[INET6_ADDRSTRLEN]; in_port_t port; // Port to print // Set pointer to address based on address family switch (address->sa_family) { case AF_INET: numericAddress = &((struct sockaddr_in *) address)->sin_addr; port = ntohs(((struct sockaddr_in *) address)->sin_port); break; case AF_INET6: numericAddress = &((struct sockaddr_in6 *) address)->sin6_addr; port = ntohs(((struct sockaddr_in6 *) address)->sin6_port); break; default: fputs("[unknown type]", stream); // Unhandled type return; } // Convert binary to printable address if (inet_ntop(address->sa_family, numericAddress, addrBuffer, sizeof (addrBuffer)) == NULL) fputs("[invalid address]", stream); // Unable to convert else { fprintf(stream, " %s", addrBuffer); if (port != 0) // Zero not valid in any socket addr fprintf(stream, "-%u
"
, port); } } // , //gcc -W -Wall -lsocket -lpthread -o httpd httpd.c linux -lsocket