nginxtra 1.0.15.0 → 1.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/VERSION +1 -1
  2. data/bin/nginxtra +1 -1
  3. data/lib/nginxtra/action.rb +10 -0
  4. data/lib/nginxtra/actions/compile.rb +16 -2
  5. data/lib/nginxtra/actions/start.rb +18 -2
  6. data/lib/nginxtra/actions/status.rb +1 -10
  7. data/lib/nginxtra/actions/stop.rb +18 -0
  8. data/lib/nginxtra/cli.rb +12 -3
  9. data/lib/nginxtra/config.rb +10 -0
  10. data/src/nginx/CHANGES +311 -90
  11. data/src/nginx/CHANGES.ru +315 -88
  12. data/src/nginx/auto/lib/pcre/conf +22 -5
  13. data/src/nginx/auto/lib/pcre/make +1 -1
  14. data/src/nginx/auto/modules +14 -3
  15. data/src/nginx/auto/options +17 -3
  16. data/src/nginx/auto/os/freebsd +8 -0
  17. data/src/nginx/auto/os/linux +5 -4
  18. data/src/nginx/auto/os/solaris +2 -1
  19. data/src/nginx/auto/sources +10 -2
  20. data/src/nginx/auto/summary +2 -0
  21. data/src/nginx/auto/types/sizeof +2 -1
  22. data/src/nginx/auto/types/typedef +1 -1
  23. data/src/nginx/auto/types/uintptr_t +7 -4
  24. data/src/nginx/auto/unix +82 -21
  25. data/src/nginx/conf/fastcgi.conf +1 -0
  26. data/src/nginx/conf/fastcgi_params +1 -0
  27. data/src/nginx/conf/scgi_params +1 -0
  28. data/src/nginx/conf/uwsgi_params +1 -0
  29. data/src/nginx/man/nginx.8 +49 -49
  30. data/src/nginx/src/core/nginx.c +10 -12
  31. data/src/nginx/src/core/nginx.h +2 -2
  32. data/src/nginx/src/core/ngx_buf.c +9 -7
  33. data/src/nginx/src/core/ngx_buf.h +2 -2
  34. data/src/nginx/src/core/ngx_conf_file.c +4 -11
  35. data/src/nginx/src/core/ngx_conf_file.h +1 -1
  36. data/src/nginx/src/core/ngx_connection.c +52 -1
  37. data/src/nginx/src/core/ngx_connection.h +6 -0
  38. data/src/nginx/src/core/ngx_core.h +5 -0
  39. data/src/nginx/src/core/ngx_cycle.c +1 -1
  40. data/src/nginx/src/core/ngx_cycle.h +2 -2
  41. data/src/nginx/src/core/ngx_file.c +1 -1
  42. data/src/nginx/src/core/ngx_inet.c +11 -8
  43. data/src/nginx/src/core/ngx_murmurhash.h +1 -1
  44. data/src/nginx/src/core/ngx_open_file_cache.c +343 -38
  45. data/src/nginx/src/core/ngx_open_file_cache.h +10 -0
  46. data/src/nginx/src/core/ngx_output_chain.c +2 -1
  47. data/src/nginx/src/core/ngx_parse.h +0 -3
  48. data/src/nginx/src/core/ngx_rbtree.c +1 -2
  49. data/src/nginx/src/core/ngx_regex.c +263 -5
  50. data/src/nginx/src/core/ngx_regex.h +6 -2
  51. data/src/nginx/src/core/ngx_resolver.c +88 -21
  52. data/src/nginx/src/core/ngx_resolver.h +7 -8
  53. data/src/nginx/src/core/ngx_shmtx.c +69 -44
  54. data/src/nginx/src/core/ngx_shmtx.h +12 -1
  55. data/src/nginx/src/core/ngx_slab.c +3 -3
  56. data/src/nginx/src/core/ngx_slab.h +1 -1
  57. data/src/nginx/src/core/ngx_string.c +19 -16
  58. data/src/nginx/src/core/ngx_times.c +2 -2
  59. data/src/nginx/src/event/modules/ngx_epoll_module.c +2 -2
  60. data/src/nginx/src/event/modules/ngx_eventport_module.c +1 -1
  61. data/src/nginx/src/event/modules/ngx_kqueue_module.c +1 -1
  62. data/src/nginx/src/event/ngx_event.c +25 -17
  63. data/src/nginx/src/event/ngx_event_openssl.c +3 -1
  64. data/src/nginx/src/event/ngx_event_pipe.c +108 -85
  65. data/src/nginx/src/event/ngx_event_pipe.h +1 -2
  66. data/src/nginx/src/event/ngx_event_timer.c +2 -3
  67. data/src/nginx/src/http/modules/ngx_http_access_module.c +9 -4
  68. data/src/nginx/src/http/modules/ngx_http_browser_module.c +5 -3
  69. data/src/nginx/src/http/modules/ngx_http_chunked_filter_module.c +1 -1
  70. data/src/nginx/src/http/modules/ngx_http_degradation_module.c +1 -1
  71. data/src/nginx/src/http/modules/ngx_http_fastcgi_module.c +144 -22
  72. data/src/nginx/src/http/modules/ngx_http_flv_module.c +8 -0
  73. data/src/nginx/src/http/modules/ngx_http_geo_module.c +3 -3
  74. data/src/nginx/src/http/modules/ngx_http_gzip_filter_module.c +20 -6
  75. data/src/nginx/src/http/modules/ngx_http_gzip_static_module.c +8 -0
  76. data/src/nginx/src/http/modules/ngx_http_headers_filter_module.c +23 -27
  77. data/src/nginx/src/http/modules/ngx_http_image_filter_module.c +1 -3
  78. data/src/nginx/src/http/modules/ngx_http_index_module.c +24 -0
  79. data/src/nginx/src/http/modules/ngx_http_limit_conn_module.c +747 -0
  80. data/src/nginx/src/http/modules/ngx_http_limit_req_module.c +289 -133
  81. data/src/nginx/src/http/modules/ngx_http_log_module.c +34 -6
  82. data/src/nginx/src/http/modules/ngx_http_memcached_module.c +19 -3
  83. data/src/nginx/src/http/modules/ngx_http_mp4_module.c +8 -0
  84. data/src/nginx/src/http/modules/ngx_http_proxy_module.c +1446 -239
  85. data/src/nginx/src/http/modules/ngx_http_realip_module.c +4 -10
  86. data/src/nginx/src/http/modules/ngx_http_scgi_module.c +90 -21
  87. data/src/nginx/src/http/modules/ngx_http_split_clients_module.c +8 -11
  88. data/src/nginx/src/http/modules/ngx_http_ssi_filter_module.c +16 -6
  89. data/src/nginx/src/http/modules/ngx_http_static_module.c +8 -0
  90. data/src/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +2 -2
  91. data/src/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c +570 -0
  92. data/src/nginx/src/http/modules/ngx_http_userid_filter_module.c +1 -5
  93. data/src/nginx/src/http/modules/ngx_http_uwsgi_module.c +77 -26
  94. data/src/nginx/src/http/modules/ngx_http_xslt_filter_module.c +171 -37
  95. data/src/nginx/src/http/modules/perl/nginx.pm +2 -1
  96. data/src/nginx/src/http/modules/perl/nginx.xs +4 -0
  97. data/src/nginx/src/http/ngx_http.c +8 -1
  98. data/src/nginx/src/http/ngx_http.h +1 -0
  99. data/src/nginx/src/http/ngx_http_busy_lock.c +2 -2
  100. data/src/nginx/src/http/ngx_http_cache.h +12 -1
  101. data/src/nginx/src/http/ngx_http_copy_filter_module.c +4 -3
  102. data/src/nginx/src/http/ngx_http_core_module.c +303 -37
  103. data/src/nginx/src/http/ngx_http_core_module.h +15 -0
  104. data/src/nginx/src/http/ngx_http_file_cache.c +226 -52
  105. data/src/nginx/src/http/ngx_http_parse.c +69 -3
  106. data/src/nginx/src/http/ngx_http_postpone_filter_module.c +4 -4
  107. data/src/nginx/src/http/ngx_http_request.c +61 -27
  108. data/src/nginx/src/http/ngx_http_request.h +3 -3
  109. data/src/nginx/src/http/ngx_http_request_body.c +1 -1
  110. data/src/nginx/src/http/ngx_http_script.c +6 -0
  111. data/src/nginx/src/http/ngx_http_upstream.c +200 -47
  112. data/src/nginx/src/http/ngx_http_upstream.h +20 -1
  113. data/src/nginx/src/http/ngx_http_upstream_round_robin.c +22 -6
  114. data/src/nginx/src/http/ngx_http_upstream_round_robin.h +1 -0
  115. data/src/nginx/src/http/ngx_http_variables.c +123 -4
  116. data/src/nginx/src/mail/ngx_mail.c +13 -0
  117. data/src/nginx/src/mail/ngx_mail.h +12 -0
  118. data/src/nginx/src/mail/ngx_mail_core_module.c +100 -15
  119. data/src/nginx/src/os/unix/ngx_daemon.c +2 -1
  120. data/src/nginx/src/os/unix/ngx_darwin.h +3 -0
  121. data/src/nginx/src/os/unix/ngx_darwin_config.h +1 -0
  122. data/src/nginx/src/os/unix/ngx_darwin_init.c +30 -0
  123. data/src/nginx/src/os/unix/ngx_darwin_sendfile_chain.c +11 -5
  124. data/src/nginx/src/os/unix/ngx_errno.h +5 -0
  125. data/src/nginx/src/os/unix/ngx_files.h +50 -1
  126. data/src/nginx/src/os/unix/ngx_freebsd.h +2 -1
  127. data/src/nginx/src/os/unix/ngx_freebsd_config.h +2 -0
  128. data/src/nginx/src/os/unix/ngx_freebsd_init.c +4 -3
  129. data/src/nginx/src/os/unix/ngx_freebsd_rfork_thread.c +2 -2
  130. data/src/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c +12 -6
  131. data/src/nginx/src/os/unix/ngx_gcc_atomic_sparc64.h +1 -1
  132. data/src/nginx/src/os/unix/ngx_linux_config.h +1 -0
  133. data/src/nginx/src/os/unix/ngx_linux_sendfile_chain.c +6 -4
  134. data/src/nginx/src/os/unix/ngx_os.h +0 -1
  135. data/src/nginx/src/os/unix/ngx_posix_config.h +3 -0
  136. data/src/nginx/src/os/unix/ngx_process.c +50 -11
  137. data/src/nginx/src/os/unix/ngx_process.h +1 -0
  138. data/src/nginx/src/os/unix/ngx_process_cycle.c +6 -15
  139. data/src/nginx/src/os/unix/ngx_readv_chain.c +8 -0
  140. data/src/nginx/src/os/unix/ngx_setaffinity.c +69 -0
  141. data/src/nginx/src/os/unix/ngx_setaffinity.h +23 -0
  142. data/src/nginx/src/os/unix/ngx_setproctitle.c +1 -1
  143. data/src/nginx/src/os/unix/ngx_solaris_config.h +2 -0
  144. data/src/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c +11 -3
  145. data/src/nginx/src/os/unix/ngx_writev_chain.c +7 -3
  146. metadata +7 -4
  147. data/src/nginx/src/http/modules/ngx_http_limit_zone_module.c +0 -553
@@ -110,6 +110,10 @@ ngx_http_flv_handler(ngx_http_request_t *r)
110
110
  of.errors = clcf->open_file_cache_errors;
111
111
  of.events = clcf->open_file_cache_events;
112
112
 
113
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
114
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
115
+ }
116
+
113
117
  if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
114
118
  != NGX_OK)
115
119
  {
@@ -127,6 +131,10 @@ ngx_http_flv_handler(ngx_http_request_t *r)
127
131
  break;
128
132
 
129
133
  case NGX_EACCES:
134
+ #if (NGX_HAVE_OPENAT)
135
+ case NGX_EMLINK:
136
+ case NGX_ELOOP:
137
+ #endif
130
138
 
131
139
  level = NGX_LOG_ERR;
132
140
  rc = NGX_HTTP_FORBIDDEN;
@@ -566,7 +566,7 @@ ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
566
566
 
567
567
  if (ctx->binary_include) {
568
568
  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
569
- "binary geo range base \"%s\" may not be mixed with usual entries",
569
+ "binary geo range base \"%s\" cannot be mixed with usual entries",
570
570
  ctx->include_name.data);
571
571
  return NGX_CONF_ERROR;
572
572
  }
@@ -1195,7 +1195,7 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
1195
1195
 
1196
1196
  if (ctx->outside_entries) {
1197
1197
  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1198
- "binary geo range base \"%s\" may not be mixed with usual entries",
1198
+ "binary geo range base \"%s\" cannot be mixed with usual entries",
1199
1199
  name->data);
1200
1200
  rc = NGX_ERROR;
1201
1201
  goto done;
@@ -1203,7 +1203,7 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
1203
1203
 
1204
1204
  if (ctx->binary_include) {
1205
1205
  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1206
- "second binary geo range base \"%s\" may not be mixed with \"%s\"",
1206
+ "second binary geo range base \"%s\" cannot be mixed with \"%s\"",
1207
1207
  name->data, ctx->include_name.data);
1208
1208
  rc = NGX_ERROR;
1209
1209
  goto done;
@@ -379,7 +379,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
379
379
 
380
380
  cl = NULL;
381
381
 
382
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &cl,
382
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl,
383
383
  (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
384
384
  ctx->nomem = 0;
385
385
  }
@@ -449,7 +449,7 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
449
449
 
450
450
  ngx_http_gzip_filter_free_copy_buf(r, ctx);
451
451
 
452
- ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out,
452
+ ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out,
453
453
  (ngx_buf_tag_t) &ngx_http_gzip_filter_module);
454
454
  ctx->last_out = &ctx->out;
455
455
 
@@ -759,6 +759,7 @@ static ngx_int_t
759
759
  ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
760
760
  {
761
761
  int rc;
762
+ ngx_buf_t *b;
762
763
  ngx_chain_t *cl;
763
764
  ngx_http_gzip_conf_t *conf;
764
765
 
@@ -770,7 +771,7 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
770
771
 
771
772
  rc = deflate(&ctx->zstream, ctx->flush);
772
773
 
773
- if (rc != Z_OK && rc != Z_STREAM_END) {
774
+ if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) {
774
775
  ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
775
776
  "deflate() failed: %d, %d", ctx->flush, rc);
776
777
  return NGX_ERROR;
@@ -819,8 +820,6 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
819
820
 
820
821
  if (ctx->flush == Z_SYNC_FLUSH) {
821
822
 
822
- ctx->zstream.avail_out = 0;
823
- ctx->out_buf->flush = 1;
824
823
  ctx->flush = Z_NO_FLUSH;
825
824
 
826
825
  cl = ngx_alloc_chain_link(r->pool);
@@ -828,7 +827,22 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
828
827
  return NGX_ERROR;
829
828
  }
830
829
 
831
- cl->buf = ctx->out_buf;
830
+ b = ctx->out_buf;
831
+
832
+ if (ngx_buf_size(b) == 0) {
833
+
834
+ b = ngx_calloc_buf(ctx->request->pool);
835
+ if (b == NULL) {
836
+ return NGX_ERROR;
837
+ }
838
+
839
+ } else {
840
+ ctx->zstream.avail_out = 0;
841
+ }
842
+
843
+ b->flush = 1;
844
+
845
+ cl->buf = b;
832
846
  cl->next = NULL;
833
847
  *ctx->last_out = cl;
834
848
  ctx->last_out = &cl->next;
@@ -130,6 +130,10 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
130
130
  of.errors = clcf->open_file_cache_errors;
131
131
  of.events = clcf->open_file_cache_events;
132
132
 
133
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
134
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
135
+ }
136
+
133
137
  if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
134
138
  != NGX_OK)
135
139
  {
@@ -145,6 +149,10 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
145
149
  return NGX_DECLINED;
146
150
 
147
151
  case NGX_EACCES:
152
+ #if (NGX_HAVE_OPENAT)
153
+ case NGX_EMLINK:
154
+ case NGX_ELOOP:
155
+ #endif
148
156
 
149
157
  level = NGX_LOG_ERR;
150
158
  break;
@@ -25,23 +25,25 @@ typedef struct {
25
25
 
26
26
  struct ngx_http_header_val_s {
27
27
  ngx_http_complex_value_t value;
28
- ngx_uint_t hash;
29
28
  ngx_str_t key;
30
29
  ngx_http_set_header_pt handler;
31
30
  ngx_uint_t offset;
32
31
  };
33
32
 
34
33
 
35
- #define NGX_HTTP_EXPIRES_OFF 0
36
- #define NGX_HTTP_EXPIRES_EPOCH 1
37
- #define NGX_HTTP_EXPIRES_MAX 2
38
- #define NGX_HTTP_EXPIRES_ACCESS 3
39
- #define NGX_HTTP_EXPIRES_MODIFIED 4
40
- #define NGX_HTTP_EXPIRES_DAILY 5
34
+ typedef enum {
35
+ NGX_HTTP_EXPIRES_OFF,
36
+ NGX_HTTP_EXPIRES_EPOCH,
37
+ NGX_HTTP_EXPIRES_MAX,
38
+ NGX_HTTP_EXPIRES_ACCESS,
39
+ NGX_HTTP_EXPIRES_MODIFIED,
40
+ NGX_HTTP_EXPIRES_DAILY,
41
+ NGX_HTTP_EXPIRES_UNSET
42
+ } ngx_http_expires_t;
41
43
 
42
44
 
43
45
  typedef struct {
44
- ngx_uint_t expires;
46
+ ngx_http_expires_t expires;
45
47
  time_t expires_time;
46
48
  ngx_array_t *headers;
47
49
  } ngx_http_headers_conf_t;
@@ -51,6 +53,8 @@ static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r,
51
53
  ngx_http_headers_conf_t *conf);
52
54
  static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r,
53
55
  ngx_http_header_val_t *hv, ngx_str_t *value);
56
+ static ngx_int_t ngx_http_add_header(ngx_http_request_t *r,
57
+ ngx_http_header_val_t *hv, ngx_str_t *value);
54
58
  static ngx_int_t ngx_http_set_last_modified(ngx_http_request_t *r,
55
59
  ngx_http_header_val_t *hv, ngx_str_t *value);
56
60
 
@@ -313,7 +317,7 @@ ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv,
313
317
  return NGX_ERROR;
314
318
  }
315
319
 
316
- h->hash = hv->hash;
320
+ h->hash = 1;
317
321
  h->key = hv->key;
318
322
  h->value = *value;
319
323
  }
@@ -366,16 +370,11 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
366
370
  {
367
371
  ngx_table_elt_t *h, **old;
368
372
 
369
- if (hv->offset) {
370
- old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
371
-
372
- } else {
373
- old = NULL;
374
- }
373
+ old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
375
374
 
376
375
  r->headers_out.last_modified_time = -1;
377
376
 
378
- if (old == NULL || *old == NULL) {
377
+ if (*old == NULL) {
379
378
 
380
379
  if (value->len == 0) {
381
380
  return NGX_OK;
@@ -386,6 +385,8 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
386
385
  return NGX_ERROR;
387
386
  }
388
387
 
388
+ *old = h;
389
+
389
390
  } else {
390
391
  h = *old;
391
392
 
@@ -395,7 +396,7 @@ ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv,
395
396
  }
396
397
  }
397
398
 
398
- h->hash = hv->hash;
399
+ h->hash = 1;
399
400
  h->key = hv->key;
400
401
  h->value = *value;
401
402
 
@@ -420,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf)
420
421
  * conf->expires_time = 0;
421
422
  */
422
423
 
423
- conf->expires = NGX_CONF_UNSET_UINT;
424
+ conf->expires = NGX_HTTP_EXPIRES_UNSET;
424
425
 
425
426
  return conf;
426
427
  }
@@ -432,11 +433,11 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child)
432
433
  ngx_http_headers_conf_t *prev = parent;
433
434
  ngx_http_headers_conf_t *conf = child;
434
435
 
435
- if (conf->expires == NGX_CONF_UNSET_UINT) {
436
+ if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
436
437
  conf->expires = prev->expires;
437
438
  conf->expires_time = prev->expires_time;
438
439
 
439
- if (conf->expires == NGX_CONF_UNSET_UINT) {
440
+ if (conf->expires == NGX_HTTP_EXPIRES_UNSET) {
440
441
  conf->expires = NGX_HTTP_EXPIRES_OFF;
441
442
  }
442
443
  }
@@ -467,7 +468,7 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
467
468
  ngx_uint_t minus, n;
468
469
  ngx_str_t *value;
469
470
 
470
- if (hcf->expires != NGX_CONF_UNSET_UINT) {
471
+ if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {
471
472
  return "is duplicate";
472
473
  }
473
474
 
@@ -532,7 +533,7 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
532
533
 
533
534
  hcf->expires_time = ngx_parse_time(&value[n], 1);
534
535
 
535
- if (hcf->expires_time == NGX_ERROR) {
536
+ if (hcf->expires_time == (time_t) NGX_ERROR) {
536
537
  return "invalid value";
537
538
  }
538
539
 
@@ -542,10 +543,6 @@ ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
542
543
  return "daily time value must be less than 24 hours";
543
544
  }
544
545
 
545
- if (hcf->expires_time == NGX_PARSE_LARGE_TIME) {
546
- return "value must be less than 68 years";
547
- }
548
-
549
546
  if (minus) {
550
547
  hcf->expires_time = - hcf->expires_time;
551
548
  }
@@ -580,7 +577,6 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
580
577
  return NGX_CONF_ERROR;
581
578
  }
582
579
 
583
- hv->hash = 1;
584
580
  hv->key = value[1];
585
581
  hv->handler = ngx_http_add_header;
586
582
  hv->offset = 0;
@@ -817,9 +817,7 @@ transparent:
817
817
 
818
818
  resize = 0;
819
819
 
820
- if ((ngx_uint_t) (dx * 100 / dy)
821
- < ctx->max_width * 100 / ctx->max_height)
822
- {
820
+ if ((double) dx / dy < (double) ctx->max_width / ctx->max_height) {
823
821
  if ((ngx_uint_t) dx > ctx->max_width) {
824
822
  dy = dy * ctx->max_width / dx;
825
823
  dy = dy ? dy : 1;
@@ -210,6 +210,10 @@ ngx_http_index_handler(ngx_http_request_t *r)
210
210
  of.errors = clcf->open_file_cache_errors;
211
211
  of.events = clcf->open_file_cache_events;
212
212
 
213
+ if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
214
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
215
+ }
216
+
213
217
  if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
214
218
  != NGX_OK)
215
219
  {
@@ -220,6 +224,14 @@ ngx_http_index_handler(ngx_http_request_t *r)
220
224
  return NGX_HTTP_INTERNAL_SERVER_ERROR;
221
225
  }
222
226
 
227
+ #if (NGX_HAVE_OPENAT)
228
+ if (of.err == NGX_EMLINK
229
+ || of.err == NGX_ELOOP)
230
+ {
231
+ return NGX_HTTP_FORBIDDEN;
232
+ }
233
+ #endif
234
+
223
235
  if (of.err == NGX_ENOTDIR
224
236
  || of.err == NGX_ENAMETOOLONG
225
237
  || of.err == NGX_EACCES)
@@ -297,11 +309,23 @@ ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf,
297
309
  of.valid = clcf->open_file_cache_valid;
298
310
  of.errors = clcf->open_file_cache_errors;
299
311
 
312
+ if (ngx_http_set_disable_symlinks(r, clcf, &dir, &of) != NGX_OK) {
313
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
314
+ }
315
+
300
316
  if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool)
301
317
  != NGX_OK)
302
318
  {
303
319
  if (of.err) {
304
320
 
321
+ #if (NGX_HAVE_OPENAT)
322
+ if (of.err == NGX_EMLINK
323
+ || of.err == NGX_ELOOP)
324
+ {
325
+ return NGX_HTTP_FORBIDDEN;
326
+ }
327
+ #endif
328
+
305
329
  if (of.err == NGX_ENOENT) {
306
330
  *last = c;
307
331
  return ngx_http_index_error(r, clcf, dir.data, NGX_ENOENT);
@@ -0,0 +1,747 @@
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
+
13
+ typedef struct {
14
+ u_char color;
15
+ u_char len;
16
+ u_short conn;
17
+ u_char data[1];
18
+ } ngx_http_limit_conn_node_t;
19
+
20
+
21
+ typedef struct {
22
+ ngx_shm_zone_t *shm_zone;
23
+ ngx_rbtree_node_t *node;
24
+ } ngx_http_limit_conn_cleanup_t;
25
+
26
+
27
+ typedef struct {
28
+ ngx_rbtree_t *rbtree;
29
+ ngx_int_t index;
30
+ ngx_str_t var;
31
+ } ngx_http_limit_conn_ctx_t;
32
+
33
+
34
+ typedef struct {
35
+ ngx_shm_zone_t *shm_zone;
36
+ ngx_uint_t conn;
37
+ } ngx_http_limit_conn_limit_t;
38
+
39
+
40
+ typedef struct {
41
+ ngx_array_t limits;
42
+ ngx_uint_t log_level;
43
+ } ngx_http_limit_conn_conf_t;
44
+
45
+
46
+ static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
47
+ ngx_http_variable_value_t *vv, uint32_t hash);
48
+ static void ngx_http_limit_conn_cleanup(void *data);
49
+ static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
50
+
51
+ static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
52
+ static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
53
+ void *child);
54
+ static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
55
+ void *conf);
56
+ static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
57
+ void *conf);
58
+ static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
59
+ void *conf);
60
+ static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
61
+
62
+
63
+ static ngx_conf_deprecated_t ngx_conf_deprecated_limit_zone = {
64
+ ngx_conf_deprecated, "limit_zone", "limit_conn_zone"
65
+ };
66
+
67
+
68
+ static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = {
69
+ { ngx_string("info"), NGX_LOG_INFO },
70
+ { ngx_string("notice"), NGX_LOG_NOTICE },
71
+ { ngx_string("warn"), NGX_LOG_WARN },
72
+ { ngx_string("error"), NGX_LOG_ERR },
73
+ { ngx_null_string, 0 }
74
+ };
75
+
76
+
77
+ static ngx_command_t ngx_http_limit_conn_commands[] = {
78
+
79
+ { ngx_string("limit_conn_zone"),
80
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
81
+ ngx_http_limit_conn_zone,
82
+ 0,
83
+ 0,
84
+ NULL },
85
+
86
+ { ngx_string("limit_zone"),
87
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
88
+ ngx_http_limit_zone,
89
+ 0,
90
+ 0,
91
+ NULL },
92
+
93
+ { ngx_string("limit_conn"),
94
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
95
+ ngx_http_limit_conn,
96
+ NGX_HTTP_LOC_CONF_OFFSET,
97
+ 0,
98
+ NULL },
99
+
100
+ { ngx_string("limit_conn_log_level"),
101
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
102
+ ngx_conf_set_enum_slot,
103
+ NGX_HTTP_LOC_CONF_OFFSET,
104
+ offsetof(ngx_http_limit_conn_conf_t, log_level),
105
+ &ngx_http_limit_conn_log_levels },
106
+
107
+ ngx_null_command
108
+ };
109
+
110
+
111
+ static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
112
+ NULL, /* preconfiguration */
113
+ ngx_http_limit_conn_init, /* postconfiguration */
114
+
115
+ NULL, /* create main configuration */
116
+ NULL, /* init main configuration */
117
+
118
+ NULL, /* create server configuration */
119
+ NULL, /* merge server configuration */
120
+
121
+ ngx_http_limit_conn_create_conf, /* create location configuration */
122
+ ngx_http_limit_conn_merge_conf /* merge location configuration */
123
+ };
124
+
125
+
126
+ ngx_module_t ngx_http_limit_conn_module = {
127
+ NGX_MODULE_V1,
128
+ &ngx_http_limit_conn_module_ctx, /* module context */
129
+ ngx_http_limit_conn_commands, /* module directives */
130
+ NGX_HTTP_MODULE, /* module type */
131
+ NULL, /* init master */
132
+ NULL, /* init module */
133
+ NULL, /* init process */
134
+ NULL, /* init thread */
135
+ NULL, /* exit thread */
136
+ NULL, /* exit process */
137
+ NULL, /* exit master */
138
+ NGX_MODULE_V1_PADDING
139
+ };
140
+
141
+
142
+ static ngx_int_t
143
+ ngx_http_limit_conn_handler(ngx_http_request_t *r)
144
+ {
145
+ size_t len, n;
146
+ uint32_t hash;
147
+ ngx_uint_t i;
148
+ ngx_slab_pool_t *shpool;
149
+ ngx_rbtree_node_t *node;
150
+ ngx_pool_cleanup_t *cln;
151
+ ngx_http_variable_value_t *vv;
152
+ ngx_http_limit_conn_ctx_t *ctx;
153
+ ngx_http_limit_conn_node_t *lc;
154
+ ngx_http_limit_conn_conf_t *lccf;
155
+ ngx_http_limit_conn_limit_t *limits;
156
+ ngx_http_limit_conn_cleanup_t *lccln;
157
+
158
+ if (r->main->limit_conn_set) {
159
+ return NGX_DECLINED;
160
+ }
161
+
162
+ lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
163
+ limits = lccf->limits.elts;
164
+
165
+ for (i = 0; i < lccf->limits.nelts; i++) {
166
+ ctx = limits[i].shm_zone->data;
167
+
168
+ vv = ngx_http_get_indexed_variable(r, ctx->index);
169
+
170
+ if (vv == NULL || vv->not_found) {
171
+ continue;
172
+ }
173
+
174
+ len = vv->len;
175
+
176
+ if (len == 0) {
177
+ continue;
178
+ }
179
+
180
+ if (len > 255) {
181
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
182
+ "the value of the \"%V\" variable "
183
+ "is more than 255 bytes: \"%v\"",
184
+ &ctx->var, vv);
185
+ continue;
186
+ }
187
+
188
+ r->main->limit_conn_set = 1;
189
+
190
+ hash = ngx_crc32_short(vv->data, len);
191
+
192
+ shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
193
+
194
+ ngx_shmtx_lock(&shpool->mutex);
195
+
196
+ node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash);
197
+
198
+ if (node == NULL) {
199
+
200
+ n = offsetof(ngx_rbtree_node_t, color)
201
+ + offsetof(ngx_http_limit_conn_node_t, data)
202
+ + len;
203
+
204
+ node = ngx_slab_alloc_locked(shpool, n);
205
+
206
+ if (node == NULL) {
207
+ ngx_shmtx_unlock(&shpool->mutex);
208
+ ngx_http_limit_conn_cleanup_all(r->pool);
209
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
210
+ }
211
+
212
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
213
+
214
+ node->key = hash;
215
+ lc->len = (u_char) len;
216
+ lc->conn = 1;
217
+ ngx_memcpy(lc->data, vv->data, len);
218
+
219
+ ngx_rbtree_insert(ctx->rbtree, node);
220
+
221
+ } else {
222
+
223
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
224
+
225
+ if ((ngx_uint_t) lc->conn >= limits[i].conn) {
226
+
227
+ ngx_shmtx_unlock(&shpool->mutex);
228
+
229
+ ngx_log_error(lccf->log_level, r->connection->log, 0,
230
+ "limiting connections by zone \"%V\"",
231
+ &limits[i].shm_zone->shm.name);
232
+
233
+ ngx_http_limit_conn_cleanup_all(r->pool);
234
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
235
+ }
236
+
237
+ lc->conn++;
238
+ }
239
+
240
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
241
+ "limit zone: %08XD %d", node->key, lc->conn);
242
+
243
+ ngx_shmtx_unlock(&shpool->mutex);
244
+
245
+ cln = ngx_pool_cleanup_add(r->pool,
246
+ sizeof(ngx_http_limit_conn_cleanup_t));
247
+ if (cln == NULL) {
248
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
249
+ }
250
+
251
+ cln->handler = ngx_http_limit_conn_cleanup;
252
+ lccln = cln->data;
253
+
254
+ lccln->shm_zone = limits[i].shm_zone;
255
+ lccln->node = node;
256
+ }
257
+
258
+ return NGX_DECLINED;
259
+ }
260
+
261
+
262
+ static void
263
+ ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
264
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
265
+ {
266
+ ngx_rbtree_node_t **p;
267
+ ngx_http_limit_conn_node_t *lcn, *lcnt;
268
+
269
+ for ( ;; ) {
270
+
271
+ if (node->key < temp->key) {
272
+
273
+ p = &temp->left;
274
+
275
+ } else if (node->key > temp->key) {
276
+
277
+ p = &temp->right;
278
+
279
+ } else { /* node->key == temp->key */
280
+
281
+ lcn = (ngx_http_limit_conn_node_t *) &node->color;
282
+ lcnt = (ngx_http_limit_conn_node_t *) &temp->color;
283
+
284
+ p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0)
285
+ ? &temp->left : &temp->right;
286
+ }
287
+
288
+ if (*p == sentinel) {
289
+ break;
290
+ }
291
+
292
+ temp = *p;
293
+ }
294
+
295
+ *p = node;
296
+ node->parent = temp;
297
+ node->left = sentinel;
298
+ node->right = sentinel;
299
+ ngx_rbt_red(node);
300
+ }
301
+
302
+
303
+ static ngx_rbtree_node_t *
304
+ ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
305
+ uint32_t hash)
306
+ {
307
+ ngx_int_t rc;
308
+ ngx_rbtree_node_t *node, *sentinel;
309
+ ngx_http_limit_conn_node_t *lcn;
310
+
311
+ node = rbtree->root;
312
+ sentinel = rbtree->sentinel;
313
+
314
+ while (node != sentinel) {
315
+
316
+ if (hash < node->key) {
317
+ node = node->left;
318
+ continue;
319
+ }
320
+
321
+ if (hash > node->key) {
322
+ node = node->right;
323
+ continue;
324
+ }
325
+
326
+ /* hash == node->key */
327
+
328
+ lcn = (ngx_http_limit_conn_node_t *) &node->color;
329
+
330
+ rc = ngx_memn2cmp(vv->data, lcn->data,
331
+ (size_t) vv->len, (size_t) lcn->len);
332
+ if (rc == 0) {
333
+ return node;
334
+ }
335
+
336
+ node = (rc < 0) ? node->left : node->right;
337
+ }
338
+
339
+ return NULL;
340
+ }
341
+
342
+
343
+ static void
344
+ ngx_http_limit_conn_cleanup(void *data)
345
+ {
346
+ ngx_http_limit_conn_cleanup_t *lccln = data;
347
+
348
+ ngx_slab_pool_t *shpool;
349
+ ngx_rbtree_node_t *node;
350
+ ngx_http_limit_conn_ctx_t *ctx;
351
+ ngx_http_limit_conn_node_t *lc;
352
+
353
+ ctx = lccln->shm_zone->data;
354
+ shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
355
+ node = lccln->node;
356
+ lc = (ngx_http_limit_conn_node_t *) &node->color;
357
+
358
+ ngx_shmtx_lock(&shpool->mutex);
359
+
360
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
361
+ "limit zone cleanup: %08XD %d", node->key, lc->conn);
362
+
363
+ lc->conn--;
364
+
365
+ if (lc->conn == 0) {
366
+ ngx_rbtree_delete(ctx->rbtree, node);
367
+ ngx_slab_free_locked(shpool, node);
368
+ }
369
+
370
+ ngx_shmtx_unlock(&shpool->mutex);
371
+ }
372
+
373
+
374
+ static ngx_inline void
375
+ ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool)
376
+ {
377
+ ngx_pool_cleanup_t *cln;
378
+
379
+ cln = pool->cleanup;
380
+
381
+ while (cln && cln->handler == ngx_http_limit_conn_cleanup) {
382
+ ngx_http_limit_conn_cleanup(cln->data);
383
+ cln = cln->next;
384
+ }
385
+
386
+ pool->cleanup = cln;
387
+ }
388
+
389
+
390
+ static ngx_int_t
391
+ ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
392
+ {
393
+ ngx_http_limit_conn_ctx_t *octx = data;
394
+
395
+ size_t len;
396
+ ngx_slab_pool_t *shpool;
397
+ ngx_rbtree_node_t *sentinel;
398
+ ngx_http_limit_conn_ctx_t *ctx;
399
+
400
+ ctx = shm_zone->data;
401
+
402
+ if (octx) {
403
+ if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
404
+ ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
405
+ "limit_conn_zone \"%V\" uses the \"%V\" variable "
406
+ "while previously it used the \"%V\" variable",
407
+ &shm_zone->shm.name, &ctx->var, &octx->var);
408
+ return NGX_ERROR;
409
+ }
410
+
411
+ ctx->rbtree = octx->rbtree;
412
+
413
+ return NGX_OK;
414
+ }
415
+
416
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
417
+
418
+ if (shm_zone->shm.exists) {
419
+ ctx->rbtree = shpool->data;
420
+
421
+ return NGX_OK;
422
+ }
423
+
424
+ ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
425
+ if (ctx->rbtree == NULL) {
426
+ return NGX_ERROR;
427
+ }
428
+
429
+ shpool->data = ctx->rbtree;
430
+
431
+ sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
432
+ if (sentinel == NULL) {
433
+ return NGX_ERROR;
434
+ }
435
+
436
+ ngx_rbtree_init(ctx->rbtree, sentinel,
437
+ ngx_http_limit_conn_rbtree_insert_value);
438
+
439
+ len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
440
+
441
+ shpool->log_ctx = ngx_slab_alloc(shpool, len);
442
+ if (shpool->log_ctx == NULL) {
443
+ return NGX_ERROR;
444
+ }
445
+
446
+ ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
447
+ &shm_zone->shm.name);
448
+
449
+ return NGX_OK;
450
+ }
451
+
452
+
453
+ static void *
454
+ ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
455
+ {
456
+ ngx_http_limit_conn_conf_t *conf;
457
+
458
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t));
459
+ if (conf == NULL) {
460
+ return NULL;
461
+ }
462
+
463
+ /*
464
+ * set by ngx_pcalloc():
465
+ *
466
+ * conf->limits.elts = NULL;
467
+ */
468
+
469
+ conf->log_level = NGX_CONF_UNSET_UINT;
470
+
471
+ return conf;
472
+ }
473
+
474
+
475
+ static char *
476
+ ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
477
+ {
478
+ ngx_http_limit_conn_conf_t *prev = parent;
479
+ ngx_http_limit_conn_conf_t *conf = child;
480
+
481
+ if (conf->limits.elts == NULL) {
482
+ conf->limits = prev->limits;
483
+ }
484
+
485
+ ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
486
+
487
+ return NGX_CONF_OK;
488
+ }
489
+
490
+
491
+ static char *
492
+ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
493
+ {
494
+ u_char *p;
495
+ ssize_t size;
496
+ ngx_str_t *value, name, s;
497
+ ngx_uint_t i;
498
+ ngx_shm_zone_t *shm_zone;
499
+ ngx_http_limit_conn_ctx_t *ctx;
500
+
501
+ value = cf->args->elts;
502
+
503
+ ctx = NULL;
504
+ size = 0;
505
+ name.len = 0;
506
+
507
+ for (i = 1; i < cf->args->nelts; i++) {
508
+
509
+ if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
510
+
511
+ name.data = value[i].data + 5;
512
+
513
+ p = (u_char *) ngx_strchr(name.data, ':');
514
+
515
+ if (p == NULL) {
516
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
517
+ "invalid zone size \"%V\"", &value[i]);
518
+ return NGX_CONF_ERROR;
519
+ }
520
+
521
+ name.len = p - name.data;
522
+
523
+ s.data = p + 1;
524
+ s.len = value[i].data + value[i].len - s.data;
525
+
526
+ size = ngx_parse_size(&s);
527
+
528
+ if (size == NGX_ERROR) {
529
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
530
+ "invalid zone size \"%V\"", &value[i]);
531
+ return NGX_CONF_ERROR;
532
+ }
533
+
534
+ if (size < (ssize_t) (8 * ngx_pagesize)) {
535
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
536
+ "zone \"%V\" is too small", &value[i]);
537
+ return NGX_CONF_ERROR;
538
+ }
539
+
540
+ continue;
541
+ }
542
+
543
+ if (value[i].data[0] == '$') {
544
+
545
+ value[i].len--;
546
+ value[i].data++;
547
+
548
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
549
+ if (ctx == NULL) {
550
+ return NGX_CONF_ERROR;
551
+ }
552
+
553
+ ctx->index = ngx_http_get_variable_index(cf, &value[i]);
554
+ if (ctx->index == NGX_ERROR) {
555
+ return NGX_CONF_ERROR;
556
+ }
557
+
558
+ ctx->var = value[i];
559
+
560
+ continue;
561
+ }
562
+
563
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
564
+ "invalid parameter \"%V\"", &value[i]);
565
+ return NGX_CONF_ERROR;
566
+ }
567
+
568
+ if (name.len == 0) {
569
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
570
+ "\"%V\" must have \"zone\" parameter",
571
+ &cmd->name);
572
+ return NGX_CONF_ERROR;
573
+ }
574
+
575
+ if (ctx == NULL) {
576
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
577
+ "no variable is defined for %V \"%V\"",
578
+ &cmd->name, &name);
579
+ return NGX_CONF_ERROR;
580
+ }
581
+
582
+ shm_zone = ngx_shared_memory_add(cf, &name, size,
583
+ &ngx_http_limit_conn_module);
584
+ if (shm_zone == NULL) {
585
+ return NGX_CONF_ERROR;
586
+ }
587
+
588
+ if (shm_zone->data) {
589
+ ctx = shm_zone->data;
590
+
591
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
592
+ "%V \"%V\" is already bound to variable \"%V\"",
593
+ &cmd->name, &name, &ctx->var);
594
+ return NGX_CONF_ERROR;
595
+ }
596
+
597
+ shm_zone->init = ngx_http_limit_conn_init_zone;
598
+ shm_zone->data = ctx;
599
+
600
+ return NGX_CONF_OK;
601
+ }
602
+
603
+
604
+ static char *
605
+ ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
606
+ {
607
+ ssize_t n;
608
+ ngx_str_t *value;
609
+ ngx_shm_zone_t *shm_zone;
610
+ ngx_http_limit_conn_ctx_t *ctx;
611
+
612
+ ngx_conf_deprecated(cf, &ngx_conf_deprecated_limit_zone, NULL);
613
+
614
+ value = cf->args->elts;
615
+
616
+ if (value[2].data[0] != '$') {
617
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
618
+ "invalid variable name \"%V\"", &value[2]);
619
+ return NGX_CONF_ERROR;
620
+ }
621
+
622
+ value[2].len--;
623
+ value[2].data++;
624
+
625
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
626
+ if (ctx == NULL) {
627
+ return NGX_CONF_ERROR;
628
+ }
629
+
630
+ ctx->index = ngx_http_get_variable_index(cf, &value[2]);
631
+ if (ctx->index == NGX_ERROR) {
632
+ return NGX_CONF_ERROR;
633
+ }
634
+
635
+ ctx->var = value[2];
636
+
637
+ n = ngx_parse_size(&value[3]);
638
+
639
+ if (n == NGX_ERROR) {
640
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
641
+ "invalid size of limit_zone \"%V\"", &value[3]);
642
+ return NGX_CONF_ERROR;
643
+ }
644
+
645
+ if (n < (ngx_int_t) (8 * ngx_pagesize)) {
646
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
647
+ "limit_zone \"%V\" is too small", &value[1]);
648
+ return NGX_CONF_ERROR;
649
+ }
650
+
651
+
652
+ shm_zone = ngx_shared_memory_add(cf, &value[1], n,
653
+ &ngx_http_limit_conn_module);
654
+ if (shm_zone == NULL) {
655
+ return NGX_CONF_ERROR;
656
+ }
657
+
658
+ if (shm_zone->data) {
659
+ ctx = shm_zone->data;
660
+
661
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
662
+ "limit_zone \"%V\" is already bound to variable \"%V\"",
663
+ &value[1], &ctx->var);
664
+ return NGX_CONF_ERROR;
665
+ }
666
+
667
+ shm_zone->init = ngx_http_limit_conn_init_zone;
668
+ shm_zone->data = ctx;
669
+
670
+ return NGX_CONF_OK;
671
+ }
672
+
673
+
674
+ static char *
675
+ ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
676
+ {
677
+ ngx_shm_zone_t *shm_zone;
678
+ ngx_http_limit_conn_conf_t *lccf = conf;
679
+ ngx_http_limit_conn_limit_t *limit, *limits;
680
+
681
+ ngx_str_t *value;
682
+ ngx_int_t n;
683
+ ngx_uint_t i;
684
+
685
+ value = cf->args->elts;
686
+
687
+ shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
688
+ &ngx_http_limit_conn_module);
689
+ if (shm_zone == NULL) {
690
+ return NGX_CONF_ERROR;
691
+ }
692
+
693
+ limits = lccf->limits.elts;
694
+
695
+ if (limits == NULL) {
696
+ if (ngx_array_init(&lccf->limits, cf->pool, 1,
697
+ sizeof(ngx_http_limit_conn_limit_t))
698
+ != NGX_OK)
699
+ {
700
+ return NGX_CONF_ERROR;
701
+ }
702
+ }
703
+
704
+ for (i = 0; i < lccf->limits.nelts; i++) {
705
+ if (shm_zone == limits[i].shm_zone) {
706
+ return "is duplicate";
707
+ }
708
+ }
709
+
710
+ n = ngx_atoi(value[2].data, value[2].len);
711
+ if (n <= 0) {
712
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
713
+ "invalid number of connections \"%V\"", &value[2]);
714
+ return NGX_CONF_ERROR;
715
+ }
716
+
717
+ if (n > 65535) {
718
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
719
+ "connection limit must be less 65536");
720
+ return NGX_CONF_ERROR;
721
+ }
722
+
723
+ limit = ngx_array_push(&lccf->limits);
724
+ limit->conn = n;
725
+ limit->shm_zone = shm_zone;
726
+
727
+ return NGX_CONF_OK;
728
+ }
729
+
730
+
731
+ static ngx_int_t
732
+ ngx_http_limit_conn_init(ngx_conf_t *cf)
733
+ {
734
+ ngx_http_handler_pt *h;
735
+ ngx_http_core_main_conf_t *cmcf;
736
+
737
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
738
+
739
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
740
+ if (h == NULL) {
741
+ return NGX_ERROR;
742
+ }
743
+
744
+ *h = ngx_http_limit_conn_handler;
745
+
746
+ return NGX_OK;
747
+ }