主要实现了静态文件访问、记录访问日志、文件目录列表
编译脚本:
gcc -Wall fasthttpd.c -o fasthttpd -levent 重启脚本: [cod="shell"] #!/bin/sh ps -ef | grep fasthttpd | grep -v grep | awk '{print $2}' | xargs -t -i kill -9 {} >/dev/null 2>&1 $(pwd)/fasthttpd
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <error.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <dirent.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <time.h> // 引入 libevent 头文件 #include <event.h> #include <evhttp.h> #define HOST_IP "127.0.0.1" #define HOST_PORT 8080 #define REQUEST_TIME_OUT 3 #define DOCUMENT_ROOT "www" #define BUFF_MAX_LEN 20000 #define SERVER_NAME "fasthttpd" #define ACCESS_LOG "logs/access.log" #define DEBUG_LOG "logs/server.log" /* 服务器调试日志 */ #define ERROR_LOG "logs/error.log" /* 服务器错误日志 */ void parser(char *s,char res[][255]); static char *strtoupper( char *s ); static long filesize(const char *filename); //static int file_exists(const char *filename); static void mime_content_type( const char *name, char *ret ); int WriteLog( const char *message, unsigned int message_type ); static int is_dir(const char *filename); static unsigned short g_is_log = 1; static int g_log_fd = 0; static char dir_root[20000]; struct http_req { char method[20]; char request_uri[500]; char http_version[100]; char client_ip[20]; char request_time[2000]; } http_req_line; // 请求处理模块 void http_handler(struct evhttp_request *req, void *arg) { char buff[20000]; char real_path[20000]; char tmp[2000]; char content_type[2000]; int fd; unsigned int http_status_code; time_t timep; struct tm *m; struct stat info; DIR *dir; struct dirent *ptr; struct evbuffer *buf; buf = evbuffer_new(); // 分析URL参数 char *decode_uri = strdup((char*) evhttp_request_uri(req)); //struct evkeyvalq http_query; //evhttp_parse_query(decode_uri, &http_query); //free(decode_uri); sprintf(http_req_line.request_uri,"%s",decode_uri); // 从http头中获取参数,如果是GET传输,这里就可以取得action的值 //const char *request_value = evhttp_find_header(&http_query, "data"); // 返回给浏览器的信息 evhttp_add_header(req->output_headers, "Server", "fasthttp"); //evhttp_add_header(req->output_headers, "Connection", "keep-alive"); evhttp_add_header(req->output_headers, "Connection", "close"); // 取得请求时间 memset(&buff,0,sizeof(buff)); time(&timep); m = localtime(&timep); sprintf(http_req_line.request_time,"%4d-%02d-%02d %02d:%02d:%02d",(1900+m->tm_year),(1+m->tm_mon),m->tm_mday,m->tm_hour,m->tm_min,m->tm_sec); // 获取请求的服务器文件路径 memset(&real_path,0,sizeof(real_path)); sprintf(real_path,"%s/%s%s",dir_root,DOCUMENT_ROOT,http_req_line.request_uri); if(stat(real_path,&info) == -1) { memset(&buff,0,sizeof(buff)); if (errno == ENOENT) { evhttp_send_error(req,404,"HTTP/1.1 404 Not Found"); sprintf(buff,"HTTP/1.1 404 Not Found\t%s\t%s\n",http_req_line.request_uri,http_req_line.request_time); } else if(access(real_path,R_OK) < 0) { evhttp_send_error(req,403,"HTTP/1.1 403 Forbidden"); sprintf(buff,"HTTP/1.1 403 Forbidden\t%s\t%s\n",http_req_line.request_uri,http_req_line.request_time); } else { evhttp_send_error(req,500,"HTTP/1.1 500 Server Error"); sprintf(buff,"HTTP/1.1 500 Server Error\t%s\t%s\n",http_req_line.request_uri,http_req_line.request_time); } evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=UTF-8"); WriteLog(buff,0); } else if(S_ISREG(info.st_mode)) { http_status_code = 200; mime_content_type(real_path,content_type); memset(&tmp,0,sizeof(tmp)); fd = open(real_path,O_RDONLY); read(fd,tmp,filesize(real_path)); close(fd); sprintf(buff,"%s; charset=UTF-8",content_type); // 记录访问日志 memset(&buff,0,sizeof(buff)); sprintf(buff,"HTTP/1.1 200 OK\t%s\t%ld\t%s\n",http_req_line.request_uri,filesize(real_path),http_req_line.request_time); WriteLog(buff,0); evhttp_add_header(req->output_headers, "Content-Type", buff); evbuffer_add_printf(buf, "%s", tmp); // 输出内容到浏览器 evhttp_send_reply(req, HTTP_OK, "OK", buf); } else if(S_ISDIR(info.st_mode)) { http_status_code = 200; memset(&tmp,0,sizeof(tmp)); memset(&buff,0,sizeof(buff)); sprintf(tmp,"<html><head><title>Index of %s</title></head><body><h1>Index of %s</h1><ul><li><a href=\"/\"> Parent Directory</a></li>",http_req_line.request_uri,http_req_line.request_uri); strcat(buff,tmp); if((dir = opendir(real_path)) != NULL) { while((ptr = readdir(dir)) != NULL) { if(strcmp(ptr->d_name,".") == 0 || strcmp(ptr->d_name,"..") == 0) { continue; } memset(&tmp,0,sizeof(tmp)); sprintf(tmp,"%s/%s",real_path,ptr->d_name); if(is_dir(tmp)) { memset(&tmp,0,sizeof(tmp)); sprintf(tmp,"<li><a href=\"%s/\"> %s/</a></li>",ptr->d_name,ptr->d_name); } else { memset(&tmp,0,sizeof(tmp)); sprintf(tmp,"<li><a href=\"%s\"> %s</a></li>",ptr->d_name,ptr->d_name); } strcat(buff,tmp); } closedir(dir); } memset(&tmp,0,sizeof(tmp)); sprintf(tmp,"%s","</ul>"); strcat(buff,tmp); evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=UTF-8"); evbuffer_add_printf(buf, "%s", buff); // 输出内容到浏览器 evhttp_send_reply(req, HTTP_OK, "OK", buf); } // 内存释放 //evhttp_clear_headers(&http_query); evbuffer_free(buf); } int main(int argc, char **argv) { int timeout = 3; getcwd(dir_root,sizeof(dir_root)); struct evhttp *httpd; event_init(); // 绑定本机ip和端口,在访问时一定要把8080端口开放出来 httpd = evhttp_start(HOST_IP, HOST_PORT); if (httpd == NULL) { fprintf(stderr, "Error: Unable to listen on %s:%d\n\n", HOST_IP, HOST_PORT); exit(1); } // 设置请求超时时间 evhttp_set_timeout(httpd, timeout); // 设置请求的处理函数 evhttp_set_gencb(httpd, http_handler, NULL); event_dispatch(); evhttp_free(httpd); return 0; } void parser(char *s,char res[][255]) { int i,j = 0; int n; // char hosts[255]; for (i = 0;s[i] != '\r';i++) /* obtain the first line in http protocol head */ ; s[i] = '\0'; n=i++; for (i = 0,j = 0;i < 3;i++,j++) /* divide the protocol head in blank */ { strcpy(res[j],strsep(&s," ")); } // for(i=n;s[i] != '\r';i++) // { // strcat(hosts,s[i]); // } // // for (i = 0,j = 0;i < 3;i++,j++) /* divide the protocol head in blank */ // { // strcpy(host[j],strsep(&hosts,":")); // } } /** * strtoupper - string to upper * */ static char *strtoupper( char *s ) { int i, len = sizeof(s); for( i = 0; i < len; i++ ) { s[i] = ( s[i] >= 'a' && s[i] <= 'z' ? s[i] + 'A' - 'a' : s[i] ); } return(s); } /** * filesize - get file size */ static long filesize(const char *filename) { struct stat buf; if (!stat(filename, &buf)) { return buf.st_size; } return 0; } /** * file_exists - check file is exist */ //static int file_exists(const char *filename) //{ // struct stat buf; // // if (stat(filename, &buf) < 0) // { // if (errno == ENOENT) // { // return 0; // } // } // return 1; //} /** * Get MIME type header * */ static void mime_content_type( const char *name, char *ret ){ char *dot, *buf; dot = strrchr(name, '.'); /* Text */ if ( strcmp(dot, ".txt") == 0 ){ buf = "text/plain"; } else if ( strcmp( dot, ".css" ) == 0 ){ buf = "text/css"; } else if ( strcmp( dot, ".js" ) == 0 ){ buf = "text/javascript"; } else if ( strcmp(dot, ".xml") == 0 || strcmp(dot, ".xsl") == 0 ){ buf = "text/xml"; } else if ( strcmp(dot, ".xhtm") == 0 || strcmp(dot, ".xhtml") == 0 || strcmp(dot, ".xht") == 0 ){ buf = "application/xhtml+xml"; } else if ( strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0 || strcmp(dot, ".shtml") == 0 || strcmp(dot, ".hts") == 0 ){ buf = "text/html"; /* Images */ } else if ( strcmp( dot, ".gif" ) == 0 ){ buf = "image/gif"; } else if ( strcmp( dot, ".png" ) == 0 ){ buf = "image/png"; } else if ( strcmp( dot, ".bmp" ) == 0 ){ buf = "application/x-MS-bmp"; } else if ( strcmp( dot, ".jpg" ) == 0 || strcmp( dot, ".jpeg" ) == 0 || strcmp( dot, ".jpe" ) == 0 || strcmp( dot, ".jpz" ) == 0 ){ buf = "image/jpeg"; /* Audio & Video */ } else if ( strcmp( dot, ".wav" ) == 0 ){ buf = "audio/wav"; } else if ( strcmp( dot, ".wma" ) == 0 ){ buf = "audio/x-ms-wma"; } else if ( strcmp( dot, ".wmv" ) == 0 ){ buf = "audio/x-ms-wmv"; } else if ( strcmp( dot, ".au" ) == 0 || strcmp( dot, ".snd" ) == 0 ){ buf = "audio/basic"; } else if ( strcmp( dot, ".midi" ) == 0 || strcmp( dot, ".mid" ) == 0 ){ buf = "audio/midi"; } else if ( strcmp( dot, ".mp3" ) == 0 || strcmp( dot, ".mp2" ) == 0 ){ buf = "audio/x-mpeg"; } else if ( strcmp( dot, ".rm" ) == 0 || strcmp( dot, ".rmvb" ) == 0 || strcmp( dot, ".rmm" ) == 0 ){ buf = "audio/x-pn-realaudio"; } else if ( strcmp( dot, ".avi" ) == 0 ){ buf = "video/x-msvideo"; } else if ( strcmp( dot, ".3gp" ) == 0 ){ buf = "video/3gpp"; } else if ( strcmp( dot, ".mov" ) == 0 ){ buf = "video/quicktime"; } else if ( strcmp( dot, ".wmx" ) == 0 ){ buf = "video/x-ms-wmx"; } else if ( strcmp( dot, ".asf" ) == 0 || strcmp( dot, ".asx" ) == 0 ){ buf = "video/x-ms-asf"; } else if ( strcmp( dot, ".mp4" ) == 0 || strcmp( dot, ".mpg4" ) == 0 ){ buf = "video/mp4"; } else if ( strcmp( dot, ".mpe" ) == 0 || strcmp( dot, ".mpeg" ) == 0 || strcmp( dot, ".mpg" ) == 0 || strcmp( dot, ".mpga" ) == 0 ){ buf = "video/mpeg"; /* Documents */ } else if ( strcmp( dot, ".pdf" ) == 0 ){ buf = "application/pdf"; } else if ( strcmp( dot, ".rtf" ) == 0 ){ buf = "application/rtf"; } else if ( strcmp( dot, ".doc" ) == 0 || strcmp( dot, ".dot" ) == 0 ){ buf = "application/msword"; } else if ( strcmp( dot, ".xls" ) == 0 || strcmp( dot, ".xla" ) == 0 ){ buf = "application/msexcel"; } else if ( strcmp( dot, ".hlp" ) == 0 || strcmp( dot, ".chm" ) == 0 ){ buf = "application/mshelp"; } else if ( strcmp( dot, ".swf" ) == 0 || strcmp( dot, ".swfl" ) == 0 || strcmp( dot, ".cab" ) == 0 ){ buf = "application/x-shockwave-flash"; } else if ( strcmp( dot, ".ppt" ) == 0 || strcmp( dot, ".ppz" ) == 0 || strcmp( dot, ".pps" ) == 0 || strcmp( dot, ".pot" ) == 0 ){ buf = "application/mspowerpoint"; /* Binary & Packages */ } else if ( strcmp( dot, ".zip" ) == 0 ){ buf = "application/zip"; } else if ( strcmp( dot, ".rar" ) == 0 ){ buf = "application/x-rar-compressed"; } else if ( strcmp( dot, ".gz" ) == 0 ){ buf = "application/x-gzip"; } else if ( strcmp( dot, ".jar" ) == 0 ){ buf = "application/java-archive"; } else if ( strcmp( dot, ".tgz" ) == 0 || strcmp( dot, ".tar" ) == 0 ){ buf = "application/x-tar"; } else { buf = "application/octet-stream"; } strcpy(ret, buf); } /** * Log message * */ int WriteLog( const char *message,unsigned int message_type ) { if ( !g_is_log ) { fprintf(stderr, "%s", message); return 0; } char g_log_path[2000]; getcwd(g_log_path, sizeof(g_log_path)); strcat(g_log_path,"/"); if(message_type == 0) { strcat(g_log_path,ACCESS_LOG); } else if(message_type == 1) { strcat(g_log_path,DEBUG_LOG); } else if(message_type == 2) { strcat(g_log_path,ERROR_LOG); } else { perror("error message type"); return -1; } if ( (g_log_fd = open(g_log_path, O_RDWR|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1 ) { perror("open log file error"); return -1; } if (write(g_log_fd, message, strlen(message)) == -1) { perror("write log error"); return -1; } return 0; } /** * is_dir - check file is directory * */ static int is_dir(const char *filename){ struct stat buf; if ( stat(filename, &buf) < 0 ){ return -1; } if (S_ISDIR(buf.st_mode)){ return 1; } return 0; }