#include
#include
#include
#define _DEF_PAGE_ "index.html"
#define _SIZE_ 1024
typedef struct bf
{
char _buf[_SIZE_];
int _fd;
int _cgi;
char _method[_SIZE_/2];
char _path[_SIZE_];
union
{
char* _query_string;
int _st_size;
};
}bf_t,*bf_p;
void printLog(const char* const str,const char* const fun,int line);
void usage(const char* const proc);
int startup(char* ip,int port);
void echo_error(int sock,int eno);
int get_line(int sock,char* buf,int size);
void clear_head(int sock);
void execute_cgi(bf_p bf);
void echo_html(bf_p bf);
void accept_request(void* ptr);
#include"http.h"
void printLog(const char* const str,const char* const fun,int line)
{
printf("%s:%s:%d\n",str,fun,line);
}
void usage(const char* const proc)
{
assert(proc);
printLog(proc,__FUNCTION__,__LINE__);
}
int startup(char* ip,int port)
{
assert(ip);
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
int opt=1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(port);
if(strncmp(ip,"any",3)==0)
{
local.sin_addr.s_addr= INADDR_ANY;
}
else
{
local.sin_addr.s_addr=inet_addr(ip);
}
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
if(listen(sock,5)<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
return sock;
}
void response_err(int sock,int eno)
{
char state_line[_SIZE_];
char err_des[30];//error description
memset(state_line,'\0',sizeof(state_line));
memset(err_des,'\0',sizeof(err_des));
switch(eno)
{
case 404:
strcpy(err_des,"Not Found");
break;
default:
break;
}
sprintf(state_line,"HTTP/1.0 %d %s\r\n\r\n",eno,err_des);
send(sock,state_line,strlen(state_line),0);
}
void echo_error(int sock,int eno)
{
switch(eno)
{
case 404:
response_err(sock,eno);
break;
case 403:
break;
default:
break;
}
return;
}
int get_line(int sock,char* buf,int size)
{
assert(buf);
int i=0;
ssize_t _s=-1;
char ch='\0';
while(i0&&ch=='\n')
recv(sock,&ch,1,0);
}
}
buf[i++]=ch;
}
else
{
buf[i++]='\n';
break;
}
}
// printf("endddddddddddd");
buf[i]='\0';
return i;
}
void clear_head(int sock)
{
char buf[_SIZE_];
buf[0]='\0';
ssize_t _s=1;
while(_s>0&&strcmp(buf,"\n")!=0)
{
_s=get_line(sock,buf,sizeof(buf));
}
}
void execute_cgi(bf_p bf)
{
int content_len=0;//post method content-length
ssize_t _s=-1;
char buf[_SIZE_];
char method_env[30];
char query_env[_SIZE_];
char content_len_env[30];
memset(buf,'\0',sizeof(buf));
memset(method_env,'\0',sizeof(method_env));
memset(query_env,'\0',sizeof(query_env));
memset(content_len_env,'\0',sizeof(content_len_env));
//if method=get,query_string not null,if method=post,query_string is null
sprintf(method_env,"REQUEST_METHOD=%s",bf->_method);
putenv(method_env);
//printf("method:%s,path:%s,query_string:%s\n",method,path,query_string);
if(strcasecmp(bf->_method,"GET")==0)
{
sprintf(query_env,"QUERY_STRING=%s",bf->_query_string);
putenv(query_env);
}
else
{
while((_s=get_line(bf->_fd,buf,sizeof(buf)))>1)
{
if(strncasecmp(buf,"Content-Length:",15)==0)
{
//printf("length::::::::::%s\n",buf);
content_len=atoi(buf+15);
// break;//not break!!!!!!!!!!!!!!!
}
}
//printf("Content-Length:%d\n",content_len);
sprintf(content_len_env,"CONTENT_LENGTH=%d",content_len);
putenv(content_len_env);
}
//printf("ready env\n");
//ready
pid_t id;
int in_fds[2];
int out_fds[2];
if(pipe(in_fds)<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
if(pipe(out_fds)<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
if((id=fork())<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
else if(id==0)//child
{
close(in_fds[1]);
close(out_fds[0]);
dup2(in_fds[0],0);
dup2(out_fds[1],1);
execl(bf->_path,bf->_path,NULL);
close(in_fds[0]);
close(out_fds[1]);
}
else//father
{
close(in_fds[0]);
close(out_fds[1]);
char vals[1024];
memset(vals,'\0',sizeof(vals));
ssize_t _s=-1;
int index=0;
char ch='0';
if(strcasecmp(bf->_method,"POST")==0)
{
while(index_fd,&ch,1)>0)
{
vals[index++]=ch;
}
}
// printf("%s\n",vals);
write(in_fds[1],vals,strlen(vals));
// printf("ffffffffffff");
memset(bf->_buf,'\0',sizeof(bf->_buf));
char* status_line="HTTP/1.0 200 ok\r\n\r\n";
sprintf(bf->_buf,status_line,strlen(status_line));
// printf("response\n");
int i=strlen(bf->_buf);
while(read(out_fds[0],&ch,1)>0)
{
bf->_buf[i++]=ch;
}
bf->_buf[i]='\0';
close(in_fds[1]);
close(out_fds[0]);
waitpid(id);
}
}
void echo_html(bf_p bf)
{
char* status_line="HTTP/1.0 200 ok\r\n\r\n";
sprintf(bf->_buf,status_line,strlen(status_line));
//printf("%s!!!!!!!!!!!!!!!!\n",bf->_buf);
}
void accept_request(void* ptr)
{
bf_p bf=(bf_p)ptr;
int ret=-1;
int i=0,j=0;
char url[_SIZE_];
memset(bf->_method,'\0',sizeof(bf->_method));
memset(bf->_buf,'\0',sizeof(bf->_buf));
memset(bf->_path,'\0',sizeof(bf->_path));
memset(url,'\0',sizeof(url));
if(get_line(bf->_fd,bf->_buf,sizeof(bf->_buf))==0)
{
printLog("errno",__FUNCTION__,__LINE__);
return;
}
i=j=0;
while('\0'!=bf->_buf[i]&&!isspace(bf->_buf[i])&&i_buf)&&j_method)-1)
{
bf->_method[j]=bf->_buf[i];//get method
++i;
++j;
}
bf->_method[j]='\0';
//printf("method:%s\n",bf->_method);
j=0;
while('\0'!=bf->_buf[i]&&isspace(bf->_buf[i]))
{
++i;
}
while('\0'!=bf->_buf[i]&&!isspace(bf->_buf[i])&&i_buf)&&j_buf[i];
++j;
++i;
}
url[j]='\0';
//printf("url:%s\n",url);
bf->_cgi=0;
if(strcasecmp(bf->_method,"POST")!=0&&strcasecmp(bf->_method,"GET")!=0)
{
echo_error(bf->_fd,500);
return;
}
bf->_query_string=NULL;
if(strcasecmp(bf->_method,"POST")==0)
{
bf->_cgi=1;
bf->_query_string=NULL;
}
if(strcasecmp(bf->_method,"GET")==0)
{
bf->_query_string=url;
while(*bf->_query_string!='\0'&&*bf->_query_string!='?')
{
++bf->_query_string;
}
//printf("query_string::::::::::::::::\n");
if(*bf->_query_string=='?')
{
*bf->_query_string='\0';
bf->_cgi=1;
++bf->_query_string;
}
}
if(strcmp(url,"/")==0)
sprintf(bf->_path,"htdocs%s",url);
else
strcpy(bf->_path,url+1);
struct stat st;
if(stat(bf->_path,&st)<0)//not exist
{
echo_error(bf->_fd,404);
return;
}
else if(S_IFDIR&st.st_mode)//dir
{
if(strcmp(bf->_path,"htdocs/")!=0)
strcpy(bf->_path,"htdocs/");
strcat(bf->_path,_DEF_PAGE_);
}
else if((st.st_mode&S_IXUSR)||(st.st_mode&S_IXGRP)||(st.st_mode&S_IXOTH))
{
bf->_cgi=1;
}
//printf("%d:%s\n",bf->_cgi,bf->_path);
if(bf->_cgi)
{
execute_cgi(bf);
}
else
{
clear_head(bf->_fd);
bf->_st_size=st.st_size;
echo_html(bf);
}
}
//main.c
#include"http.h"
int main(int argc,char* argv[])
{
if(argc!=3)
{
usage(argv[0]);
return 1;
}
char* ip=argv[1];
int port=atoi(argv[2]);
int listen_sock=startup(ip,port);
struct sockaddr_in client;
socklen_t len=sizeof(client);
int epo_fd=epoll_create(256);
if(epo_fd<0)//success:not 0 fd/error:-1
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
return -1;
}
bf_p fd_bf=(bf_p)malloc(sizeof(bf_t));
memset(fd_bf->_buf,'\0',sizeof(fd_bf->_buf));
fd_bf->_fd=listen_sock;
struct epoll_event ev;
ev.events=EPOLLIN;
ev.data.fd=listen_sock;
if(epoll_ctl(epo_fd,EPOLL_CTL_ADD,listen_sock,&ev)<0)//success:0 fail:-1
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
return -1;
}
struct epoll_event evfds[_SIZE_];//_SIZE_ 1024
int _timeout=5000;
int ret=-1;
int i=0;
while(1)
{
switch((ret=epoll_wait(epo_fd,evfds,_SIZE_,_timeout)))
{
case -1://error
printLog(strerror(errno),__FUNCTION__,__LINE__);
break;
case 0://time out
printf("time out...\n");
break;
default://normal
{
for(i=0;i_buf,'\0',sizeof(_bf->_buf));
_bf->_fd=new_sock;
ev.events=EPOLLIN;
ev.data.ptr=_bf;
epoll_ctl(epo_fd,EPOLL_CTL_ADD,new_sock,&ev);
}
else if(((bf_p)(evfds[i].data.ptr))->_fd>0&&evfds[i].events&EPOLLIN)
{
accept_request(evfds[i].data.ptr);
ev.events=EPOLLOUT;
ev.data.ptr=evfds[i].data.ptr;
epoll_ctl(epo_fd,EPOLL_CTL_MOD,((bf_p)(evfds[i].data.ptr))->_fd,&ev);
}
else if(((bf_p)(evfds[i].data.ptr))->_fd>0&&evfds[i].events&EPOLLOUT)
{
//printf("OOOOOOOOOOOOOOOut\n");
bf_p _bf=(bf_p)evfds[i].data.ptr;
if(_bf->_cgi)//cgi=1
{
send(_bf->_fd,_bf->_buf,strlen(_bf->_buf),0);
}
else
{
char* path=_bf->_path;
int fd=open(path,O_RDONLY);
if(fd<0)
{
printLog(strerror(errno),__FUNCTION__,__LINE__);
exit(1);
}
send(_bf->_fd,_bf->_buf,strlen(_bf->_buf),0);
if(sendfile(_bf->_fd,fd,NULL,_bf->_st_size)<0)
{
printf("error");
}
close(fd);
}
epoll_ctl(epo_fd,EPOLL_CTL_DEL,_bf->_fd,NULL);
close(_bf->_fd);
free(_bf);
}
}
break;
}
}
}
return 0;
}