diff src/http/ngx_http.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children 4b2dafa26fe2
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http.c
@@ -0,0 +1,642 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_http.h>
+
+
+static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_http_merge_locations(ngx_conf_t *cf,
+                                      ngx_array_t *locations,
+                                      void **loc_conf,
+                                      ngx_http_module_t *module,
+                                      ngx_uint_t ctx_index);
+
+int         ngx_http_max_module;
+
+ngx_uint_t  ngx_http_total_requests;
+uint64_t    ngx_http_total_sent;
+
+
+ngx_int_t  (*ngx_http_top_header_filter) (ngx_http_request_t *r);
+ngx_int_t  (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+
+
+static ngx_command_t  ngx_http_commands[] = {
+
+    {ngx_string("http"),
+     NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+     ngx_http_block,
+     0,
+     0,
+     NULL},
+
+    ngx_null_command
+};
+
+    
+static ngx_core_module_t  ngx_http_module_ctx = {
+    ngx_string("http"),
+    NULL,
+    NULL
+};  
+
+
+ngx_module_t  ngx_http_module = {
+    NGX_MODULE,
+    &ngx_http_module_ctx,                  /* module context */
+    ngx_http_commands,                     /* module directives */
+    NGX_CORE_MODULE,                       /* module type */
+    NULL,                                  /* init module */
+    NULL                                   /* init child */
+};
+
+
+static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char                        *rv;
+    ngx_uint_t                   mi, m, s, l, p, a, n;
+    ngx_uint_t                   port_found, addr_found, virtual_names;
+    ngx_conf_t                   pcf;
+    ngx_array_t                  in_ports;
+    ngx_listening_t             *ls;
+    ngx_http_listen_t           *lscf;
+    ngx_http_module_t           *module;
+    ngx_http_handler_pt         *h;
+    ngx_http_conf_ctx_t         *ctx;
+    ngx_http_in_port_t          *in_port, *inport;
+    ngx_http_in_addr_t          *in_addr, *inaddr;
+    ngx_http_server_name_t      *s_name, *name;
+    ngx_http_core_srv_conf_t   **cscfp, *cscf;
+    ngx_http_core_loc_conf_t    *clcf;
+    ngx_http_core_main_conf_t   *cmcf;
+#if (WIN32)
+    ngx_iocp_conf_t             *iocpcf;
+#endif
+
+    /* the main http context */
+    ngx_test_null(ctx,
+                  ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
+                  NGX_CONF_ERROR);
+
+    *(ngx_http_conf_ctx_t **) conf = ctx;
+
+    /* count the number of the http modules and set up their indices */
+
+    ngx_http_max_module = 0;
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        ngx_modules[m]->ctx_index = ngx_http_max_module++;
+    }
+
+    /* the main http main_conf, it's the same in the all http contexts */
+    ngx_test_null(ctx->main_conf,
+                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
+                  NGX_CONF_ERROR);
+
+    /* the http null srv_conf, it's used to merge the server{}s' srv_conf's */
+    ngx_test_null(ctx->srv_conf,
+                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
+                  NGX_CONF_ERROR);
+
+    /* the http null loc_conf, it's used to merge the server{}s' loc_conf's */
+    ngx_test_null(ctx->loc_conf,
+                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
+                  NGX_CONF_ERROR);
+
+
+    /* create the main_conf, srv_conf and loc_conf in all http modules */
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+        mi = ngx_modules[m]->ctx_index;
+
+        if (module->pre_conf) {
+            if (module->pre_conf(cf) != NGX_OK) {
+                return NGX_CONF_ERROR;
+            }
+        }
+
+        if (module->create_main_conf) {
+            ngx_test_null(ctx->main_conf[mi], module->create_main_conf(cf),
+                          NGX_CONF_ERROR);
+        }
+
+        if (module->create_srv_conf) {
+            ngx_test_null(ctx->srv_conf[mi], module->create_srv_conf(cf),
+                          NGX_CONF_ERROR);
+        }
+
+        if (module->create_loc_conf) {
+            ngx_test_null(ctx->loc_conf[mi], module->create_loc_conf(cf),
+                          NGX_CONF_ERROR);
+        }
+    }
+
+    /* parse inside the http{} block */
+
+    pcf = *cf;
+    cf->ctx = ctx;
+    cf->module_type = NGX_HTTP_MODULE;
+    cf->cmd_type = NGX_HTTP_MAIN_CONF;
+    rv = ngx_conf_parse(cf, NULL);
+
+    if (rv != NGX_CONF_OK) {
+        *cf = pcf;
+        return rv;
+    }
+
+    /*
+     * init http{} main_conf's, merge the server{}s' srv_conf's
+     * and its location{}s' loc_conf's
+     */
+
+    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
+    cscfp = cmcf->servers.elts;
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+        mi = ngx_modules[m]->ctx_index;
+
+        /* init http{} main_conf's */
+
+        if (module->init_main_conf) {
+            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
+            if (rv != NGX_CONF_OK) {
+                *cf = pcf;
+                return rv;
+            }
+        }
+
+        for (s = 0; s < cmcf->servers.nelts; s++) {
+
+            /* merge the server{}s' srv_conf's */
+
+            if (module->merge_srv_conf) {
+                rv = module->merge_srv_conf(cf,
+                                            ctx->srv_conf[mi],
+                                            cscfp[s]->ctx->srv_conf[mi]);
+                if (rv != NGX_CONF_OK) {
+                    *cf = pcf;
+                    return rv;
+                }
+            }
+
+            if (module->merge_loc_conf) {
+
+                /* merge the server{}'s loc_conf */
+
+                rv = module->merge_loc_conf(cf,
+                                            ctx->loc_conf[mi],
+                                            cscfp[s]->ctx->loc_conf[mi]);
+                if (rv != NGX_CONF_OK) {
+                    *cf = pcf;
+                    return rv;
+                }
+
+                /* merge the locations{}' loc_conf's */
+
+                rv = ngx_http_merge_locations(cf, &cscfp[s]->locations,
+                                              cscfp[s]->ctx->loc_conf,
+                                              module, mi);
+                if (rv != NGX_CONF_OK) {
+                    *cf = pcf;
+                    return rv;
+                }
+
+#if 0
+                clcfp = (ngx_http_core_loc_conf_t **) cscfp[s]->locations.elts;
+
+                for (l = 0; l < cscfp[s]->locations.nelts; l++) {
+                    rv = module->merge_loc_conf(cf,
+                                                cscfp[s]->ctx->loc_conf[mi],
+                                                clcfp[l]->loc_conf[mi]);
+                    if (rv != NGX_CONF_OK) {
+                        *cf = pcf;
+                        return rv;
+                    }
+                }
+#endif
+            }
+        }
+    }
+
+    /* we needed "http"'s cf->ctx while merging configuration */
+    *cf = pcf;
+
+    /* init lists of the handlers */
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
+                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+    cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK;
+
+
+    /* the special find config phase for single handler */
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers,
+                   cf->cycle->pool, 1, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+    cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK;
+
+    ngx_test_null(h, ngx_push_array(
+                           &cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers),
+                  NGX_CONF_ERROR);
+    *h = ngx_http_find_location_config;
+
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
+                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+    cmcf->phases[NGX_HTTP_ACCESS_PHASE].type = NGX_DECLINED;
+
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
+                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+    cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK;
+
+
+    /*
+     * create the lists of the ports, the addresses and the server names
+     * to allow quickly find the server core module configuration at run-time
+     */
+
+    ngx_init_array(in_ports, cf->pool, 10, sizeof(ngx_http_in_port_t),
+                   NGX_CONF_ERROR);
+
+    /* "server" directives */
+    cscfp = cmcf->servers.elts;
+    for (s = 0; s < cmcf->servers.nelts; s++) {
+
+        /* "listen" directives */
+        lscf = cscfp[s]->listen.elts;
+        for (l = 0; l < cscfp[s]->listen.nelts; l++) {
+
+            port_found = 0;
+
+            /* AF_INET only */
+
+            in_port = in_ports.elts;
+            for (p = 0; p < in_ports.nelts; p++) {
+
+                if (lscf[l].port == in_port[p].port) {
+
+                    /* the port is already in the port list */
+
+                    port_found = 1;
+                    addr_found = 0;
+
+                    in_addr = in_port[p].addrs.elts;
+                    for (a = 0; a < in_port[p].addrs.nelts; a++) {
+
+                        if (lscf[l].addr == in_addr[a].addr) {
+
+                            /* the address is already bound to this port */
+
+                            /* "server_name" directives */
+                            s_name = cscfp[s]->server_names.elts;
+                            for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
+
+                                /*
+                                 * add the server name and server core module
+                                 * configuration to the address:port
+                                 */
+
+                                /* TODO: duplicate names can be checked here */
+
+                                ngx_test_null(name,
+                                              ngx_push_array(&in_addr[a].names),
+                                              NGX_CONF_ERROR);
+
+                                name->name = s_name[n].name;
+                                name->core_srv_conf = s_name[n].core_srv_conf;
+                            }
+
+                            /*
+                             * check duplicate "default" server that
+                             * serves this address:port
+                             */
+
+                            if (lscf[l].default_server) {
+                                if (in_addr[a].default_server) {
+                                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
+                                           "duplicate default server in %s:%d",
+                                           lscf[l].file_name.data,
+                                           lscf[l].line);
+
+                                    return NGX_CONF_ERROR;
+                                }
+
+                                in_addr[a].core_srv_conf = cscfp[s];
+                                in_addr[a].default_server = 1;
+                            }
+
+                            addr_found = 1;
+
+                            break;
+
+                        } else if (in_addr[a].addr == INADDR_ANY) {
+
+                            /*
+                             * "*:port" must be the last resort so move it
+                             * to the end of the address list and add
+                             * the new address at its place
+                             */
+
+                            ngx_test_null(inaddr,
+                                          ngx_push_array(&in_port[p].addrs),
+                                          NGX_CONF_ERROR);
+
+                            ngx_memcpy(inaddr, &in_addr[a],
+                                       sizeof(ngx_http_in_addr_t));
+
+                            in_addr[a].addr = lscf[l].addr;
+                            in_addr[a].default_server = lscf[l].default_server;
+                            in_addr[a].core_srv_conf = cscfp[s];
+
+                            /*
+                             * create the empty list of the server names that
+                             * can be served on this address:port
+                             */
+
+                            ngx_init_array(inaddr->names, cf->pool, 10,
+                                           sizeof(ngx_http_server_name_t),
+                                           NGX_CONF_ERROR);
+
+                            addr_found = 1;
+
+                            break;
+                        }
+                    }
+
+                    if (!addr_found) {
+
+                        /*
+                         * add the address to the addresses list that
+                         * bound to this port
+                         */
+
+                        ngx_test_null(inaddr,
+                                      ngx_push_array(&in_port[p].addrs),
+                                      NGX_CONF_ERROR);
+
+                        inaddr->addr = lscf[l].addr;
+                        inaddr->default_server = lscf[l].default_server;
+                        inaddr->core_srv_conf = cscfp[s];
+
+                        /*
+                         * create the empty list of the server names that
+                         * can be served on this address:port
+                         */
+
+                        ngx_init_array(inaddr->names, cf->pool, 10,
+                                       sizeof(ngx_http_server_name_t),
+                                       NGX_CONF_ERROR);
+                    }
+                }
+            }
+
+            if (!port_found) {
+
+                /* add the port to the in_port list */
+
+                ngx_test_null(in_port,
+                              ngx_push_array(&in_ports),
+                              NGX_CONF_ERROR);
+
+                in_port->port = lscf[l].port;
+
+                ngx_test_null(in_port->port_text.data, ngx_palloc(cf->pool, 7),
+                              NGX_CONF_ERROR);
+                in_port->port_text.len = ngx_snprintf((char *)
+                                                      in_port->port_text.data,
+                                                      7, ":%d",
+                                                      in_port->port);
+
+                /* create list of the addresses that bound to this port ... */
+
+                ngx_init_array(in_port->addrs, cf->pool, 10,
+                               sizeof(ngx_http_in_addr_t),
+                               NGX_CONF_ERROR);
+
+                ngx_test_null(inaddr, ngx_push_array(&in_port->addrs),
+                              NGX_CONF_ERROR);
+
+                /* ... and add the address to this list */
+
+                inaddr->addr = lscf[l].addr;
+                inaddr->default_server = lscf[l].default_server;
+                inaddr->core_srv_conf = cscfp[s];
+
+                /*
+                 * create the empty list of the server names that
+                 * can be served on this address:port
+                 */
+
+                ngx_init_array(inaddr->names, cf->pool, 10,
+                               sizeof(ngx_http_server_name_t),
+                               NGX_CONF_ERROR);
+            }
+        }
+    }
+
+    /* optimize the lists of the ports, the addresses and the server names */
+
+    /* AF_INET only */
+
+    in_port = in_ports.elts;
+    for (p = 0; p < in_ports.nelts; p++) {
+
+        /* check whether the all server names point to the same server */
+
+        in_addr = in_port[p].addrs.elts;
+        for (a = 0; a < in_port[p].addrs.nelts; a++) {
+
+            virtual_names = 0;
+
+            name = in_addr[a].names.elts;
+            for (n = 0; n < in_addr[a].names.nelts; n++) {
+                if (in_addr[a].core_srv_conf != name[n].core_srv_conf) {
+                    virtual_names = 1;
+                    break;
+                }
+            }
+
+            /*
+             * if the all server names point to the same server
+             * then we do not need to check them at run-time
+             */
+
+            if (!virtual_names) {
+                in_addr[a].names.nelts = 0;
+            }
+        }
+
+        /*
+         * if there's the binding to "*:port" then we need to bind()
+         * to "*:port" only and ignore the other bindings
+         */
+
+        if (in_addr[a - 1].addr == INADDR_ANY) {
+            a--;
+
+        } else {
+            a = 0;
+        }
+
+        in_addr = in_port[p].addrs.elts;
+        while (a < in_port[p].addrs.nelts) {
+
+            ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
+                                                  in_port[p].port);
+            if (ls == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            ls->backlog = -1;
+#if 0
+#if 0
+            ls->nonblocking = 1;
+#else
+            ls->nonblocking = 0;
+#endif
+#endif
+            ls->addr_ntop = 1;
+
+            ls->handler = ngx_http_init_connection;
+
+            cscf = in_addr[a].core_srv_conf;
+            ls->pool_size = cscf->connection_pool_size;
+            ls->post_accept_timeout = cscf->post_accept_timeout;
+
+            clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];
+            ls->log = clcf->err_log;
+
+#if (WIN32)
+            iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
+            if (iocpcf->acceptex_read) {
+                ls->post_accept_buffer_size = cscf->client_header_buffer_size;
+            }
+#endif
+
+            ls->ctx = ctx;
+
+            if (in_port[p].addrs.nelts > 1) {
+
+                in_addr = in_port[p].addrs.elts;
+                if (in_addr[in_port[p].addrs.nelts - 1].addr != INADDR_ANY) {
+
+                    /*
+                     * if this port has not the "*:port" binding then create
+                     * the separate ngx_http_in_port_t for the all bindings
+                     */
+
+                    ngx_test_null(inport,
+                                  ngx_palloc(cf->pool,
+                                             sizeof(ngx_http_in_port_t)),
+                                  NGX_CONF_ERROR);
+
+                    inport->port = in_port[p].port;
+                    inport->port_text = in_port[p].port_text;
+
+                    /* init list of the addresses ... */
+
+                    ngx_init_array(inport->addrs, cf->pool, 1,
+                                   sizeof(ngx_http_in_addr_t),
+                                   NGX_CONF_ERROR);
+
+                    /* ... and set up it with the first address */
+
+                    inport->addrs.nelts = 1;
+                    inport->addrs.elts = in_port[p].addrs.elts;
+
+                    ls->servers = inport;
+
+                    /* prepare for the next cycle */
+
+                    in_port[p].addrs.elts = (char *) in_port[p].addrs.elts
+                                                       + in_port[p].addrs.size;
+                    in_port[p].addrs.nelts--;
+
+                    in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts;
+                    a = 0;
+
+                    continue;
+                }
+            }
+
+            ls->servers = &in_port[p];
+            a++;
+        }
+    }
+
+#if (NGX_DEBUG)
+    in_port = in_ports.elts;
+    for (p = 0; p < in_ports.nelts; p++) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                      "port: %d %08x", in_port[p].port, &in_port[p]);
+        in_addr = in_port[p].addrs.elts;
+        for (a = 0; a < in_port[p].addrs.nelts; a++) {
+            u_char ip[20];
+            ngx_inet_ntop(AF_INET, &in_addr[a].addr, ip, 20);
+            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                           "%s %08x", ip, in_addr[a].core_srv_conf);
+            s_name = in_addr[a].names.elts;
+            for (n = 0; n < in_addr[a].names.nelts; n++) {
+                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
+                                "%s %08x", s_name[n].name.data,
+                                s_name[n].core_srv_conf);
+            }
+        }
+    }
+#endif
+
+    return NGX_CONF_OK;
+}
+
+
+static char *ngx_http_merge_locations(ngx_conf_t *cf,
+                                      ngx_array_t *locations,
+                                      void **loc_conf,
+                                      ngx_http_module_t *module,
+                                      ngx_uint_t ctx_index)
+{
+    char                       *rv;
+    ngx_uint_t                  i;
+    ngx_http_core_loc_conf_t  **clcfp;
+
+    clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts;
+
+    for (i = 0; i < locations->nelts; i++) {
+        rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
+                                    clcfp[i]->loc_conf[ctx_index]);
+        if (rv != NGX_CONF_OK) {
+            return rv;
+        }
+
+        rv = ngx_http_merge_locations(cf, &clcfp[i]->locations,
+                                      clcfp[i]->loc_conf, module, ctx_index);
+        if (rv != NGX_CONF_OK) {
+            return rv;
+        }
+    }
+
+    return NGX_CONF_OK;
+}