src/core/ngx_regex.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. typedef struct {
  8.     ngx_flag_t  pcre_jit;
  9. } ngx_regex_conf_t;


  10. static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
  11. static void ngx_libc_cdecl ngx_regex_free(void *p);
  12. #if (NGX_HAVE_PCRE_JIT)
  13. static void ngx_pcre_free_studies(void *data);
  14. #endif

  15. static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);

  16. static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
  17. static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);

  18. static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
  19. static ngx_conf_post_t  ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };


  20. static ngx_command_t  ngx_regex_commands[] = {

  21.     { ngx_string("pcre_jit"),
  22.       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
  23.       ngx_conf_set_flag_slot,
  24.       0,
  25.       offsetof(ngx_regex_conf_t, pcre_jit),
  26.       &ngx_regex_pcre_jit_post },

  27.       ngx_null_command
  28. };


  29. static ngx_core_module_t  ngx_regex_module_ctx = {
  30.     ngx_string("regex"),
  31.     ngx_regex_create_conf,
  32.     ngx_regex_init_conf
  33. };


  34. ngx_module_t  ngx_regex_module = {
  35.     NGX_MODULE_V1,
  36.     &ngx_regex_module_ctx,                 /* module context */
  37.     ngx_regex_commands,                    /* module directives */
  38.     NGX_CORE_MODULE,                       /* module type */
  39.     NULL,                                  /* init master */
  40.     ngx_regex_module_init,                 /* init module */
  41.     NULL,                                  /* init process */
  42.     NULL,                                  /* init thread */
  43.     NULL,                                  /* exit thread */
  44.     NULL,                                  /* exit process */
  45.     NULL,                                  /* exit master */
  46.     NGX_MODULE_V1_PADDING
  47. };


  48. static ngx_pool_t  *ngx_pcre_pool;
  49. static ngx_list_t  *ngx_pcre_studies;


  50. void
  51. ngx_regex_init(void)
  52. {
  53.     pcre_malloc = ngx_regex_malloc;
  54.     pcre_free = ngx_regex_free;
  55. }


  56. static ngx_inline void
  57. ngx_regex_malloc_init(ngx_pool_t *pool)
  58. {
  59. #if (NGX_THREADS)
  60.     ngx_core_tls_t  *tls;

  61.     if (ngx_threaded) {
  62.         tls = ngx_thread_get_tls(ngx_core_tls_key);
  63.         tls->pool = pool;
  64.         return;
  65.     }

  66. #endif

  67.     ngx_pcre_pool = pool;
  68. }


  69. static ngx_inline void
  70. ngx_regex_malloc_done(void)
  71. {
  72. #if (NGX_THREADS)
  73.     ngx_core_tls_t  *tls;

  74.     if (ngx_threaded) {
  75.         tls = ngx_thread_get_tls(ngx_core_tls_key);
  76.         tls->pool = NULL;
  77.         return;
  78.     }

  79. #endif

  80.     ngx_pcre_pool = NULL;
  81. }


  82. ngx_int_t
  83. ngx_regex_compile(ngx_regex_compile_t *rc)
  84. {
  85.     int               n, erroff;
  86.     char             *p;
  87.     pcre             *re;
  88.     const char       *errstr;
  89.     ngx_regex_elt_t  *elt;

  90.     ngx_regex_malloc_init(rc->pool);

  91.     re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
  92.                       &errstr, &erroff, NULL);

  93.     /* ensure that there is no current pool */
  94.     ngx_regex_malloc_done();

  95.     if (re == NULL) {
  96.         if ((size_t) erroff == rc->pattern.len) {
  97.            rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
  98.                               "pcre_compile() failed: %s in \"%V\"",
  99.                                errstr, &rc->pattern)
  100.                       - rc->err.data;

  101.         } else {
  102.            rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
  103.                               "pcre_compile() failed: %s in \"%V\" at \"%s\"",
  104.                                errstr, &rc->pattern, rc->pattern.data + erroff)
  105.                       - rc->err.data;
  106.         }

  107.         return NGX_ERROR;
  108.     }

  109.     rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
  110.     if (rc->regex == NULL) {
  111.         goto nomem;
  112.     }

  113.     rc->regex->code = re;

  114.     /* do not study at runtime */

  115.     if (ngx_pcre_studies != NULL) {
  116.         elt = ngx_list_push(ngx_pcre_studies);
  117.         if (elt == NULL) {
  118.             goto nomem;
  119.         }

  120.         elt->regex = rc->regex;
  121.         elt->name = rc->pattern.data;
  122.     }

  123.     n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
  124.     if (n < 0) {
  125.         p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
  126.         goto failed;
  127.     }

  128.     if (rc->captures == 0) {
  129.         return NGX_OK;
  130.     }

  131.     n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
  132.     if (n < 0) {
  133.         p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
  134.         goto failed;
  135.     }

  136.     if (rc->named_captures == 0) {
  137.         return NGX_OK;
  138.     }

  139.     n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
  140.     if (n < 0) {
  141.         p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
  142.         goto failed;
  143.     }

  144.     n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
  145.     if (n < 0) {
  146.         p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
  147.         goto failed;
  148.     }

  149.     return NGX_OK;

  150. failed:

  151.     rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
  152.                   - rc->err.data;
  153.     return NGX_ERROR;

  154. nomem:

  155.     rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
  156.                                "regex \"%V\" compilation failed: no memory",
  157.                                &rc->pattern)
  158.                   - rc->err.data;
  159.     return NGX_ERROR;
  160. }


  161. ngx_int_t
  162. ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
  163. {
  164.     ngx_int_t         n;
  165.     ngx_uint_t        i;
  166.     ngx_regex_elt_t  *re;

  167.     re = a->elts;

  168.     for (i = 0; i < a->nelts; i++) {

  169.         n = ngx_regex_exec(re[i].regex, s, NULL, 0);

  170.         if (n == NGX_REGEX_NO_MATCHED) {
  171.             continue;
  172.         }

  173.         if (n < 0) {
  174.             ngx_log_error(NGX_LOG_ALERT, log, 0,
  175.                           ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
  176.                           n, s, re[i].name);
  177.             return NGX_ERROR;
  178.         }

  179.         /* match */

  180.         return NGX_OK;
  181.     }

  182.     return NGX_DECLINED;
  183. }


  184. static void * ngx_libc_cdecl
  185. ngx_regex_malloc(size_t size)
  186. {
  187.     ngx_pool_t      *pool;
  188. #if (NGX_THREADS)
  189.     ngx_core_tls_t  *tls;

  190.     if (ngx_threaded) {
  191.         tls = ngx_thread_get_tls(ngx_core_tls_key);
  192.         pool = tls->pool;

  193.     } else {
  194.         pool = ngx_pcre_pool;
  195.     }

  196. #else

  197.     pool = ngx_pcre_pool;

  198. #endif

  199.     if (pool) {
  200.         return ngx_palloc(pool, size);
  201.     }

  202.     return NULL;
  203. }


  204. static void ngx_libc_cdecl
  205. ngx_regex_free(void *p)
  206. {
  207.     return;
  208. }


  209. #if (NGX_HAVE_PCRE_JIT)

  210. static void
  211. ngx_pcre_free_studies(void *data)
  212. {
  213.     ngx_list_t *studies = data;

  214.     ngx_uint_t        i;
  215.     ngx_list_part_t  *part;
  216.     ngx_regex_elt_t  *elts;

  217.     part = &studies->part;
  218.     elts = part->elts;

  219.     for (i = 0 ; /* void */ ; i++) {

  220.         if (i >= part->nelts) {
  221.             if (part->next == NULL) {
  222.                 break;
  223.             }

  224.             part = part->next;
  225.             elts = part->elts;
  226.             i = 0;
  227.         }

  228.         if (elts[i].regex->extra != NULL) {
  229.             pcre_free_study(elts[i].regex->extra);
  230.         }
  231.     }
  232. }

  233. #endif


  234. static ngx_int_t
  235. ngx_regex_module_init(ngx_cycle_t *cycle)
  236. {
  237.     int               opt;
  238.     const char       *errstr;
  239.     ngx_uint_t        i;
  240.     ngx_list_part_t  *part;
  241.     ngx_regex_elt_t  *elts;

  242.     opt = 0;

  243. #if (NGX_HAVE_PCRE_JIT)
  244.     {
  245.     ngx_regex_conf_t    *rcf;
  246.     ngx_pool_cleanup_t  *cln;

  247.     rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);

  248.     if (rcf->pcre_jit) {
  249.         opt = PCRE_STUDY_JIT_COMPILE;

  250.         /*
  251.          * The PCRE JIT compiler uses mmap for its executable codes, so we
  252.          * have to explicitly call the pcre_free_study() function to free
  253.          * this memory.
  254.          */

  255.         cln = ngx_pool_cleanup_add(cycle->pool, 0);
  256.         if (cln == NULL) {
  257.             return NGX_ERROR;
  258.         }

  259.         cln->handler = ngx_pcre_free_studies;
  260.         cln->data = ngx_pcre_studies;
  261.     }
  262.     }
  263. #endif

  264.     ngx_regex_malloc_init(cycle->pool);

  265.     part = &ngx_pcre_studies->part;
  266.     elts = part->elts;

  267.     for (i = 0 ; /* void */ ; i++) {

  268.         if (i >= part->nelts) {
  269.             if (part->next == NULL) {
  270.                 break;
  271.             }

  272.             part = part->next;
  273.             elts = part->elts;
  274.             i = 0;
  275.         }

  276.         elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr);

  277.         if (errstr != NULL) {
  278.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  279.                           "pcre_study() failed: %s in \"%s\"",
  280.                           errstr, elts[i].name);
  281.         }

  282. #if (NGX_HAVE_PCRE_JIT)
  283.         if (opt & PCRE_STUDY_JIT_COMPILE) {
  284.             int jit, n;

  285.             jit = 0;
  286.             n = pcre_fullinfo(elts[i].regex->code, elts[i].regex->extra,
  287.                               PCRE_INFO_JIT, &jit);

  288.             if (n != 0 || jit != 1) {
  289.                 ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
  290.                               "JIT compiler does not support pattern: \"%s\"",
  291.                               elts[i].name);
  292.             }
  293.         }
  294. #endif
  295.     }

  296.     ngx_regex_malloc_done();

  297.     ngx_pcre_studies = NULL;

  298.     return NGX_OK;
  299. }


  300. static void *
  301. ngx_regex_create_conf(ngx_cycle_t *cycle)
  302. {
  303.     ngx_regex_conf_t  *rcf;

  304.     rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
  305.     if (rcf == NULL) {
  306.         return NULL;
  307.     }

  308.     rcf->pcre_jit = NGX_CONF_UNSET;

  309.     ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
  310.     if (ngx_pcre_studies == NULL) {
  311.         return NULL;
  312.     }

  313.     return rcf;
  314. }


  315. static char *
  316. ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
  317. {
  318.     ngx_regex_conf_t *rcf = conf;

  319.     ngx_conf_init_value(rcf->pcre_jit, 0);

  320.     return NGX_CONF_OK;
  321. }


  322. static char *
  323. ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
  324. {
  325.     ngx_flag_t  *fp = data;

  326.     if (*fp == 0) {
  327.         return NGX_CONF_OK;
  328.     }

  329. #if (NGX_HAVE_PCRE_JIT)
  330.     {
  331.     int  jit, r;

  332.     jit = 0;
  333.     r = pcre_config(PCRE_CONFIG_JIT, &jit);

  334.     if (r != 0 || jit != 1) {
  335.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  336.                            "PCRE library does not support JIT");
  337.         *fp = 0;
  338.     }
  339.     }
  340. #else
  341.     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  342.                        "nginx was built without PCRE JIT support");
  343.     *fp = 0;
  344. #endif

  345.     return NGX_CONF_OK;
  346. }