Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 typedef struct {
0014     ngx_flag_t  enable;
0015 } ngx_http_random_index_loc_conf_t;
0016 
0017 
0018 #define NGX_HTTP_RANDOM_INDEX_PREALLOCATE  50
0019 
0020 
0021 static ngx_int_t ngx_http_random_index_error(ngx_http_request_t *r,
0022     ngx_dir_t *dir, ngx_str_t *name);
0023 static ngx_int_t ngx_http_random_index_init(ngx_conf_t *cf);
0024 static void *ngx_http_random_index_create_loc_conf(ngx_conf_t *cf);
0025 static char *ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf,
0026     void *parent, void *child);
0027 
0028 
0029 static ngx_command_t  ngx_http_random_index_commands[] = {
0030 
0031     { ngx_string("random_index"),
0032       NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0033       ngx_conf_set_flag_slot,
0034       NGX_HTTP_LOC_CONF_OFFSET,
0035       offsetof(ngx_http_random_index_loc_conf_t, enable),
0036       NULL },
0037 
0038       ngx_null_command
0039 };
0040 
0041 
0042 static ngx_http_module_t  ngx_http_random_index_module_ctx = {
0043     NULL,                                  /* preconfiguration */
0044     ngx_http_random_index_init,            /* postconfiguration */
0045 
0046     NULL,                                  /* create main configuration */
0047     NULL,                                  /* init main configuration */
0048 
0049     NULL,                                  /* create server configuration */
0050     NULL,                                  /* merge server configuration */
0051 
0052     ngx_http_random_index_create_loc_conf, /* create location configuration */
0053     ngx_http_random_index_merge_loc_conf   /* merge location configuration */
0054 };
0055 
0056 
0057 ngx_module_t  ngx_http_random_index_module = {
0058     NGX_MODULE_V1,
0059     &ngx_http_random_index_module_ctx,     /* module context */
0060     ngx_http_random_index_commands,        /* module directives */
0061     NGX_HTTP_MODULE,                       /* module type */
0062     NULL,                                  /* init master */
0063     NULL,                                  /* init module */
0064     NULL,                                  /* init process */
0065     NULL,                                  /* init thread */
0066     NULL,                                  /* exit thread */
0067     NULL,                                  /* exit process */
0068     NULL,                                  /* exit master */
0069     NGX_MODULE_V1_PADDING
0070 };
0071 
0072 
0073 static ngx_int_t
0074 ngx_http_random_index_handler(ngx_http_request_t *r)
0075 {
0076     u_char                            *last, *filename;
0077     size_t                             len, allocated, root;
0078     ngx_err_t                          err;
0079     ngx_int_t                          rc;
0080     ngx_str_t                          path, uri, *name;
0081     ngx_dir_t                          dir;
0082     ngx_uint_t                         n, level;
0083     ngx_array_t                        names;
0084     ngx_http_random_index_loc_conf_t  *rlcf;
0085 
0086     if (r->uri.data[r->uri.len - 1] != '/') {
0087         return NGX_DECLINED;
0088     }
0089 
0090     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
0091         return NGX_DECLINED;
0092     }
0093 
0094     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module);
0095 
0096     if (!rlcf->enable) {
0097         return NGX_DECLINED;
0098     }
0099 
0100 #if (NGX_HAVE_D_TYPE)
0101     len = NGX_DIR_MASK_LEN;
0102 #else
0103     len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE;
0104 #endif
0105 
0106     last = ngx_http_map_uri_to_path(r, &path, &root, len);
0107     if (last == NULL) {
0108         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0109     }
0110 
0111     allocated = path.len;
0112 
0113     path.len = last - path.data - 1;
0114     path.data[path.len] = '\0';
0115 
0116     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0117                    "http random index: \"%s\"", path.data);
0118 
0119     if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
0120         err = ngx_errno;
0121 
0122         if (err == NGX_ENOENT
0123             || err == NGX_ENOTDIR
0124             || err == NGX_ENAMETOOLONG)
0125         {
0126             level = NGX_LOG_ERR;
0127             rc = NGX_HTTP_NOT_FOUND;
0128 
0129         } else if (err == NGX_EACCES) {
0130             level = NGX_LOG_ERR;
0131             rc = NGX_HTTP_FORBIDDEN;
0132 
0133         } else {
0134             level = NGX_LOG_CRIT;
0135             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0136         }
0137 
0138         ngx_log_error(level, r->connection->log, err,
0139                       ngx_open_dir_n " \"%s\" failed", path.data);
0140 
0141         return rc;
0142     }
0143 
0144     if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) {
0145         return ngx_http_random_index_error(r, &dir, &path);
0146     }
0147 
0148     filename = path.data;
0149     filename[path.len] = '/';
0150 
0151     for ( ;; ) {
0152         ngx_set_errno(0);
0153 
0154         if (ngx_read_dir(&dir) == NGX_ERROR) {
0155             err = ngx_errno;
0156 
0157             if (err != NGX_ENOMOREFILES) {
0158                 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
0159                               ngx_read_dir_n " \"%V\" failed", &path);
0160                 return ngx_http_random_index_error(r, &dir, &path);
0161             }
0162 
0163             break;
0164         }
0165 
0166         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0167                        "http random index file: \"%s\"", ngx_de_name(&dir));
0168 
0169         if (ngx_de_name(&dir)[0] == '.') {
0170             continue;
0171         }
0172 
0173         len = ngx_de_namelen(&dir);
0174 
0175         if (dir.type == 0 || ngx_de_is_link(&dir)) {
0176 
0177             /* 1 byte for '/' and 1 byte for terminating '\0' */
0178 
0179             if (path.len + 1 + len + 1 > allocated) {
0180                 allocated = path.len + 1 + len + 1
0181                                      + NGX_HTTP_RANDOM_INDEX_PREALLOCATE;
0182 
0183                 filename = ngx_pnalloc(r->pool, allocated);
0184                 if (filename == NULL) {
0185                     return ngx_http_random_index_error(r, &dir, &path);
0186                 }
0187 
0188                 last = ngx_cpystrn(filename, path.data, path.len + 1);
0189                 *last++ = '/';
0190             }
0191 
0192             ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
0193 
0194             if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
0195                 err = ngx_errno;
0196 
0197                 if (err != NGX_ENOENT) {
0198                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
0199                                   ngx_de_info_n " \"%s\" failed", filename);
0200                     return ngx_http_random_index_error(r, &dir, &path);
0201                 }
0202 
0203                 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
0204                     ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
0205                                   ngx_de_link_info_n " \"%s\" failed",
0206                                   filename);
0207                     return ngx_http_random_index_error(r, &dir, &path);
0208                 }
0209             }
0210         }
0211 
0212         if (!ngx_de_is_file(&dir)) {
0213             continue;
0214         }
0215 
0216         name = ngx_array_push(&names);
0217         if (name == NULL) {
0218             return ngx_http_random_index_error(r, &dir, &path);
0219         }
0220 
0221         name->len = len;
0222 
0223         name->data = ngx_pnalloc(r->pool, len);
0224         if (name->data == NULL) {
0225             return ngx_http_random_index_error(r, &dir, &path);
0226         }
0227 
0228         ngx_memcpy(name->data, ngx_de_name(&dir), len);
0229     }
0230 
0231     if (ngx_close_dir(&dir) == NGX_ERROR) {
0232         ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
0233                       ngx_close_dir_n " \"%V\" failed", &path);
0234     }
0235 
0236     n = names.nelts;
0237 
0238     if (n == 0) {
0239         return NGX_DECLINED;
0240     }
0241 
0242     name = names.elts;
0243 
0244     n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000);
0245 
0246     uri.len = r->uri.len + name[n].len;
0247 
0248     uri.data = ngx_pnalloc(r->pool, uri.len);
0249     if (uri.data == NULL) {
0250         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0251     }
0252 
0253     last = ngx_copy(uri.data, r->uri.data, r->uri.len);
0254     ngx_memcpy(last, name[n].data, name[n].len);
0255 
0256     return ngx_http_internal_redirect(r, &uri, &r->args);
0257 }
0258 
0259 
0260 static ngx_int_t
0261 ngx_http_random_index_error(ngx_http_request_t *r, ngx_dir_t *dir,
0262     ngx_str_t *name)
0263 {
0264     if (ngx_close_dir(dir) == NGX_ERROR) {
0265         ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
0266                       ngx_close_dir_n " \"%V\" failed", name);
0267     }
0268 
0269     return NGX_HTTP_INTERNAL_SERVER_ERROR;
0270 }
0271 
0272 
0273 static void *
0274 ngx_http_random_index_create_loc_conf(ngx_conf_t *cf)
0275 {
0276     ngx_http_random_index_loc_conf_t  *conf;
0277 
0278     conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t));
0279     if (conf == NULL) {
0280         return NULL;
0281     }
0282 
0283     conf->enable = NGX_CONF_UNSET;
0284 
0285     return conf;
0286 }
0287 
0288 
0289 static char *
0290 ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0291 {
0292     ngx_http_random_index_loc_conf_t *prev = parent;
0293     ngx_http_random_index_loc_conf_t *conf = child;
0294 
0295     ngx_conf_merge_value(conf->enable, prev->enable, 0);
0296 
0297     return NGX_CONF_OK;
0298 }
0299 
0300 
0301 static ngx_int_t
0302 ngx_http_random_index_init(ngx_conf_t *cf)
0303 {
0304     ngx_http_handler_pt        *h;
0305     ngx_http_core_main_conf_t  *cmcf;
0306 
0307     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0308 
0309     h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
0310     if (h == NULL) {
0311         return NGX_ERROR;
0312     }
0313 
0314     *h = ngx_http_random_index_handler;
0315 
0316     return NGX_OK;
0317 }