概述:
简介:
Mongoose是c语言写成的网络库。
它为TCP、UDP、HTTP、WebSocket、CoAP、MQTT实现了事件驱动型的非阻塞api。其具备如下特性:
跨平台:可在linux/unix macos QNX eCos Windows Android Iphone FreeRtos上运行
原生支持PicoTCP的嵌入式tcp/ip协议栈,支持LWIP嵌入式tcp/ip协议栈
单线程,异步,非阻塞核心与简单的基于事件的API
可配置为:
纯TCP,纯UDP SSL/TLS但双向的客户端和服务器;HTTP,WebSocket,MQTT,CoAP,DNS的客户端和服务器,同时可做为异步dns解析器。
在运行和占用很小的内存,源代码符合ISO C 和ISO c++
同时仅仅复制mongoose.c mongoose.h到你的工程便可完成整合。
Mongoose设计思路:
拥有3个基本类型的数据结构
1 struct mg_mgr;///事件管理器,保存全部的活动连接 2 struct mg_connection;///描述一个连接 3 struct mbuf;///接收和发送的数据
一个连接能够是listening(监听),outbound
(出站)或者inbound(入站)。
outbound
(出站)连接可经过调用mg_connect()产生。listening(监听)连接可经过调用mg_bind()产生。(入站)inbound连接是由listening(监听)连接所收到的连接。每一个连接都使用struct mg_connection进行描述,此结构中有,socket,事件处理函数,发送/接收缓冲区,以及其余标志。
使用mongoose的应用程序应该遵循事件驱动的标准模式:
1 struct mg_mgr mgr; 2 mg_mgr_init(&mgr, NULL);////建立并初始化事件管理器 3 struct mg_connection *c = mg_bind(&mgr, "80", ev_handler_function); 4 mg_set_protocol_http_websocket(c);///建立连接,上面2行代码是服务器应用程序建立的监听连接 5 for (;;) { 6 mg_mgr_poll(&mgr, 1000); 7 }///经过调用mg_mgr_pool()建立事件循环。
mg_mgr_poll()遍历全部的套接字,接受新连接,发送,接收数据,关闭连接。并为各自的事件调用事件处理函数。有关完整实例,可参考TCP echo server的使用实例。
内存缓冲区:
每一个连接都有接收和发送的数据缓冲区:
struct mg_connection::recv_mbuf,
struct mg_connection::send_mbuf
.当接收到数据的时候Mongoose将数据追加到recv_mbuf,而且触发MG_EV_RECV事件。用户可调用
mg_send(),mg_printf()
这些输出函数将数据追加到send_mbuf中并发送回去。当mongoose成功地向socket写入数据的时候,mongoose会将此数据从send_mbuf中丢弃,并发送MG_EV_SEND事件。当连接关闭的时候,发送MG_EV_CLOSE事件。

事件处理函数:
每一个连接都有其与之相关的事件处理函数。此事件处理函数由用户本身实现。事件处理函数是mongoose程序的关键,由于其定义了应用程序的具体行为。事件处理函数以下:
1 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { 2 switch (ev) { 3 /* Event handler code that defines behavior of the connection */ 4 ... 5 } 6 } 7 ////////////////////////////////////解读//////////////////////////////////////////// 8 struct mg_connection *nc;///链接所接收到的事件 9 int ev;///事件编号,可在mongoose.h中找到。当(入站)连接收到数据的时候,ev=MG_EV_RECV 10 void *ev_data;///此指针指向事件特定数据,对于不一样事件有不一样含义。每一个事件都描述了ev_data的具体含义。特定协议的事件ev_data一般指向包含协议特定信息的结构。 11 /* 12 MG_EV_RECV事件:ev_data是一个int *,保存从连接中接收,并保存到接收IO缓冲区中字节数 13 struct mg_connection 有应用程序特定数据占位符void *user_data。 14 mongoose不适用指针,事件处理函数user_data这个指针,事件处理函数可在此存储任何信息。 15 */
事件:php
mongoose接收连接,读写数据并为每一个连接调用指定的事件处理函数。典型的事件序列:
出站连接:
MG_EV_CONNECT->(MG_EV_RECV,MG_EV_SEND,MG_EV_POLL...)->MG_EV_CLOSE
入站连接:
MG_EV_ACCEPT->(MG_EV_RECV,MG_EV_SEND,MG_EV_POLL...)->MG_EV_CLOSE
下面是mongoose触发的核心事件列表:(除了核心事件外,每一个协议都会触发协议的特定事件)
MG_EV_ACCEPT:监听连接接收到一个新的连接,void *ev_data 是远程连接的union socket_addres
MG_EV_ACCEPT:监听连接接收到一个新的连接,void *ev_data 是远程连接的union socket_addres
MG_EV_CONNECT:mg_connect()建立一个出站连接(不管mg_connect()调用是否成功),void *ev_data 是 int *success.
success=0,连接创建成功,不然连接创建失败,并包含一个错误码。可查看mg_connect_opt()查看
代码实例。
MG_EV_RECV:接收到新数据,并将数据追加到recv_mbuf.void * ev_data是 int *num_received_bytes.一般状况下事件处理程序应该在nc->recv_mbuf()检查接受到的数据,经过调用mbuf_remove()丢弃处理后的数据,必要时设置连接标志nc->flags(查看struct mg_connection).使用mg_send()向远程连接点发送数据。
mongoose使用realloc()来扩展接收缓冲区,从接收缓冲区的开头丢弃处理过的数据是用户的责任。注意上面的mbuf_remove().
MG_EV_SEND:mongoos向远程链接点写入数据,并将mg_connectiong::send_mbuf中数据丢弃。void *ev_data是int *num_sent_bytes即发送的字节数。mongoose输出函数仅仅是将数据追加到sned_mbuf,不作任何socket写操做。实际的IO写操做是由mg_mgr_pool()完成,MG_EV_SEND仅仅是一个关于IO操做已经完成的通知。
MG_EV_POLL:将每次调用mg_mgr_poll()发送到每一个连接。此事件可作任何事情。例如检测某个超时连接是否关闭,或者发送心跳。
MG_EV_TIMER: 向某个调用mg_set_timer()的连接发送
连接flags:
每一个连接都有flasg位域。有些flags是由mongoose设置的,例如若是用户使用udp://1.2.3.4:5678建立一个出站的UDP连接。mongoose会为此连接设置MG_F_UDP标记。其余标志只能由用户事件处理程序设置,告诉mongoose作何种操做。下面是由事件处理程序设置的连接flags列表:
MG_F_FINISHED_SENDING_DATA:告诉mongoose全部数据已经追加到send_mbuf,只要mongoose将数据写入socket,此连接就会关闭。
MG_F_BUFFER_BUT_DONT_SEND:告诉mongoose追加
数据到send_mbuf,但数据要立刻发送,由于此数据稍后会被修改。而后经过清除
MG_F_BUFFER_BUT_DONT_SEND标志将数据发送出去。
MG_F_CLOSE_IMMEDIATELY:告诉mongoose当即关闭连接 ,一般在产生错误后发送此事件。
MG_F_CLOSE_IMMEDIATELY:告诉mongoose当即关闭连接 ,一般在产生错误后发送此事件。
MG_USER_1,MG_USER_2,MG_USER_3,MG_USER_4:开发者可用它来存储特定应用程序的状态
下面是由mongoose设置的flags:
MG_F_SSL_HANDSHAKE_DONE:仅使用ssl,在ssl握手完成时设置
MG_F_CONNECTING:在mg_connect()调用后连接处于连接状态但未完成连接时设置。
MG_F_LISTENING:设置全部监听连接
MG_F_LISTENING:设置全部监听连接
MG_F_UDP:连接是udp时设置。
MG_F_WEBSOCKET:连接是websocket时设置。
MG_F_WEBSOCKET_NO_DEFRAG:若是用户想关闭websocket的自动帧碎片整理功能,则由用户设置此标记。
MG_F_WEBSOCKET_NO_DEFRAG:若是用户想关闭websocket的自动帧碎片整理功能,则由用户设置此标记。
编译选项:
mongoose源代在一个.c文件中,此文件包含全部受支持协议(模块)的功能。能够在编译时设置预处理器编制来禁用模块,以减小可执行文件的大小。一些预处理器标志能够调整mongoose的内部参数。在编译期间可以使用-D<PREPROCESSOR_FLAG>设置编译器选项。例如要禁用MQTT和CoAP,编译应用程序my_app.c在linux下用:
启用标志 | |
Flag | 介绍 |
MG_ENABLE_SSL | 启用SSL/TLS支持(OpenSSL API) |
MG_ENABLE_IPV6 | 启用IPV6支持 |
MG_ENABLE_MQTT | 启用MQTT客户端(默认状况下设置为0表示禁用) |
MG_ENABLE_MQTT_BROKER | 启用MQTT broker |
MG_ENABLE_DNS_SERVER | 启用DNS服务器 |
MG_ENABLE_COAP | 启用CoAP协议 |
MG_ENABLE_HTTP | 启用HTTP协议支持(默认状况下,设置0表示禁用) |
MG_ENABLE_HTTP_CGI | 启用CGI |
MG_ENABLE_HTTP_SSI | 启用Server Side |
MG_ENABLE_HTTP_SSI_EXEC | 启用SSI exec操做 |
MG_ENABLE_HTTP_WEBDAV | 启用HTTP的WebDAV扩展 |
MG_ENABLE_HTTP_WEBSOCKET | 启用HTTP的WebSocket扩展,默认状况下 设置0禁止 |
MG_ENABLE_BROADCAST | 启用mg_broadcast()API |
MG_ENABLE_GETADDRINFO | 启用在mg_resolve2()中的getaddrinfo() |
MG_ENABLE_THREADS | 启用在mg_start_thread()API |
禁用标志 | |
MG_DISABLE_HTTP_DIGEST_AUTH | 禁用HTTP摘要(MD5)受权支持 |
CS_DISABLE_SHA1 | 禁用WebSocket中的SHA1支持 |
CS_DISABLE_MD5 | 禁用HTTP鉴权中的MD5支持 |
MG_DISABLE_HTTP_KEEP_ALIVE | 用于嵌入式系统节省资源 |
平台相关选项(mongoose会尽量的检测目标平台,可是在某些状况下,必须明确声明目标平台的部分特性) | |
MG_CC3200 | 为TICC3200板子启用工做区 |
MG_ESP8266 | 为ESP8266板子添加RTOS_SDK来指定RTOS_SDK风格 |
可调整 | |
MG_MALLOC,MG_CALLOC,MG_REALLOC,MG_FREE | 容许使用开发者自定义的内存分配处理函数 -DMG_MALLCO=my_malloc |
MG_USE_READ_WRITE | 设置后,将recv的调用替换为read,send。从而容许向事件管理器添加任何类型的文件描述符(文件,串行设备) |
MG_SSL_CRYPTO_MODERN,MG_SSL_CRYPTO_OLD | 选择modern或者old密码替换默认的Intermediate密码。在下面网址查看各类密码形式的详细信息 https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations |
MG_USER_FILE_FUNCTIONS | 容许开发者经过定义本身的mg_stat,mg_fopen,mg_open,mg_fread,mg_fwrite去自定义文件操做函数 |
实例:TCP echo server
复制mongoose.c mongoose.h到你的工程;在my_app.c中使用mongoose的API写代码。编译代码
$$cc my_app.c mongoose.c
1 /********************my_app.c*******************/ 2 #include "mongoose.h" // Include Mongoose API definitions 3 // Define an event handler function 4 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { 5 struct mbuf *io = &nc->recv_mbuf; 6 switch (ev) { 7 case MG_EV_RECV: 8 // This event handler implements simple TCP echo server 9 mg_send(nc, io->buf, io->len); // Echo received data back 10 mbuf_remove(io, io->len); // Discard data from recv buffer 11 break; 12 default: 13 break; 14 } 15 } 16 17 int main(void) { 18 struct mg_mgr mgr; 19 mg_mgr_init(&mgr, NULL); // Initialize event manager object 20 // Note that many connections can be added to a single event manager 21 // Connections can be created at any point, e.g. in event handler function 22 mg_bind(&mgr, "1234", ev_handler); // Create listening connection and add it to the event manager 23 for (;;) { // Start infinite event loop 24 mg_mgr_poll(&mgr, 1000); 25 } 26 mg_mgr_free(&mgr); 27 return 0; 28 }
HTTP:
实例一:HTTP server
1,使用mg_bind()或者mg_bind_opt()建立立监听连接
2.调用mg_set_protocol_http_websocket()去监听全部连接。此函数附加了一个内置的http事件处理事件,用于解析并触发特定的HTTP事件。例如当HTTP请求被彻底缓冲时,内置的HTPP处理程序将解析请求并使用MG_EV_HTTP_REQUEST事件调用用户定义的事件处理函数,并将HTTP请求解析为事件数据。
3.建立事件处理函数。事件处理程序接收全部的事件(低级别TCP事件(MG_EV_RECV)和高级别HTTP事件(MG_EV_HTTP_REQUEST))。一般事件处理函数应该只处理高级别事件MG_EV_HTTP_REQUEST
下面是HTTP server的实例代码,其中省略了错误检查
1 // Copyright (c) 2015 Cesanta Software Limited 2 // All rights reserved 3 4 #include "mongoose.h" 5 6 static const char *s_http_port = "8000"; 7 static struct mg_serve_http_opts s_http_server_opts; 8 9 static void ev_handler(struct mg_connection *nc, int ev, void *p) { 10 if (ev == MG_EV_HTTP_REQUEST) { 11 mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); 12 } 13 } 14 15 int main(void) { 16 struct mg_mgr mgr; 17 struct mg_connection *nc; 18 19 mg_mgr_init(&mgr, NULL); 20 printf("Starting web server on port %s\n", s_http_port); 21 nc = mg_bind(&mgr, s_http_port, ev_handler); 22 if (nc == NULL) { 23 printf("Failed to create listener\n"); 24 return 1; 25 } 26 27 // Set up HTTP server parameters 28 mg_set_protocol_http_websocket(nc); 29 s_http_server_opts.document_root = "."; // Serve current directory 30 s_http_server_opts.enable_directory_listing = "yes"; 31 32 for (;;) { 33 mg_mgr_poll(&mgr, 1000); 34 } 35 mg_mgr_free(&mgr); 36 37 return 0; 38 }
实例二:HTTP Client
1:使用mg_connect_http()建立出站连接
2:建立事件处理函数用于处理MG_EV_HTTP_REPLY事件
HTTP事件:
正如在概述中所讨论的,mg_set_protocol_http_websocket()函数解析传入的数据,将其视为HTTP或WebSocket,并触发高级HTTP或WebSocket事件。下面是一个特定于HTTP的事件列表:
MG_EV_HTTP_REQUEST:收到一个http请求,解析后的请求
整理为struct http_message结构,并经过void * ev_data指针传递。
MG_EV_HTTP_REPLY:收到一个http回应,解析后的回应整理为struct http_message结构,并经过void * ev_data指针传递。
MG_EV_HTTP_MULTIPART_REQUEST:收到一个分多个包传递的http请求,在http的body开始解析前发送此事件。在此事件后用户会收到一些列的MG_HTTP_PART_BEGIN/DATA/END请求。这也是最后一次访问标头和http中其余请求字段。
MG_EV_HTTP_MULTIPART_REQUEST:收到一个分多个包传递的http请求,在http的body开始解析前发送此事件。在此事件后用户会收到一些列的MG_HTTP_PART_BEGIN/DATA/END请求。这也是最后一次访问标头和http中其余请求字段。
MG_EV_HTTP_CHUNK:收到一个http编码块,解析后的http应答整理为struct http_message结构,并经过void * ev_data指针传递。http_message::body将包含从新组装的不完整body块。http_message::body伴随着每一个新块的到达而增加,此过程可能消耗大量内存。事件处理函数可在块到来的时候处理body,并经过设置在mg_connection::flags设置MG_F_DELETE_CHUNK标记来告知mongoose去删除已经解析处理过的body块。(若是事件处理函数没有告知mongoose去删除已经处理过的body)当接收到最后一个0数据块的时候,mongoose发送MG_F_HTTP_REPLY事件并带有重组的完整的body.
MG_F_HTTP_PART_BEGIN:开始接收 分包传递的消息的一部分消息,并在mg_http_multipart中国传递额外参数。
MG_F_HTTP_PART_DATA:开始接收 分包传递的消息的新数据部分没有额外的表头可用只有
数据和数据大小
MG_F_HTTP_PART_END:收到最后一个边界,相似可能用来找到包的结尾。须要注意的是mongoose在编译的时候应该设置MG_ENABLE_HTTP_MULTIPART去使能多部分事件。
Serving files:
mg_serve_http()函数使得从文件系统提供文件变得时分简单。通常来此函数是http server实现的用于提供cgi,ssl等静态文件的。它的行为合并到了struct mg_serve_http_opts结构的选项列表中.mg_serve_http()功能的完整列表可参考struct mg_serve_http_opts.
为了建立一个服务于当前目录中的静态文件的web服务器。按以下方式实现事件处理器函数:
1 static void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 2 if (ev == MG_EV_HTTP_REQUEST) { 3 struct mg_serve_http_opts opts; 4 5 memset(&opts, 0, sizeof(opts); // Reset all options to defaults 6 opts.document_root = "."; // Serve files from the current directory 7 8 mg_serve_http(c, (struct http_message *) ev_data, s_http_server_opts); 9 } 10 }
有时候不须要完整的静态web服务器。例如在RESTful的服务器上工做,若是某些端点必须返回静态文件的内容,可以使用简单的mg_http_serve_file()函数
1 static void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 2 switch (ev) { 3 case MG_EV_HTTP_REQUEST: { 4 struct http_message *hm = (struct http_message *) ev_data; 5 mg_http_serve_file(c, hm, "file.txt", 6 mg_mk_str("text/plain"), mg_mk_str("")); 7 break; 8 } 9 ... 10 } 11 }
CGI:
cgi是一种简单的动态内容生成机制。为了去使用cgi,调用mg_serve_http()函数并对cgi文件使用.cgi扩展名便可。更准确地说,匹配struct mg_serve_opts中cgi_file_pattern模式的文件都视为cgi,若是cgi_file_pattern是NULL则**.cgi$或者**.php$均可使用。
若是mongoose将一个文件看做是cgi文件,它会去执行此文件,并其输出发送回client.所以cgi文件必须是可执行的。若是同时使用PHP和Perl CGIs,那么在各自cgi脚本的第一行必须是#!/path/to/php-cgi.exe和
#!/path/to/perl.exe.能够为全部的cgi脚本硬编码到cgi解释器的路径而不考虑shebang line。为此在mg_serve_http_opts中设置cgi_interpreter.注意php脚本必须使用php-cgi.exe做为cgi解析器而不是php.exe
opts.cgi_interpreter = "C:\\ruby\\ruby.exe";
在cgi处理程序中,咱们没有显式地使用系统调用waitpid()来获取僵尸进程。相反咱们将SIGCHLD处理程序设置为SIG_IGN.其致使僵尸进程会自动获取。入股全部的SIGCHLD被忽略,并非全部的操做系统都会获取僵尸进程。
SSI:
文件上传:
为了实现文件上传,使用以下html
<form method="POST" action="/upload" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Upload"> </form>
上传文件会经过POST请求将文件发送到/upload目录。HTTP的body将会包含文件内容的多部分编码缓冲区。为保存文件使用以下:
1 struct mg_str cb(struct mg_connection *c, struct mg_str file_name) { 2 // Return the same filename. Do not actually do this except in test! 3 // fname is user-controlled and needs to be sanitized. 4 return file_name; 5 } 6 7 void ev_handler(struct mg_connection *c, int ev, void *ev_data) { 8 switch (ev) { 9 ... 10 case MG_EV_HTTP_PART_BEGIN: 11 case MG_EV_HTTP_PART_DATA: 12 case MG_EV_HTTP_PART_END: 13 mg_file_upload_handler(c, ev, ev_data, cb); 14 break; 15 } 16 }
使能SSL(HTTPS):
在http服务器端使能ssl须要按照以下步骤:
1.获取ssl证书和私钥文件
2.声明struct mg_bind_opts,初始化化ssl_cert和ssl_key
3.使用mg_bind_opt()去建立监听socket
实例:(更多介绍:查看examples中的https server 实例)
1 int main(void) { 2 struct mg_mgr mgr; 3 struct mg_connection *c; 4 struct mg_bind_opts bind_opts; 5 6 mg_mgr_init(&mgr, NULL); 7 8 memset(&bind_opts, 0, sizeof(bind_opts)); 9 bind_opts.ssl_cert = "server.pem"; 10 bind_opts.ssl_key = "key.pem"; 11 12 // Use bind_opts to specify SSL certificate & key file 13 c = mg_bind_opt(&mgr, "443", ev_handler, bind_opts); 14 mg_set_protocol_http_websocket(c); 15 16 ... 17 }
Digest身份认证
mongoose有一个内置的digest(md5)认证支持。为了启用digest认证,须要再保护目录中建立一个.htpasswd文件。此文件应该采用apache的htdigest使用程序的格式。
你可使用Apache的htdigest实例,或者mongoose在
https://www.cesanta.com/binary.htm预构建一个二进制并添加新用户到这个文件。
mongoose -A /path/to/.htdigest mydomain.com joe joes_password
通用API参考:
1 struct http_message { 2 struct mg_str message; /* Whole message: request line + headers + body */ 3 struct mg_str body; /* Message body. 0-length for requests with no body */ 4 5 /* HTTP Request line (or HTTP response line) */ 6 struct mg_str method; /* "GET" */ 7 struct mg_str uri; /* "/my_file.html" */ 8 struct mg_str proto; /* "HTTP/1.1" -- for both request and response */ 9 10 /* For responses, code and response status message are set */ 11 int resp_code; 12 struct mg_str resp_status_msg; 13 14 /* 15 * Query-string part of the URI. For example, for HTTP request 16 * GET /foo/bar?param1=val1¶m2=val2 17 * | uri | query_string | 18 * 19 * Note that question mark character doesn't belong neither to the uri, 20 * nor to the query_string 21 */ 22 struct mg_str query_string; 23 24 /* Headers */ 25 struct mg_str header_names[MG_MAX_HTTP_HEADERS]; 26 struct mg_str header_values[MG_MAX_HTTP_HEADERS]; 27 };///HTTP消息 28 struct websocket_message { 29 unsigned char *data; 30 size_t size; 31 unsigned char flags; 32 };///websocket消息 33 struct mg_http_multipart_part { 34 const char *file_name; 35 const char *var_name; 36 struct mg_str data; 37 int status; /* <0 on error */ 38 void *user_data; 39 };///HTTP分包部分 40 struct mg_ssi_call_ctx { 41 struct http_message *req; /* The request being processed. */ 42 struct mg_str file; /* Filesystem path of the file being processed. */ 43 struct mg_str arg; /* The argument passed to the tag: <!-- call arg -->. */ 44 };///SSI调用上下文 45 void mg_set_protocol_http_websocket(struct mg_connection *nc); 46 void mg_send_websocket_handshake(struct mg_connection *nc, const char *uri, 47 const char *extra_headers); 48 void mg_send_websocket_handshake2(struct mg_connection *nc, const char *path, 49 const char *host, const char *protocol, 50 const char *extra_headers); 51 void mg_send_websocket_handshake3(struct mg_connection *nc, const char *path, 52 const char *host, const char *protocol, 53 const char *extra_headers, const char *user, 54 const char *pass); 55 void mg_send_websocket_handshake3v(struct mg_connection *nc, 56 const struct mg_str path, 57 const struct mg_str host, 58 const struct mg_str protocol, 59 const struct mg_str extra_headers, 60 const struct mg_str user, 61 const struct mg_str pass); 62 struct mg_connection *mg_connect_ws(struct mg_mgr *mgr, 63 MG_CB(mg_event_handler_t event_handler, 64 void *user_data), 65 const char *url, const char *protocol, 66 const char *extra_headers); 67 struct mg_connection *mg_connect_ws_opt( 68 struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), 69 struct mg_connect_opts opts, const char *url, const char *protocol, 70 const char *extra_headers); 71 void mg_send_websocket_frame(struct mg_connection *nc, int op_and_flags, 72 const void *data, size_t data_len); 73 void mg_send_websocket_framev(struct mg_connection *nc, int op_and_flags, 74 const struct mg_str *strings, int num_strings); 75 void mg_printf_websocket_frame(struct mg_connection *nc, int op_and_flags, 76 const char *fmt, ...); 77 int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, 78 int is_form_url_encoded); 79 extern void mg_hash_md5_v(size_t num_msgs, const uint8_t *msgs[], 80 const size_t *msg_lens, uint8_t *digest); 81 extern void mg_hash_sha1_v(size_t num_msgs, const uint8_t *msgs[], 82 const size_t *msg_lens, uint8_t *digest); 83
http server端API参考:
1 int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req); 2 /**解析http消息,若是is_req=1 此消息是http请求,is_req=0 此消息是http回应 3 *返回解析的字节数 若是http消息不完整则返回0 若是解析出错,则返回负数*/ 4 struct mg_str *mg_get_http_header(struct http_message *hm, const char *name); 5 /**搜索并返回解析后的http消息hm中的表头名称,若是没有找到标头,则返回NULL 6 *实例:struct mg_str *host_hdr = mg_get_http_header(hm, "Host");*/ 7 int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf, 8 size_t buf_size); 9 /**解析http头hdr,查找变量var_name并将其值存储到buf中,若是没有找到变量,返回0不然返回非0。此函数用于解析cookies验证头等。若是成功则返回变量值的长度,若是buf缓冲区不够大,或者没有找到此变量则返回0 10 char user[20]; 11 struct mg_str *hdr = mg_get_http_header(hm, "Authorization"); 12 mg_http_parse_header(hdr, "username", user, sizeof(user)); 13 */ 14 int mg_get_http_basic_auth(struct http_message *hm, char *user, size_t user_len, 15 char *pass, size_t pass_len); 16 /*获取并解析受权,若是没有找到受权头或者mg_parse_http_basic_auth解析结果头失败*/ 17 int mg_parse_http_basic_auth(struct mg_str *hdr, char *user, size_t user_len, 18 char *pass, size_t pass_len); 19 /*解析受权,如受权类型不是Basic或者出现其余错误(如用于base64编码的用户密码不对)基本头返回-1*/ 20 size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name, 21 size_t var_name_len, char *file_name, 22 size_t file_name_len, const char **chunk, 23 size_t *chunk_len); 24 /*解析包含多部分表单数据库的缓冲区buf,buf_len,将块名存储在var_name,var_name_len缓冲区中。若是块是上传文件,那么file_name,file_name_len将会被一个上传的文件名填充。chunk,chunk_len指向块数据。返回要跳到下一个块的字节数,若是没有更多块则返回0*/ 25 int mg_get_http_var(const struct mg_str *buf, const char *name, char *dst, 26 size_t dst_len); 27 /*获取Http表单变量。从buf获取变量名,到指定dst指定长度dst_len的缓冲区。目的地址老是0终止,返回获取到的变量的长度,若是没有找到变量,则返回0.buf必须是有效的url编码缓冲区。若是dst长度过小或者发生错误返回负数*/ 28 29 //此结构定义了mg_serve_http()的工做方式,最佳是设置须要的,其他为NULL 30 struct mg_serve_http_opts { 31 const char *document_root;///web根目录路径 32 const char *index_files;///索引文件列表,默认是"" 33 /* 34 per_directory_auth_file =NULL表示禁用身份验证 35 per_directory_auth_file =".htpasswd" 要使用身份认证来保护目录,而后在任何目录建立使用 digest认证的.htpasswd文件。使用mongoose web服务器二进制文件或 者Apache的htpasswd实例建立/操做密码文件 36 确保auth_domain是一个有效的域 37 */ 38 const char *per_directory_auth_file; 39 const char *auth_domain;//受权域。即web服务器的域名 40 /* 41 global_auth_file = NULL 禁用身份认证 42 一般只保护document_root根目录选定的目录。若是对web服务器的全部访问都必须通过身份验证, 无论URI是什么,将此选项设置为密码文件的路径。此文件的格式与.htpasswd的格式同样,并把此 文件放在document_root根目录以外,以防他人获取到此文件 43 */ 44 const char *global_auth_file; 45 const char *enable_directory_listing;//设置为"no"禁用目录列表,默认启用 46 const char *ssi_pattern;///ssi匹配模式 源码有详细介绍 47 const char *ip_acl;///ip_acl=NULL表示全部IP均可连接 48 #if MG_ENABLE_HTTP_URL_REWRITES 49 const char *url_rewrites;/////源码有详细介绍 50 #endif 51 const char *dav_document_root;///DAV的根目录,dav_document_root=NULL 则DAV请求失败 52 const char *dav_auth_file;//DAV密码文件,dav_auth_file=NULL 则DAV请求失败 dav_auth_file="-" 禁用DAV鉴权 53 const char *hidden_file_pattern;///文件隐藏的Glob模式 54 const char *cgi_file_pattern;///cgi_file_pattern != NULL 则使能cgi,即此目录下知足 **.cgi$|**.php$"都视为cgi文件 55 const char *cgi_interpreter;///若是不是NULL,请忽略CGI脚本hashbang并使用这个解释器 56 const char *custom_mime_types; 57 /*Comma-separated list of Content-Type overrides for path suffixes,".txt=text/plain; charset=utf-8,.c=text/plain"e.g.*/ 58 const char *extra_headers;///添加到每一个http相应的额外的header,要启用CORS,请将此设置为"Access-Control-Allow-Origin: *"。 59 } 60 void mg_serve_http(struct mg_connection *nc, struct http_message *hm, 61 struct mg_serve_http_opts opts); 62 /*根据opts的内容,提供特定的http请求*/ 63 void mg_http_serve_file(struct mg_connection *nc, struct http_message *hm, 64 const char *path, const struct mg_str mime_type, 65 const struct mg_str extra_headers); 66 /*提供具备给定MIME类型和可选extra_headers头的特定文件*/ 67 typedef struct mg_str (*mg_fu_fname_fn)(struct mg_connection *nc, 68 struct mg_str fname);///mg_file_upload_handler()的回调函数原型 69 void mg_file_upload_handler(struct mg_connection *nc, int ev, void *ev_data, 70 mg_fu_fname_fn local_name_fn 71 MG_UD_ARG(void *user_data)); 72 /*文件上传处理程序。这个处理程序能够用最少的代码实现文件上传.此程序处理MG_EV_HTTPPART事件并保存文件数据到本地。local_name_fn将以客户端提供的名字调用并以指望的本地文件名称打开。若是返回NULL将终止文件上传(客户端获得403),若是返回不是NULL,返回的字符串必须是堆分配的,且调用方须要释放这些字符串。异常状况:返回彻底相同的字符串, 73 */ 74 void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path, 75 MG_CB(mg_event_handler_t handler, 76 void *user_data)); 77 /*为nc注册回调函数,若是注册了回调函数,其会被调用欧冠,而不是调用mg_bind()中提供的回调函数*/ 78 struct mg_http_endpoint_opts { 79 void *user_data; 80 /*受权域 (realm) */ 81 const char *auth_domain; 82 const char *auth_file; 83 }; 84 void mg_register_http_endpoint_opt(struct mg_connection *nc, 85 const char *uri_path, 86 mg_event_handler_t handler, 87 struct mg_http_endpoint_opts opts); 88 int mg_http_check_digest_auth(struct http_message *hm, const char *auth_domain, 89 FILE *fp); 90 /*根据打开的密码文件验证HTTP请求。若是通过身份验证,返回1,不然返回0*/ 91 int mg_check_digest_auth(struct mg_str method, struct mg_str uri, 92 struct mg_str username, struct mg_str cnonce, 93 struct mg_str response, struct mg_str qop, 94 struct mg_str nc, struct mg_str nonce, 95 struct mg_str auth_domain, FILE *fp); 96 /*对打开的密码文件验证给定的响应参数。若是通过身份验证,返回1,不然返回0。 97 由 mg_http_check_digest_auth().调用 98 */ 99 void mg_send_http_chunk(struct mg_connection *nc, const char *buf, size_t len); 100 /* 101 使用组块HTTP编码向客户端发送大小为len的缓冲区buf.这个函数首先将 发送缓冲区大小(16进制)+换行符+缓冲区+换行符发出。例如,mg_send_http_chunk(nc,“foo”,3)将把 "3\r\nfoo\r\n"字符串追加到nc->send_mbuf输出IO缓冲区 102 HTTP头“传输编码:块化”应该在使用此函数以前发送 103 不要忘记在响应结束时发送一个空块,告诉客户端全部内容都已发送 104 */ 105 void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); 106 /*发送一个printf格式的HTTP块。功能相似于mg_send_http_chunk()。*/ 107 void mg_send_response_line(struct mg_connection *nc, int status_code, 108 const char *extra_headers); 109 /*发送响应状态行。若是extra_headers不是NULL,那么extra_headers也会在响应行以后发送。extra_headers不能以新行结束*/ 110 void mg_http_send_error(struct mg_connection *nc, int code, const char *reason); 111 /*发送一个错误的回应。若是缘由为空,消息将从错误代码中推断出来(若是支持的话)*/ 112 void mg_http_send_redirect(struct mg_connection *nc, int status_code, 113 const struct mg_str location, 114 const struct mg_str extra_headers); 115 /*发送一个重定向响应。status_code应该是301或302,位置指向新位置。若是extra_headers不是空的,那么extra_headers也会在响应行以后发送。extra_headers不能以新行结束。*/ 116 void mg_send_head(struct mg_connection *n, int status_code, 117 int64_t content_length, const char *extra_headers); 118 /*发送响应行和标题。这个函数用status_code发送响应行,并自动发送一个标题:"Content-Length"或 "Transfer-Encoding"。若是content_length为负,则发送“Transfer-Encoding: chunked”报头,不然发送“Content-Length”报头。若是转换编码被分割,那么消息体必须使用mg_send_http_chunk()或mg_printf_http_chunk()函数发送。不然,必须使用mg_send()或mg_printf()。额外的标题能够经过extra_headers设置。注意,extra_headers不能被一个新的行终止*/ 119 void mg_printf_html_escape(struct mg_connection *nc, const char *fmt, ...); 120 /*发送一个打印格式的HTTP块,转义HTML标记*/ 121 void mg_http_reverse_proxy(struct mg_connection *nc, 122 const struct http_message *hm, struct mg_str mount, 123 struct mg_str upstream); 124 /*将给定的请求代理给给定的上游http服务器.挂载中的路径前缀将被剥离到上游服务器请求的路径,例如若是挂载为/api,上游为 http://localhost:8001/foo 那么向/api传入的请求将传入到 http://localhost:8001/foo/bar*/ 125 126
client 端API参考:
1 struct mg_connection *mg_connect_http( 2 struct mg_mgr *mgr, 3 MG_CB(mg_event_handler_t event_handler, void *user_data), const char *url, 4 const char *extra_headers, const char *post_data); 5 /*建立出站HTTP链接的助手函数 6 url是要获取的url。它必须被正确地url编码,例如没有空格,等等.默认状况下,mg_connect_http()发送链接和主机头 7 extra_headers是一个额外的HTTP头:"User-Agent: my-app\r\n" 8 若是post_data为空,则建立一个GET请求。不然,将使用指定的POST数据建立POST请求。 9 注意,若是要提交的数据是表单提交,那么应该相应地设置Content-Type报头(参见下面的示例)。 10 nc1 = mg_connect_http(mgr, ev_handler_1, "http://www.google.com", NULL, 11 NULL); 12 nc2 = mg_connect_http(mgr, ev_handler_1, "https://github.com", NULL, NULL); 13 nc3 = mg_connect_http( 14 mgr, ev_handler_1, "my_server:8000/form_submit/", 15 "Content-Type: application/x-www-form-urlencoded\r\n", 16 "var_1=value_1&var_2=value_2"); 17 */ 18 struct mg_connection *mg_connect_http_opt( 19 struct mg_mgr *mgr, MG_CB(mg_event_handler_t ev_handler, void *user_data), 20 struct mg_connect_opts opts, const char *url, const char *extra_headers, 21 const char *post_data); 22 /*建立出站HTTP链接的助手函数.与mg_connect_http基本相同,但容许提供额外的参数(例如SSL参数)*/ 23 int mg_http_create_digest_auth_header(char *buf, size_t buf_len, 24 const char *method, const char *uri, 25 const char *auth_domain, const char *user, 26 const char *passwd); 27 /*为客户机请求建立摘要身份验证头*/