Mongoose源码分析

来源:互联网 发布:centos 6.5 squid 编辑:程序博客网 时间:2024/04/30 06:52

Mongoose是一个简易的web服务器,所谓web服务器,简单的说就是把服务断的数据返回给客户端。

的源码很简单,主要就是Mongoose.c文件,里面包含了大部分的处理。

Mongoose里面有几个比较重要点的数据结构:

[cpp] view plaincopyprint?
  1. 1、mg_context详解  
  2.   
  3. mg_context结构体——表示Mongoose的上下文,也称为一个实例句柄。它的成员如下:  
  4.   
  5. struct mg_context {  
  6.     int     stop_flag;  /* Should we stop event loop    */  
  7.     SSL_CTX     *ssl_ctx;   /* SSL context          */  
  8.   
  9.     FILE        *access_log;    /* Opened access log        */  
  10.     FILE        *error_log; /* Opened error log     */  
  11.   
  12.     struct socket   listeners[MAX_LISTENING_SOCKETS];  
  13.     int     num_listeners;  
  14.   
  15.     struct callback callbacks[MAX_CALLBACKS];  
  16.     int     num_callbacks;  
  17.   
  18.     char        *options[NUM_OPTIONS];  /* Configured opions    */  
  19.     pthread_mutex_t opt_mutex[NUM_OPTIONS]; /* Option protector */  
  20.   
  21.     int     max_threads;    /* Maximum number of threads    */  
  22.     int     num_threads;    /* Number of threads        */  
  23.     int     num_idle;   /* Number of idle threads   */  
  24.     pthread_mutex_t thr_mutex;  /* Protects (max|num)_threads   */  
  25.     pthread_cond_t  thr_cond;  
  26.     pthread_mutex_t bind_mutex; /* Protects bind operations */  
  27.   
  28.     struct socket   queue[20];  /* Accepted sockets     */  
  29.     int     sq_head;    /* Head of the socket queue */  
  30.     int     sq_tail;    /* Tail of the socket queue */  
  31.     pthread_cond_t  empty_cond; /* Socket queue empty condvar   */  
  32.     pthread_cond_t  full_cond;  /* Socket queue full condvar    */  
  33.   
  34.     mg_spcb_t   ssl_password_callback;  
  35.     mg_callback_t   log_callback;  
  36. };  
  37. 这个结构体在mg_start()中创建和初始化,其它函数大部分都会用它。因此mg_start()应该首先被调用。它非常重要,几乎所有的函数都要用到它。  
  38.   
  39. 1)、stop_flag表示是否应该停止的标记,它有三个可能的值0、1、2。 stop_flag=0表示 不应该停止,这是初始值;stop_flag=1表示停止,在mg_stop()函数中的一开始设置stop_flag=1,这会触发mg_fini(),且在mg_stop()中会一直等待mg_fini执行完成;stop_flag=2用于通知mg_stop(),mg_fini已经执行完成,stop_flag=2在mg_fini函数中的末尾设置。  
  40.   
  41. 2)、ssl_ctx是结构体ssl_ctx_st的实例,它来自OpenSSL开源项目,作者把它放到这里的原因是使其独立于OpenSSL的源码安装,这样只有系统上面安装有SSL库,mongoose+SSL就能编译通过。  
  42.   
  43. 3)、access_log、error_log很明显是指向访问日志文件、错误日志文件。  
  44.   
  45. 4)、listeners数组存储mongoose建立的多个web server,每个web server都是listeners数组中的一个元素。例如,一个服务器可以分别在端口8080、8888建立web server,这样8080端口的那个server是listerns数组中的一个元素,8888端口的那个server也是listeners数组中的一个元素。换句话说,listeners数组表示web server的socket地址。num_listeners表示listeners数组的元素个数。  
  46.   
  47. 5)、callbacks是结构体callback的数组,而callback本身是一个结构体,包含几个回调句柄。num_callbacks是callbacks数组元素的个数。  
  48.   
  49. 6)、options数组,是用于存储配置选项的,例如端口号、工作目录等等。opt_mutext对配置进行操作的互斥变量。  
  50.   
  51. 7)、max_threads表示允许的最大线程数量、num_threads表示当前的线程数量、num_idle表示空闲的线程数量。之所以会有空闲进程,是因为当创建一个线程处理连接请求之后,它会保持一段时间空闲而不是直接销毁。如果这里再用新的连接到来或等待队列中有需要处理的连接,空闲进程会被分配去处理。  
  52.   
  53. 8)、thr_mutex、thr_cond、bind_mutex是用于互斥信号量和条件变量。  
  54.   
  55. 9)、queue[20]队列数组存储client的连接请求,每个元素都是client的socket。sq_head、sq_tail分别是队列头、尾用于操作队列queue。empty_cond、full_cond分别表示队列是否为空、满的条件变量。  
  56.   
  57. 10)、ssl_password_callback和log_callback都是函数指针,分别指向SSL密码处理函数、log处理函数。他们原型是:  
  58.   
  59. /* 
  60.  * Register SSL password handler. 
  61.  * This is needed only if SSL certificate asks for a password. Instead of 
  62.  * prompting for a password on a console a specified function will be called. 
  63.  */  
  64. typedef int (*mg_spcb_t)(char *buf, int num, int w, void *key);  
  65.   
  66. /* 
  67.  * User-defined callback function prototype for URI handling, error handling, 
  68.  * or logging server messages. 
  69.  */  
  70. typedef void (*mg_callback_t)(struct mg_connection *,  
  71.         const struct mg_request_info *info, void *user_data  
[cpp] view plaincopyprint?
  1. 2、mg_connection详解  
  2. 故名思意,这个结构体用户保存client的连接信息。它的成员如下:  
  3. /* 
  4.  * Client connection. 
  5.  */  
  6. struct mg_connection {  
  7.     struct mg_request_info  request_info;  
  8.     struct mg_context *ctx;     /* Mongoose context we belong to*/  
  9.     SSL     *ssl;       /* SSL descriptor       */  
  10.     struct socket   client;     /* Connected client     */  
  11.     time_t      birth_time; /* Time connection was accepted */  
  12.     bool_t      free_post_data; /* post_data was malloc-ed  */  
  13.     bool_t      embedded_auth;  /* Used for authorization   */  
  14.     uint64_t    num_bytes_sent; /* Total bytes sent to client   */  
  15. };  
  16. 上面的字段意思都很明显这里就不一一阐述了。可以看出, 每个连接都保存了一个Mongoose上下文(mg_context * ctx),这个很重要,对连接请求进行处理时都会用到。这里也可以看出mg_context相当于一个实例句柄。  
  17. 结构体mg_request_info用于保存每个请求的信息,例如,当我打开博客主页http://www.cnblogs.com/skynet/的时候,会发出一个请求信息,包括请求的方法是POST还是GET等、uri即http://www.cnblogs.com/skynet/、http版本、还有一些http头信息等等。关于结构体mg_request_info的详细信息参见下一小节。  

主要就是上面的两个数据结构了

下面看下如何使用它。

首先我们需要启动http服务,这是通过调用mg_start来实现的

[cpp] view plaincopyprint?
  1. struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,  
  2.         const char **options) {  
这个函数包括一个mg_callback_t类型的回调,user_data可以为NULL,option是一引起需要设置的选项,没有的话会使用里面默认的,如端口默认是8080等。

[cpp] view plaincopyprint?
  1. struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,  
  2.         const char **options) {  
  3.     struct mg_context *ctx;  
  4.     const char *name, *value, *default_value;  
  5.     int i;  
  6.   
  7.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 1111");  
  8.   
  9. #if defined(_WIN32) && !defined(__SYMBIAN32__)  
  10.     WSADATA data;  
  11.     WSAStartup(MAKEWORD(2,2), &data);  
  12. #endif // _WIN32  
  13.     // Allocate context and initialize reasonable general case defaults.  
  14.     // TODO(lsm): do proper error handling here.  
  15.     ctx = (struct mg_context *) calloc(1, sizeof(*ctx));  
  16.     ctx->user_callback = user_callback;  //保存回调  
  17.     ctx->user_data = user_data;  
  18.   
  19.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 2222");  
  20.     while (options && (name = *options++) != NULL) {  //解析option  
  21.         if ((i = get_option_index(name)) == -1) {  
  22.             __android_log_print(ANDROID_LOG_DEBUG, "mongoose""Invalid option: %s", name);  
  23.             free_context(ctx);  
  24.             return NULL;  
  25.         } else if ((value = *options++) == NULL) {  
  26.             __android_log_print(ANDROID_LOG_DEBUG, "mongoose""%s: option value cannot be NULL", name);  
  27.             free_context(ctx);  
  28.             return NULL;  
  29.         }  
  30.         ctx->config[i] = mg_strdup(value);  
  31.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""config:[%s] -> [%s]", name, value);  
  32.     }  
  33.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 3333");  
  34.     // Set default value if needed  
  35.     for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) {  
  36.         default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2];  
  37.         if (ctx->config[i] == NULL && default_value != NULL) {  
  38.             ctx->config[i] = mg_strdup(default_value);  
  39.             DEBUG_TRACE(("Setting default: [%s] -> [%s]",  
  40.                             config_options[i * ENTRIES_PER_CONFIG_OPTION + 1],  
  41.                             default_value));  
  42.         }  
  43.     }  
  44.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 4444");  
  45.     // NOTE(lsm): order is important here. SSL certificates must  
  46.     // be initialized before listening ports. UID must be set last.  
  47.   
  48.     int a = !set_gpass_option(ctx);  
  49.     int b = !set_ssl_option(ctx);  
  50.     int c = !set_ports_option(ctx);//设置监听端口  
  51.     int d = !set_uid_option(ctx);  
  52.     int e = !set_acl_option(ctx);  
  53.   
  54.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set_gpass_option(ctx):%d",a);  
  55.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set_ports_option(ctx):%d",b);  
  56.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set_acl_option(ctx):%d",c);  
  57.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set_uid_option(ctx):%d",d);  
  58.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set_ssl_option(ctx):%d",e);  
  59.   
  60.     if (a || b || c || d || e) {  
  61.   
  62.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start set.......");  
  63.   
  64.         free_context(ctx);  
  65.         return NULL;  
  66.     }  
  67.   
  68.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 5555");  
  69. #if !defined(_WIN32) && !defined(__SYMBIAN32__)  
  70.     // Ignore SIGPIPE signal, so if browser cancels the request, it  
  71.     // won't kill the whole process.  
  72.     (void) signal(SIGPIPE, SIG_IGN);  
  73. #endif // !_WIN32  
  74.     (void) pthread_mutex_init(&ctx->mutex, NULL);  
  75.     (void) pthread_cond_init(&ctx->cond, NULL);  
  76.     (void) pthread_cond_init(&ctx->sq_empty, NULL);  
  77.     (void) pthread_cond_init(&ctx->sq_full, NULL);  
  78.   
  79.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 6666");  
  80.     // Start master (listening) thread  
  81.     start_thread(ctx, (mg_thread_func_t) master_thread, ctx);//启动主线程,处理到来的连接  
  82.   
  83.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 7777");  
  84.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""atoi(ctx->config[NUM_THREADS]) = %d.", atoi(ctx->config[NUM_THREADS]));  
  85.     // Start worker threads  
  86.     for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {  
  87.         if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) {//启动工作线程,具体连接处理  
  88.             cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);  
  89.         } else {  
  90.             ctx->num_threads++;  
  91.         }  
  92.     }  
  93.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""hp mg_start 8888");  
  94.     return ctx;  
  95. }  

mg_start主要是进行一些初始化操作,然后等待启动一个线程等待客户端连接的到来。再启动了一定数量的工作线程进行具体的处理

首先来看一下主线程:

[cpp] view plaincopyprint?
  1. static void master_thread(struct mg_context *ctx) {  
  2.     fd_set read_set;  
  3.     struct timeval tv;  
  4.     struct socket *sp;  
  5.     int max_fd;  
  6.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""master_thread");  
  7.     while (ctx->stop_flag == 0) {  
  8.         FD_ZERO(&read_set);  
  9.         max_fd = -1;  
  10.   
  11.         // Add listening sockets to the read set  
  12.         for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {  
  13.             add_to_set(sp->sock, &read_set, &max_fd);  
  14.         }  
  15.   
  16.         tv.tv_sec = 0;  
  17.         tv.tv_usec = 200 * 1000;  
  18.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""before  select");  
  19.         if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) { //是否有连接到来  
  20. #ifdef _WIN32  
  21.             // On windows, if read_set and write_set are empty,  
  22.             // select() returns "Invalid parameter" error  
  23.             // (at least on my Windows XP Pro). So in this case, we sleep here.  
  24.             sleep(1);  
  25. #endif // _WIN32  
  26.         } else {  
  27.             for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {  
  28.                 if (FD_ISSET(sp->sock, &read_set)) {  
  29.                     accept_new_connection(sp, ctx);//处理到来的连接  
  30.                 }  
  31.             }  
  32.         }  
  33.     }DEBUG_TRACE(("stopping workers"));  
  34.   
  35.     // Stop signal received: somebody called mg_stop. Quit.  
  36.     close_all_listening_sockets(ctx);  
  37.   
  38.     // Wakeup workers that are waiting for connections to handle.  
  39.     pthread_cond_broadcast(&ctx->sq_full);  
  40.   
  41.     // Wait until all threads finish  
  42.     (void) pthread_mutex_lock(&ctx->mutex);  
  43.     while (ctx->num_threads > 0) {  
  44.         (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);  
  45.     }  
  46.     (void) pthread_mutex_unlock(&ctx->mutex);  
  47.   
  48.     // All threads exited, no sync is needed. Destroy mutex and condvars  
  49.     (void) pthread_mutex_destroy(&ctx->mutex);  
  50.     (void) pthread_cond_destroy(&ctx->cond);  
  51.     (void) pthread_cond_destroy(&ctx->sq_empty);  
  52.     (void) pthread_cond_destroy(&ctx->sq_full);  
  53.   
  54.     // Signal mg_stop() that we're done  
  55.     ctx->stop_flag = 2;  
  56.   
  57.     DEBUG_TRACE(("exiting"));  
  58. }  

这里主要是有连接到来的时候调用accept_new_connection把它加入到一个队列里面去。后面的代码就不跟踪了

再来年下worker_thread

[cpp] view plaincopyprint?
  1. static void worker_thread(struct mg_context *ctx) {  
  2.     struct mg_connection *conn;  
  3.     int buf_size = atoi(ctx->config[MAX_REQUEST_SIZE]);  
  4.   
  5.     conn = (struct mg_connection *) calloc(1, sizeof(*conn) + buf_size);  
  6.     conn->buf_size = buf_size;  
  7.     conn->buf = (char *) (conn + 1);  
  8.     assert(conn != NULL);  
  9.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""worker_thread");  
  10.     while (ctx->stop_flag == 0 && consume_socket(ctx, &conn->client)) {//从队列里面去取一个client socket  
  11.         conn->birth_time = time(NULL);  
  12.         conn->ctx = ctx;  
  13.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""into while");  
  14.         // Fill in IP, port info early so even if SSL setup below fails,  
  15.         // error handler would have the corresponding info.  
  16.         // Thanks to Johannes Winkelmann for the patch.  
  17.         conn->request_info.remote_port = ntohs(conn->client.rsa.u.sin.sin_port);  
  18.         memcpy(&conn->request_info.remote_ip,  
  19.                 &conn->client.rsa.u.sin.sin_addr.s_addr, 4);  
  20.         conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);  
  21.         conn->request_info.is_ssl = conn->client.is_ssl;  
  22.   
  23.         if (!conn->client.is_ssl || (conn->client.is_ssl && sslize(conn,  
  24.                 SSL_accept))) {  
  25.             process_new_connection(conn);//进行具体的处理  
  26.         }  
  27.   
  28.         close_connection(conn);  
  29.     }  
  30.     free(conn);  
  31.   
  32.     // Signal master that we're done with connection and exiting  
  33.     (void) pthread_mutex_lock(&ctx->mutex);  
  34.     ctx->num_threads--;  
  35.     (void) pthread_cond_signal(&ctx->cond);  
  36.     assert(ctx->num_threads >= 0);  
  37.     (void) pthread_mutex_unlock(&ctx->mutex);  
  38.   
  39.     DEBUG_TRACE(("exiting"));  
  40. }  

具体的处理是通过process_new_connection进行的

[cpp] view plaincopyprint?
  1. static void process_new_connection(struct mg_connection *conn) {  
  2.     struct mg_request_info *ri = &conn->request_info;  
  3.     int keep_alive_enabled;  
  4.     const char *cl;  
  5.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""process_new_connection");  
  6.     keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");  
  7.   
  8.     do {  
  9.         reset_per_request_attributes(conn);  
  10.   
  11.         // If next request is not pipelined, read it in  
  12.         if ((conn->request_len = get_request_len(conn->buf, conn->data_len))  
  13.                 == 0) {  
  14.                 __android_log_print(ANDROID_LOG_DEBUG, "mongoose""conn->request_len = %d.", conn->request_len);  
  15.             conn->request_len = read_request(NULL, conn->client.sock,//这里进行client数据的读取  
  16.                     conn->ssl, conn->buf, conn->buf_size, &conn->data_len);  
  17.         }  
  18.         assert(conn->data_len >= conn->request_len);  
  19.         if (conn->request_len == 0 && conn->data_len == conn->buf_size) {  
  20.             send_http_error(conn, 413, "Request Too Large""");  
  21.             return;  
  22.         }  
  23.         if (conn->request_len <= 0) {  
  24.             return// Remote end closed the connection  
  25.         }  
  26.   
  27.         // Nul-terminate the request cause parse_http_request() uses sscanf  
  28.         conn->buf[conn->request_len - 1] = '\0';  
  29.         if (!parse_http_request(conn->buf, ri) || (!conn->client.is_proxy<span style="white-space:pre">   </span>//<span style="color: rgb(51, 51, 51); font-family: Georgia, 'Times New Roman', Times, san-serif; font-size: 14px; line-height: 25px; text-align: left; ">请求解析</span>  
  30.                 && !is_valid_uri(ri->uri))) {  
  31.             // Do not put garbage in the access log, just send it back to the client  
  32.             send_http_error(conn, 400, "Bad Request",  
  33.                     "Cannot parse HTTP request: [%.*s]", conn->data_len,  
  34.                     conn->buf);  
  35.         } else if (strcmp(ri->http_version, "1.0") && strcmp(ri->http_version,  
  36.                 "1.1")) {  
  37.             // Request seems valid, but HTTP version is strange  
  38.             send_http_error(conn, 505, "HTTP version not supported""");  
  39.             log_access(conn);  
  40.         } else {  
  41.             // Request is valid, handle it  
  42.             cl = get_header(ri, "Content-Length");  
  43.             conn->content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);  
  44.             conn->birth_time = time(NULL);  
  45.             if (conn->client.is_proxy) {  
  46.                 handle_proxy_request(conn);  
  47.             } else {  
  48.                 handle_request(conn);//处理请求  
  49.             }  
  50.             log_access(conn);  
  51.             discard_current_request_from_buffer(conn);  
  52.         }  
  53.         // conn->peer is not NULL only for SSL-ed proxy connections  
  54.     } while (conn->peer || (keep_alive_enabled && should_keep_alive(conn)));  
  55. }  

这里面的读取请求是通过read_request,里面再调用pull进行数据的读取

[cpp] view plaincopyprint?
  1. static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {  
  2.     int nread;  
  3.   
  4.     if (ssl != NULL) {  
  5.         nread = SSL_read(ssl, buf, len);  
  6.     } else if (fp != NULL) {  
  7.         // Use read() instead of fread(), because if we're reading from the CGI  
  8.         // pipe, fread() may block until IO buffer is filled up. We cannot afford  
  9.         // to block and must pass all read bytes immediately to the client.  
  10.         nread = read(fileno(fp), buf, (size_t) len);  
  11.         if (ferror(fp))  
  12.             nread = -1;  
  13.     } else {  
  14.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""sock = %d", sock);  
  15.         nread = recv(sock, buf, (size_t) len, 0);  
  16.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""buf = %s", buf);  
  17.     }  
  18.   
  19.     return nread;  
  20. }  

handle_request进行用户请求的处理,

[cpp] view plaincopyprint?
  1. // This is the heart of the Mongoose's logic.  
  2. // This function is called when the request is read, parsed and validated,  
  3. // and Mongoose must decide what action to take: serve a file, or  
  4. // a directory, or call embedded function, etcetera.  
  5. static void handle_request(struct mg_connection *conn) {  
  6.     struct mg_request_info *ri = &conn->request_info;  
  7.     char path[PATH_MAX];  
  8.     int uri_len;  
  9.     struct mgstat st;  
  10.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""handle_request");  
  11.     if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {  
  12.         *conn->request_info.query_string++ = '\0';  
  13.     }  
  14.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""ri->uri = %s.", ri->uri);  
  15.     uri_len = strlen(ri->uri);  
  16.     (void) url_decode(ri->uri, (size_t) uri_len, ri->uri,  
  17.             (size_t) (uri_len + 1), 0);  
  18.     remove_double_dots_and_double_slashes(ri->uri);  
  19.     convert_uri_to_file_name(conn, ri->uri, path, sizeof(path));  
  20.     __android_log_print(ANDROID_LOG_DEBUG, "mongoose""ri->request_method = %s.", ri->request_method);  
  21.     DEBUG_TRACE(("%s", ri->uri));  
  22.     if (!check_authorization(conn, path)) {  
  23.         send_authorization_request(conn);  
  24.     } else if (call_user(conn, MG_NEW_REQUEST) != NULL) {//这里调用用户注册的函数  
  25.             __android_log_print(ANDROID_LOG_DEBUG, "mongoose""call_user  .MG_NEW_REQUEST");  
  26.         // Do nothing, callback has served the request  
  27.     } else if (strstr(path, PASSWORDS_FILE_NAME)) {  
  28.         // Do not allow to view passwords files  
  29.         send_http_error(conn, 403, "Forbidden""Access Forbidden");  
  30.     } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {  
  31.         send_http_error(conn, 404, "Not Found""Not Found");  
  32.     } else if ((!strcmp(ri->request_method, "PUT") || !strcmp(  
  33.             ri->request_method, "DELETE"))  
  34.             && (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL  
  35.                     || !is_authorized_for_put(conn))) {  
  36.         send_authorization_request(conn);  
  37.     } else if (!strcmp(ri->request_method, "PUT")) {  
  38.         put_file(conn, path);  
  39.     } else if (!strcmp(ri->request_method, "DELETE")) {  
  40.         if (mg_remove(path) == 0) {  
  41.             send_http_error(conn, 200, "OK""");  
  42.         } else {  
  43.             send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,  
  44.                     strerror(ERRNO));  
  45.         }  
  46.     } else if (mg_stat(path, &st) != 0) {  
  47.         send_http_error(conn, 404, "Not Found""%s""File not found");  
  48.     } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {  
  49.         (void) mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"  
  50.             "Location: %s/\r\n\r\n", ri->uri);  
  51.     } else if (st.is_directory && !substitute_index_file(conn, path,  
  52.             sizeof(path), &st)) {  
  53.         if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {  
  54.             handle_directory_request(conn, path);  
  55.         } else {  
  56.             send_http_error(conn, 403, "Directory Listing Denied",  
  57.                     "Directory listing denied");  
  58.         }  
  59.     } else if (match_extension(path, conn->ctx->config[CGI_EXTENSIONS])) {  
  60.         if (strcmp(ri->request_method, "POST") && strcmp(ri->request_method,  
  61.                 "GET")) {  
  62.             send_http_error(conn, 501, "Not Implemented",  
  63.                     "Method %s is not implemented", ri->request_method);  
  64.         } else {  
  65.             handle_cgi_request(conn, path);  
  66.         }  
  67.     } else if (match_extension(path, conn->ctx->config[SSI_EXTENSIONS])) {  
  68.         handle_ssi_file_request(conn, path);  
  69.     } else if (is_not_modified(conn, &st)) {  
  70.         send_http_error(conn, 304, "Not Modified""");  
  71.     } else {  
  72.         __android_log_print(ANDROID_LOG_DEBUG, "mongoose""handle_file_request");  
  73.         handle_file_request(conn, path, &st);  
  74.     }  
  75. }  

再来看一下请求解析的函数:

[cpp] view plaincopyprint?
  1. static int parse_http_request(char *buf, struct mg_request_info *ri) {  
  2.     int status = 0;  
  3.   
  4.     // RFC says that all initial whitespaces should be ingored  
  5.     while (*buf != '\0' && isspace(* (unsigned char *) buf)) {  
  6.         buf++;  
  7.     }  
  8.   
  9.     ri->request_method = skip(&buf, " ");  
  10.     ri->uri = skip(&buf, " ");  
  11.     ri->http_version = skip(&buf, "\r\n");  
  12.   
  13.     if (is_valid_http_method(ri->request_method) && strncmp(ri->http_version,  
  14.             "HTTP/", 5) == 0) {  
  15.         ri->http_version += 5; /* Skip "HTTP/" */  
  16.         parse_http_headers(&buf, ri);  
  17.         status = 1;  
  18.     }  
  19.   
  20.     return status;  
  21. }  

它的主要工作就是从buf中提取出信息放到ri(一个mg_request_info结构)中去,因为buf是一个无结构的字符串数组。要将它存储到ri中去,需要找到对应的子串。
这里主要用到了skip()、parse_http_headers()方法,其中skip()很关键


当我们要发送数据给client端时,可以通过mg_write函数来实现,这个函数可以在回调函数里面去调用。

[cpp] view plaincopyprint?
  1. int mg_write(struct mg_connection *conn, const void *buf, size_t len) {  
  2.     return (int) push(NULL, conn->client.sock, conn->ssl, (const char *) buf,  
  3.             (int64_t) len);  
  4. }  

[cpp] view plaincopyprint?
  1. // Write data to the IO channel - opened file descriptor, socket or SSL  
  2. // descriptor. Return number of bytes written.  
  3. static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,  
  4.         int64_t len) {  
  5.     int64_t sent;  
  6.     int n, k;  
  7.   
  8.     sent = 0;  
  9.     while (sent < len) {  
  10.   
  11.         /* How many bytes we send in this iteration */  
  12.         k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);  
  13.   
  14.         if (ssl != NULL) {  
  15.             n = SSL_write(ssl, buf + sent, k);  
  16.         } else if (fp != NULL) {  
  17.             n = fwrite(buf + sent, 1, (size_t) k, fp);  
  18.             if (ferror(fp))  
  19.                 n = -1;  
  20.         } else {  
  21.             n = send(sock, buf + sent, (size_t) k, 0);  
  22.         }  
  23.   
  24.         if (n < 0)  
  25.             break;  
  26.         if(n == 0){  
  27.             usleep(1000);  
  28.         }  
  29.         sent += n;  
  30.     }  
  31.   
  32.     return sent;  
  33. }  

主要就是send发送数据过去


mongoose的基本流程大概也就这样,其它的就以后需要时再去具体分析吧。

0 0
原创粉丝点击