libevent实现http server

 libevent 是一个事件触发的网络库,适用于 windows、linux、bsd 、Android 等多种平台,内部使用 select、epoll、kqueue 、完成端口等系统调用管理事件机制。著名分布式缓存软件 memcached 也是 libevent based 。

    最近在学习 libevent ,之前基于 libevent 实现了一个 http client ,没有用到 bufferevent 。这次实现了一个 http server ,很简单,只支持 GET 方法,不支持 Range 请求,但完全自己实现,是一个完整可用的示例。这里使用 libevent-2.1.3-alpha 。

    我关于 libevent 的其它文章,列在这里供参考:

  • libevent实现http client
  • libevent实现echoclient
  • libevent http client
  • libevent 在 Android 上的一个改进

    使用 libevent 实现一个 http server ,有这么几个步骤:

  1. 监听
  2. 启动事件循环
  3. 接受连接
  4. 解析 http 请求
  5. 回应客户端

    关于监听, libevent 提供了 evconnlistener ,使用起来非常简单,通过一些设置,调用 evconnlistener_new_bind 即可完成一个服务端 socket 的创建,可以参考官方文档Connection Listeners 。下面是启动 server 的代码:

[cpp]  view plain copy
  1. int start_http_server(struct event_base *evbase)  
  2. {  
  3.     int bind_times = 0;  
  4.     struct sockaddr_in sin;  
  5.   
  6.     memset(&sin, 0, sizeof(sin));  
  7.     sin.sin_family = AF_INET;  
  8. #ifdef WIN32  
  9.     sin.sin_addr.S_un.S_addr = inet_addr(g_host);  
  10. #else  
  11.     sin.sin_addr.s_addr = inet_addr(g_host);  
  12. #endif  
  13.     sin.sin_port = htons(g_port);  
  14.   
  15. trybind:  
  16.     g_listener = evconnlistener_new_bind(  
  17.                 evbase, _accept_connection, 0,  
  18.                 LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_DEFERRED_ACCEPT, -1,  
  19.                 (struct sockaddr*)&sin, sizeof(sin));  
  20.     if (!g_listener)  
  21.     {  
  22.         if(bind_times++ >=3)  
  23.         {  
  24.             printf("couldn\'t create listener\n");  
  25.             return 1;  
  26.         }  
  27.         else  
  28.         {  
  29.             sin.sin_port = 0;  
  30.             goto trybind;  
  31.         }  
  32.     }  
  33.     else if(bind_times > 0)  
  34.     {  
  35.         socklen_t len = sizeof(sin);  
  36.         getsockname(evconnlistener_get_fd(g_listener),  
  37.                     (struct sockaddr*)&sin, &len);  
  38.         g_port = ntohs(sin.sin_port);  
  39.     }  
  40.     evconnlistener_set_error_cb(g_listener, _accept_error_cb);  
  41.   
  42.     return 0;  
  43. }  

    关于事件循环,event_base_new 可以创建一个 event_base 实例, event_base_loop 可以进入事件循环。下面是 main() 函数中关于事件循环的代码:

[cpp]  view plain copy
  1. g_evbase = event_base_new();  
  2.   
  3. if( 0 == start_http_server(g_evbase) )  
  4. {  
  5.     event_base_loop(g_evbase, EVLOOP_NO_EXIT_ON_EMPTY);  
  6.     printf("httpserver exit now.\n");  
  7. }  
  8. else  
  9. {  
  10.     printf("httpserver, start server failed\n");  
  11. }  
  12.   
  13. event_base_free(g_evbase);  
    上面的代码中,启动事件循环时传递了一个标志 EVLOOP_NO_EXIT_ON_EMPTY ,对于服务器程序,这是必须的,否则在没有待处理事件时,事件循环会立即退出。

    通过给 evconnlistener 设置一些回调,就可以接受连接、处理错误。下面是相关代码:

[cpp]  view plain copy
  1. static void _accept_connection(struct evconnlistener *listener,  
  2.                                evutil_socket_t fd, struct sockaddr *addr  
  3.                                , int socklen, void * ctx)  
  4. {  
  5.     char address[64];  
  6.     struct http_connection *conn;  
  7.     struct sockaddr_in sin;  
  8.     short port = 0;  
  9.     /* get address and port*/  
  10.     memcpy(&sin, addr, sizeof(sin));  
  11.     sprintf(address, "%s", inet_ntoa(sin.sin_addr));  
  12.     port = ntohs(sin.sin_port);  
  13. #ifdef HTTP_SERVER_DEBUG  
  14.     printf("httpserver, accept one connection from %s:%d\n", address, port);  
  15. #endif  
  16.     conn = new_http_connection(evconnlistener_get_base(listener),  
  17.                                fd,  
  18.                                address,  
  19.                                port);  
  20. }  
  21.   
  22. static void _accept_error_cb(struct evconnlistener *listener, void *ctx)  
  23. {  
  24.     int err = EVUTIL_SOCKET_ERROR();  
  25.     printf("httpserver, got an error %d (%s) on the listener.\n"  
  26.               , err, evutil_socket_error_to_string(err));  
  27. }  
    在创建调用 evconnlistener_new_bind 时我们传入了 _accept_connection 函数,当有连接进来时,_accept_connection 调用 new_http_connection 函数来处理。错误处理回调 _accept_error_cb 是通过 evconnlistener_set_error_cb 设置的,在上面的错误处理回调函数中,我们仅仅是输出了一条日志。

    解析 http 请求,这里还是使用 《使用http_parser解析URL》一文中提到的http_parser 。先看下 new_http_connection 函数的实现:

[cpp]  view plain copy
  1. struct http_connection * new_http_connection(  
  2.                                              struct event_base *evbase,  
  3.                                              evutil_socket_t fd,  
  4.                                              char *address, int port)  
  5. {  
  6.     struct http_connection * conn = (struct http_connection*)malloc(sizeof(struct http_connection));  
  7.     conn->evbase = evbase;  
  8.     conn->fd = fd;  
  9.     conn->peer_address = strdup(address);  
  10.     conn->peer_port = port;  
  11.     conn->tv_timeout.tv_sec = 10;  
  12.     conn->tv_timeout.tv_usec = 0;  
  13.   
  14.     conn->bev = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE);  
  15.     bufferevent_setcb(conn->bev, _read_callback, _write_callback, _event_callback, conn);  
  16.     bufferevent_enable(conn->bev, EV_READ|EV_TIMEOUT);  
  17.     bufferevent_set_timeouts(conn->bev, &conn->tv_timeout, &conn->tv_timeout);  
  18.   
  19.     conn->parser_settings.on_message_begin = onHttpMessageBegin;  
  20.     conn->parser_settings.on_url = onHttpUrl;  
  21.     conn->parser_settings.on_header_field = onHttpHeaderField;  
  22.     conn->parser_settings.on_header_value = onHttpHeaderValue;  
  23.     conn->parser_settings.on_headers_complete = onHttpHeadersComplete;  
  24.     conn->parser_settings.on_body = onHttpBody;  
  25.     conn->parser_settings.on_message_complete = onHttpMessageComplete;  
  26.     conn->cur_header_tag = 0;  
  27.     conn->cur_tag_cap = 0;  
  28.     conn->cur_tag_size = 0;  
  29.     conn->cur_header_value = 0;  
  30.     conn->cur_value_cap = 0;  
  31.     conn->cur_value_size = 0;  
  32.     conn->header_tags = 0;  
  33.     conn->header_size = 0;  
  34.     conn->header_capacity = 0;  
  35.     conn->header_values = 0;  
  36.     conn->fp = 0;  
  37.     conn->data_size = 0;  
  38.     conn->remain = 0;  
  39.     conn->method = 0;  
  40.     conn->path = 0;  
  41.     conn->query_string = 0;  
  42.     conn->status_code = 0;  
  43.   
  44.     conn->parser.data = conn;  
  45.     http_parser_init(&conn->parser, HTTP_REQUEST);  
  46.   
  47.     return conn;  
  48. }  
    上面的代码根据传入的 socket 描述符和 event_base 完成了传入连接的配置工作。主要有几部分:

  • 创建 bufferevent
  • 设置读写回调
  • 配置 http_parser_setting ,主要是一些回调函数,http_parser 分析数据后酌情调用
  • 初始化 http_parser,调用 http_parser_init,注意传入类型是 HTTP_REQUEST

    上面代码中的结构体 struct http_connection 保存了一个连接相关的所有数据,其定义如下:

[cpp]  view plain copy
  1. struct http_connection {  
  2.     struct http_parser parser;  
  3.     struct http_parser_settings parser_settings;  
  4.     char *cur_header_tag;  
  5.     int cur_tag_cap;  
  6.     int cur_tag_size;  
  7.     char *cur_header_value;  
  8.     int cur_value_cap;  
  9.     int cur_value_size;  
  10.     char buffer[BUFFER_SIZE];  
  11.   
  12.     struct event_base *evbase;  
  13.     evutil_socket_t fd;  
  14.     struct bufferevent *bev;  
  15.     struct timeval tv_timeout;  
  16.   
  17.     char *peer_address;  
  18.     int peer_port;  
  19.     int state;  
  20.     unsigned write_enabled:1;  
  21.     unsigned user_stop:1;  
  22.   
  23.     /* request info */  
  24.     const char * method;  
  25.     char * path;  
  26.     char * query_string;  
  27.     char version[4];  
  28.     char **header_tags;  
  29.     char **header_values;  
  30.     int header_capacity;  
  31.     int header_size;  
  32.   
  33.     /* response info */  
  34.     FILE *fp;  
  35.     long remain;  
  36.     int data_size;  
  37.     int status_code;  
  38. };  
    需要说明的是,这里只是个示例, http 请求、响应、连接处理全部放在了一起,看起来比较方面。

    关于 http 头部、数据解析, http_parser 会为我们做好一切,我们只要保存即可。

    关于 http 响应,需要我们自己构建状态行、必要的头部信息(如 Content-Length )。

    所有这些,请参考文后的代码。

    回应客户端的这里使用 bufferevent socket 。 libevent 抽象了一种缓冲机制,来给大多数应用场景提供方便,关于 bufferevents ,请参考官方文档(http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html)。

    使用 bufferevent socket 处理连接非常简单,只需要设置读写回调即可,这在上面已经提到,不再赘述。

    到这里为止,关于一个 http server 的所有事情就说完了。下面是 http_connection.c 的所有代码( new_http_connection 函数的代码在前面),可以正常运行。为使代码比较清晰,这里关于错误、封装、解耦等都简化处理了。

[cpp]  view plain copy
  1. #define HTTP_HEADER_BEGIN        0x1  
  2. #define HTTP_HEADER_COMPLETE     0x2  
  3. #define HTTP_MESSAGE_BEGIN       0x4  
  4. #define HTTP_MESSAGE_COMPLETE    0x8  
  5.   
  6.   
  7. #define STATUS_CODE(code, str) case code: return str;  
  8.   
  9. static const char * _status_string(int code)  
  10. {  
  11.     switch(code)  
  12.     {  
  13.     STATUS_CODE(100, "Continue")  
  14.     STATUS_CODE(101, "Switching Protocols")  
  15.     STATUS_CODE(102, "Processing")                 // RFC 2518) obsoleted by RFC 4918  
  16.     STATUS_CODE(200, "OK")  
  17.     STATUS_CODE(201, "Created")  
  18.     STATUS_CODE(202, "Accepted")  
  19.     STATUS_CODE(203, "Non-Authoritative Information")  
  20.     STATUS_CODE(204, "No Content")  
  21.     STATUS_CODE(205, "Reset Content")  
  22.     STATUS_CODE(206, "Partial Content")  
  23.     STATUS_CODE(207, "Multi-Status")               // RFC 4918  
  24.     STATUS_CODE(300, "Multiple Choices")  
  25.     STATUS_CODE(301, "Moved Permanently")  
  26.     STATUS_CODE(302, "Moved Temporarily")  
  27.     STATUS_CODE(303, "See Other")  
  28.     STATUS_CODE(304, "Not Modified")  
  29.     STATUS_CODE(305, "Use Proxy")  
  30.     STATUS_CODE(307, "Temporary Redirect")  
  31.     STATUS_CODE(400, "Bad Request")  
  32.     STATUS_CODE(401, "Unauthorized")  
  33.     STATUS_CODE(402, "Payment Required")  
  34.     STATUS_CODE(403, "Forbidden")  
  35.     STATUS_CODE(404, "Not Found")  
  36.     STATUS_CODE(405, "Method Not Allowed")  
  37.     STATUS_CODE(406, "Not Acceptable")  
  38.     STATUS_CODE(407, "Proxy Authentication Required")  
  39.     STATUS_CODE(408, "Request Time-out")  
  40.     STATUS_CODE(409, "Conflict")  
  41.     STATUS_CODE(410, "Gone")  
  42.     STATUS_CODE(411, "Length Required")  
  43.     STATUS_CODE(412, "Precondition Failed")  
  44.     STATUS_CODE(413, "Request Entity Too Large")  
  45.     STATUS_CODE(414, "Request-URI Too Large")  
  46.     STATUS_CODE(415, "Unsupported Media Type")  
  47.     STATUS_CODE(416, "Requested Range Not Satisfiable")  
  48.     STATUS_CODE(417, "Expectation Failed")  
  49.     STATUS_CODE(418, "I\"m a teapot")              // RFC 2324  
  50.     STATUS_CODE(422, "Unprocessable Entity")       // RFC 4918  
  51.     STATUS_CODE(423, "Locked")                     // RFC 4918  
  52.     STATUS_CODE(424, "Failed Dependency")          // RFC 4918  
  53.     STATUS_CODE(425, "Unordered Collection")       // RFC 4918  
  54.     STATUS_CODE(426, "Upgrade Required")           // RFC 2817  
  55.     STATUS_CODE(500, "Internal Server Error")  
  56.     STATUS_CODE(501, "Not Implemented")  
  57.     STATUS_CODE(502, "Bad Gateway")  
  58.     STATUS_CODE(503, "Service Unavailable")  
  59.     STATUS_CODE(504, "Gateway Time-out")  
  60.     STATUS_CODE(505, "HTTP Version not supported")  
  61.     STATUS_CODE(506, "Variant Also Negotiates")    // RFC 2295  
  62.     STATUS_CODE(507, "Insufficient Storage")       // RFC 4918  
  63.     STATUS_CODE(509, "Bandwidth Limit Exceeded")  
  64.     STATUS_CODE(510, "Not Extended")                // RFC 2774  
  65.     }  
  66.   
  67.     return 0;  
  68. }  
  69.   
  70. static void _prepare_response(struct http_connection *conn);  
  71. static void _disable_write(struct http_connection *conn);  
  72. static void _enable_write(struct http_connection *conn);  
  73. static void _close_socket(struct http_connection * conn);  
  74. static void _peacefull_close(struct http_connection * conn);  
  75. static void _send_response_header(struct http_connection *conn);  
  76.   
  77. /* 
  78. * http_parser callback 
  79. */  
  80. static int onHttpMessageBegin(http_parser *parser)  
  81. {  
  82.     struct http_connection * conn = (struct http_connection *)parser->data;  
  83.     conn->state |= HTTP_MESSAGE_BEGIN;  
  84.     return 0;  
  85. }  
  86.   
  87. static int onHttpUrl(http_parser *parser, const char *at, size_t length)  
  88. {  
  89.     struct http_connection *conn = (struct http_connection *)parser->data;  
  90.     int i= 0;  
  91.   
  92.     conn->path = (char*)malloc(length+1);  
  93.     strncpy(conn->path, at, length);  
  94.     conn->path[length] = 0;  
  95.   
  96.     for(; i < length && at[i] != '?'; i++);  
  97.     if(i < length)  
  98.     {  
  99.         /* got query string */  
  100.         i++;  
  101.         if(i < length)  
  102.         {  
  103.             int qlen = length - i;  
  104.             conn->query_string = (char*)malloc(qlen + 1);  
  105.             strncpy(conn->query_string, at+i, qlen);  
  106.             conn->query_string[qlen] = 0;  
  107.         }  
  108.     }  
  109.     return 0;  
  110. }  
  111.   
  112. static inline void check_insert_header(http_parser *parser, struct http_connection *conn)  
  113. {  
  114.     /* 
  115.      * insert the header we parsed previously 
  116.      * into the header map 
  117.      */  
  118.     if( (conn->cur_header_tag && conn->cur_header_tag[0] != 0) &&  
  119.             (conn->cur_header_value && conn->cur_header_value[0] != 0))  
  120.     {  
  121.         if(!conn->header_tags ||  
  122.                 conn->header_size == conn->header_capacity)  
  123.         {  
  124.             conn->header_capacity += 8;  
  125.             conn->header_tags = (char**)realloc(conn->header_tags,sizeof(char*)*conn->header_capacity);  
  126.             conn->header_values = (char**)realloc(conn->header_tags, sizeof(char*)*conn->header_capacity);  
  127.         }  
  128.   
  129.         conn->header_tags[conn->header_size] = conn->cur_header_tag;  
  130.         conn->header_values[conn->header_size++] = conn->cur_header_value;  
  131.   
  132.         /* 
  133.          *  clear header value. this sets up a nice 
  134.          * feedback loop where the next time 
  135.          * HeaderValue is called, it can simply append 
  136.         */  
  137.   
  138.         conn->cur_header_tag = 0;  
  139.         conn->cur_tag_cap = 0;  
  140.         conn->cur_tag_size = 0;  
  141.         conn->cur_header_value = 0;  
  142.         conn->cur_value_cap = 0;  
  143.         conn->cur_value_size = 0;  
  144.     }  
  145. }  
  146.   
  147. static void check_dynamic_string(char **str, int *cap, int size, int add_size)  
  148. {  
  149.     if(!*str || size + add_size >= *cap)  
  150.     {  
  151.         *cap = size + add_size + 64;  
  152.         *str = (char*)realloc(*str, *cap);  
  153.     }  
  154. }  
  155.   
  156. static int onHttpHeaderField(http_parser *parser, const char *at, size_t length)  
  157. {  
  158.     struct http_connection * conn = (struct http_connection *)parser->data;  
  159.   
  160.     check_insert_header(parser, conn);  
  161.     check_dynamic_string(&conn->cur_header_tag,  
  162.                          &conn->cur_tag_cap, conn->cur_tag_size, length);  
  163.     strncpy(conn->cur_header_tag + conn->cur_tag_size, at, length);  
  164.   
  165.     return 0;  
  166. }  
  167.   
  168. static int onHttpHeaderValue(http_parser *parser, const char *at, size_t length)  
  169. {  
  170.     struct http_connection * conn = (struct http_connection *)parser->data;  
  171.     check_dynamic_string(&conn->cur_header_value,  
  172.                          &conn->cur_value_cap, conn->cur_value_size, length);  
  173.     strncpy(conn->cur_header_value + conn->cur_value_size, at, length);  
  174.   
  175.     return 0;  
  176. }  
  177.   
  178. static int onHttpHeadersComplete(http_parser *parser)  
  179. {  
  180.     printf("server, http_connection, onHttpHeadersComplete\n");  
  181.     if(parser)  
  182.     {  
  183.         struct http_connection * conn = (struct http_connection *)parser->data;  
  184.         if(conn)  
  185.         {  
  186. #ifdef HTTP_SERVER_DEBUG  
  187.             int i = 0;  
  188. #endif  
  189.             check_insert_header(parser, conn);  
  190.   
  191.             conn->state |= HTTP_HEADER_COMPLETE;  
  192.   
  193.             conn->method = http_method_str((enum http_method)conn->parser.method);  
  194.             sprintf(conn->version, "%.1d.%.1d", conn->parser.http_major,  
  195.                     conn->parser.http_minor);  
  196.   
  197.         #ifdef HTTP_SERVER_DEBUG  
  198.             printf("server,http_connection, %d headers\n", conn->header_size);  
  199.             for(; i < conn->header_size; i++)  
  200.             {  
  201.                 printf("header key %s value %s\n", conn->header_tags[i], conn->header_values[i]);  
  202.             }  
  203.         #endif  
  204.         }  
  205.     }  
  206.     return 0;  
  207. }  
  208.   
  209. static int onHttpBody(http_parser *parser, const char *at, size_t length)  
  210. {  
  211.     /* TODO: implement */  
  212.     return 0;  
  213. }  
  214.   
  215. static int onHttpMessageComplete(http_parser *parser)  
  216. {  
  217.     struct http_connection * conn = (struct http_connection *)parser->data;  
  218.     if(conn)  
  219.     {  
  220.         _prepare_response(conn);;  
  221.         conn->state |= HTTP_MESSAGE_COMPLETE;  
  222.         _enable_write(conn);  
  223.         _send_response_header(conn);  
  224.         switch(conn->status_code)  
  225.         {  
  226.         case 200:  
  227.         case 206:  
  228.             break;  
  229.         default:  
  230.             _disable_write(conn);  
  231.             _peacefull_close(conn);  
  232.             break;  
  233.         }  
  234.     }  
  235.     return 0;  
  236. }  
  237.   
  238. static void _prepare_response(struct http_connection *conn)  
  239. {  
  240.     char *filename = conn->path;  
  241.     char *p;  
  242.     int i = 0;  
  243.   
  244.     if(strncmp(conn->method, "GET", 3) != 0)  
  245.     {  
  246.         conn->status_code = 403;  
  247.         return;  
  248.     }  
  249.   
  250.     while(*filename == '/') filename++;  
  251.     p = filename;  
  252.     while(*p != '?' && *p != 0) p++;  
  253.     if(*p == '?') *p = 0;  
  254.   
  255.     conn->fp = fopen(filename, "rb");  
  256.     if(conn->fp)  
  257.     {  
  258.         fseek(conn->fp, 0, SEEK_END);  
  259.         conn->remain = ftell(conn->fp);  
  260.         fseek(conn->fp, 0, SEEK_SET);  
  261.         conn->status_code = 200;  
  262.         printf("open %s OK\n", filename);  
  263.     }  
  264.     else  
  265.     {  
  266.         conn->status_code = 404;  
  267.     }  
  268. }  
  269.   
  270. static void _send_response_header(struct http_connection *conn)  
  271. {  
  272.     char * p = conn->buffer;  
  273.     p += sprintf(p, "HTTP/1.1 %d %s\r\n",  
  274.                          conn->status_code,  
  275.                          _status_string(conn->status_code));  
  276.     if(conn->status_code == 200)  
  277.     {  
  278.         p += sprintf(p, "Content-Length: %d\r\n"  
  279.                      "Content-Type: application/octet-stream\r\n",  
  280.                      conn->remain);  
  281.     }  
  282.   
  283.     p += sprintf(p, "\r\n");  
  284.     //printf("response headers: %s\n", conn->buffer);  
  285.   
  286.     bufferevent_write(conn->bev, conn->buffer, p - conn->buffer);  
  287. }  
  288.   
  289. static void _close_socket(struct http_connection * conn)  
  290. {  
  291.     if(conn && conn->fd != 0)  
  292.     {  
  293.         if(conn->bev)  
  294.         {  
  295.             bufferevent_free(conn->bev);  
  296.             conn->bev = 0;  
  297.         }  
  298.         evutil_closesocket(conn->fd);  
  299.         conn->fd = 0;  
  300.     }  
  301. }  
  302.   
  303.   
  304. static void _peacefull_close(struct http_connection * conn)  
  305. {  
  306.     if( evbuffer_get_length(bufferevent_get_output(conn->bev)) == 0)  
  307.     {  
  308.         printf("http_connection, all data sent, close connection(%s:%d)\n"  
  309.                   , conn->peer_address, conn->peer_port);  
  310.   
  311.         /* delete this connection */  
  312.         delete_http_connection(conn);  
  313.         return;  
  314.     }  
  315.     else  
  316.     {  
  317.         printf("http_connection, wait bufferevent_socket to flush data\n");  
  318.     }  
  319. }  
  320.   
  321. static void _event_callback(struct bufferevent *bev, short what, void *ctx)  
  322. {  
  323.     struct http_connection * conn = (struct http_connection *)ctx;  
  324.     if( (what & (BEV_EVENT_READING | BEV_EVENT_TIMEOUT)) == (BEV_EVENT_READING | BEV_EVENT_TIMEOUT))  
  325.     {  
  326.         /* TODO: check socket alive */  
  327.     }  
  328.     else if((what &(BEV_EVENT_WRITING | BEV_EVENT_TIMEOUT)) == (BEV_EVENT_WRITING | BEV_EVENT_TIMEOUT))  
  329.     {  
  330.         /* TODO: check socket alive */  
  331.     }  
  332.     else if(what & BEV_EVENT_ERROR)  
  333.     {  
  334.         /* TODO: error notify */  
  335.         printf( "http_connection, %s:%d, error - %s\n", conn->peer_address,  
  336.                    conn->peer_port,  
  337.                    evutil_socket_error_to_string( evutil_socket_geterror(conn->fd) ) );  
  338.         _close_socket(conn);  
  339.     }  
  340. }  
  341.   
  342. static void _disable_write(struct http_connection *conn)  
  343. {  
  344.     if(conn->write_enabled)  
  345.     {  
  346.         bufferevent_disable(conn->bev, EV_WRITE|EV_TIMEOUT);  
  347.         conn->write_enabled = 0;  
  348.     }  
  349. }  
  350.   
  351. static void _enable_write(struct http_connection *conn)  
  352. {  
  353.     if(!conn->write_enabled)  
  354.     {  
  355.         bufferevent_enable(conn->bev, EV_WRITE | EV_TIMEOUT);  
  356.         conn->write_enabled = 1;  
  357.     }  
  358. }  
  359.   
  360.   
  361. // default write callback  
  362. static void _write_callback(struct bufferevent *bev, void * args)  
  363. {  
  364.     struct http_connection * conn = (struct http_connection *)args;  
  365.     if(conn->fp)  
  366.     {  
  367.         if(feof(conn->fp))  
  368.         {  
  369.             printf("http_connection, call peacefull_close via EOF\n");  
  370.             _peacefull_close(conn);  
  371.         }  
  372.         else  
  373.         {  
  374.             int to_read = BUFFER_SIZE;  
  375.             if(to_read > conn->remain) to_read = conn->remain;  
  376.             conn->data_size = fread(conn->buffer, 1, to_read, conn->fp);  
  377.             conn->remain -= conn->data_size;  
  378. #ifdef HTTP_SERVER_DEBUG  
  379.             printf("http_connection, read %d bytes\n", conn->data_size);  
  380. #endif  
  381.             if(conn->data_size)bufferevent_write(bev, conn->buffer, conn->data_size);  
  382.   
  383.         }  
  384.     }  
  385.     else  
  386.     {  
  387.         printf("http_connection, call peacefull_close via fp NULL\n");  
  388.         _peacefull_close(conn);  
  389.     }  
  390. }  
  391.   
  392. // default read callback  
  393. static void _read_callback(struct bufferevent *bev, void * args)  
  394. {  
  395.     struct http_connection * conn = (struct http_connection *)args;  
  396.     int n;  
  397.     while( (n = bufferevent_read(bev, conn->buffer, BUFFER_SIZE)) > 0 )  
  398.     {  
  399.         http_parser_execute(&conn->parser, &conn->parser_settings, conn->buffer, n);  
  400.     }  
  401. }  
  402.   
  403. void delete_http_connection(struct http_connection *conn)  
  404. {  
  405.     int i = 0;  
  406.     _disable_write(conn);  
  407.     _close_socket(conn);  
  408.     /* free resources */  
  409.     if(conn->peer_address)free(conn->peer_address);  
  410.     if(conn->fp)fclose(conn->fp);  
  411.     if(conn->cur_header_tag)free(conn->cur_header_tag);  
  412.     if(conn->cur_header_value)free(conn->cur_header_value);  
  413.     if(conn->path)free(conn->path);  
  414.     if(conn->query_string)free(conn->query_string);  
  415.     for(; i < conn->header_size; i++)  
  416.     {  
  417.         free(conn->header_tags[i]);  
  418.         free(conn->header_values[i]);  
  419.     }  
  420.     free(conn->header_tags);  
  421.     free(conn->header_values);  
  422.     free(conn);  
  423. }  

你可能感兴趣的:(libevent实现http server)