Annotation of embedaddon/nginx/src/http/modules/ngx_http_log_module.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (C) Igor Sysoev
        !             4:  * Copyright (C) Nginx, Inc.
        !             5:  */
        !             6: 
        !             7: 
        !             8: #include <ngx_config.h>
        !             9: #include <ngx_core.h>
        !            10: #include <ngx_http.h>
        !            11: 
        !            12: #if (NGX_ZLIB)
        !            13: #include <zlib.h>
        !            14: #endif
        !            15: 
        !            16: 
        !            17: typedef struct ngx_http_log_op_s  ngx_http_log_op_t;
        !            18: 
        !            19: typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
        !            20:     ngx_http_log_op_t *op);
        !            21: 
        !            22: typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r,
        !            23:     uintptr_t data);
        !            24: 
        !            25: 
        !            26: struct ngx_http_log_op_s {
        !            27:     size_t                      len;
        !            28:     ngx_http_log_op_getlen_pt   getlen;
        !            29:     ngx_http_log_op_run_pt      run;
        !            30:     uintptr_t                   data;
        !            31: };
        !            32: 
        !            33: 
        !            34: typedef struct {
        !            35:     ngx_str_t                   name;
        !            36:     ngx_array_t                *flushes;
        !            37:     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
        !            38: } ngx_http_log_fmt_t;
        !            39: 
        !            40: 
        !            41: typedef struct {
        !            42:     ngx_array_t                 formats;    /* array of ngx_http_log_fmt_t */
        !            43:     ngx_uint_t                  combined_used; /* unsigned  combined_used:1 */
        !            44: } ngx_http_log_main_conf_t;
        !            45: 
        !            46: 
        !            47: typedef struct {
        !            48:     u_char                     *start;
        !            49:     u_char                     *pos;
        !            50:     u_char                     *last;
        !            51: 
        !            52:     ngx_event_t                *event;
        !            53:     ngx_msec_t                  flush;
        !            54:     ngx_int_t                   gzip;
        !            55: } ngx_http_log_buf_t;
        !            56: 
        !            57: 
        !            58: typedef struct {
        !            59:     ngx_array_t                *lengths;
        !            60:     ngx_array_t                *values;
        !            61: } ngx_http_log_script_t;
        !            62: 
        !            63: 
        !            64: typedef struct {
        !            65:     ngx_open_file_t            *file;
        !            66:     ngx_http_log_script_t      *script;
        !            67:     time_t                      disk_full_time;
        !            68:     time_t                      error_log_time;
        !            69:     ngx_http_log_fmt_t         *format;
        !            70: } ngx_http_log_t;
        !            71: 
        !            72: 
        !            73: typedef struct {
        !            74:     ngx_array_t                *logs;       /* array of ngx_http_log_t */
        !            75: 
        !            76:     ngx_open_file_cache_t      *open_file_cache;
        !            77:     time_t                      open_file_cache_valid;
        !            78:     ngx_uint_t                  open_file_cache_min_uses;
        !            79: 
        !            80:     ngx_uint_t                  off;        /* unsigned  off:1 */
        !            81: } ngx_http_log_loc_conf_t;
        !            82: 
        !            83: 
        !            84: typedef struct {
        !            85:     ngx_str_t                   name;
        !            86:     size_t                      len;
        !            87:     ngx_http_log_op_run_pt      run;
        !            88: } ngx_http_log_var_t;
        !            89: 
        !            90: 
        !            91: static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
        !            92:     u_char *buf, size_t len);
        !            93: static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
        !            94:     ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
        !            95: 
        !            96: #if (NGX_ZLIB)
        !            97: static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
        !            98:     ngx_int_t level, ngx_log_t *log);
        !            99: 
        !           100: static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
        !           101: static void ngx_http_log_gzip_free(void *opaque, void *address);
        !           102: #endif
        !           103: 
        !           104: static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
        !           105: static void ngx_http_log_flush_handler(ngx_event_t *ev);
        !           106: 
        !           107: static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
        !           108:     ngx_http_log_op_t *op);
        !           109: static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf,
        !           110:     ngx_http_log_op_t *op);
        !           111: static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf,
        !           112:     ngx_http_log_op_t *op);
        !           113: static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf,
        !           114:     ngx_http_log_op_t *op);
        !           115: static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
        !           116:     ngx_http_log_op_t *op);
        !           117: static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf,
        !           118:     ngx_http_log_op_t *op);
        !           119: static u_char *ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
        !           120:     ngx_http_log_op_t *op);
        !           121: static u_char *ngx_http_log_body_bytes_sent(ngx_http_request_t *r,
        !           122:     u_char *buf, ngx_http_log_op_t *op);
        !           123: static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
        !           124:     ngx_http_log_op_t *op);
        !           125: 
        !           126: static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
        !           127:     ngx_http_log_op_t *op, ngx_str_t *value);
        !           128: static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
        !           129:     uintptr_t data);
        !           130: static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
        !           131:     ngx_http_log_op_t *op);
        !           132: static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
        !           133: 
        !           134: 
        !           135: static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
        !           136: static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf);
        !           137: static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
        !           138:     void *child);
        !           139: static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
        !           140:     void *conf);
        !           141: static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
        !           142:     void *conf);
        !           143: static char *ngx_http_log_compile_format(ngx_conf_t *cf,
        !           144:     ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
        !           145: static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
        !           146:     void *conf);
        !           147: static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
        !           148: 
        !           149: 
        !           150: static ngx_command_t  ngx_http_log_commands[] = {
        !           151: 
        !           152:     { ngx_string("log_format"),
        !           153:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
        !           154:       ngx_http_log_set_format,
        !           155:       NGX_HTTP_MAIN_CONF_OFFSET,
        !           156:       0,
        !           157:       NULL },
        !           158: 
        !           159:     { ngx_string("access_log"),
        !           160:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
        !           161:                         |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE,
        !           162:       ngx_http_log_set_log,
        !           163:       NGX_HTTP_LOC_CONF_OFFSET,
        !           164:       0,
        !           165:       NULL },
        !           166: 
        !           167:     { ngx_string("open_log_file_cache"),
        !           168:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
        !           169:       ngx_http_log_open_file_cache,
        !           170:       NGX_HTTP_LOC_CONF_OFFSET,
        !           171:       0,
        !           172:       NULL },
        !           173: 
        !           174:       ngx_null_command
        !           175: };
        !           176: 
        !           177: 
        !           178: static ngx_http_module_t  ngx_http_log_module_ctx = {
        !           179:     NULL,                                  /* preconfiguration */
        !           180:     ngx_http_log_init,                     /* postconfiguration */
        !           181: 
        !           182:     ngx_http_log_create_main_conf,         /* create main configuration */
        !           183:     NULL,                                  /* init main configuration */
        !           184: 
        !           185:     NULL,                                  /* create server configuration */
        !           186:     NULL,                                  /* merge server configuration */
        !           187: 
        !           188:     ngx_http_log_create_loc_conf,          /* create location configuration */
        !           189:     ngx_http_log_merge_loc_conf            /* merge location configuration */
        !           190: };
        !           191: 
        !           192: 
        !           193: ngx_module_t  ngx_http_log_module = {
        !           194:     NGX_MODULE_V1,
        !           195:     &ngx_http_log_module_ctx,              /* module context */
        !           196:     ngx_http_log_commands,                 /* module directives */
        !           197:     NGX_HTTP_MODULE,                       /* module type */
        !           198:     NULL,                                  /* init master */
        !           199:     NULL,                                  /* init module */
        !           200:     NULL,                                  /* init process */
        !           201:     NULL,                                  /* init thread */
        !           202:     NULL,                                  /* exit thread */
        !           203:     NULL,                                  /* exit process */
        !           204:     NULL,                                  /* exit master */
        !           205:     NGX_MODULE_V1_PADDING
        !           206: };
        !           207: 
        !           208: 
        !           209: static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
        !           210: 
        !           211: 
        !           212: static ngx_str_t  ngx_http_combined_fmt =
        !           213:     ngx_string("$remote_addr - $remote_user [$time_local] "
        !           214:                "\"$request\" $status $body_bytes_sent "
        !           215:                "\"$http_referer\" \"$http_user_agent\"");
        !           216: 
        !           217: 
        !           218: static ngx_http_log_var_t  ngx_http_log_vars[] = {
        !           219:     { ngx_string("pipe"), 1, ngx_http_log_pipe },
        !           220:     { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1,
        !           221:                           ngx_http_log_time },
        !           222:     { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
        !           223:                           ngx_http_log_iso8601 },
        !           224:     { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec },
        !           225:     { ngx_string("request_time"), NGX_TIME_T_LEN + 4,
        !           226:                           ngx_http_log_request_time },
        !           227:     { ngx_string("status"), NGX_INT_T_LEN, ngx_http_log_status },
        !           228:     { ngx_string("bytes_sent"), NGX_OFF_T_LEN, ngx_http_log_bytes_sent },
        !           229:     { ngx_string("body_bytes_sent"), NGX_OFF_T_LEN,
        !           230:                           ngx_http_log_body_bytes_sent },
        !           231:     { ngx_string("request_length"), NGX_SIZE_T_LEN,
        !           232:                           ngx_http_log_request_length },
        !           233: 
        !           234:     { ngx_null_string, 0, NULL }
        !           235: };
        !           236: 
        !           237: 
        !           238: static ngx_int_t
        !           239: ngx_http_log_handler(ngx_http_request_t *r)
        !           240: {
        !           241:     u_char                   *line, *p;
        !           242:     size_t                    len;
        !           243:     ngx_uint_t                i, l;
        !           244:     ngx_http_log_t           *log;
        !           245:     ngx_http_log_op_t        *op;
        !           246:     ngx_http_log_buf_t       *buffer;
        !           247:     ngx_http_log_loc_conf_t  *lcf;
        !           248: 
        !           249:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           250:                    "http log handler");
        !           251: 
        !           252:     lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
        !           253: 
        !           254:     if (lcf->off) {
        !           255:         return NGX_OK;
        !           256:     }
        !           257: 
        !           258:     log = lcf->logs->elts;
        !           259:     for (l = 0; l < lcf->logs->nelts; l++) {
        !           260: 
        !           261:         if (ngx_time() == log[l].disk_full_time) {
        !           262: 
        !           263:             /*
        !           264:              * on FreeBSD writing to a full filesystem with enabled softupdates
        !           265:              * may block process for much longer time than writing to non-full
        !           266:              * filesystem, so we skip writing to a log for one second
        !           267:              */
        !           268: 
        !           269:             continue;
        !           270:         }
        !           271: 
        !           272:         ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
        !           273: 
        !           274:         len = 0;
        !           275:         op = log[l].format->ops->elts;
        !           276:         for (i = 0; i < log[l].format->ops->nelts; i++) {
        !           277:             if (op[i].len == 0) {
        !           278:                 len += op[i].getlen(r, op[i].data);
        !           279: 
        !           280:             } else {
        !           281:                 len += op[i].len;
        !           282:             }
        !           283:         }
        !           284: 
        !           285:         len += NGX_LINEFEED_SIZE;
        !           286: 
        !           287:         buffer = log[l].file ? log[l].file->data : NULL;
        !           288: 
        !           289:         if (buffer) {
        !           290: 
        !           291:             if (len > (size_t) (buffer->last - buffer->pos)) {
        !           292: 
        !           293:                 ngx_http_log_write(r, &log[l], buffer->start,
        !           294:                                    buffer->pos - buffer->start);
        !           295: 
        !           296:                 buffer->pos = buffer->start;
        !           297:             }
        !           298: 
        !           299:             if (len <= (size_t) (buffer->last - buffer->pos)) {
        !           300: 
        !           301:                 p = buffer->pos;
        !           302: 
        !           303:                 if (buffer->event && p == buffer->start) {
        !           304:                     ngx_add_timer(buffer->event, buffer->flush);
        !           305:                 }
        !           306: 
        !           307:                 for (i = 0; i < log[l].format->ops->nelts; i++) {
        !           308:                     p = op[i].run(r, p, &op[i]);
        !           309:                 }
        !           310: 
        !           311:                 ngx_linefeed(p);
        !           312: 
        !           313:                 buffer->pos = p;
        !           314: 
        !           315:                 continue;
        !           316:             }
        !           317: 
        !           318:             if (buffer->event && buffer->event->timer_set) {
        !           319:                 ngx_del_timer(buffer->event);
        !           320:             }
        !           321:         }
        !           322: 
        !           323:         line = ngx_pnalloc(r->pool, len);
        !           324:         if (line == NULL) {
        !           325:             return NGX_ERROR;
        !           326:         }
        !           327: 
        !           328:         p = line;
        !           329: 
        !           330:         for (i = 0; i < log[l].format->ops->nelts; i++) {
        !           331:             p = op[i].run(r, p, &op[i]);
        !           332:         }
        !           333: 
        !           334:         ngx_linefeed(p);
        !           335: 
        !           336:         ngx_http_log_write(r, &log[l], line, p - line);
        !           337:     }
        !           338: 
        !           339:     return NGX_OK;
        !           340: }
        !           341: 
        !           342: 
        !           343: static void
        !           344: ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
        !           345:     size_t len)
        !           346: {
        !           347:     u_char              *name;
        !           348:     time_t               now;
        !           349:     ssize_t              n;
        !           350:     ngx_err_t            err;
        !           351: #if (NGX_ZLIB)
        !           352:     ngx_http_log_buf_t  *buffer;
        !           353: #endif
        !           354: 
        !           355:     if (log->script == NULL) {
        !           356:         name = log->file->name.data;
        !           357: 
        !           358: #if (NGX_ZLIB)
        !           359:         buffer = log->file->data;
        !           360: 
        !           361:         if (buffer && buffer->gzip) {
        !           362:             n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
        !           363:                                   r->connection->log);
        !           364:         } else {
        !           365:             n = ngx_write_fd(log->file->fd, buf, len);
        !           366:         }
        !           367: #else
        !           368:         n = ngx_write_fd(log->file->fd, buf, len);
        !           369: #endif
        !           370: 
        !           371:     } else {
        !           372:         name = NULL;
        !           373:         n = ngx_http_log_script_write(r, log->script, &name, buf, len);
        !           374:     }
        !           375: 
        !           376:     if (n == (ssize_t) len) {
        !           377:         return;
        !           378:     }
        !           379: 
        !           380:     now = ngx_time();
        !           381: 
        !           382:     if (n == -1) {
        !           383:         err = ngx_errno;
        !           384: 
        !           385:         if (err == NGX_ENOSPC) {
        !           386:             log->disk_full_time = now;
        !           387:         }
        !           388: 
        !           389:         if (now - log->error_log_time > 59) {
        !           390:             ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
        !           391:                           ngx_write_fd_n " to \"%s\" failed", name);
        !           392: 
        !           393:             log->error_log_time = now;
        !           394:         }
        !           395: 
        !           396:         return;
        !           397:     }
        !           398: 
        !           399:     if (now - log->error_log_time > 59) {
        !           400:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
        !           401:                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
        !           402:                       name, n, len);
        !           403: 
        !           404:         log->error_log_time = now;
        !           405:     }
        !           406: }
        !           407: 
        !           408: 
        !           409: static ssize_t
        !           410: ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script,
        !           411:     u_char **name, u_char *buf, size_t len)
        !           412: {
        !           413:     size_t                     root;
        !           414:     ssize_t                    n;
        !           415:     ngx_str_t                  log, path;
        !           416:     ngx_open_file_info_t       of;
        !           417:     ngx_http_log_loc_conf_t   *llcf;
        !           418:     ngx_http_core_loc_conf_t  *clcf;
        !           419: 
        !           420:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
        !           421: 
        !           422:     if (!r->root_tested) {
        !           423: 
        !           424:         /* test root directory existence */
        !           425: 
        !           426:         if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
        !           427:             /* simulate successful logging */
        !           428:             return len;
        !           429:         }
        !           430: 
        !           431:         path.data[root] = '\0';
        !           432: 
        !           433:         ngx_memzero(&of, sizeof(ngx_open_file_info_t));
        !           434: 
        !           435:         of.valid = clcf->open_file_cache_valid;
        !           436:         of.min_uses = clcf->open_file_cache_min_uses;
        !           437:         of.test_dir = 1;
        !           438:         of.test_only = 1;
        !           439:         of.errors = clcf->open_file_cache_errors;
        !           440:         of.events = clcf->open_file_cache_events;
        !           441: 
        !           442:         if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
        !           443:             /* simulate successful logging */
        !           444:             return len;
        !           445:         }
        !           446: 
        !           447:         if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
        !           448:             != NGX_OK)
        !           449:         {
        !           450:             if (of.err == 0) {
        !           451:                 /* simulate successful logging */
        !           452:                 return len;
        !           453:             }
        !           454: 
        !           455:             ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err,
        !           456:                           "testing \"%s\" existence failed", path.data);
        !           457: 
        !           458:             /* simulate successful logging */
        !           459:             return len;
        !           460:         }
        !           461: 
        !           462:         if (!of.is_dir) {
        !           463:             ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR,
        !           464:                           "testing \"%s\" existence failed", path.data);
        !           465: 
        !           466:             /* simulate successful logging */
        !           467:             return len;
        !           468:         }
        !           469:     }
        !           470: 
        !           471:     if (ngx_http_script_run(r, &log, script->lengths->elts, 1,
        !           472:                             script->values->elts)
        !           473:         == NULL)
        !           474:     {
        !           475:         /* simulate successful logging */
        !           476:         return len;
        !           477:     }
        !           478: 
        !           479:     log.data[log.len - 1] = '\0';
        !           480:     *name = log.data;
        !           481: 
        !           482:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           483:                    "http log \"%s\"", log.data);
        !           484: 
        !           485:     llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
        !           486: 
        !           487:     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
        !           488: 
        !           489:     of.log = 1;
        !           490:     of.valid = llcf->open_file_cache_valid;
        !           491:     of.min_uses = llcf->open_file_cache_min_uses;
        !           492:     of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
        !           493: 
        !           494:     if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) {
        !           495:         /* simulate successful logging */
        !           496:         return len;
        !           497:     }
        !           498: 
        !           499:     if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool)
        !           500:         != NGX_OK)
        !           501:     {
        !           502:         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
        !           503:                       "%s \"%s\" failed", of.failed, log.data);
        !           504:         /* simulate successful logging */
        !           505:         return len;
        !           506:     }
        !           507: 
        !           508:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
        !           509:                    "http log #%d", of.fd);
        !           510: 
        !           511:     n = ngx_write_fd(of.fd, buf, len);
        !           512: 
        !           513:     return n;
        !           514: }
        !           515: 
        !           516: 
        !           517: #if (NGX_ZLIB)
        !           518: 
        !           519: static ssize_t
        !           520: ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
        !           521:     ngx_log_t *log)
        !           522: {
        !           523:     int          rc, wbits, memlevel;
        !           524:     u_char      *out;
        !           525:     size_t       size;
        !           526:     ssize_t      n;
        !           527:     z_stream     zstream;
        !           528:     ngx_err_t    err;
        !           529:     ngx_pool_t  *pool;
        !           530: 
        !           531:     wbits = MAX_WBITS;
        !           532:     memlevel = MAX_MEM_LEVEL - 1;
        !           533: 
        !           534:     while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
        !           535:         wbits--;
        !           536:         memlevel--;
        !           537:     }
        !           538: 
        !           539:     /*
        !           540:      * This is a formula from deflateBound() for conservative upper bound of
        !           541:      * compressed data plus 18 bytes of gzip wrapper.
        !           542:      */
        !           543: 
        !           544:     size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
        !           545: 
        !           546:     ngx_memzero(&zstream, sizeof(z_stream));
        !           547: 
        !           548:     pool = ngx_create_pool(256, log);
        !           549:     if (pool == NULL) {
        !           550:         /* simulate successful logging */
        !           551:         return len;
        !           552:     }
        !           553: 
        !           554:     pool->log = log;
        !           555: 
        !           556:     zstream.zalloc = ngx_http_log_gzip_alloc;
        !           557:     zstream.zfree = ngx_http_log_gzip_free;
        !           558:     zstream.opaque = pool;
        !           559: 
        !           560:     out = ngx_pnalloc(pool, size);
        !           561:     if (out == NULL) {
        !           562:         goto done;
        !           563:     }
        !           564: 
        !           565:     zstream.next_in = buf;
        !           566:     zstream.avail_in = len;
        !           567:     zstream.next_out = out;
        !           568:     zstream.avail_out = size;
        !           569: 
        !           570:     rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
        !           571:                       Z_DEFAULT_STRATEGY);
        !           572: 
        !           573:     if (rc != Z_OK) {
        !           574:         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
        !           575:         goto done;
        !           576:     }
        !           577: 
        !           578:     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
        !           579:                    "deflate in: ni:%p no:%p ai:%ud ao:%ud",
        !           580:                    zstream.next_in, zstream.next_out,
        !           581:                    zstream.avail_in, zstream.avail_out);
        !           582: 
        !           583:     rc = deflate(&zstream, Z_FINISH);
        !           584: 
        !           585:     if (rc != Z_STREAM_END) {
        !           586:         ngx_log_error(NGX_LOG_ALERT, log, 0,
        !           587:                       "deflate(Z_FINISH) failed: %d", rc);
        !           588:         goto done;
        !           589:     }
        !           590: 
        !           591:     ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
        !           592:                    "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
        !           593:                    zstream.next_in, zstream.next_out,
        !           594:                    zstream.avail_in, zstream.avail_out,
        !           595:                    rc);
        !           596: 
        !           597:     size -= zstream.avail_out;
        !           598: 
        !           599:     rc = deflateEnd(&zstream);
        !           600: 
        !           601:     if (rc != Z_OK) {
        !           602:         ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
        !           603:         goto done;
        !           604:     }
        !           605: 
        !           606:     n = ngx_write_fd(fd, out, size);
        !           607: 
        !           608:     if (n != (ssize_t) size) {
        !           609:         err = (n == -1) ? ngx_errno : 0;
        !           610: 
        !           611:         ngx_destroy_pool(pool);
        !           612: 
        !           613:         ngx_set_errno(err);
        !           614:         return -1;
        !           615:     }
        !           616: 
        !           617: done:
        !           618: 
        !           619:     ngx_destroy_pool(pool);
        !           620: 
        !           621:     /* simulate successful logging */
        !           622:     return len;
        !           623: }
        !           624: 
        !           625: 
        !           626: static void *
        !           627: ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
        !           628: {
        !           629:     ngx_pool_t *pool = opaque;
        !           630: 
        !           631:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
        !           632:                    "gzip alloc: n:%ud s:%ud", items, size);
        !           633: 
        !           634:     return ngx_palloc(pool, items * size);
        !           635: }
        !           636: 
        !           637: 
        !           638: static void
        !           639: ngx_http_log_gzip_free(void *opaque, void *address)
        !           640: {
        !           641: #if 0
        !           642:     ngx_pool_t *pool = opaque;
        !           643: 
        !           644:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
        !           645: #endif
        !           646: }
        !           647: 
        !           648: #endif
        !           649: 
        !           650: 
        !           651: static void
        !           652: ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
        !           653: {
        !           654:     size_t               len;
        !           655:     ssize_t              n;
        !           656:     ngx_http_log_buf_t  *buffer;
        !           657: 
        !           658:     buffer = file->data;
        !           659: 
        !           660:     len = buffer->pos - buffer->start;
        !           661: 
        !           662:     if (len == 0) {
        !           663:         return;
        !           664:     }
        !           665: 
        !           666: #if (NGX_ZLIB)
        !           667:     if (buffer->gzip) {
        !           668:         n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
        !           669:     } else {
        !           670:         n = ngx_write_fd(file->fd, buffer->start, len);
        !           671:     }
        !           672: #else
        !           673:     n = ngx_write_fd(file->fd, buffer->start, len);
        !           674: #endif
        !           675: 
        !           676:     if (n == -1) {
        !           677:         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
        !           678:                       ngx_write_fd_n " to \"%s\" failed",
        !           679:                       file->name.data);
        !           680: 
        !           681:     } else if ((size_t) n != len) {
        !           682:         ngx_log_error(NGX_LOG_ALERT, log, 0,
        !           683:                       ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
        !           684:                       file->name.data, n, len);
        !           685:     }
        !           686: 
        !           687:     buffer->pos = buffer->start;
        !           688: 
        !           689:     if (buffer->event && buffer->event->timer_set) {
        !           690:         ngx_del_timer(buffer->event);
        !           691:     }
        !           692: }
        !           693: 
        !           694: 
        !           695: static void
        !           696: ngx_http_log_flush_handler(ngx_event_t *ev)
        !           697: {
        !           698:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
        !           699:                    "http log buffer flush handler");
        !           700: 
        !           701:     ngx_http_log_flush(ev->data, ev->log);
        !           702: }
        !           703: 
        !           704: 
        !           705: static u_char *
        !           706: ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
        !           707:     ngx_http_log_op_t *op)
        !           708: {
        !           709:     size_t     len;
        !           710:     uintptr_t  data;
        !           711: 
        !           712:     len = op->len;
        !           713:     data = op->data;
        !           714: 
        !           715:     while (len--) {
        !           716:         *buf++ = (u_char) (data & 0xff);
        !           717:         data >>= 8;
        !           718:     }
        !           719: 
        !           720:     return buf;
        !           721: }
        !           722: 
        !           723: 
        !           724: static u_char *
        !           725: ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf,
        !           726:     ngx_http_log_op_t *op)
        !           727: {
        !           728:     return ngx_cpymem(buf, (u_char *) op->data, op->len);
        !           729: }
        !           730: 
        !           731: 
        !           732: static u_char *
        !           733: ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           734: {
        !           735:     if (r->pipeline) {
        !           736:         *buf = 'p';
        !           737:     } else {
        !           738:         *buf = '.';
        !           739:     }
        !           740: 
        !           741:     return buf + 1;
        !           742: }
        !           743: 
        !           744: 
        !           745: static u_char *
        !           746: ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           747: {
        !           748:     return ngx_cpymem(buf, ngx_cached_http_log_time.data,
        !           749:                       ngx_cached_http_log_time.len);
        !           750: }
        !           751: 
        !           752: static u_char *
        !           753: ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           754: {
        !           755:     return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data,
        !           756:                       ngx_cached_http_log_iso8601.len);
        !           757: }
        !           758: 
        !           759: static u_char *
        !           760: ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           761: {
        !           762:     ngx_time_t  *tp;
        !           763: 
        !           764:     tp = ngx_timeofday();
        !           765: 
        !           766:     return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec);
        !           767: }
        !           768: 
        !           769: 
        !           770: static u_char *
        !           771: ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf,
        !           772:     ngx_http_log_op_t *op)
        !           773: {
        !           774:     ngx_time_t      *tp;
        !           775:     ngx_msec_int_t   ms;
        !           776: 
        !           777:     tp = ngx_timeofday();
        !           778: 
        !           779:     ms = (ngx_msec_int_t)
        !           780:              ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));
        !           781:     ms = ngx_max(ms, 0);
        !           782: 
        !           783:     return ngx_sprintf(buf, "%T.%03M", (time_t) ms / 1000, ms % 1000);
        !           784: }
        !           785: 
        !           786: 
        !           787: static u_char *
        !           788: ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           789: {
        !           790:     ngx_uint_t  status;
        !           791: 
        !           792:     if (r->err_status) {
        !           793:         status = r->err_status;
        !           794: 
        !           795:     } else if (r->headers_out.status) {
        !           796:         status = r->headers_out.status;
        !           797: 
        !           798:     } else if (r->http_version == NGX_HTTP_VERSION_9) {
        !           799:         status = 9;
        !           800: 
        !           801:     } else {
        !           802:         status = 0;
        !           803:     }
        !           804: 
        !           805:     return ngx_sprintf(buf, "%03ui", status);
        !           806: }
        !           807: 
        !           808: 
        !           809: static u_char *
        !           810: ngx_http_log_bytes_sent(ngx_http_request_t *r, u_char *buf,
        !           811:     ngx_http_log_op_t *op)
        !           812: {
        !           813:     return ngx_sprintf(buf, "%O", r->connection->sent);
        !           814: }
        !           815: 
        !           816: 
        !           817: /*
        !           818:  * although there is a real $body_bytes_sent variable,
        !           819:  * this log operation code function is more optimized for logging
        !           820:  */
        !           821: 
        !           822: static u_char *
        !           823: ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
        !           824:     ngx_http_log_op_t *op)
        !           825: {
        !           826:     off_t  length;
        !           827: 
        !           828:     length = r->connection->sent - r->header_size;
        !           829: 
        !           830:     if (length > 0) {
        !           831:         return ngx_sprintf(buf, "%O", length);
        !           832:     }
        !           833: 
        !           834:     *buf = '0';
        !           835: 
        !           836:     return buf + 1;
        !           837: }
        !           838: 
        !           839: 
        !           840: static u_char *
        !           841: ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
        !           842:     ngx_http_log_op_t *op)
        !           843: {
        !           844:     return ngx_sprintf(buf, "%O", r->request_length);
        !           845: }
        !           846: 
        !           847: 
        !           848: static ngx_int_t
        !           849: ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
        !           850:     ngx_str_t *value)
        !           851: {
        !           852:     ngx_int_t  index;
        !           853: 
        !           854:     index = ngx_http_get_variable_index(cf, value);
        !           855:     if (index == NGX_ERROR) {
        !           856:         return NGX_ERROR;
        !           857:     }
        !           858: 
        !           859:     op->len = 0;
        !           860:     op->getlen = ngx_http_log_variable_getlen;
        !           861:     op->run = ngx_http_log_variable;
        !           862:     op->data = index;
        !           863: 
        !           864:     return NGX_OK;
        !           865: }
        !           866: 
        !           867: 
        !           868: static size_t
        !           869: ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data)
        !           870: {
        !           871:     uintptr_t                   len;
        !           872:     ngx_http_variable_value_t  *value;
        !           873: 
        !           874:     value = ngx_http_get_indexed_variable(r, data);
        !           875: 
        !           876:     if (value == NULL || value->not_found) {
        !           877:         return 1;
        !           878:     }
        !           879: 
        !           880:     len = ngx_http_log_escape(NULL, value->data, value->len);
        !           881: 
        !           882:     value->escape = len ? 1 : 0;
        !           883: 
        !           884:     return value->len + len * 3;
        !           885: }
        !           886: 
        !           887: 
        !           888: static u_char *
        !           889: ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op)
        !           890: {
        !           891:     ngx_http_variable_value_t  *value;
        !           892: 
        !           893:     value = ngx_http_get_indexed_variable(r, op->data);
        !           894: 
        !           895:     if (value == NULL || value->not_found) {
        !           896:         *buf = '-';
        !           897:         return buf + 1;
        !           898:     }
        !           899: 
        !           900:     if (value->escape == 0) {
        !           901:         return ngx_cpymem(buf, value->data, value->len);
        !           902: 
        !           903:     } else {
        !           904:         return (u_char *) ngx_http_log_escape(buf, value->data, value->len);
        !           905:     }
        !           906: }
        !           907: 
        !           908: 
        !           909: static uintptr_t
        !           910: ngx_http_log_escape(u_char *dst, u_char *src, size_t size)
        !           911: {
        !           912:     ngx_uint_t      n;
        !           913:     static u_char   hex[] = "0123456789ABCDEF";
        !           914: 
        !           915:     static uint32_t   escape[] = {
        !           916:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        !           917: 
        !           918:                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
        !           919:         0x00000004, /* 0000 0000 0000 0000  0000 0000 0000 0100 */
        !           920: 
        !           921:                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
        !           922:         0x10000000, /* 0001 0000 0000 0000  0000 0000 0000 0000 */
        !           923: 
        !           924:                     /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
        !           925:         0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
        !           926: 
        !           927:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        !           928:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        !           929:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        !           930:         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        !           931:     };
        !           932: 
        !           933: 
        !           934:     if (dst == NULL) {
        !           935: 
        !           936:         /* find the number of the characters to be escaped */
        !           937: 
        !           938:         n = 0;
        !           939: 
        !           940:         while (size) {
        !           941:             if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
        !           942:                 n++;
        !           943:             }
        !           944:             src++;
        !           945:             size--;
        !           946:         }
        !           947: 
        !           948:         return (uintptr_t) n;
        !           949:     }
        !           950: 
        !           951:     while (size) {
        !           952:         if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
        !           953:             *dst++ = '\\';
        !           954:             *dst++ = 'x';
        !           955:             *dst++ = hex[*src >> 4];
        !           956:             *dst++ = hex[*src & 0xf];
        !           957:             src++;
        !           958: 
        !           959:         } else {
        !           960:             *dst++ = *src++;
        !           961:         }
        !           962:         size--;
        !           963:     }
        !           964: 
        !           965:     return (uintptr_t) dst;
        !           966: }
        !           967: 
        !           968: 
        !           969: static void *
        !           970: ngx_http_log_create_main_conf(ngx_conf_t *cf)
        !           971: {
        !           972:     ngx_http_log_main_conf_t  *conf;
        !           973: 
        !           974:     ngx_http_log_fmt_t  *fmt;
        !           975: 
        !           976:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t));
        !           977:     if (conf == NULL) {
        !           978:         return NULL;
        !           979:     }
        !           980: 
        !           981:     if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t))
        !           982:         != NGX_OK)
        !           983:     {
        !           984:         return NULL;
        !           985:     }
        !           986: 
        !           987:     fmt = ngx_array_push(&conf->formats);
        !           988:     if (fmt == NULL) {
        !           989:         return NULL;
        !           990:     }
        !           991: 
        !           992:     ngx_str_set(&fmt->name, "combined");
        !           993: 
        !           994:     fmt->flushes = NULL;
        !           995: 
        !           996:     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
        !           997:     if (fmt->ops == NULL) {
        !           998:         return NULL;
        !           999:     }
        !          1000: 
        !          1001:     return conf;
        !          1002: }
        !          1003: 
        !          1004: 
        !          1005: static void *
        !          1006: ngx_http_log_create_loc_conf(ngx_conf_t *cf)
        !          1007: {
        !          1008:     ngx_http_log_loc_conf_t  *conf;
        !          1009: 
        !          1010:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t));
        !          1011:     if (conf == NULL) {
        !          1012:         return NULL;
        !          1013:     }
        !          1014: 
        !          1015:     conf->open_file_cache = NGX_CONF_UNSET_PTR;
        !          1016: 
        !          1017:     return conf;
        !          1018: }
        !          1019: 
        !          1020: 
        !          1021: static char *
        !          1022: ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
        !          1023: {
        !          1024:     ngx_http_log_loc_conf_t *prev = parent;
        !          1025:     ngx_http_log_loc_conf_t *conf = child;
        !          1026: 
        !          1027:     ngx_http_log_t            *log;
        !          1028:     ngx_http_log_fmt_t        *fmt;
        !          1029:     ngx_http_log_main_conf_t  *lmcf;
        !          1030: 
        !          1031:     if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
        !          1032: 
        !          1033:         conf->open_file_cache = prev->open_file_cache;
        !          1034:         conf->open_file_cache_valid = prev->open_file_cache_valid;
        !          1035:         conf->open_file_cache_min_uses = prev->open_file_cache_min_uses;
        !          1036: 
        !          1037:         if (conf->open_file_cache == NGX_CONF_UNSET_PTR) {
        !          1038:             conf->open_file_cache = NULL;
        !          1039:         }
        !          1040:     }
        !          1041: 
        !          1042:     if (conf->logs || conf->off) {
        !          1043:         return NGX_CONF_OK;
        !          1044:     }
        !          1045: 
        !          1046:     conf->logs = prev->logs;
        !          1047:     conf->off = prev->off;
        !          1048: 
        !          1049:     if (conf->logs || conf->off) {
        !          1050:         return NGX_CONF_OK;
        !          1051:     }
        !          1052: 
        !          1053:     conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
        !          1054:     if (conf->logs == NULL) {
        !          1055:         return NGX_CONF_ERROR;
        !          1056:     }
        !          1057: 
        !          1058:     log = ngx_array_push(conf->logs);
        !          1059:     if (log == NULL) {
        !          1060:         return NGX_CONF_ERROR;
        !          1061:     }
        !          1062: 
        !          1063:     log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
        !          1064:     if (log->file == NULL) {
        !          1065:         return NGX_CONF_ERROR;
        !          1066:     }
        !          1067: 
        !          1068:     log->script = NULL;
        !          1069:     log->disk_full_time = 0;
        !          1070:     log->error_log_time = 0;
        !          1071: 
        !          1072:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
        !          1073:     fmt = lmcf->formats.elts;
        !          1074: 
        !          1075:     /* the default "combined" format */
        !          1076:     log->format = &fmt[0];
        !          1077:     lmcf->combined_used = 1;
        !          1078: 
        !          1079:     return NGX_CONF_OK;
        !          1080: }
        !          1081: 
        !          1082: 
        !          1083: static char *
        !          1084: ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
        !          1085: {
        !          1086:     ngx_http_log_loc_conf_t *llcf = conf;
        !          1087: 
        !          1088:     ssize_t                     size;
        !          1089:     ngx_int_t                   gzip;
        !          1090:     ngx_uint_t                  i, n;
        !          1091:     ngx_msec_t                  flush;
        !          1092:     ngx_str_t                  *value, name, s;
        !          1093:     ngx_http_log_t             *log;
        !          1094:     ngx_http_log_buf_t         *buffer;
        !          1095:     ngx_http_log_fmt_t         *fmt;
        !          1096:     ngx_http_log_main_conf_t   *lmcf;
        !          1097:     ngx_http_script_compile_t   sc;
        !          1098: 
        !          1099:     value = cf->args->elts;
        !          1100: 
        !          1101:     if (ngx_strcmp(value[1].data, "off") == 0) {
        !          1102:         llcf->off = 1;
        !          1103:         if (cf->args->nelts == 2) {
        !          1104:             return NGX_CONF_OK;
        !          1105:         }
        !          1106: 
        !          1107:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1108:                            "invalid parameter \"%V\"", &value[2]);
        !          1109:         return NGX_CONF_ERROR;
        !          1110:     }
        !          1111: 
        !          1112:     if (llcf->logs == NULL) {
        !          1113:         llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
        !          1114:         if (llcf->logs == NULL) {
        !          1115:             return NGX_CONF_ERROR;
        !          1116:         }
        !          1117:     }
        !          1118: 
        !          1119:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
        !          1120: 
        !          1121:     log = ngx_array_push(llcf->logs);
        !          1122:     if (log == NULL) {
        !          1123:         return NGX_CONF_ERROR;
        !          1124:     }
        !          1125: 
        !          1126:     ngx_memzero(log, sizeof(ngx_http_log_t));
        !          1127: 
        !          1128:     n = ngx_http_script_variables_count(&value[1]);
        !          1129: 
        !          1130:     if (n == 0) {
        !          1131:         log->file = ngx_conf_open_file(cf->cycle, &value[1]);
        !          1132:         if (log->file == NULL) {
        !          1133:             return NGX_CONF_ERROR;
        !          1134:         }
        !          1135: 
        !          1136:     } else {
        !          1137:         if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
        !          1138:             return NGX_CONF_ERROR;
        !          1139:         }
        !          1140: 
        !          1141:         log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t));
        !          1142:         if (log->script == NULL) {
        !          1143:             return NGX_CONF_ERROR;
        !          1144:         }
        !          1145: 
        !          1146:         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
        !          1147: 
        !          1148:         sc.cf = cf;
        !          1149:         sc.source = &value[1];
        !          1150:         sc.lengths = &log->script->lengths;
        !          1151:         sc.values = &log->script->values;
        !          1152:         sc.variables = n;
        !          1153:         sc.complete_lengths = 1;
        !          1154:         sc.complete_values = 1;
        !          1155: 
        !          1156:         if (ngx_http_script_compile(&sc) != NGX_OK) {
        !          1157:             return NGX_CONF_ERROR;
        !          1158:         }
        !          1159:     }
        !          1160: 
        !          1161:     if (cf->args->nelts >= 3) {
        !          1162:         name = value[2];
        !          1163: 
        !          1164:         if (ngx_strcmp(name.data, "combined") == 0) {
        !          1165:             lmcf->combined_used = 1;
        !          1166:         }
        !          1167: 
        !          1168:     } else {
        !          1169:         ngx_str_set(&name, "combined");
        !          1170:         lmcf->combined_used = 1;
        !          1171:     }
        !          1172: 
        !          1173:     fmt = lmcf->formats.elts;
        !          1174:     for (i = 0; i < lmcf->formats.nelts; i++) {
        !          1175:         if (fmt[i].name.len == name.len
        !          1176:             && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
        !          1177:         {
        !          1178:             log->format = &fmt[i];
        !          1179:             break;
        !          1180:         }
        !          1181:     }
        !          1182: 
        !          1183:     if (log->format == NULL) {
        !          1184:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1185:                            "unknown log format \"%V\"", &name);
        !          1186:         return NGX_CONF_ERROR;
        !          1187:     }
        !          1188: 
        !          1189:     size = 0;
        !          1190:     flush = 0;
        !          1191:     gzip = 0;
        !          1192: 
        !          1193:     for (i = 3; i < cf->args->nelts; i++) {
        !          1194: 
        !          1195:         if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
        !          1196:             s.len = value[i].len - 7;
        !          1197:             s.data = value[i].data + 7;
        !          1198: 
        !          1199:             size = ngx_parse_size(&s);
        !          1200: 
        !          1201:             if (size == NGX_ERROR || size == 0) {
        !          1202:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1203:                                    "invalid buffer size \"%V\"", &s);
        !          1204:                 return NGX_CONF_ERROR;
        !          1205:             }
        !          1206: 
        !          1207:             continue;
        !          1208:         }
        !          1209: 
        !          1210:         if (ngx_strncmp(value[i].data, "flush=", 6) == 0) {
        !          1211:             s.len = value[i].len - 6;
        !          1212:             s.data = value[i].data + 6;
        !          1213: 
        !          1214:             flush = ngx_parse_time(&s, 0);
        !          1215: 
        !          1216:             if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) {
        !          1217:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1218:                                    "invalid flush time \"%V\"", &s);
        !          1219:                 return NGX_CONF_ERROR;
        !          1220:             }
        !          1221: 
        !          1222:             continue;
        !          1223:         }
        !          1224: 
        !          1225:         if (ngx_strncmp(value[i].data, "gzip", 4) == 0
        !          1226:             && (value[i].len == 4 || value[i].data[4] == '='))
        !          1227:         {
        !          1228: #if (NGX_ZLIB)
        !          1229:             if (size == 0) {
        !          1230:                 size = 64 * 1024;
        !          1231:             }
        !          1232: 
        !          1233:             if (value[i].len == 4) {
        !          1234:                 gzip = Z_BEST_SPEED;
        !          1235:                 continue;
        !          1236:             }
        !          1237: 
        !          1238:             s.len = value[i].len - 5;
        !          1239:             s.data = value[i].data + 5;
        !          1240: 
        !          1241:             gzip = ngx_atoi(s.data, s.len);
        !          1242: 
        !          1243:             if (gzip < 1 || gzip > 9) {
        !          1244:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1245:                                    "invalid compression level \"%V\"", &s);
        !          1246:                 return NGX_CONF_ERROR;
        !          1247:             }
        !          1248: 
        !          1249:             continue;
        !          1250: 
        !          1251: #else
        !          1252:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1253:                                "nginx was built without zlib support");
        !          1254:             return NGX_CONF_ERROR;
        !          1255: #endif
        !          1256:         }
        !          1257: 
        !          1258:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1259:                            "invalid parameter \"%V\"", &value[i]);
        !          1260:         return NGX_CONF_ERROR;
        !          1261:     }
        !          1262: 
        !          1263:     if (flush && size == 0) {
        !          1264:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1265:                            "no buffer is defined for access_log \"%V\"",
        !          1266:                            &value[1]);
        !          1267:         return NGX_CONF_ERROR;
        !          1268:     }
        !          1269: 
        !          1270:     if (size) {
        !          1271: 
        !          1272:         if (log->script) {
        !          1273:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1274:                                "buffered logs cannot have variables in name");
        !          1275:             return NGX_CONF_ERROR;
        !          1276:         }
        !          1277: 
        !          1278:         if (log->file->data) {
        !          1279:             buffer = log->file->data;
        !          1280: 
        !          1281:             if (buffer->last - buffer->start != size
        !          1282:                 || buffer->flush != flush
        !          1283:                 || buffer->gzip != gzip)
        !          1284:             {
        !          1285:                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1286:                                    "access_log \"%V\" already defined "
        !          1287:                                    "with conflicting parameters",
        !          1288:                                    &value[1]);
        !          1289:                 return NGX_CONF_ERROR;
        !          1290:             }
        !          1291: 
        !          1292:             return NGX_CONF_OK;
        !          1293:         }
        !          1294: 
        !          1295:         buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t));
        !          1296:         if (buffer == NULL) {
        !          1297:             return NGX_CONF_ERROR;
        !          1298:         }
        !          1299: 
        !          1300:         buffer->start = ngx_pnalloc(cf->pool, size);
        !          1301:         if (buffer->start == NULL) {
        !          1302:             return NGX_CONF_ERROR;
        !          1303:         }
        !          1304: 
        !          1305:         buffer->pos = buffer->start;
        !          1306:         buffer->last = buffer->start + size;
        !          1307: 
        !          1308:         if (flush) {
        !          1309:             buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
        !          1310:             if (buffer->event == NULL) {
        !          1311:                 return NGX_CONF_ERROR;
        !          1312:             }
        !          1313: 
        !          1314:             buffer->event->data = log->file;
        !          1315:             buffer->event->handler = ngx_http_log_flush_handler;
        !          1316:             buffer->event->log = &cf->cycle->new_log;
        !          1317: 
        !          1318:             buffer->flush = flush;
        !          1319:         }
        !          1320: 
        !          1321:         buffer->gzip = gzip;
        !          1322: 
        !          1323:         log->file->flush = ngx_http_log_flush;
        !          1324:         log->file->data = buffer;
        !          1325:     }
        !          1326: 
        !          1327:     return NGX_CONF_OK;
        !          1328: }
        !          1329: 
        !          1330: 
        !          1331: static char *
        !          1332: ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
        !          1333: {
        !          1334:     ngx_http_log_main_conf_t *lmcf = conf;
        !          1335: 
        !          1336:     ngx_str_t           *value;
        !          1337:     ngx_uint_t           i;
        !          1338:     ngx_http_log_fmt_t  *fmt;
        !          1339: 
        !          1340:     if (cf->cmd_type != NGX_HTTP_MAIN_CONF) {
        !          1341:         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
        !          1342:                            "the \"log_format\" directive may be used "
        !          1343:                            "only on \"http\" level");
        !          1344:     }
        !          1345: 
        !          1346:     value = cf->args->elts;
        !          1347: 
        !          1348:     fmt = lmcf->formats.elts;
        !          1349:     for (i = 0; i < lmcf->formats.nelts; i++) {
        !          1350:         if (fmt[i].name.len == value[1].len
        !          1351:             && ngx_strcmp(fmt[i].name.data, value[1].data) == 0)
        !          1352:         {
        !          1353:             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1354:                                "duplicate \"log_format\" name \"%V\"",
        !          1355:                                &value[1]);
        !          1356:             return NGX_CONF_ERROR;
        !          1357:         }
        !          1358:     }
        !          1359: 
        !          1360:     fmt = ngx_array_push(&lmcf->formats);
        !          1361:     if (fmt == NULL) {
        !          1362:         return NGX_CONF_ERROR;
        !          1363:     }
        !          1364: 
        !          1365:     fmt->name = value[1];
        !          1366: 
        !          1367:     fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
        !          1368:     if (fmt->flushes == NULL) {
        !          1369:         return NGX_CONF_ERROR;
        !          1370:     }
        !          1371: 
        !          1372:     fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
        !          1373:     if (fmt->ops == NULL) {
        !          1374:         return NGX_CONF_ERROR;
        !          1375:     }
        !          1376: 
        !          1377:     return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
        !          1378: }
        !          1379: 
        !          1380: 
        !          1381: static char *
        !          1382: ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
        !          1383:     ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
        !          1384: {
        !          1385:     u_char              *data, *p, ch;
        !          1386:     size_t               i, len;
        !          1387:     ngx_str_t           *value, var;
        !          1388:     ngx_int_t           *flush;
        !          1389:     ngx_uint_t           bracket;
        !          1390:     ngx_http_log_op_t   *op;
        !          1391:     ngx_http_log_var_t  *v;
        !          1392: 
        !          1393:     value = args->elts;
        !          1394: 
        !          1395:     for ( /* void */ ; s < args->nelts; s++) {
        !          1396: 
        !          1397:         i = 0;
        !          1398: 
        !          1399:         while (i < value[s].len) {
        !          1400: 
        !          1401:             op = ngx_array_push(ops);
        !          1402:             if (op == NULL) {
        !          1403:                 return NGX_CONF_ERROR;
        !          1404:             }
        !          1405: 
        !          1406:             data = &value[s].data[i];
        !          1407: 
        !          1408:             if (value[s].data[i] == '$') {
        !          1409: 
        !          1410:                 if (++i == value[s].len) {
        !          1411:                     goto invalid;
        !          1412:                 }
        !          1413: 
        !          1414:                 if (value[s].data[i] == '{') {
        !          1415:                     bracket = 1;
        !          1416: 
        !          1417:                     if (++i == value[s].len) {
        !          1418:                         goto invalid;
        !          1419:                     }
        !          1420: 
        !          1421:                     var.data = &value[s].data[i];
        !          1422: 
        !          1423:                 } else {
        !          1424:                     bracket = 0;
        !          1425:                     var.data = &value[s].data[i];
        !          1426:                 }
        !          1427: 
        !          1428:                 for (var.len = 0; i < value[s].len; i++, var.len++) {
        !          1429:                     ch = value[s].data[i];
        !          1430: 
        !          1431:                     if (ch == '}' && bracket) {
        !          1432:                         i++;
        !          1433:                         bracket = 0;
        !          1434:                         break;
        !          1435:                     }
        !          1436: 
        !          1437:                     if ((ch >= 'A' && ch <= 'Z')
        !          1438:                         || (ch >= 'a' && ch <= 'z')
        !          1439:                         || (ch >= '0' && ch <= '9')
        !          1440:                         || ch == '_')
        !          1441:                     {
        !          1442:                         continue;
        !          1443:                     }
        !          1444: 
        !          1445:                     break;
        !          1446:                 }
        !          1447: 
        !          1448:                 if (bracket) {
        !          1449:                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1450:                                        "the closing bracket in \"%V\" "
        !          1451:                                        "variable is missing", &var);
        !          1452:                     return NGX_CONF_ERROR;
        !          1453:                 }
        !          1454: 
        !          1455:                 if (var.len == 0) {
        !          1456:                     goto invalid;
        !          1457:                 }
        !          1458: 
        !          1459:                 for (v = ngx_http_log_vars; v->name.len; v++) {
        !          1460: 
        !          1461:                     if (v->name.len == var.len
        !          1462:                         && ngx_strncmp(v->name.data, var.data, var.len) == 0)
        !          1463:                     {
        !          1464:                         op->len = v->len;
        !          1465:                         op->getlen = NULL;
        !          1466:                         op->run = v->run;
        !          1467:                         op->data = 0;
        !          1468: 
        !          1469:                         goto found;
        !          1470:                     }
        !          1471:                 }
        !          1472: 
        !          1473:                 if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
        !          1474:                     return NGX_CONF_ERROR;
        !          1475:                 }
        !          1476: 
        !          1477:                 if (flushes) {
        !          1478: 
        !          1479:                     flush = ngx_array_push(flushes);
        !          1480:                     if (flush == NULL) {
        !          1481:                         return NGX_CONF_ERROR;
        !          1482:                     }
        !          1483: 
        !          1484:                     *flush = op->data; /* variable index */
        !          1485:                 }
        !          1486: 
        !          1487:             found:
        !          1488: 
        !          1489:                 continue;
        !          1490:             }
        !          1491: 
        !          1492:             i++;
        !          1493: 
        !          1494:             while (i < value[s].len && value[s].data[i] != '$') {
        !          1495:                 i++;
        !          1496:             }
        !          1497: 
        !          1498:             len = &value[s].data[i] - data;
        !          1499: 
        !          1500:             if (len) {
        !          1501: 
        !          1502:                 op->len = len;
        !          1503:                 op->getlen = NULL;
        !          1504: 
        !          1505:                 if (len <= sizeof(uintptr_t)) {
        !          1506:                     op->run = ngx_http_log_copy_short;
        !          1507:                     op->data = 0;
        !          1508: 
        !          1509:                     while (len--) {
        !          1510:                         op->data <<= 8;
        !          1511:                         op->data |= data[len];
        !          1512:                     }
        !          1513: 
        !          1514:                 } else {
        !          1515:                     op->run = ngx_http_log_copy_long;
        !          1516: 
        !          1517:                     p = ngx_pnalloc(cf->pool, len);
        !          1518:                     if (p == NULL) {
        !          1519:                         return NGX_CONF_ERROR;
        !          1520:                     }
        !          1521: 
        !          1522:                     ngx_memcpy(p, data, len);
        !          1523:                     op->data = (uintptr_t) p;
        !          1524:                 }
        !          1525:             }
        !          1526:         }
        !          1527:     }
        !          1528: 
        !          1529:     return NGX_CONF_OK;
        !          1530: 
        !          1531: invalid:
        !          1532: 
        !          1533:     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data);
        !          1534: 
        !          1535:     return NGX_CONF_ERROR;
        !          1536: }
        !          1537: 
        !          1538: 
        !          1539: static char *
        !          1540: ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
        !          1541: {
        !          1542:     ngx_http_log_loc_conf_t *llcf = conf;
        !          1543: 
        !          1544:     time_t       inactive, valid;
        !          1545:     ngx_str_t   *value, s;
        !          1546:     ngx_int_t    max, min_uses;
        !          1547:     ngx_uint_t   i;
        !          1548: 
        !          1549:     if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) {
        !          1550:         return "is duplicate";
        !          1551:     }
        !          1552: 
        !          1553:     value = cf->args->elts;
        !          1554: 
        !          1555:     max = 0;
        !          1556:     inactive = 10;
        !          1557:     valid = 60;
        !          1558:     min_uses = 1;
        !          1559: 
        !          1560:     for (i = 1; i < cf->args->nelts; i++) {
        !          1561: 
        !          1562:         if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
        !          1563: 
        !          1564:             max = ngx_atoi(value[i].data + 4, value[i].len - 4);
        !          1565:             if (max == NGX_ERROR) {
        !          1566:                 goto failed;
        !          1567:             }
        !          1568: 
        !          1569:             continue;
        !          1570:         }
        !          1571: 
        !          1572:         if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
        !          1573: 
        !          1574:             s.len = value[i].len - 9;
        !          1575:             s.data = value[i].data + 9;
        !          1576: 
        !          1577:             inactive = ngx_parse_time(&s, 1);
        !          1578:             if (inactive == (time_t) NGX_ERROR) {
        !          1579:                 goto failed;
        !          1580:             }
        !          1581: 
        !          1582:             continue;
        !          1583:         }
        !          1584: 
        !          1585:         if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) {
        !          1586: 
        !          1587:             min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9);
        !          1588:             if (min_uses == NGX_ERROR) {
        !          1589:                 goto failed;
        !          1590:             }
        !          1591: 
        !          1592:             continue;
        !          1593:         }
        !          1594: 
        !          1595:         if (ngx_strncmp(value[i].data, "valid=", 6) == 0) {
        !          1596: 
        !          1597:             s.len = value[i].len - 6;
        !          1598:             s.data = value[i].data + 6;
        !          1599: 
        !          1600:             valid = ngx_parse_time(&s, 1);
        !          1601:             if (valid == (time_t) NGX_ERROR) {
        !          1602:                 goto failed;
        !          1603:             }
        !          1604: 
        !          1605:             continue;
        !          1606:         }
        !          1607: 
        !          1608:         if (ngx_strcmp(value[i].data, "off") == 0) {
        !          1609: 
        !          1610:             llcf->open_file_cache = NULL;
        !          1611: 
        !          1612:             continue;
        !          1613:         }
        !          1614: 
        !          1615:     failed:
        !          1616: 
        !          1617:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1618:                            "invalid \"open_log_file_cache\" parameter \"%V\"",
        !          1619:                            &value[i]);
        !          1620:         return NGX_CONF_ERROR;
        !          1621:     }
        !          1622: 
        !          1623:     if (llcf->open_file_cache == NULL) {
        !          1624:         return NGX_CONF_OK;
        !          1625:     }
        !          1626: 
        !          1627:     if (max == 0) {
        !          1628:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
        !          1629:                         "\"open_log_file_cache\" must have \"max\" parameter");
        !          1630:         return NGX_CONF_ERROR;
        !          1631:     }
        !          1632: 
        !          1633:     llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
        !          1634: 
        !          1635:     if (llcf->open_file_cache) {
        !          1636: 
        !          1637:         llcf->open_file_cache_valid = valid;
        !          1638:         llcf->open_file_cache_min_uses = min_uses;
        !          1639: 
        !          1640:         return NGX_CONF_OK;
        !          1641:     }
        !          1642: 
        !          1643:     return NGX_CONF_ERROR;
        !          1644: }
        !          1645: 
        !          1646: 
        !          1647: static ngx_int_t
        !          1648: ngx_http_log_init(ngx_conf_t *cf)
        !          1649: {
        !          1650:     ngx_str_t                  *value;
        !          1651:     ngx_array_t                 a;
        !          1652:     ngx_http_handler_pt        *h;
        !          1653:     ngx_http_log_fmt_t         *fmt;
        !          1654:     ngx_http_log_main_conf_t   *lmcf;
        !          1655:     ngx_http_core_main_conf_t  *cmcf;
        !          1656: 
        !          1657:     lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
        !          1658: 
        !          1659:     if (lmcf->combined_used) {
        !          1660:         if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) {
        !          1661:             return NGX_ERROR;
        !          1662:         }
        !          1663: 
        !          1664:         value = ngx_array_push(&a);
        !          1665:         if (value == NULL) {
        !          1666:             return NGX_ERROR;
        !          1667:         }
        !          1668: 
        !          1669:         *value = ngx_http_combined_fmt;
        !          1670:         fmt = lmcf->formats.elts;
        !          1671: 
        !          1672:         if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
        !          1673:             != NGX_CONF_OK)
        !          1674:         {
        !          1675:             return NGX_ERROR;
        !          1676:         }
        !          1677:     }
        !          1678: 
        !          1679:     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
        !          1680: 
        !          1681:     h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
        !          1682:     if (h == NULL) {
        !          1683:         return NGX_ERROR;
        !          1684:     }
        !          1685: 
        !          1686:     *h = ngx_http_log_handler;
        !          1687: 
        !          1688:     return NGX_OK;
        !          1689: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>