Mercurial > hg > nginx-vendor-0-6
view src/core/ngx_conf_file.c @ 34:aab2ea7c0458 NGINX_0_1_17
nginx 0.1.17
*) Change: the ngx_http_rewrite_module was rewritten from the scratch.
Now it is possible to redirect, to return the error codes, to check
the variables and referrers. The directives can be used inside
locations. The redirect directive was canceled.
*) Feature: the ngx_http_geo_module.
*) Feature: the proxy_set_x_var and fastcgi_set_var directives.
*) Bugfix: the location configuration with "=" modifier may be used in
another location.
*) Bugfix: the correct content type was set only for requests that use
small caps letters in extension.
*) Bugfix: if the proxy_pass or fastcgi_pass directives were set in the
location, and access was denied, and the error was redirected to a
static page, then the segmentation fault occurred.
*) Bugfix: if in a proxied "Location" header was a relative URL, then a
host name and a slash were added to them; bug appeared in 0.1.14.
*) Bugfix: the system error message was not logged on Linux.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Thu, 03 Feb 2005 00:00:00 +0300 |
parents | da8c190bdaba |
children | a39d1b793287 |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev */ #include <ngx_config.h> #include <ngx_core.h> static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_conf_commands[] = { { ngx_string("include"), NGX_ANY_CONF|NGX_CONF_TAKE1, ngx_conf_include, 0, 0, NULL }, ngx_null_command }; ngx_module_t ngx_conf_module = { NGX_MODULE, NULL, /* module context */ ngx_conf_commands, /* module directives */ NGX_CONF_MODULE, /* module type */ NULL, /* init module */ NULL /* init child */ }; /* The ten fixed arguments */ static int argument_number[] = { NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2, NGX_CONF_TAKE3, NGX_CONF_TAKE4, NGX_CONF_TAKE5, NGX_CONF_TAKE6, NGX_CONF_TAKE7 }; static int ngx_conf_read_token(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { int m, rc, found, valid; char *rv; void *conf, **confp; ngx_fd_t fd; ngx_str_t *name; ngx_conf_file_t *prev; ngx_command_t *cmd; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; if (!(cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t)))) { return NGX_CONF_ERROR; } if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, ngx_pagesize); if (cf->conf_file->buffer == NULL) { return NGX_CONF_ERROR; } cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log;; cf->conf_file->line = 1; } for ( ;; ) { rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { break; } if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) { break; } if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } else if (rv == NGX_CONF_ERROR) { rc = NGX_ERROR; break; } else { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "%s in %s:%d", rv, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } } name = (ngx_str_t *) cf->args->elts; found = 0; for (m = 0; rc != NGX_ERROR && !found && ngx_modules[m]; m++) { /* look up the directive in the appropriate modules */ if (ngx_modules[m]->type != NGX_CONF_MODULE && ngx_modules[m]->type != cf->module_type) { continue; } cmd = ngx_modules[m]->commands; if (cmd == NULL) { continue; } while (cmd->name.len) { if (name->len == cmd->name.len && ngx_strcmp(name->data, cmd->name.data) == 0) { found = 1; /* is the directive's location right ? */ if ((cmd->type & cf->cmd_type) == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "directive \"%s\" in %s:%d " "is not allowed here", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } if (!(cmd->type & NGX_CONF_BLOCK) && rc != NGX_OK) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "directive \"%s\" in %s:%d " "is not terminated by \";\"", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } if ((cmd->type & NGX_CONF_BLOCK) && rc != NGX_CONF_BLOCK_START) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "directive \"%s\" in %s:%d " "has not the opening \"{\"", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } /* is the directive's argument count right ? */ if (cmd->type & NGX_CONF_ANY) { valid = 1; } else if (cmd->type & NGX_CONF_FLAG) { if (cf->args->nelts == 2) { valid = 1; } else { valid = 0; } } else if (cmd->type & NGX_CONF_1MORE) { if (cf->args->nelts > 1) { valid = 1; } else { valid = 0; } } else if (cmd->type & NGX_CONF_2MORE) { if (cf->args->nelts > 2) { valid = 1; } else { valid = 0; } } else if (cf->args->nelts <= 10 && (cmd->type & argument_number[cf->args->nelts - 1])) { valid = 1; } else { valid = 0; } if (!valid) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "invalid number arguments in " "directive \"%s\" in %s:%d", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } /* set up the directive's configuration context */ conf = NULL; if (cmd->type & NGX_DIRECT_CONF) { conf = ((void **) cf->ctx)[ngx_modules[m]->index]; } else if (cmd->type & NGX_MAIN_CONF) { conf = &(((void **) cf->ctx)[ngx_modules[m]->index]); } else if (cf->ctx) { confp = *(void **) ((char *) cf->ctx + cmd->conf); if (confp) { conf = confp[ngx_modules[m]->ctx_index]; } } rv = cmd->set(cf, cmd, conf); if (rv == NGX_CONF_OK) { break; } else if (rv == NGX_CONF_ERROR) { rc = NGX_ERROR; break; } else { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"%s\" directive %s in %s:%d", name->data, rv, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } } cmd++; } } if (!found) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unknown directive \"%s\" in %s:%d", name->data, cf->conf_file->file.name.data, cf->conf_file->line); rc = NGX_ERROR; break; } if (rc == NGX_ERROR) { break; } } if (filename) { cf->conf_file = prev; if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", cf->conf_file->file.name.data); return NGX_CONF_ERROR; } } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; } static int ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; int len; int found, need_space, last_space, sharp_comment; int quoted, s_quoted, d_quoted; ssize_t n; ngx_str_t *word; ngx_buf_t *b; found = 0; need_space = 0; last_space = 1; sharp_comment = 0; quoted = s_quoted = d_quoted = 0; cf->args->nelts = 0; b = cf->conf_file->buffer; start = b->pos; for ( ;; ) { if (b->pos >= b->last) { if (cf->conf_file->file.offset >= ngx_file_size(&cf->conf_file->file.info)) { return NGX_CONF_FILE_DONE; } if (b->pos - start) { ngx_memcpy(b->start, start, b->pos - start); } n = ngx_read_file(&cf->conf_file->file, b->start + (b->pos - start), b->end - (b->start + (b->pos - start)), cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } b->pos = b->start + (b->pos - start); start = b->start; b->last = b->pos + n; } ch = *b->pos++; if (ch == LF) { cf->conf_file->line++; if (sharp_comment) { sharp_comment = 0; } } if (sharp_comment) { continue; } if (quoted) { quoted = 0; continue; } if (need_space) { if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { last_space = 1; need_space = 0; continue; } if (ch == ';') { return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unexpected '%c' in %s:%d", ch, cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; } if (last_space) { if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { continue; } start = b->pos - 1; switch (ch) { case ';': case '{': if (cf->args->nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unexpected '%c' in %s:%d", ch, cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; } if (ch == '{') { return NGX_CONF_BLOCK_START; } return NGX_OK; case '}': if (cf->args->nelts > 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "unexpected '}' in %s:%d", cf->conf_file->file.name.data, cf->conf_file->line); return NGX_ERROR; } return NGX_CONF_BLOCK_DONE; case '#': sharp_comment = 1; continue; case '\\': quoted = 1; last_space = 0; continue; case '"': start++; d_quoted = 1; last_space = 0; continue; case '\'': start++; s_quoted = 1; last_space = 0; continue; default: last_space = 0; } } else { if (ch == '\\') { quoted = 1; continue; } if (d_quoted) { if (ch == '"') { d_quoted = 0; need_space = 1; found = 1; } } else if (s_quoted) { if (ch == '\'') { s_quoted = 0; need_space = 1; found = 1; } } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF || ch == ';' || ch == '{') { last_space = 1; found = 1; } if (found) { if (!(word = ngx_push_array(cf->args))) { return NGX_ERROR; } if (!(word->data = ngx_palloc(cf->pool, b->pos - start + 1))) { return NGX_ERROR; } for (dst = word->data, src = start, len = 0; src < b->pos - 1; len++) { if (*src == '\\') { switch (src[1]) { case '"': case '\'': case '\\': src++; break; case 't': *dst++ = '\t'; src += 2; continue; case 'r': *dst++ = '\r'; src += 2; continue; case 'n': *dst++ = '\n'; src += 2; continue; } } *dst++ = *src++; } *dst = '\0'; word->len = len; if (ch == ';') { return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } found = 0; } } } } static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_str_t *value, file; value = cf->args->elts; file = value[1]; if (ngx_conf_full_name(cf->cycle, &file) == NGX_ERROR){ return NGX_CONF_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); return ngx_conf_parse(cf, &file); } ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name) { u_char *p; ngx_str_t old; if (name->data[0] == '/') { return NGX_OK; } #if (NGX_WIN32) if (name->len > 2 && name->data[1] == ':' && ((name->data[0] >= 'a' && name->data[0] <= 'z') || (name->data[0] >= 'A' && name->data[0] <= 'Z'))) { return NGX_OK; } #endif old = *name; name->len = cycle->root.len + old.len; if (cycle->connections) { if (!(name->data = ngx_palloc(cycle->pool, name->len + 1))) { return NGX_ERROR; } } else { /* the init_cycle */ if (!(name->data = ngx_alloc(name->len + 1, cycle->log))) { return NGX_ERROR; } } p = ngx_cpymem(name->data, cycle->root.data, cycle->root.len), ngx_cpystrn(p, old.data, old.len + 1); return NGX_OK; } ngx_open_file_t *ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name) { ngx_str_t full; ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; #if (NGX_SUPPRESS_WARN) full.len = 0; full.data = NULL; #endif if (name) { full = *name; if (ngx_conf_full_name(cycle, &full) == NGX_ERROR) { return NULL; } part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (full.len != file[i].name.len) { continue; } if (ngx_strcmp(full.data, file[i].name.data) == 0) { return &file[i]; } } } if (!(file = ngx_list_push(&cycle->open_files))) { return NULL; } if (name) { file->fd = NGX_INVALID_FILE; file->name = full; } else { file->fd = ngx_stderr_fileno; file->name.len = 0; file->name.data = NULL; } return file; } void ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err, char *fmt, ...) { u_char errstr[NGX_MAX_CONF_ERRSTR], *buf, *last; va_list args; last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); buf = ngx_vsnprintf(errstr, last - errstr, fmt, args); va_end(args); *buf = '\0'; if (err) { buf = ngx_snprintf(buf, last - buf - 1, " (%d: ", err); buf = ngx_strerror_r(err, buf, last - buf - 1); *buf++ = ')'; *buf = '\0'; } ngx_log_error(level, cf->log, 0, "%s in %s:%d", errstr, cf->conf_file->file.name.data, cf->conf_file->line); } char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_str_t *value; ngx_flag_t *fp; ngx_conf_post_t *post; fp = (ngx_flag_t *) (p + cmd->offset); if (*fp != NGX_CONF_UNSET) { return "is duplicate"; } value = cf->args->elts; if (ngx_strcasecmp(value[1].data, "on") == 0) { *fp = 1; } else if (ngx_strcasecmp(value[1].data, "off") == 0) { *fp = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%s\" in \"%s\" directive, " "it must be \"on\" or \"off\"", value[1].data, cmd->name.data); return NGX_CONF_ERROR; } if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, fp); } return NGX_CONF_OK; } char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_str_t *field, *value; ngx_conf_post_t *post; field = (ngx_str_t *) (p + cmd->offset); if (field->data) { return "is duplicate"; } value = cf->args->elts; *field = value[1]; if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, field); } return NGX_CONF_OK; } char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_int_t *np; ngx_str_t *value; ngx_conf_post_t *post; np = (ngx_int_t *) (p + cmd->offset); if (*np != NGX_CONF_UNSET) { return "is duplicate"; } value = cf->args->elts; *np = ngx_atoi(value[1].data, value[1].len); if (*np == NGX_ERROR) { return "invalid number"; } if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, np); } return NGX_CONF_OK; } char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; size_t *sp; ngx_str_t *value; ngx_conf_post_t *post; sp = (size_t *) (p + cmd->offset); if (*sp != NGX_CONF_UNSET_SIZE) { return "is duplicate"; } value = cf->args->elts; *sp = ngx_parse_size(&value[1]); if (*sp == (size_t) NGX_ERROR) { return "invalid value"; } if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, sp); } return NGX_CONF_OK; } char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_msec_t *msp; ngx_str_t *value; ngx_conf_post_t *post; msp = (ngx_msec_t *) (p + cmd->offset); if (*msp != NGX_CONF_UNSET_MSEC) { return "is duplicate"; } value = cf->args->elts; *msp = ngx_parse_time(&value[1], 0); if (*msp == (ngx_msec_t) NGX_ERROR) { return "invalid value"; } if (*msp == (ngx_msec_t) NGX_PARSE_LARGE_TIME) { return "value must be less than 597 hours"; } if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, msp); } return NGX_CONF_OK; } char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; time_t *sp; ngx_str_t *value; ngx_conf_post_t *post; sp = (time_t *) (p + cmd->offset); if (*sp != NGX_CONF_UNSET) { return "is duplicate"; } value = cf->args->elts; *sp = ngx_parse_time(&value[1], 1); if (*sp == NGX_ERROR) { return "invalid value"; } if (*sp == NGX_PARSE_LARGE_TIME) { return "value must be less than 68 years"; } if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, sp); } return NGX_CONF_OK; } char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_str_t *value; ngx_bufs_t *bufs; bufs = (ngx_bufs_t *) (p + cmd->offset); if (bufs->num) { return "is duplicate"; } value = cf->args->elts; bufs->num = ngx_atoi(value[1].data, value[1].len); if (bufs->num == NGX_ERROR || bufs->num == 0) { return "invalid value"; } bufs->size = ngx_parse_size(&value[2]); if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) { return "invalid value"; } return NGX_CONF_OK; } char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_uint_t *np, i; ngx_str_t *value; ngx_conf_enum_t *e; np = (ngx_uint_t *) (p + cmd->offset); if (*np != NGX_CONF_UNSET_UINT) { return "is duplicate"; } value = cf->args->elts; e = cmd->post; for (i = 0; e[i].name.len != 0; i++) { if (e[i].name.len != value[1].len || ngx_strcasecmp(e[i].name.data, value[1].data) != 0) { continue; } *np = e[i].value; return NGX_CONF_OK; } ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "invalid value \"%s\"", value[1].data); return NGX_CONF_ERROR; } char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_uint_t *np, i, m; ngx_str_t *value; ngx_conf_bitmask_t *mask; np = (ngx_uint_t *) (p + cmd->offset); value = cf->args->elts; mask = cmd->post; for (i = 1; i < cf->args->nelts; i++) { for (m = 0; mask[m].name.len != 0; m++) { if (mask[m].name.len != value[i].len || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0) { continue; } if (*np & mask[m].mask) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "duplicate value \"%s\"", value[i].data); } else { *np |= mask[m].mask; } break; } if (mask[m].name.len == 0) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "invalid value \"%s\"", value[i].data); return NGX_CONF_ERROR; } } return NGX_CONF_OK; } char *ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { return "unsupported on this platform"; } char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data) { ngx_conf_num_bounds_t *bounds = post; ngx_int_t *np = data; if (bounds->high == -1) { if (*np >= bounds->low) { return NGX_CONF_OK; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "value must be equal or more than %d", bounds->low); return NGX_CONF_ERROR; } if (*np >= bounds->low && *np <= bounds->high) { return NGX_CONF_OK; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "value must be between %d and %d", bounds->low, bounds->high); return NGX_CONF_ERROR; }