nginxtra 1.6.3.9 → 1.8.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/bin/nginxtra +1 -1
  3. data/bin/nginxtra_rails +1 -1
  4. data/lib/nginxtra/version.rb +1 -1
  5. data/vendor/nginx/CHANGES +358 -14
  6. data/vendor/nginx/CHANGES.ru +372 -18
  7. data/vendor/nginx/LICENSE +2 -2
  8. data/vendor/nginx/auto/cc/clang +5 -0
  9. data/vendor/nginx/auto/cc/gcc +5 -0
  10. data/vendor/nginx/auto/lib/google-perftools/conf +1 -1
  11. data/vendor/nginx/auto/lib/openssl/make +0 -5
  12. data/vendor/nginx/auto/lib/perl/conf +9 -1
  13. data/vendor/nginx/auto/make +1 -1
  14. data/vendor/nginx/auto/modules +11 -0
  15. data/vendor/nginx/auto/options +10 -2
  16. data/vendor/nginx/auto/os/darwin +0 -1
  17. data/vendor/nginx/auto/os/freebsd +6 -23
  18. data/vendor/nginx/auto/sources +16 -14
  19. data/vendor/nginx/auto/summary +3 -24
  20. data/vendor/nginx/auto/threads +20 -0
  21. data/vendor/nginx/auto/types/sizeof +2 -12
  22. data/vendor/nginx/auto/unix +50 -6
  23. data/vendor/nginx/configure +5 -0
  24. data/vendor/nginx/contrib/vim/syntax/nginx.vim +183 -50
  25. data/vendor/nginx/src/core/nginx.c +21 -9
  26. data/vendor/nginx/src/core/nginx.h +8 -2
  27. data/vendor/nginx/src/core/ngx_buf.c +88 -0
  28. data/vendor/nginx/src/core/ngx_buf.h +15 -1
  29. data/vendor/nginx/src/core/ngx_conf_file.c +4 -1
  30. data/vendor/nginx/src/core/ngx_connection.c +25 -66
  31. data/vendor/nginx/src/core/ngx_connection.h +1 -3
  32. data/vendor/nginx/src/core/ngx_core.h +11 -3
  33. data/vendor/nginx/src/core/ngx_crypt.c +1 -1
  34. data/vendor/nginx/src/core/ngx_cycle.c +7 -1
  35. data/vendor/nginx/src/core/ngx_cycle.h +6 -2
  36. data/vendor/nginx/src/core/ngx_file.c +13 -5
  37. data/vendor/nginx/src/core/ngx_file.h +6 -0
  38. data/vendor/nginx/src/core/ngx_log.c +215 -21
  39. data/vendor/nginx/src/core/ngx_log.h +9 -1
  40. data/vendor/nginx/src/core/ngx_output_chain.c +104 -15
  41. data/vendor/nginx/src/core/ngx_palloc.c +3 -7
  42. data/vendor/nginx/src/core/ngx_rbtree.c +2 -4
  43. data/vendor/nginx/src/core/ngx_rbtree.h +2 -4
  44. data/vendor/nginx/src/core/ngx_regex.c +14 -6
  45. data/vendor/nginx/src/core/ngx_resolver.c +16 -23
  46. data/vendor/nginx/src/core/ngx_resolver.h +8 -7
  47. data/vendor/nginx/src/core/ngx_shmtx.c +1 -1
  48. data/vendor/nginx/src/core/ngx_slab.c +89 -2
  49. data/vendor/nginx/src/core/ngx_slab.h +3 -0
  50. data/vendor/nginx/src/core/ngx_string.c +58 -2
  51. data/vendor/nginx/src/core/ngx_string.h +1 -0
  52. data/vendor/nginx/src/core/ngx_syslog.c +374 -0
  53. data/vendor/nginx/src/core/ngx_syslog.h +30 -0
  54. data/vendor/nginx/src/core/ngx_thread_pool.c +630 -0
  55. data/vendor/nginx/src/core/ngx_thread_pool.h +36 -0
  56. data/vendor/nginx/src/core/ngx_times.c +19 -2
  57. data/vendor/nginx/src/core/ngx_times.h +1 -0
  58. data/vendor/nginx/src/event/modules/ngx_aio_module.c +1 -1
  59. data/vendor/nginx/src/event/modules/ngx_devpoll_module.c +9 -24
  60. data/vendor/nginx/src/event/modules/ngx_epoll_module.c +152 -28
  61. data/vendor/nginx/src/event/modules/ngx_eventport_module.c +43 -25
  62. data/vendor/nginx/src/event/modules/ngx_kqueue_module.c +86 -156
  63. data/vendor/nginx/src/event/modules/ngx_poll_module.c +21 -37
  64. data/vendor/nginx/src/event/modules/ngx_rtsig_module.c +15 -27
  65. data/vendor/nginx/src/event/modules/ngx_select_module.c +10 -12
  66. data/vendor/nginx/src/event/modules/ngx_win32_select_module.c +7 -9
  67. data/vendor/nginx/src/event/ngx_event.c +5 -33
  68. data/vendor/nginx/src/event/ngx_event.h +15 -50
  69. data/vendor/nginx/src/event/ngx_event_accept.c +11 -10
  70. data/vendor/nginx/src/event/ngx_event_connect.c +0 -11
  71. data/vendor/nginx/src/event/ngx_event_connect.h +1 -4
  72. data/vendor/nginx/src/event/ngx_event_openssl.c +622 -38
  73. data/vendor/nginx/src/event/ngx_event_openssl.h +20 -2
  74. data/vendor/nginx/src/event/ngx_event_openssl_stapling.c +5 -1
  75. data/vendor/nginx/src/event/ngx_event_pipe.c +45 -19
  76. data/vendor/nginx/src/event/ngx_event_pipe.h +3 -0
  77. data/vendor/nginx/src/event/ngx_event_posted.c +7 -145
  78. data/vendor/nginx/src/event/ngx_event_posted.h +12 -39
  79. data/vendor/nginx/src/event/ngx_event_timer.c +50 -70
  80. data/vendor/nginx/src/event/ngx_event_timer.h +2 -14
  81. data/vendor/nginx/src/http/modules/ngx_http_addition_filter_module.c +1 -1
  82. data/vendor/nginx/src/http/modules/ngx_http_autoindex_module.c +416 -71
  83. data/vendor/nginx/src/http/modules/ngx_http_charset_filter_module.c +19 -15
  84. data/vendor/nginx/src/http/modules/ngx_http_dav_module.c +16 -4
  85. data/vendor/nginx/src/http/modules/ngx_http_fastcgi_module.c +601 -134
  86. data/vendor/nginx/src/http/modules/ngx_http_geo_module.c +1 -1
  87. data/vendor/nginx/src/http/modules/ngx_http_geoip_module.c +9 -3
  88. data/vendor/nginx/src/http/modules/ngx_http_gunzip_filter_module.c +9 -3
  89. data/vendor/nginx/src/http/modules/ngx_http_gzip_filter_module.c +9 -3
  90. data/vendor/nginx/src/http/modules/ngx_http_gzip_static_module.c +0 -2
  91. data/vendor/nginx/src/http/modules/ngx_http_headers_filter_module.c +197 -91
  92. data/vendor/nginx/src/http/modules/ngx_http_image_filter_module.c +1 -0
  93. data/vendor/nginx/src/http/modules/ngx_http_limit_conn_module.c +65 -162
  94. data/vendor/nginx/src/http/modules/ngx_http_limit_req_module.c +53 -67
  95. data/vendor/nginx/src/http/modules/ngx_http_log_module.c +128 -23
  96. data/vendor/nginx/src/http/modules/ngx_http_memcached_module.c +25 -6
  97. data/vendor/nginx/src/http/modules/ngx_http_mp4_module.c +1 -1
  98. data/vendor/nginx/src/http/modules/ngx_http_not_modified_filter_module.c +39 -13
  99. data/vendor/nginx/src/http/modules/ngx_http_proxy_module.c +697 -141
  100. data/vendor/nginx/src/http/modules/ngx_http_rewrite_module.c +5 -1
  101. data/vendor/nginx/src/http/modules/ngx_http_scgi_module.c +282 -125
  102. data/vendor/nginx/src/http/modules/ngx_http_ssi_filter_module.c +4 -1
  103. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.c +44 -1
  104. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.h +2 -0
  105. data/vendor/nginx/src/http/modules/ngx_http_stub_status_module.c +10 -8
  106. data/vendor/nginx/src/http/modules/ngx_http_sub_filter_module.c +18 -3
  107. data/vendor/nginx/src/http/modules/ngx_http_upstream_hash_module.c +641 -0
  108. data/vendor/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +1 -1
  109. data/vendor/nginx/src/http/modules/ngx_http_upstream_keepalive_module.c +3 -21
  110. data/vendor/nginx/src/http/modules/ngx_http_upstream_least_conn_module.c +0 -5
  111. data/vendor/nginx/src/http/modules/ngx_http_uwsgi_module.c +449 -125
  112. data/vendor/nginx/src/http/modules/ngx_http_xslt_filter_module.c +4 -2
  113. data/vendor/nginx/src/http/modules/perl/ngx_http_perl_module.c +2 -1
  114. data/vendor/nginx/src/http/ngx_http.c +10 -5
  115. data/vendor/nginx/src/http/ngx_http.h +4 -4
  116. data/vendor/nginx/src/http/ngx_http_cache.h +26 -1
  117. data/vendor/nginx/src/http/ngx_http_copy_filter_module.c +109 -68
  118. data/vendor/nginx/src/http/ngx_http_core_module.c +191 -46
  119. data/vendor/nginx/src/http/ngx_http_core_module.h +16 -4
  120. data/vendor/nginx/src/http/ngx_http_file_cache.c +584 -67
  121. data/vendor/nginx/src/http/ngx_http_parse.c +55 -4
  122. data/vendor/nginx/src/http/ngx_http_request.c +14 -6
  123. data/vendor/nginx/src/http/ngx_http_request.h +12 -4
  124. data/vendor/nginx/src/http/ngx_http_request_body.c +114 -28
  125. data/vendor/nginx/src/http/ngx_http_spdy.c +383 -229
  126. data/vendor/nginx/src/http/ngx_http_spdy.h +8 -5
  127. data/vendor/nginx/src/http/ngx_http_spdy_filter_module.c +12 -4
  128. data/vendor/nginx/src/http/ngx_http_special_response.c +2 -2
  129. data/vendor/nginx/src/http/ngx_http_upstream.c +808 -132
  130. data/vendor/nginx/src/http/ngx_http_upstream.h +33 -3
  131. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.c +72 -65
  132. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.h +1 -2
  133. data/vendor/nginx/src/http/ngx_http_variables.c +47 -3
  134. data/vendor/nginx/src/http/ngx_http_write_filter_module.c +15 -6
  135. data/vendor/nginx/src/mail/ngx_mail.c +2 -3
  136. data/vendor/nginx/src/mail/ngx_mail.h +2 -0
  137. data/vendor/nginx/src/mail/ngx_mail_auth_http_module.c +140 -11
  138. data/vendor/nginx/src/mail/ngx_mail_core_module.c +3 -3
  139. data/vendor/nginx/src/mail/ngx_mail_handler.c +79 -2
  140. data/vendor/nginx/src/mail/ngx_mail_imap_module.c +3 -1
  141. data/vendor/nginx/src/mail/ngx_mail_pop3_module.c +3 -1
  142. data/vendor/nginx/src/mail/ngx_mail_smtp_module.c +3 -1
  143. data/vendor/nginx/src/mail/ngx_mail_ssl_module.c +125 -1
  144. data/vendor/nginx/src/mail/ngx_mail_ssl_module.h +8 -0
  145. data/vendor/nginx/src/misc/ngx_cpp_test_module.cpp +1 -1
  146. data/vendor/nginx/src/os/unix/ngx_aio_read_chain.c +1 -1
  147. data/vendor/nginx/src/os/unix/ngx_channel.c +0 -7
  148. data/vendor/nginx/src/os/unix/ngx_darwin_config.h +0 -3
  149. data/vendor/nginx/src/os/unix/ngx_darwin_sendfile_chain.c +44 -208
  150. data/vendor/nginx/src/os/unix/ngx_file_aio_read.c +25 -17
  151. data/vendor/nginx/src/os/unix/ngx_files.c +109 -0
  152. data/vendor/nginx/src/os/unix/ngx_files.h +6 -0
  153. data/vendor/nginx/src/os/unix/ngx_freebsd_config.h +0 -6
  154. data/vendor/nginx/src/os/unix/ngx_freebsd_sendfile_chain.c +78 -206
  155. data/vendor/nginx/src/os/unix/ngx_linux_aio_read.c +25 -14
  156. data/vendor/nginx/src/os/unix/ngx_linux_config.h +4 -1
  157. data/vendor/nginx/src/os/unix/ngx_linux_sendfile_chain.c +235 -194
  158. data/vendor/nginx/src/os/unix/ngx_os.h +25 -3
  159. data/vendor/nginx/src/os/unix/ngx_posix_init.c +4 -2
  160. data/vendor/nginx/src/os/unix/ngx_process_cycle.c +13 -195
  161. data/vendor/nginx/src/os/unix/ngx_process_cycle.h +0 -1
  162. data/vendor/nginx/src/os/unix/ngx_readv_chain.c +27 -108
  163. data/vendor/nginx/src/os/unix/ngx_setproctitle.h +2 -2
  164. data/vendor/nginx/src/os/unix/ngx_solaris_sendfilev_chain.c +12 -67
  165. data/vendor/nginx/src/os/unix/ngx_thread.h +26 -83
  166. data/vendor/nginx/src/os/unix/ngx_thread_cond.c +87 -0
  167. data/vendor/nginx/src/os/unix/ngx_thread_id.c +70 -0
  168. data/vendor/nginx/src/os/unix/ngx_thread_mutex.c +174 -0
  169. data/vendor/nginx/src/os/unix/ngx_user.c +2 -20
  170. data/vendor/nginx/src/os/unix/ngx_writev_chain.c +129 -98
  171. metadata +16 -17
  172. data/vendor/nginx/auto/lib/zlib/patch.zlib.h +0 -10
  173. data/vendor/nginx/src/event/ngx_event_busy_lock.c +0 -286
  174. data/vendor/nginx/src/event/ngx_event_busy_lock.h +0 -65
  175. data/vendor/nginx/src/event/ngx_event_mutex.c +0 -70
  176. data/vendor/nginx/src/http/ngx_http_busy_lock.c +0 -307
  177. data/vendor/nginx/src/http/ngx_http_busy_lock.h +0 -54
  178. data/vendor/nginx/src/os/unix/ngx_freebsd_rfork_thread.c +0 -756
  179. data/vendor/nginx/src/os/unix/ngx_freebsd_rfork_thread.h +0 -122
  180. data/vendor/nginx/src/os/unix/ngx_pthread_thread.c +0 -278
  181. data/vendor/nginx/src/os/unix/rfork_thread.S +0 -73
@@ -10,13 +10,8 @@
10
10
  #include <ngx_event.h>
11
11
 
12
12
 
13
- #if (NGX_THREADS)
14
- ngx_mutex_t *ngx_event_timer_mutex;
15
- #endif
16
-
17
-
18
- ngx_thread_volatile ngx_rbtree_t ngx_event_timer_rbtree;
19
- static ngx_rbtree_node_t ngx_event_timer_sentinel;
13
+ ngx_rbtree_t ngx_event_timer_rbtree;
14
+ static ngx_rbtree_node_t ngx_event_timer_sentinel;
20
15
 
21
16
  /*
22
17
  * the event timer rbtree may contain the duplicate keys, however,
@@ -30,20 +25,6 @@ ngx_event_timer_init(ngx_log_t *log)
30
25
  ngx_rbtree_init(&ngx_event_timer_rbtree, &ngx_event_timer_sentinel,
31
26
  ngx_rbtree_insert_timer_value);
32
27
 
33
- #if (NGX_THREADS)
34
-
35
- if (ngx_event_timer_mutex) {
36
- ngx_event_timer_mutex->log = log;
37
- return NGX_OK;
38
- }
39
-
40
- ngx_event_timer_mutex = ngx_mutex_init(log, 0);
41
- if (ngx_event_timer_mutex == NULL) {
42
- return NGX_ERROR;
43
- }
44
-
45
- #endif
46
-
47
28
  return NGX_OK;
48
29
  }
49
30
 
@@ -58,15 +39,11 @@ ngx_event_find_timer(void)
58
39
  return NGX_TIMER_INFINITE;
59
40
  }
60
41
 
61
- ngx_mutex_lock(ngx_event_timer_mutex);
62
-
63
42
  root = ngx_event_timer_rbtree.root;
64
43
  sentinel = ngx_event_timer_rbtree.sentinel;
65
44
 
66
45
  node = ngx_rbtree_min(root, sentinel);
67
46
 
68
- ngx_mutex_unlock(ngx_event_timer_mutex);
69
-
70
47
  timer = (ngx_msec_int_t) (node->key - ngx_current_msec);
71
48
 
72
49
  return (ngx_msec_t) (timer > 0 ? timer : 0);
@@ -82,9 +59,6 @@ ngx_event_expire_timers(void)
82
59
  sentinel = ngx_event_timer_rbtree.sentinel;
83
60
 
84
61
  for ( ;; ) {
85
-
86
- ngx_mutex_lock(ngx_event_timer_mutex);
87
-
88
62
  root = ngx_event_timer_rbtree.root;
89
63
 
90
64
  if (root == sentinel) {
@@ -93,66 +67,72 @@ ngx_event_expire_timers(void)
93
67
 
94
68
  node = ngx_rbtree_min(root, sentinel);
95
69
 
96
- /* node->key <= ngx_current_time */
70
+ /* node->key > ngx_current_time */
97
71
 
98
- if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) {
99
- ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
72
+ if ((ngx_msec_int_t) (node->key - ngx_current_msec) > 0) {
73
+ return;
74
+ }
100
75
 
101
- #if (NGX_THREADS)
76
+ ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
102
77
 
103
- if (ngx_threaded && ngx_trylock(ev->lock) == 0) {
78
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
79
+ "event timer del: %d: %M",
80
+ ngx_event_ident(ev->data), ev->timer.key);
104
81
 
105
- /*
106
- * We cannot change the timer of the event that is being
107
- * handled by another thread. And we cannot easy walk
108
- * the rbtree to find next expired timer so we exit the loop.
109
- * However, it should be a rare case when the event that is
110
- * being handled has an expired timer.
111
- */
82
+ ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
112
83
 
113
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
114
- "event %p is busy in expire timers", ev);
115
- break;
116
- }
84
+ #if (NGX_DEBUG)
85
+ ev->timer.left = NULL;
86
+ ev->timer.right = NULL;
87
+ ev->timer.parent = NULL;
117
88
  #endif
118
89
 
119
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
120
- "event timer del: %d: %M",
121
- ngx_event_ident(ev->data), ev->timer.key);
122
-
123
- ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
90
+ ev->timer_set = 0;
124
91
 
125
- ngx_mutex_unlock(ngx_event_timer_mutex);
92
+ ev->timedout = 1;
126
93
 
127
- #if (NGX_DEBUG)
128
- ev->timer.left = NULL;
129
- ev->timer.right = NULL;
130
- ev->timer.parent = NULL;
131
- #endif
94
+ ev->handler(ev);
95
+ }
96
+ }
132
97
 
133
- ev->timer_set = 0;
134
98
 
135
- #if (NGX_THREADS)
136
- if (ngx_threaded) {
137
- ev->posted_timedout = 1;
99
+ void
100
+ ngx_event_cancel_timers(void)
101
+ {
102
+ ngx_event_t *ev;
103
+ ngx_rbtree_node_t *node, *root, *sentinel;
138
104
 
139
- ngx_post_event(ev, &ngx_posted_events);
105
+ sentinel = ngx_event_timer_rbtree.sentinel;
140
106
 
141
- ngx_unlock(ev->lock);
107
+ for ( ;; ) {
108
+ root = ngx_event_timer_rbtree.root;
142
109
 
143
- continue;
144
- }
145
- #endif
110
+ if (root == sentinel) {
111
+ return;
112
+ }
146
113
 
147
- ev->timedout = 1;
114
+ node = ngx_rbtree_min(root, sentinel);
148
115
 
149
- ev->handler(ev);
116
+ ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
150
117
 
151
- continue;
118
+ if (!ev->cancelable) {
119
+ return;
152
120
  }
153
121
 
154
- break;
155
- }
122
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
123
+ "event timer cancel: %d: %M",
124
+ ngx_event_ident(ev->data), ev->timer.key);
125
+
126
+ ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
156
127
 
157
- ngx_mutex_unlock(ngx_event_timer_mutex);
128
+ #if (NGX_DEBUG)
129
+ ev->timer.left = NULL;
130
+ ev->timer.right = NULL;
131
+ ev->timer.parent = NULL;
132
+ #endif
133
+
134
+ ev->timer_set = 0;
135
+
136
+ ev->handler(ev);
137
+ }
158
138
  }
@@ -22,14 +22,10 @@
22
22
  ngx_int_t ngx_event_timer_init(ngx_log_t *log);
23
23
  ngx_msec_t ngx_event_find_timer(void);
24
24
  void ngx_event_expire_timers(void);
25
+ void ngx_event_cancel_timers(void);
25
26
 
26
27
 
27
- #if (NGX_THREADS)
28
- extern ngx_mutex_t *ngx_event_timer_mutex;
29
- #endif
30
-
31
-
32
- extern ngx_thread_volatile ngx_rbtree_t ngx_event_timer_rbtree;
28
+ extern ngx_rbtree_t ngx_event_timer_rbtree;
33
29
 
34
30
 
35
31
  static ngx_inline void
@@ -39,12 +35,8 @@ ngx_event_del_timer(ngx_event_t *ev)
39
35
  "event timer del: %d: %M",
40
36
  ngx_event_ident(ev->data), ev->timer.key);
41
37
 
42
- ngx_mutex_lock(ngx_event_timer_mutex);
43
-
44
38
  ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
45
39
 
46
- ngx_mutex_unlock(ngx_event_timer_mutex);
47
-
48
40
  #if (NGX_DEBUG)
49
41
  ev->timer.left = NULL;
50
42
  ev->timer.right = NULL;
@@ -89,12 +81,8 @@ ngx_event_add_timer(ngx_event_t *ev, ngx_msec_t timer)
89
81
  "event timer add: %d: %M:%M",
90
82
  ngx_event_ident(ev->data), timer, ev->timer.key);
91
83
 
92
- ngx_mutex_lock(ngx_event_timer_mutex);
93
-
94
84
  ngx_rbtree_insert(&ngx_event_timer_rbtree, &ev->timer);
95
85
 
96
- ngx_mutex_unlock(ngx_event_timer_mutex);
97
-
98
86
  ev->timer_set = 1;
99
87
  }
100
88
 
@@ -121,7 +121,7 @@ ngx_http_addition_header_filter(ngx_http_request_t *r)
121
121
 
122
122
  ngx_http_clear_content_length(r);
123
123
  ngx_http_clear_accept_ranges(r);
124
- ngx_http_clear_etag(r);
124
+ ngx_http_weak_etag(r);
125
125
 
126
126
  return ngx_http_next_header_filter(r);
127
127
  }
@@ -30,6 +30,7 @@ typedef struct {
30
30
  size_t escape_html;
31
31
 
32
32
  unsigned dir:1;
33
+ unsigned file:1;
33
34
 
34
35
  time_t mtime;
35
36
  off_t size;
@@ -38,26 +39,51 @@ typedef struct {
38
39
 
39
40
  typedef struct {
40
41
  ngx_flag_t enable;
42
+ ngx_uint_t format;
41
43
  ngx_flag_t localtime;
42
44
  ngx_flag_t exact_size;
43
45
  } ngx_http_autoindex_loc_conf_t;
44
46
 
45
47
 
48
+ #define NGX_HTTP_AUTOINDEX_HTML 0
49
+ #define NGX_HTTP_AUTOINDEX_JSON 1
50
+ #define NGX_HTTP_AUTOINDEX_JSONP 2
51
+ #define NGX_HTTP_AUTOINDEX_XML 3
52
+
46
53
  #define NGX_HTTP_AUTOINDEX_PREALLOCATE 50
47
54
 
48
55
  #define NGX_HTTP_AUTOINDEX_NAME_LEN 50
49
56
 
50
57
 
58
+ static ngx_buf_t *ngx_http_autoindex_html(ngx_http_request_t *r,
59
+ ngx_array_t *entries);
60
+ static ngx_buf_t *ngx_http_autoindex_json(ngx_http_request_t *r,
61
+ ngx_array_t *entries, ngx_str_t *callback);
62
+ static ngx_int_t ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r,
63
+ ngx_str_t *callback);
64
+ static ngx_buf_t *ngx_http_autoindex_xml(ngx_http_request_t *r,
65
+ ngx_array_t *entries);
66
+
51
67
  static int ngx_libc_cdecl ngx_http_autoindex_cmp_entries(const void *one,
52
68
  const void *two);
53
69
  static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r,
54
70
  ngx_dir_t *dir, ngx_str_t *name);
71
+
55
72
  static ngx_int_t ngx_http_autoindex_init(ngx_conf_t *cf);
56
73
  static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf);
57
74
  static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf,
58
75
  void *parent, void *child);
59
76
 
60
77
 
78
+ static ngx_conf_enum_t ngx_http_autoindex_format[] = {
79
+ { ngx_string("html"), NGX_HTTP_AUTOINDEX_HTML },
80
+ { ngx_string("json"), NGX_HTTP_AUTOINDEX_JSON },
81
+ { ngx_string("jsonp"), NGX_HTTP_AUTOINDEX_JSONP },
82
+ { ngx_string("xml"), NGX_HTTP_AUTOINDEX_XML },
83
+ { ngx_null_string, 0 }
84
+ };
85
+
86
+
61
87
  static ngx_command_t ngx_http_autoindex_commands[] = {
62
88
 
63
89
  { ngx_string("autoindex"),
@@ -67,6 +93,13 @@ static ngx_command_t ngx_http_autoindex_commands[] = {
67
93
  offsetof(ngx_http_autoindex_loc_conf_t, enable),
68
94
  NULL },
69
95
 
96
+ { ngx_string("autoindex_format"),
97
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
98
+ ngx_conf_set_enum_slot,
99
+ NGX_HTTP_LOC_CONF_OFFSET,
100
+ offsetof(ngx_http_autoindex_loc_conf_t, format),
101
+ &ngx_http_autoindex_format },
102
+
70
103
  { ngx_string("autoindex_localtime"),
71
104
  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
72
105
  ngx_conf_set_flag_slot,
@@ -116,47 +149,23 @@ ngx_module_t ngx_http_autoindex_module = {
116
149
  };
117
150
 
118
151
 
119
- static u_char title[] =
120
- "<html>" CRLF
121
- "<head><title>Index of "
122
- ;
123
-
124
-
125
- static u_char header[] =
126
- "</title></head>" CRLF
127
- "<body bgcolor=\"white\">" CRLF
128
- "<h1>Index of "
129
- ;
130
-
131
- static u_char tail[] =
132
- "</body>" CRLF
133
- "</html>" CRLF
134
- ;
135
-
136
-
137
152
  static ngx_int_t
138
153
  ngx_http_autoindex_handler(ngx_http_request_t *r)
139
154
  {
140
- u_char *last, *filename, scale;
141
- off_t length;
142
- size_t len, char_len, escape_html, allocated, root;
143
- ngx_tm_t tm;
155
+ u_char *last, *filename;
156
+ size_t len, allocated, root;
144
157
  ngx_err_t err;
145
158
  ngx_buf_t *b;
146
- ngx_int_t rc, size;
147
- ngx_str_t path;
159
+ ngx_int_t rc;
160
+ ngx_str_t path, callback;
148
161
  ngx_dir_t dir;
149
- ngx_uint_t i, level, utf8;
162
+ ngx_uint_t level, format;
150
163
  ngx_pool_t *pool;
151
- ngx_time_t *tp;
152
164
  ngx_chain_t out;
153
165
  ngx_array_t entries;
154
166
  ngx_http_autoindex_entry_t *entry;
155
167
  ngx_http_autoindex_loc_conf_t *alcf;
156
168
 
157
- static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
158
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
159
-
160
169
  if (r->uri.data[r->uri.len - 1] != '/') {
161
170
  return NGX_DECLINED;
162
171
  }
@@ -189,6 +198,18 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
189
198
  ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
190
199
  "http autoindex: \"%s\"", path.data);
191
200
 
201
+ format = alcf->format;
202
+
203
+ if (format == NGX_HTTP_AUTOINDEX_JSONP) {
204
+ if (ngx_http_autoindex_jsonp_callback(r, &callback) != NGX_OK) {
205
+ return NGX_HTTP_BAD_REQUEST;
206
+ }
207
+
208
+ if (callback.len == 0) {
209
+ format = NGX_HTTP_AUTOINDEX_JSON;
210
+ }
211
+ }
212
+
192
213
  if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
193
214
  err = ngx_errno;
194
215
 
@@ -231,8 +252,28 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
231
252
  }
232
253
 
233
254
  r->headers_out.status = NGX_HTTP_OK;
234
- r->headers_out.content_type_len = sizeof("text/html") - 1;
235
- ngx_str_set(&r->headers_out.content_type, "text/html");
255
+
256
+ switch (format) {
257
+
258
+ case NGX_HTTP_AUTOINDEX_JSON:
259
+ ngx_str_set(&r->headers_out.content_type, "application/json");
260
+ break;
261
+
262
+ case NGX_HTTP_AUTOINDEX_JSONP:
263
+ ngx_str_set(&r->headers_out.content_type, "application/javascript");
264
+ break;
265
+
266
+ case NGX_HTTP_AUTOINDEX_XML:
267
+ ngx_str_set(&r->headers_out.content_type, "text/xml");
268
+ ngx_str_set(&r->headers_out.charset, "utf-8");
269
+ break;
270
+
271
+ default: /* NGX_HTTP_AUTOINDEX_HTML */
272
+ ngx_str_set(&r->headers_out.content_type, "text/html");
273
+ break;
274
+ }
275
+
276
+ r->headers_out.content_type_len = r->headers_out.content_type.len;
236
277
  r->headers_out.content_type_lowcase = NULL;
237
278
 
238
279
  rc = ngx_http_send_header(r);
@@ -249,16 +290,6 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
249
290
  filename = path.data;
250
291
  filename[path.len] = '/';
251
292
 
252
- if (r->headers_out.charset.len == 5
253
- && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
254
- == 0)
255
- {
256
- utf8 = 1;
257
-
258
- } else {
259
- utf8 = 0;
260
- }
261
-
262
293
  for ( ;; ) {
263
294
  ngx_set_errno(0);
264
295
 
@@ -339,19 +370,8 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
339
370
 
340
371
  ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
341
372
 
342
- entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len,
343
- NGX_ESCAPE_URI_COMPONENT);
344
-
345
- entry->escape_html = ngx_escape_html(NULL, entry->name.data,
346
- entry->name.len);
347
-
348
- if (utf8) {
349
- entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len);
350
- } else {
351
- entry->utf_len = len;
352
- }
353
-
354
373
  entry->dir = ngx_de_is_dir(&dir);
374
+ entry->file = ngx_de_is_file(&dir);
355
375
  entry->mtime = ngx_de_mtime(&dir);
356
376
  entry->size = ngx_de_size(&dir);
357
377
  }
@@ -361,6 +381,93 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
361
381
  ngx_close_dir_n " \"%V\" failed", &path);
362
382
  }
363
383
 
384
+ if (entries.nelts > 1) {
385
+ ngx_qsort(entries.elts, (size_t) entries.nelts,
386
+ sizeof(ngx_http_autoindex_entry_t),
387
+ ngx_http_autoindex_cmp_entries);
388
+ }
389
+
390
+ switch (format) {
391
+
392
+ case NGX_HTTP_AUTOINDEX_JSON:
393
+ b = ngx_http_autoindex_json(r, &entries, NULL);
394
+ break;
395
+
396
+ case NGX_HTTP_AUTOINDEX_JSONP:
397
+ b = ngx_http_autoindex_json(r, &entries, &callback);
398
+ break;
399
+
400
+ case NGX_HTTP_AUTOINDEX_XML:
401
+ b = ngx_http_autoindex_xml(r, &entries);
402
+ break;
403
+
404
+ default: /* NGX_HTTP_AUTOINDEX_HTML */
405
+ b = ngx_http_autoindex_html(r, &entries);
406
+ break;
407
+ }
408
+
409
+ if (b == NULL) {
410
+ return NGX_ERROR;
411
+ }
412
+
413
+ /* TODO: free temporary pool */
414
+
415
+ if (r == r->main) {
416
+ b->last_buf = 1;
417
+ }
418
+
419
+ b->last_in_chain = 1;
420
+
421
+ out.buf = b;
422
+ out.next = NULL;
423
+
424
+ return ngx_http_output_filter(r, &out);
425
+ }
426
+
427
+
428
+ static ngx_buf_t *
429
+ ngx_http_autoindex_html(ngx_http_request_t *r, ngx_array_t *entries)
430
+ {
431
+ u_char *last, scale;
432
+ off_t length;
433
+ size_t len, char_len, escape_html;
434
+ ngx_tm_t tm;
435
+ ngx_buf_t *b;
436
+ ngx_int_t size;
437
+ ngx_uint_t i, utf8;
438
+ ngx_time_t *tp;
439
+ ngx_http_autoindex_entry_t *entry;
440
+ ngx_http_autoindex_loc_conf_t *alcf;
441
+
442
+ static u_char title[] =
443
+ "<html>" CRLF
444
+ "<head><title>Index of "
445
+ ;
446
+
447
+ static u_char header[] =
448
+ "</title></head>" CRLF
449
+ "<body bgcolor=\"white\">" CRLF
450
+ "<h1>Index of "
451
+ ;
452
+
453
+ static u_char tail[] =
454
+ "</body>" CRLF
455
+ "</html>" CRLF
456
+ ;
457
+
458
+ static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
459
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
460
+
461
+ if (r->headers_out.charset.len == 5
462
+ && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5)
463
+ == 0)
464
+ {
465
+ utf8 = 1;
466
+
467
+ } else {
468
+ utf8 = 0;
469
+ }
470
+
364
471
  escape_html = ngx_escape_html(NULL, r->uri.data, r->uri.len);
365
472
 
366
473
  len = sizeof(title) - 1
@@ -372,8 +479,22 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
372
479
  + sizeof("</pre><hr>") - 1
373
480
  + sizeof(tail) - 1;
374
481
 
375
- entry = entries.elts;
376
- for (i = 0; i < entries.nelts; i++) {
482
+ entry = entries->elts;
483
+ for (i = 0; i < entries->nelts; i++) {
484
+ entry[i].escape = 2 * ngx_escape_uri(NULL, entry[i].name.data,
485
+ entry[i].name.len,
486
+ NGX_ESCAPE_URI_COMPONENT);
487
+
488
+ entry[i].escape_html = ngx_escape_html(NULL, entry[i].name.data,
489
+ entry[i].name.len);
490
+
491
+ if (utf8) {
492
+ entry[i].utf_len = ngx_utf8_length(entry[i].name.data,
493
+ entry[i].name.len);
494
+ } else {
495
+ entry[i].utf_len = entry[i].name.len;
496
+ }
497
+
377
498
  len += sizeof("<a href=\"") - 1
378
499
  + entry[i].name.len + entry[i].escape
379
500
  + 1 /* 1 is for "/" */
@@ -389,13 +510,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
389
510
 
390
511
  b = ngx_create_temp_buf(r->pool, len);
391
512
  if (b == NULL) {
392
- return NGX_ERROR;
393
- }
394
-
395
- if (entries.nelts > 1) {
396
- ngx_qsort(entry, (size_t) entries.nelts,
397
- sizeof(ngx_http_autoindex_entry_t),
398
- ngx_http_autoindex_cmp_entries);
513
+ return NULL;
399
514
  }
400
515
 
401
516
  b->last = ngx_cpymem(b->last, title, sizeof(title) - 1);
@@ -416,9 +531,10 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
416
531
  b->last = ngx_cpymem(b->last, "<hr><pre><a href=\"../\">../</a>" CRLF,
417
532
  sizeof("<hr><pre><a href=\"../\">../</a>" CRLF) - 1);
418
533
 
534
+ alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
419
535
  tp = ngx_timeofday();
420
536
 
421
- for (i = 0; i < entries.nelts; i++) {
537
+ for (i = 0; i < entries->nelts; i++) {
422
538
  b->last = ngx_cpymem(b->last, "<a href=\"", sizeof("<a href=\"") - 1);
423
539
 
424
540
  if (entry[i].escape) {
@@ -565,22 +681,248 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
565
681
  *b->last++ = LF;
566
682
  }
567
683
 
568
- /* TODO: free temporary pool */
569
-
570
684
  b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);
571
685
 
572
686
  b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
573
687
 
574
- if (r == r->main) {
575
- b->last_buf = 1;
688
+ return b;
689
+ }
690
+
691
+
692
+ static ngx_buf_t *
693
+ ngx_http_autoindex_json(ngx_http_request_t *r, ngx_array_t *entries,
694
+ ngx_str_t *callback)
695
+ {
696
+ size_t len;
697
+ ngx_buf_t *b;
698
+ ngx_uint_t i;
699
+ ngx_http_autoindex_entry_t *entry;
700
+
701
+ len = sizeof("[" CRLF CRLF "]") - 1;
702
+
703
+ if (callback) {
704
+ len += sizeof("/* callback */" CRLF "();") - 1 + callback->len;
576
705
  }
577
706
 
578
- b->last_in_chain = 1;
707
+ entry = entries->elts;
579
708
 
580
- out.buf = b;
581
- out.next = NULL;
709
+ for (i = 0; i < entries->nelts; i++) {
710
+ entry[i].escape = ngx_escape_json(NULL, entry[i].name.data,
711
+ entry[i].name.len);
582
712
 
583
- return ngx_http_output_filter(r, &out);
713
+ len += sizeof("{ }," CRLF) - 1
714
+ + sizeof("\"name\":\"\"") - 1
715
+ + entry[i].name.len + entry[i].escape
716
+ + sizeof(", \"type\":\"directory\"") - 1
717
+ + sizeof(", \"mtime\":\"Wed, 31 Dec 1986 10:00:00 GMT\"") - 1;
718
+
719
+ if (entry[i].file) {
720
+ len += sizeof(", \"size\":") - 1 + NGX_OFF_T_LEN;
721
+ }
722
+ }
723
+
724
+ b = ngx_create_temp_buf(r->pool, len);
725
+ if (b == NULL) {
726
+ return NULL;
727
+ }
728
+
729
+ if (callback) {
730
+ b->last = ngx_cpymem(b->last, "/* callback */" CRLF,
731
+ sizeof("/* callback */" CRLF) - 1);
732
+
733
+ b->last = ngx_cpymem(b->last, callback->data, callback->len);
734
+
735
+ *b->last++ = '(';
736
+ }
737
+
738
+ *b->last++ = '[';
739
+
740
+ for (i = 0; i < entries->nelts; i++) {
741
+ b->last = ngx_cpymem(b->last, CRLF "{ \"name\":\"",
742
+ sizeof(CRLF "{ \"name\":\"") - 1);
743
+
744
+ if (entry[i].escape) {
745
+ b->last = (u_char *) ngx_escape_json(b->last, entry[i].name.data,
746
+ entry[i].name.len);
747
+ } else {
748
+ b->last = ngx_cpymem(b->last, entry[i].name.data,
749
+ entry[i].name.len);
750
+ }
751
+
752
+ b->last = ngx_cpymem(b->last, "\", \"type\":\"",
753
+ sizeof("\", \"type\":\"") - 1);
754
+
755
+ if (entry[i].dir) {
756
+ b->last = ngx_cpymem(b->last, "directory", sizeof("directory") - 1);
757
+
758
+ } else if (entry[i].file) {
759
+ b->last = ngx_cpymem(b->last, "file", sizeof("file") - 1);
760
+
761
+ } else {
762
+ b->last = ngx_cpymem(b->last, "other", sizeof("other") - 1);
763
+ }
764
+
765
+ b->last = ngx_cpymem(b->last, "\", \"mtime\":\"",
766
+ sizeof("\", \"mtime\":\"") - 1);
767
+
768
+ b->last = ngx_http_time(b->last, entry[i].mtime);
769
+
770
+ if (entry[i].file) {
771
+ b->last = ngx_cpymem(b->last, "\", \"size\":",
772
+ sizeof("\", \"size\":") - 1);
773
+ b->last = ngx_sprintf(b->last, "%O", entry[i].size);
774
+
775
+ } else {
776
+ *b->last++ = '"';
777
+ }
778
+
779
+ b->last = ngx_cpymem(b->last, " },", sizeof(" },") - 1);
780
+ }
781
+
782
+ if (i > 0) {
783
+ b->last--; /* strip last comma */
784
+ }
785
+
786
+ b->last = ngx_cpymem(b->last, CRLF "]", sizeof(CRLF "]") - 1);
787
+
788
+ if (callback) {
789
+ *b->last++ = ')'; *b->last++ = ';';
790
+ }
791
+
792
+ return b;
793
+ }
794
+
795
+
796
+ static ngx_int_t
797
+ ngx_http_autoindex_jsonp_callback(ngx_http_request_t *r, ngx_str_t *callback)
798
+ {
799
+ u_char *p, c, ch;
800
+ ngx_uint_t i;
801
+
802
+ if (ngx_http_arg(r, (u_char *) "callback", 8, callback) != NGX_OK) {
803
+ callback->len = 0;
804
+ return NGX_OK;
805
+ }
806
+
807
+ if (callback->len > 128) {
808
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
809
+ "client sent too long callback name: \"%V\"", callback);
810
+ return NGX_DECLINED;
811
+ }
812
+
813
+ p = callback->data;
814
+
815
+ for (i = 0; i < callback->len; i++) {
816
+ ch = p[i];
817
+
818
+ c = (u_char) (ch | 0x20);
819
+ if (c >= 'a' && c <= 'z') {
820
+ continue;
821
+ }
822
+
823
+ if ((ch >= '0' && ch <= '9') || ch == '_' || ch == '.') {
824
+ continue;
825
+ }
826
+
827
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
828
+ "client sent invalid callback name: \"%V\"", callback);
829
+
830
+ return NGX_DECLINED;
831
+ }
832
+
833
+ return NGX_OK;
834
+ }
835
+
836
+
837
+ static ngx_buf_t *
838
+ ngx_http_autoindex_xml(ngx_http_request_t *r, ngx_array_t *entries)
839
+ {
840
+ size_t len;
841
+ ngx_tm_t tm;
842
+ ngx_buf_t *b;
843
+ ngx_str_t type;
844
+ ngx_uint_t i;
845
+ ngx_http_autoindex_entry_t *entry;
846
+
847
+ static u_char head[] = "<?xml version=\"1.0\"?>" CRLF "<list>" CRLF;
848
+ static u_char tail[] = "</list>" CRLF;
849
+
850
+ len = sizeof(head) - 1 + sizeof(tail) - 1;
851
+
852
+ entry = entries->elts;
853
+
854
+ for (i = 0; i < entries->nelts; i++) {
855
+ entry[i].escape = ngx_escape_html(NULL, entry[i].name.data,
856
+ entry[i].name.len);
857
+
858
+ len += sizeof("<directory></directory>" CRLF) - 1
859
+ + entry[i].name.len + entry[i].escape
860
+ + sizeof(" mtime=\"1986-12-31T10:00:00Z\"") - 1;
861
+
862
+ if (entry[i].file) {
863
+ len += sizeof(" size=\"\"") - 1 + NGX_OFF_T_LEN;
864
+ }
865
+ }
866
+
867
+ b = ngx_create_temp_buf(r->pool, len);
868
+ if (b == NULL) {
869
+ return NULL;
870
+ }
871
+
872
+ b->last = ngx_cpymem(b->last, head, sizeof(head) - 1);
873
+
874
+ for (i = 0; i < entries->nelts; i++) {
875
+ *b->last++ = '<';
876
+
877
+ if (entry[i].dir) {
878
+ ngx_str_set(&type, "directory");
879
+
880
+ } else if (entry[i].file) {
881
+ ngx_str_set(&type, "file");
882
+
883
+ } else {
884
+ ngx_str_set(&type, "other");
885
+ }
886
+
887
+ b->last = ngx_cpymem(b->last, type.data, type.len);
888
+
889
+ b->last = ngx_cpymem(b->last, " mtime=\"", sizeof(" mtime=\"") - 1);
890
+
891
+ ngx_gmtime(entry[i].mtime, &tm);
892
+
893
+ b->last = ngx_sprintf(b->last, "%4d-%02d-%02dT%02d:%02d:%02dZ",
894
+ tm.ngx_tm_year, tm.ngx_tm_mon,
895
+ tm.ngx_tm_mday, tm.ngx_tm_hour,
896
+ tm.ngx_tm_min, tm.ngx_tm_sec);
897
+
898
+ if (entry[i].file) {
899
+ b->last = ngx_cpymem(b->last, "\" size=\"",
900
+ sizeof("\" size=\"") - 1);
901
+ b->last = ngx_sprintf(b->last, "%O", entry[i].size);
902
+ }
903
+
904
+ *b->last++ = '"'; *b->last++ = '>';
905
+
906
+ if (entry[i].escape) {
907
+ b->last = (u_char *) ngx_escape_html(b->last, entry[i].name.data,
908
+ entry[i].name.len);
909
+ } else {
910
+ b->last = ngx_cpymem(b->last, entry[i].name.data,
911
+ entry[i].name.len);
912
+ }
913
+
914
+ *b->last++ = '<'; *b->last++ = '/';
915
+
916
+ b->last = ngx_cpymem(b->last, type.data, type.len);
917
+
918
+ *b->last++ = '>';
919
+
920
+ *b->last++ = CR; *b->last++ = LF;
921
+ }
922
+
923
+ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
924
+
925
+ return b;
584
926
  }
585
927
 
586
928
 
@@ -665,6 +1007,7 @@ ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf)
665
1007
  }
666
1008
 
667
1009
  conf->enable = NGX_CONF_UNSET;
1010
+ conf->format = NGX_CONF_UNSET_UINT;
668
1011
  conf->localtime = NGX_CONF_UNSET;
669
1012
  conf->exact_size = NGX_CONF_UNSET;
670
1013
 
@@ -679,6 +1022,8 @@ ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
679
1022
  ngx_http_autoindex_loc_conf_t *conf = child;
680
1023
 
681
1024
  ngx_conf_merge_value(conf->enable, prev->enable, 0);
1025
+ ngx_conf_merge_uint_value(conf->format, prev->format,
1026
+ NGX_HTTP_AUTOINDEX_HTML);
682
1027
  ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
683
1028
  ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
684
1029