Codebase list nginx / 34bbfa3
#704210 Added FancyIndexs module Kartik Mistry 11 years ago
12 changed file(s) with 1564 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
77 [ Kartik Mistry ]
88 * debian/modules/nginx-upload:
99 + This module no longer works with 1.3.x and above. Removed as of now.
10 * debian/modules/ngx-fancyindex:
11 + Added Fancy Indexes module (Closes: #704210)
1012 * debian/copyright:
1113 + Fixed path for modules in Files: field.
1214 + Updated copyright for debian/*
5555 nginx-dav-ext-module
5656 Homepage: https://github.com/arut/nginx-dav-ext-module
5757 Version: v0.0.2-2-g54cebc1.tar.gz
58
59 ngx-fancyindex
60 Homepage: https://github.com/aperezdc/ngx-fancyindex
61 Version: fd3950172a
0 ===================================
1 Fancy Index module Hacking HOW-TO
2 ===================================
3
4 .. contents::
5
6
7 How to modify the template
8 ==========================
9
10 The template is in the ``template.html`` file. Note that comment markers are
11 used to control how the ``template.awk`` Awk script generates the C header
12 which gets ultimately included in the compiled object code. Comment markers
13 have the ``<!-- var identifier -->`` format. Here ``identifier`` must be
14 a valid C identifier. All the text following the marker until the next
15 marker will be flattened into a C string.
16
17 If the identifier is ``NONE`` (capitalized) the text from that marker up to
18 the next marker will be discarded.
19
20
21 Regenerating the C header
22 ~~~~~~~~~~~~~~~~~~~~~~~~~
23 You will need Awk. I hope any decent implementation will do, but the GNU one
24 is known to work flawlessly. Just do::
25
26 $ awk -f template.awk template.html > template.h
27
28 If your copy of ``awk`` is not the GNU implementation, you will need to
29 install it and use ``gawk`` instead in the command line above.
30
31 .. vim: spell spelllang=en expandtab
32
0 Redistribution and use in source and binary forms, with or without
1 modification, are permitted provided that the following conditions
2 are met:
3 1. Redistributions of source code must retain the above copyright
4 notice, this list of conditions and the following disclaimer.
5 2. Redistributions in binary form must reproduce the above copyright
6 notice, this list of conditions and the following disclaimer in the
7 documentation and/or other materials provided with the distribution.
8
9 THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
10 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
11 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12 ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
13 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
15 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
16 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19 SUCH DAMAGE.
0 ========================
1 Nginx Fancy Index module
2 ========================
3
4 .. contents::
5
6 The Fancy Index module makes possible the generation of file listings, like
7 the built-in `autoindex <http://wiki.nginx.org/NginxHttpAutoindexModule>`__
8 module does, but adding a touch of style. This is possible because the module
9 module allows a certain degree of customization of the generated content:
10
11 * Custom headers. Either local or stored remotely.
12 * Custom footers. Either local or stored remotely.
13 * Add you own CSS style rules.
14
15 This module is designed to work with Nginx_, a high performance open source web
16 server written by `Igor Sysoev <http://sysoev.ru>`__.
17
18
19 Requirements
20 ============
21
22 You will need the sources for Nginx_. Any version starting from the 0.7
23 series onwards will work. Note that the modules *might* compile with
24 versions in the 0.6 series by applying ``nginx-0.6-support.patch``, but this
25 is unsupported (YMMV).
26
27
28 Building
29 ========
30
31 1. Unpack the Nginx_ sources::
32
33 $ gunzip -c nginx-?.?.?.tar.gz | tar -xvf -
34
35 2. Unpack the sources for the fancy indexing module::
36
37 $ gunzip -c nginx-fancyindex-?.?.?.tar.gz | tar -xvf -
38
39 3. Change to the directory which contains the Nginx_ sources, run the
40 configuration script with the desired options and be sure to put an
41 ``--add-module`` flag pointing to the directory which contains the source
42 of the fancy indexing module::
43
44 $ cd nginx-?.?.?
45 $ ./configure --add-module=../nginx-fancyindex-?.?.? [extra desired options]
46
47 4. Build and install the software::
48
49 $ make
50
51 And then, as ``root``::
52
53 # make install
54
55 5. Configure Nginx_ by using the modules' configuration directives_.
56
57
58 Example
59 =======
60
61 You can test the default built-in style by adding the following lines into
62 a ``server`` section in your Nginx_ configuration file::
63
64 location / {
65 fancyindex on; # Enable fancy indexes.
66 fancyindex_exact_size off; # Output human-readable file sizes.
67 }
68
69
70 Directives
71 ==========
72
73 fancyindex
74 ~~~~~~~~~~
75 :Syntax: *fancyindex* [*on* | *off*]
76 :Default: fancyindex off
77 :Context: http, server, location
78 :Description:
79 Enables or disables fancy directory indexes.
80
81 fancyindex_css_href
82 ~~~~~~~~~~~~~~~~~~~
83 :Syntax: *fancyindex_css_href uri*
84 :Default: fancyindex_css_href ""
85 :Context: http, server, location
86 :Description:
87 Allows inserting a link to a CSS style sheet in generated listings. The
88 provided *uri* parameter will be inserted as-is in a ``<link>`` HTML tag.
89 The link is inserted after the built-in CSS rules, so you can override the
90 default styles.
91
92 fancyindex_exact_size
93 ~~~~~~~~~~~~~~~~~~~~~
94 :Syntax: *fancyindex_exact_size* [*on* | *off*]
95 :Default: fancyindex_exact_size on
96 :Context: http, server, location
97 :Description:
98 Defines how to represent file sizes in the directory listing; either
99 accurately, or rounding off to the kilobyte, the megabyte and the
100 gigabyte.
101
102 fancyindex_footer
103 ~~~~~~~~~~~~~~~~~
104 :Syntax: *fancyindex_footer path*
105 :Default: fancyindex_footer ""
106 :Context: http, server, location
107 :Description:
108 Specifies which file should be inserted at the foot of directory listings.
109 If set to an empty string, the default footer supplied by the module will
110 be sent.
111
112 .. warning:: When inserting custom header/footer a subrequest will be
113 issued so potentially any URL can be used as source for them. Although it
114 will work with external URLs, only using internal ones is supported.
115 External URLs are totally untested and using them will make Nginx_ block
116 while waiting for the subrequest to complete. If you feel like external
117 header/footer is a must-have for you, please
118 `let me know <mailto:aperez@igalia.com>`__.
119
120 fancyindex_header
121 ~~~~~~~~~~~~~~~~~
122 :Syntax: *fancyindex_header path*
123 :Default: fancyindex_header ""
124 :Context: http, server, location
125 :Description:
126 Specifies which file should be inserted at the head of directory listings.
127 If set to an empty string, the default header supplied by the module will
128 be sent.
129
130 fancyindex_ignore
131 ~~~~~~~~~~~~~~~~~
132 :Syntax: *fancyindex_ignore string1 [string2 [... stringN]]*
133 :Default: No default.
134 :Context: http, server, location
135 :Description:
136 Specifies a list of file names which will be not be shown in generated
137 listings. If Nginx was built with PCRE support strings are interpreted as
138 regular expressions.
139
140 fancyindex_localtime
141 ~~~~~~~~~~~~~~~~~~~~
142 :Syntax: *fancyindex_localtime* [*on* | *off*]
143 :Default: fancyindex_localtime off
144 :Context: http, server, location
145 :Description:
146 Enables showing file times as local time. Default is “off” (GMT time).
147
148 .. _nginx: http://nginx.net
149
150 .. vim:ft=rst:spell:spelllang=en:
0 # vim:ft=sh:
1 ngx_addon_name=ngx_http_fancyindex_module
2
3 # XXX: Insert fancyindex module *after* index module!
4 #
5 HTTP_MODULES=`echo "${HTTP_MODULES}" | sed -e \
6 's/ngx_http_index_module/ngx_http_fancyindex_module ngx_http_index_module/'`
7 NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_fancyindex_module.c"
0 === modified file 'ngx_http_fancyindex_module.c'
1 --- ngx_http_fancyindex_module.c 2008-09-11 17:55:52 +0000
2 +++ ngx_http_fancyindex_module.c 2008-12-10 01:33:43 +0000
3 @@ -383,7 +383,7 @@
4 entry->mtime = ngx_de_mtime(&dir);
5 entry->size = ngx_de_size(&dir);
6 entry->utf_len = (r->utf8)
7 - ? ngx_utf8_length(entry->name.data, entry->name.len)
8 + ? ngx_utf_length(entry->name.data, entry->name.len)
9 : len;
10 }
11
12 @@ -478,8 +478,7 @@
13 copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1;
14 }
15
16 - b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data,
17 - copy, entry[i].name.len);
18 + b->last = ngx_utf_cpystrn(b->last, entry[i].name.data, copy);
19 last = b->last;
20
21 } else {
22
0 /*
1 * ngx_http_fancyindex_module.c
2 * Copyright © 2007-2011 Adrian Perez <aperez@igalia.com>
3 *
4 * Module used for fancy indexing of directories. Features and differences
5 * with the stock nginx autoindex module:
6 *
7 * - Output is a table instead of a <pre> element with embedded <a> links.
8 * - Header and footer may be added to every generated directory listing.
9 * - Default header and/or footer are generated if custom ones are not
10 * configured. Files used for header and footer can only be local path
11 * names (i.e. you cannot insert the result of a subrequest.)
12 * - Proper HTML is generated: it should validate both as XHTML 1.0 Strict
13 * and HTML 4.01.
14 *
15 * Base functionality heavy based upon the stock nginx autoindex module,
16 * which in turn was made by Igor Sysoev, like the majority of nginx.
17 *
18 * Distributed under terms of the BSD license.
19 */
20
21 #include <ngx_config.h>
22 #include <ngx_core.h>
23 #include <ngx_http.h>
24 #include <ngx_log.h>
25
26 #include "template.h"
27
28 #if defined(__GNUC__) && (__GNUC__ >= 3)
29 # define ngx_force_inline __attribute__((__always_inline__))
30 #else /* !__GNUC__ */
31 # define ngx_force_inline
32 #endif /* __GNUC__ */
33
34
35
36 /**
37 * Configuration structure for the fancyindex module. The configuration
38 * commands defined in the module do fill in the members of this structure.
39 */
40 typedef struct {
41 ngx_flag_t enable; /**< Module is enabled. */
42 ngx_flag_t localtime; /**< File mtime dates are sent in local time. */
43 ngx_flag_t exact_size; /**< Sizes are sent always in bytes. */
44
45 ngx_str_t header; /**< File name for header, or empty if none. */
46 ngx_str_t footer; /**< File name for footer, or empty if none. */
47 ngx_str_t css_href; /**< Link to a CSS stylesheet, or empty if none. */
48
49 ngx_array_t *ignore; /**< List of files to ignore in listings. */
50 } ngx_http_fancyindex_loc_conf_t;
51
52
53 #define NGX_HTTP_FANCYINDEX_PREALLOCATE 50
54 #define NGX_HTTP_FANCYINDEX_NAME_LEN 50
55
56
57 /**
58 * Calculates the length of a NULL-terminated string. It is ugly having to
59 * remember to substract 1 from the sizeof result.
60 */
61 #define ngx_sizeof_ssz(_s) (sizeof(_s) - 1)
62
63
64 /**
65 * Copy a static zero-terminated string. Useful to output template
66 * string pieces into a temporary buffer.
67 */
68 #define ngx_cpymem_ssz(_p, _t) \
69 (ngx_cpymem((_p), (_t), sizeof(_t) - 1))
70
71 /**
72 * Copy a ngx_str_t.
73 */
74 #define ngx_cpymem_str(_p, _s) \
75 (ngx_cpymem((_p), (_s).data, (_s).len))
76
77 /**
78 * Check whether a particular bit is set in a particular value.
79 */
80 #define ngx_has_flag(_where, _what) \
81 (((_where) & (_what)) == (_what))
82
83
84
85
86 typedef struct {
87 ngx_str_t name;
88 size_t utf_len;
89 ngx_uint_t escape;
90 ngx_uint_t dir;
91 time_t mtime;
92 off_t size;
93 } ngx_http_fancyindex_entry_t;
94
95
96
97 static int ngx_libc_cdecl
98 ngx_http_fancyindex_cmp_entries(const void *one, const void *two);
99
100 static ngx_int_t ngx_http_fancyindex_error(ngx_http_request_t *r,
101 ngx_dir_t *dir, ngx_str_t *name);
102
103 static ngx_int_t ngx_http_fancyindex_init(ngx_conf_t *cf);
104
105 static void *ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf);
106
107 static char *ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf,
108 void *parent, void *child);
109
110 static char *ngx_http_fancyindex_ignore(ngx_conf_t *cf,
111 ngx_command_t *cmd,
112 void *conf);
113
114 static uintptr_t
115 ngx_fancyindex_escape_uri(u_char *dst, u_char*src, size_t size);
116
117 /*
118 * These are used only once per handler invocation. We can tell GCC to
119 * inline them always, if possible (see how ngx_force_inline is defined
120 * above).
121 */
122 static ngx_inline ngx_buf_t*
123 make_header_buf(ngx_http_request_t *r, const ngx_str_t css_href)
124 ngx_force_inline;
125
126 static ngx_inline ngx_buf_t*
127 make_footer_buf(ngx_http_request_t *r)
128 ngx_force_inline;
129
130
131
132 static ngx_command_t ngx_http_fancyindex_commands[] = {
133
134 { ngx_string("fancyindex"),
135 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
136 ngx_conf_set_flag_slot,
137 NGX_HTTP_LOC_CONF_OFFSET,
138 offsetof(ngx_http_fancyindex_loc_conf_t, enable),
139 NULL },
140
141 { ngx_string("fancyindex_localtime"),
142 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
143 ngx_conf_set_flag_slot,
144 NGX_HTTP_LOC_CONF_OFFSET,
145 offsetof(ngx_http_fancyindex_loc_conf_t, localtime),
146 NULL },
147
148 { ngx_string("fancyindex_exact_size"),
149 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
150 ngx_conf_set_flag_slot,
151 NGX_HTTP_LOC_CONF_OFFSET,
152 offsetof(ngx_http_fancyindex_loc_conf_t, exact_size),
153 NULL },
154
155 { ngx_string("fancyindex_header"),
156 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
157 ngx_conf_set_str_slot,
158 NGX_HTTP_LOC_CONF_OFFSET,
159 offsetof(ngx_http_fancyindex_loc_conf_t, header),
160 NULL },
161
162 { ngx_string("fancyindex_footer"),
163 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
164 ngx_conf_set_str_slot,
165 NGX_HTTP_LOC_CONF_OFFSET,
166 offsetof(ngx_http_fancyindex_loc_conf_t, footer),
167 NULL },
168
169 { ngx_string("fancyindex_css_href"),
170 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
171 ngx_conf_set_str_slot,
172 NGX_HTTP_LOC_CONF_OFFSET,
173 offsetof(ngx_http_fancyindex_loc_conf_t, css_href),
174 NULL },
175
176 { ngx_string("fancyindex_ignore"),
177 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
178 ngx_http_fancyindex_ignore,
179 NGX_HTTP_LOC_CONF_OFFSET,
180 0,
181 NULL },
182
183 ngx_null_command
184 };
185
186
187 static ngx_http_module_t ngx_http_fancyindex_module_ctx = {
188 NULL, /* preconfiguration */
189 ngx_http_fancyindex_init, /* postconfiguration */
190
191 NULL, /* create main configuration */
192 NULL, /* init main configuration */
193
194 NULL, /* create server configuration */
195 NULL, /* merge server configuration */
196
197 ngx_http_fancyindex_create_loc_conf, /* create location configration */
198 ngx_http_fancyindex_merge_loc_conf /* merge location configration */
199 };
200
201
202 ngx_module_t ngx_http_fancyindex_module = {
203 NGX_MODULE_V1,
204 &ngx_http_fancyindex_module_ctx, /* module context */
205 ngx_http_fancyindex_commands, /* module directives */
206 NGX_HTTP_MODULE, /* module type */
207 NULL, /* init master */
208 NULL, /* init module */
209 NULL, /* init process */
210 NULL, /* init thread */
211 NULL, /* exit thread */
212 NULL, /* exit process */
213 NULL, /* exit master */
214 NGX_MODULE_V1_PADDING
215 };
216
217
218
219 static const ngx_str_t css_href_pre =
220 ngx_string("<link rel=\"stylesheet\" href=\"");
221 static const ngx_str_t css_href_post =
222 ngx_string("\" type=\"text/css\"/>\n");
223
224
225 static uintptr_t
226 ngx_fancyindex_escape_uri(u_char *dst, u_char *src, size_t size)
227 {
228 /*
229 * The ngx_escape_uri() function will not escape colons or the
230 * ? character, which signals the beginning of the query string.
231 * So we handle those characters ourselves.
232 *
233 * TODO: Get rid of this once ngx_escape_uri() works as expected!
234 */
235
236 u_int escapes = 0;
237 u_char *psrc = src;
238 size_t psize = size;
239
240 while (psize--) {
241 switch (*psrc++) {
242 case ':':
243 case '?':
244 escapes++;
245 break;
246 }
247 }
248
249 if (dst == NULL) {
250 return escapes + ngx_escape_uri(NULL, src, size, NGX_ESCAPE_HTML);
251 }
252 else if (escapes == 0) {
253 /* No need to do extra escaping, avoid the temporary buffer */
254 return ngx_escape_uri(dst, src, size, NGX_ESCAPE_HTML);
255 }
256 else {
257 uintptr_t uescapes = ngx_escape_uri(NULL, src, size, NGX_ESCAPE_HTML);
258 size_t bufsz = size + 2 * uescapes;
259
260 /*
261 * GCC and CLANG both support stack-allocated variable length
262 * arrays. Take advantage of that to avoid a malloc-free cycle.
263 */
264 #if defined(__GNUC__) || defined(__clang__)
265 u_char cbuf[bufsz];
266 u_char *buf = cbuf;
267 #else /* __GNUC__ || __clang__ */
268 u_char *buf = (u_char*) malloc(sizeof(u_char) * bufsz);
269 #endif /* __GNUC__ || __clang__ */
270
271 ngx_escape_uri(buf, src, size, NGX_ESCAPE_HTML);
272
273 while (bufsz--) {
274 switch (*buf) {
275 case ':':
276 *dst++ = '%';
277 *dst++ = '3';
278 *dst++ = 'A';
279 break;
280 case '?':
281 *dst++ = '%';
282 *dst++ = '3';
283 *dst++ = 'F';
284 break;
285 default:
286 *dst++ = *buf;
287 }
288 buf++;
289 }
290
291 #if !defined(__GNUC__) && !defined(__clang__)
292 free(buf);
293 #endif /* !__GNUC__ && !__clang__ */
294
295 return escapes + uescapes;
296 }
297 }
298
299
300 static ngx_inline ngx_buf_t*
301 make_header_buf(ngx_http_request_t *r, const ngx_str_t css_href)
302 {
303 size_t blen = r->uri.len
304 + ngx_sizeof_ssz(t01_head1)
305 + ngx_sizeof_ssz(t02_head2)
306 + ngx_sizeof_ssz(t03_head3)
307 + ngx_sizeof_ssz(t04_body1)
308 ;
309
310 if (css_href.len) {
311 blen += css_href_pre.len \
312 + css_href.len \
313 + css_href_post.len
314 ;
315 }
316
317 ngx_buf_t *b = ngx_create_temp_buf(r->pool, blen);
318
319 if (b == NULL) goto bailout;
320
321 b->last = ngx_cpymem_ssz(b->last, t01_head1);
322
323 if (css_href.len) {
324 b->last = ngx_cpymem_str(b->last, css_href_pre);
325 b->last = ngx_cpymem_str(b->last, css_href);
326 b->last = ngx_cpymem_str(b->last, css_href_post);
327 }
328
329 b->last = ngx_cpymem_ssz(b->last, t02_head2);
330 b->last = ngx_cpymem_str(b->last, r->uri);
331 b->last = ngx_cpymem_ssz(b->last, t03_head3);
332 b->last = ngx_cpymem_ssz(b->last, t04_body1);
333
334 bailout:
335 return b;
336 }
337
338
339
340 static ngx_inline ngx_buf_t*
341 make_footer_buf(ngx_http_request_t *r)
342 {
343 /*
344 * TODO: Make this buffer static (i.e. readonly and reusable from
345 * one request to another.
346 */
347 ngx_buf_t *b = ngx_create_temp_buf(r->pool, ngx_sizeof_ssz(t08_foot1));
348
349 if (b == NULL) goto bailout;
350
351 b->last = ngx_cpymem_ssz(b->last, t08_foot1);
352
353 bailout:
354 return b;
355 }
356
357
358
359 static ngx_inline ngx_int_t
360 make_content_buf(
361 ngx_http_request_t *r, ngx_buf_t **pb,
362 ngx_http_fancyindex_loc_conf_t *alcf)
363 {
364 ngx_http_fancyindex_entry_t *entry;
365
366 off_t length;
367 size_t len, root, copy, allocated;
368 u_char *filename, *last, scale;
369 ngx_tm_t tm;
370 ngx_array_t entries;
371 ngx_time_t *tp;
372 ngx_uint_t i;
373 ngx_int_t size;
374 ngx_str_t path;
375 ngx_dir_t dir;
376 ngx_buf_t *b;
377
378 static char *months[] = {
379 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
380 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
381 };
382
383 /*
384 * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE
385 */
386 if ((last = ngx_http_map_uri_to_path(r, &path, &root,
387 NGX_HTTP_FANCYINDEX_PREALLOCATE)) == NULL)
388 return NGX_HTTP_INTERNAL_SERVER_ERROR;
389
390 allocated = path.len;
391 path.len = last - path.data - 1;
392 path.data[path.len] = '\0';
393
394 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
395 "http fancyindex: \"%s\"", path.data);
396
397 if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
398 ngx_int_t rc, err = ngx_errno;
399 ngx_uint_t level;
400
401 if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) {
402 level = NGX_LOG_ERR;
403 rc = NGX_HTTP_NOT_FOUND;
404 } else if (err == NGX_EACCES) {
405 level = NGX_LOG_ERR;
406 rc = NGX_HTTP_FORBIDDEN;
407 } else {
408 level = NGX_LOG_CRIT;
409 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
410 }
411
412 ngx_log_error(level, r->connection->log, err,
413 ngx_open_dir_n " \"%s\" failed", path.data);
414
415 return rc;
416 }
417
418 #if (NGX_SUPPRESS_WARN)
419 /* MSVC thinks 'entries' may be used without having been initialized */
420 ngx_memzero(&entries, sizeof(ngx_array_t));
421 #endif /* NGX_SUPPRESS_WARN */
422
423
424 if (ngx_array_init(&entries, r->pool, 40,
425 sizeof(ngx_http_fancyindex_entry_t)) != NGX_OK)
426 return ngx_http_fancyindex_error(r, &dir, &path);
427
428 filename = path.data;
429 filename[path.len] = '/';
430
431 /* Read directory entries and their associated information. */
432 for (;;) {
433 ngx_set_errno(0);
434
435 if (ngx_read_dir(&dir) == NGX_ERROR) {
436 ngx_int_t err = ngx_errno;
437
438 if (err != NGX_ENOMOREFILES) {
439 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
440 ngx_read_dir_n " \"%V\" failed", &path);
441 return ngx_http_fancyindex_error(r, &dir, &path);
442 }
443 break;
444 }
445
446 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
447 "http fancyindex file: \"%s\"", ngx_de_name(&dir));
448
449 len = ngx_de_namelen(&dir);
450
451 if (ngx_de_name(&dir)[0] == '.')
452 continue;
453
454 #if NGX_PCRE
455 {
456 ngx_str_t str = { len, ngx_de_name(&dir) };
457
458 if (alcf->ignore && ngx_regex_exec_array(alcf->ignore, &str,
459 r->connection->log)
460 != NGX_DECLINED)
461 {
462 continue;
463 }
464 }
465 #else /* !NGX_PCRE */
466 if (alcf->ignore) {
467 u_int match_found = 0;
468 ngx_str_t *s = alcf->ignore->elts;
469
470 for (i = 0; i < alcf->ignore->nelts; i++, s++) {
471 if (ngx_strcmp(ngx_de_name(&dir), s->data) == 0) {
472 match_found = 1;
473 break;
474 }
475 }
476
477 if (match_found) {
478 continue;
479 }
480 }
481 #endif /* NGX_PCRE */
482
483 if (!dir.valid_info) {
484 /* 1 byte for '/' and 1 byte for terminating '\0' */
485 if (path.len + 1 + len + 1 > allocated) {
486 allocated = path.len + 1 + len + 1
487 + NGX_HTTP_FANCYINDEX_PREALLOCATE;
488
489 if ((filename = ngx_palloc(r->pool, allocated)) == NULL)
490 return ngx_http_fancyindex_error(r, &dir, &path);
491
492 last = ngx_cpystrn(filename, path.data, path.len + 1);
493 *last++ = '/';
494 }
495
496 ngx_cpystrn(last, ngx_de_name(&dir), len + 1);
497
498 if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
499 ngx_int_t err = ngx_errno;
500
501 if (err != NGX_ENOENT) {
502 ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
503 ngx_de_info_n " \"%s\" failed", filename);
504 continue;
505 }
506
507 if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) {
508 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
509 ngx_de_link_info_n " \"%s\" failed", filename);
510 return ngx_http_fancyindex_error(r, &dir, &path);
511 }
512 }
513 }
514
515 if ((entry = ngx_array_push(&entries)) == NULL)
516 return ngx_http_fancyindex_error(r, &dir, &path);
517
518 entry->name.len = len;
519 entry->name.data = ngx_palloc(r->pool, len + 1);
520 if (entry->name.data == NULL)
521 return ngx_http_fancyindex_error(r, &dir, &path);
522
523 ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1);
524 entry->escape = 2 * ngx_fancyindex_escape_uri(NULL,
525 ngx_de_name(&dir),
526 len);
527
528 entry->dir = ngx_de_is_dir(&dir);
529 entry->mtime = ngx_de_mtime(&dir);
530 entry->size = ngx_de_size(&dir);
531 entry->utf_len = (r->headers_out.charset.len == 5 &&
532 ngx_strncasecmp(r->headers_out.charset.data, (u_char*) "utf-8", 5) == 0)
533 ? ngx_utf8_length(entry->name.data, entry->name.len)
534 : len;
535 }
536
537 if (ngx_close_dir(&dir) == NGX_ERROR) {
538 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
539 ngx_close_dir_n " \"%s\" failed", &path);
540 }
541
542 /*
543 * Calculate needed buffer length.
544 */
545 len = r->uri.len
546 + ngx_sizeof_ssz(t05_body2)
547 + ngx_sizeof_ssz(t06_list1)
548 + ngx_sizeof_ssz(t07_list2)
549 ;
550
551 entry = entries.elts;
552 for (i = 0; i < entries.nelts; i++) {
553 /*
554 * Genearated table rows are as follows, unneeded whitespace
555 * is stripped out:
556 *
557 * <tr class="X">
558 * <td><a href="U">fname</a></td>
559 * <td>size</td><td>date</td>
560 * </tr>
561 */
562 len += ngx_sizeof_ssz("<tr class=\"X\"><td><a href=\"")
563 + entry[i].name.len + entry[i].escape /* Escaped URL */
564 + ngx_sizeof_ssz("\">")
565 + entry[i].name.len + entry[i].utf_len
566 + NGX_HTTP_FANCYINDEX_NAME_LEN + ngx_sizeof_ssz("&gt;")
567 + ngx_sizeof_ssz("</a></td><td>")
568 + 20 /* File size */
569 + ngx_sizeof_ssz("</td><td>")
570 + ngx_sizeof_ssz(" 28-Sep-1970 12:00 ")
571 + ngx_sizeof_ssz("</td></tr>\n")
572 + 2 /* CR LF */
573 ;
574 }
575
576 if ((b = ngx_create_temp_buf(r->pool, len)) == NULL)
577 return NGX_HTTP_INTERNAL_SERVER_ERROR;
578
579 /* Sort entries, if needed */
580 if (entries.nelts > 1) {
581 ngx_qsort(entry, (size_t) entries.nelts,
582 sizeof(ngx_http_fancyindex_entry_t),
583 ngx_http_fancyindex_cmp_entries);
584 }
585
586 b->last = ngx_cpymem_str(b->last, r->uri);
587 b->last = ngx_cpymem_ssz(b->last, t05_body2);
588 b->last = ngx_cpymem_ssz(b->last, t06_list1);
589
590 tp = ngx_timeofday();
591
592 for (i = 0; i < entries.nelts; i++) {
593 static const char _evenodd[] = { 'e', 'o' };
594 b->last = ngx_cpymem_ssz(b->last, "<tr class=\"");
595 *b->last++ = _evenodd[i & 0x01];
596 /*
597 * Alternative implementation:
598 * *b->last++ = (i & 0x01) ? 'e' : 'o';
599 */
600 b->last = ngx_cpymem_ssz(b->last, "\"><td><a href=\"");
601
602 if (entry[i].escape) {
603 ngx_fancyindex_escape_uri(b->last,
604 entry[i].name.data,
605 entry[i].name.len);
606
607 b->last += entry[i].name.len + entry[i].escape;
608
609 } else {
610 b->last = ngx_cpymem_str(b->last, entry[i].name);
611 }
612
613 if (entry[i].dir) {
614 *b->last++ = '/';
615 }
616
617 *b->last++ = '"';
618 *b->last++ = '>';
619
620 len = entry[i].utf_len;
621
622 if (entry[i].name.len - len) {
623 if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) {
624 copy = NGX_HTTP_FANCYINDEX_NAME_LEN - 3 + 1;
625 } else {
626 copy = NGX_HTTP_FANCYINDEX_NAME_LEN + 1;
627 }
628
629 b->last = ngx_utf8_cpystrn(b->last, entry[i].name.data,
630 copy, entry[i].name.len);
631 last = b->last;
632
633 } else {
634 b->last = ngx_cpystrn(b->last, entry[i].name.data,
635 NGX_HTTP_FANCYINDEX_NAME_LEN + 1);
636 last = b->last - 3;
637 }
638
639 if (len > NGX_HTTP_FANCYINDEX_NAME_LEN) {
640 b->last = ngx_cpymem_ssz(last, "..&gt;</a></td><td>");
641
642 } else {
643 if (entry[i].dir && NGX_HTTP_FANCYINDEX_NAME_LEN - len > 0) {
644 *b->last++ = '/';
645 len++;
646 }
647
648 b->last = ngx_cpymem_ssz(b->last, "</a></td><td>");
649 }
650
651 if (alcf->exact_size) {
652 if (entry[i].dir) {
653 *b->last++ = '-';
654 } else {
655 b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
656 }
657
658 } else {
659 if (entry[i].dir) {
660 *b->last++ = '-';
661 } else {
662 length = entry[i].size;
663
664 if (length > 1024 * 1024 * 1024 - 1) {
665 size = (ngx_int_t) (length / (1024 * 1024 * 1024));
666 if ((length % (1024 * 1024 * 1024))
667 > (1024 * 1024 * 1024 / 2 - 1))
668 {
669 size++;
670 }
671 scale = 'G';
672
673 } else if (length > 1024 * 1024 - 1) {
674 size = (ngx_int_t) (length / (1024 * 1024));
675 if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) {
676 size++;
677 }
678 scale = 'M';
679
680 } else if (length > 9999) {
681 size = (ngx_int_t) (length / 1024);
682 if (length % 1024 > 511) {
683 size++;
684 }
685 scale = 'K';
686
687 } else {
688 size = (ngx_int_t) length;
689 scale = '\0';
690 }
691
692 if (scale) {
693 b->last = ngx_sprintf(b->last, "%6i%c", size, scale);
694
695 } else {
696 b->last = ngx_sprintf(b->last, " %6i", size);
697 }
698 }
699 }
700
701 ngx_gmtime(entry[i].mtime + tp->gmtoff * 60 * alcf->localtime, &tm);
702
703 b->last = ngx_sprintf(b->last, "</td><td>%02d-%s-%d %02d:%02d</td></tr>",
704 tm.ngx_tm_mday,
705 months[tm.ngx_tm_mon - 1],
706 tm.ngx_tm_year,
707 tm.ngx_tm_hour,
708 tm.ngx_tm_min);
709
710
711 *b->last++ = CR;
712 *b->last++ = LF;
713 }
714
715 /* Output table bottom */
716 b->last = ngx_cpymem_ssz(b->last, t07_list2);
717
718 *pb = b;
719 return NGX_OK;
720 }
721
722
723
724 static ngx_int_t
725 ngx_http_fancyindex_handler(ngx_http_request_t *r)
726 {
727 ngx_http_request_t *sr;
728 ngx_str_t *sr_uri;
729 ngx_str_t rel_uri;
730 ngx_int_t rc;
731 ngx_http_fancyindex_loc_conf_t *alcf;
732 ngx_chain_t out[3] = {
733 { NULL, NULL }, { NULL, NULL}, { NULL, NULL }};
734
735
736 if (r->uri.data[r->uri.len - 1] != '/') {
737 return NGX_DECLINED;
738 }
739
740 /* TODO: Win32 */
741 #if defined(nginx_version) \
742 && ((nginx_version < 7066) \
743 || ((nginx_version > 8000) && (nginx_version < 8038)))
744 if (r->zero_in_uri) {
745 return NGX_DECLINED;
746 }
747 #endif
748
749 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
750 return NGX_DECLINED;
751 }
752
753 alcf = ngx_http_get_module_loc_conf(r, ngx_http_fancyindex_module);
754
755 if (!alcf->enable) {
756 return NGX_DECLINED;
757 }
758
759 if ((rc = make_content_buf(r, &out[0].buf, alcf) != NGX_OK))
760 return rc;
761
762 out[0].buf->last_in_chain = 1;
763
764 r->headers_out.status = NGX_HTTP_OK;
765 r->headers_out.content_type_len = ngx_sizeof_ssz("text/html");
766 r->headers_out.content_type.len = ngx_sizeof_ssz("text/html");
767 r->headers_out.content_type.data = (u_char *) "text/html";
768
769 rc = ngx_http_send_header(r);
770
771 if (rc != NGX_OK || r->header_only)
772 return rc;
773
774 if (alcf->header.len > 0) {
775 /* URI is configured, make Nginx take care of with a subrequest. */
776 sr_uri = &alcf->header;
777
778 if (*sr_uri->data != '/') {
779 /* Relative path */
780 rel_uri.len = r->uri.len + alcf->header.len;
781 rel_uri.data = ngx_palloc(r->pool, rel_uri.len);
782 if (rel_uri.data == NULL) {
783 return NGX_HTTP_INTERNAL_SERVER_ERROR;
784 }
785 ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len),
786 alcf->header.data, alcf->header.len);
787 sr_uri = &rel_uri;
788 }
789
790 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
791 "http fancyindex: header subrequest \"%V\"", sr_uri);
792
793 rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0);
794 if (rc == NGX_ERROR || rc == NGX_DONE) {
795 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
796 "http fancyindex: header subrequest for \"%V\" failed", sr_uri);
797 return rc;
798 }
799
800 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
801 "http fancyindex: header subrequest status = %i",
802 sr->headers_out.status);
803 /* ngx_http_subrequest returns NGX_OK(0), not NGX_HTTP_OK(200) */
804 if (sr->headers_out.status != NGX_OK) {
805 /*
806 * XXX: Should we write a message to the error log just in case
807 * we get something different from a 404?
808 */
809 goto add_builtin_header;
810 }
811 }
812 else {
813 add_builtin_header:
814 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
815 "http fancyindex: adding built-in header");
816 /* Make space before */
817 out[1].next = out[0].next;
818 out[1].buf = out[0].buf;
819 /* Chain header buffer */
820 out[0].next = &out[1];
821 out[0].buf = make_header_buf(r, alcf->css_href);
822 }
823
824 /* If footer is disabled, chain up footer buffer. */
825 if (alcf->footer.len == 0) {
826 ngx_uint_t last = (alcf->header.len == 0) ? 2 : 1;
827
828 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
829 "http fancyindex: adding built-in footer at %i", last);
830
831 out[last-1].next = &out[last];
832 out[last].buf = make_footer_buf(r);
833
834 out[last-1].buf->last_in_chain = 0;
835 out[last].buf->last_in_chain = 1;
836 out[last].buf->last_buf = 1;
837 /* Send everything with a single call :D */
838 return ngx_http_output_filter(r, &out[0]);
839 }
840
841 /*
842 * If we reach here, we were asked to send a custom footer. We need to:
843 * partially send whatever is referenced from out[0] and then send the
844 * footer as a subrequest. If the subrequest fails, we should send the
845 * standard footer as well.
846 */
847 rc = ngx_http_output_filter(r, &out[0]);
848
849 if (rc != NGX_OK && rc != NGX_AGAIN)
850 return NGX_HTTP_INTERNAL_SERVER_ERROR;
851
852 /* URI is configured, make Nginx take care of with a subrequest. */
853 sr_uri = &alcf->footer;
854
855 if (*sr_uri->data != '/') {
856 /* Relative path */
857 rel_uri.len = r->uri.len + alcf->footer.len;
858 rel_uri.data = ngx_palloc(r->pool, rel_uri.len);
859 if (rel_uri.data == NULL) {
860 return NGX_HTTP_INTERNAL_SERVER_ERROR;
861 }
862 ngx_memcpy(ngx_cpymem(rel_uri.data, r->uri.data, r->uri.len),
863 alcf->footer.data, alcf->footer.len);
864 sr_uri = &rel_uri;
865 }
866
867 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
868 "http fancyindex: footer subrequest \"%V\"", sr_uri);
869
870 rc = ngx_http_subrequest(r, sr_uri, NULL, &sr, NULL, 0);
871 if (rc == NGX_ERROR || rc == NGX_DONE) {
872 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
873 "http fancyindex: footer subrequest for \"%V\" failed", sr_uri);
874 return rc;
875 }
876
877 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
878 "http fancyindex: header subrequest status = %i",
879 sr->headers_out.status);
880
881 /* see above: ngx_http_subrequest resturns NGX_OK (0) not NGX_HTTP_OK (200) */
882 if (sr->headers_out.status != NGX_OK) {
883 /*
884 * XXX: Should we write a message to the error log just in case
885 * we get something different from a 404?
886 */
887 out[0].next = NULL;
888 out[0].buf = make_footer_buf(r);
889 out[0].buf->last_in_chain = 1;
890 out[0].buf->last_buf = 1;
891 /* Directly send out the builtin footer */
892 return ngx_http_output_filter(r, &out[0]);
893 }
894
895 return (r != r->main) ? rc : ngx_http_send_special(r, NGX_HTTP_LAST);
896 }
897
898
899 static int ngx_libc_cdecl
900 ngx_http_fancyindex_cmp_entries(const void *one, const void *two)
901 {
902 ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one;
903 ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two;
904
905 if (first->dir && !second->dir) {
906 /* move the directories to the start */
907 return -1;
908 }
909
910 if (!first->dir && second->dir) {
911 /* move the directories to the start */
912 return 1;
913 }
914
915 return (int) ngx_strcmp(first->name.data, second->name.data);
916 }
917
918
919
920
921 static ngx_int_t
922 ngx_http_fancyindex_error(ngx_http_request_t *r, ngx_dir_t *dir, ngx_str_t *name)
923 {
924 if (ngx_close_dir(dir) == NGX_ERROR) {
925 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
926 ngx_close_dir_n " \"%V\" failed", name);
927 }
928
929 return NGX_HTTP_INTERNAL_SERVER_ERROR;
930 }
931
932
933 static void *
934 ngx_http_fancyindex_create_loc_conf(ngx_conf_t *cf)
935 {
936 ngx_http_fancyindex_loc_conf_t *conf;
937
938 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fancyindex_loc_conf_t));
939 if (conf == NULL) {
940 return NGX_CONF_ERROR;
941 }
942
943 /*
944 * Set by ngx_pcalloc:
945 * conf->header.len = 0
946 * conf->header.data = NULL
947 * conf->footer.len = 0
948 * conf->footer.data = NULL
949 */
950 conf->enable = NGX_CONF_UNSET;
951 conf->localtime = NGX_CONF_UNSET;
952 conf->exact_size = NGX_CONF_UNSET;
953 conf->ignore = NGX_CONF_UNSET_PTR;
954
955 return conf;
956 }
957
958
959 static char *
960 ngx_http_fancyindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
961 {
962 ngx_http_fancyindex_loc_conf_t *prev = parent;
963 ngx_http_fancyindex_loc_conf_t *conf = child;
964
965 ngx_conf_merge_value(conf->enable, prev->enable, 0);
966 ngx_conf_merge_value(conf->localtime, prev->localtime, 0);
967 ngx_conf_merge_value(conf->exact_size, prev->exact_size, 1);
968
969 ngx_conf_merge_str_value(conf->header, prev->header, "");
970 ngx_conf_merge_str_value(conf->footer, prev->footer, "");
971
972 ngx_conf_merge_ptr_value(conf->ignore, prev->ignore, NULL);
973
974 return NGX_CONF_OK;
975 }
976
977
978 static char*
979 ngx_http_fancyindex_ignore(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
980 {
981 ngx_http_fancyindex_loc_conf_t *alcf = conf;
982 ngx_str_t *value;
983
984 #if (NGX_PCRE)
985 ngx_uint_t i;
986 ngx_regex_elt_t *re;
987 ngx_regex_compile_t rc;
988 u_char errstr[NGX_MAX_CONF_ERRSTR];
989
990 if (alcf->ignore == NGX_CONF_UNSET_PTR) {
991 alcf->ignore = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t));
992 if (alcf->ignore == NULL) {
993 return NGX_CONF_ERROR;
994 }
995 }
996
997 value = cf->args->elts;
998
999 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
1000
1001 rc.err.data = errstr;
1002 rc.err.len = NGX_MAX_CONF_ERRSTR;
1003 rc.pool = cf->pool;
1004
1005 for (i = 1; i < cf->args->nelts; i++) {
1006 re = ngx_array_push(alcf->ignore);
1007 if (re == NULL) {
1008 return NGX_CONF_ERROR;
1009 }
1010
1011 rc.pattern = value[i];
1012 rc.options = NGX_REGEX_CASELESS;
1013
1014 if (ngx_regex_compile(&rc) != NGX_OK) {
1015 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
1016 return NGX_CONF_ERROR;
1017 }
1018
1019 re->name = value[i].data;
1020 re->regex = rc.regex;
1021 }
1022
1023 return NGX_CONF_OK;
1024 #else /* !NGX_PCRE */
1025 ngx_uint_t i;
1026 ngx_str_t *str;
1027
1028 if (alcf->ignore == NGX_CONF_UNSET_PTR) {
1029 alcf->ignore = ngx_array_create(cf->pool, 2, sizeof(ngx_str_t));
1030 if (alcf->ignore == NULL) {
1031 return NGX_CONF_ERROR;
1032 }
1033 }
1034
1035 value = cf->args->elts;
1036
1037 for (i = 1; i < cf->args->nelts; i++) {
1038 str = ngx_array_push(alcf->ignore);
1039 if (str == NULL) {
1040 return NGX_CONF_ERROR;
1041 }
1042
1043 str->data = value[i].data;
1044 str->len = value[i].len;
1045 }
1046
1047 return NGX_CONF_OK;
1048 #endif /* NGX_PCRE */
1049
1050 }
1051
1052
1053 static ngx_int_t
1054 ngx_http_fancyindex_init(ngx_conf_t *cf)
1055 {
1056 ngx_http_handler_pt *h;
1057 ngx_http_core_main_conf_t *cmcf;
1058
1059 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1060
1061 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
1062 if (h == NULL) {
1063 return NGX_ERROR;
1064 }
1065
1066 *h = ngx_http_fancyindex_handler;
1067
1068 return NGX_OK;
1069 }
1070
1071 /* vim:et:sw=4:ts=4:
1072 */
0 #! /usr/bin/awk -f
1 #
2 # Copyright © Adrian Perez <aperez@igalia.com>
3 #
4 # Converts an HTML template into a C header suitable for inclusion.
5 # Take a look at the HACKING.rst file to know how to use it :-)
6 #
7 # This code is placed in the public domain.
8
9 BEGIN {
10 varname = 0;
11 print "/* Automagically generated, do not edit! */"
12 vars_count = 0;
13 }
14
15 /^<!--[[:space:]]*var[[:space:]]+[^[:space:]]+[[:space:]]*-->$/ {
16 if (varname) print ";";
17 if ($3 == "NONE") {
18 varname = 0;
19 next;
20 }
21 varname = $3;
22 vars[vars_count++] = varname;
23 print "static const u_char " varname "[] = \"\"";
24 next;
25 }
26
27 /^$/ {
28 if (!varname) next;
29 print "\"\\n\"";
30 next;
31 }
32
33 {
34 if (!varname) next;
35 # Order matters
36 gsub(/[\t\v\n\r\f]+/, "");
37 gsub(/\\/, "\\\\");
38 gsub(/"/, "\\\"");
39 print "\"" $0 "\""
40 }
41
42
43 END {
44 if (varname) print ";";
45 print "#define NFI_TEMPLATE_SIZE (0 \\";
46 for (var in vars) {
47 print "\t+ nfi_sizeof_ssz(" vars[var] ") \\";
48 }
49 print "\t)"
50 }
51
0 /* Automagically generated, do not edit! */
1 static const u_char t01_head1[] = ""
2 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
3 "\n"
4 "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
5 "\n"
6 "<head>"
7 "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\"/>"
8 "<style type=\"text/css\">"
9 "body,html {"
10 "background:#fff;"
11 "font-family:\"Bitstream Vera Sans\",\"Lucida Grande\","
12 "\"Lucida Sans Unicode\",Lucidux,Verdana,Lucida,sans-serif;"
13 "}"
14 "tr.e {"
15 "background:#f4f4f4;"
16 "}"
17 "th,td {"
18 "padding:0.1em 0.5em;"
19 "}"
20 "th {"
21 "text-align:left;"
22 "font-weight:bold;"
23 "background:#eee;"
24 "border-bottom:1px solid #aaa;"
25 "}"
26 "#list {"
27 "border:1px solid #aaa;"
28 "width:100%;"
29 "}"
30 "a {"
31 "color:#a33;"
32 "}"
33 "a:hover {"
34 "color:#e33;"
35 "}"
36 "</style>"
37 "\n"
38 ;
39 static const u_char t02_head2[] = ""
40 "\n"
41 "<title>Index of "
42 ;
43 static const u_char t03_head3[] = ""
44 "</title>"
45 "\n"
46 "</head>"
47 ;
48 static const u_char t04_body1[] = ""
49 "<body>"
50 "<h1>Index of "
51 ;
52 static const u_char t05_body2[] = ""
53 "</h1>"
54 "\n"
55 ;
56 static const u_char t06_list1[] = ""
57 "<table id=\"list\" cellpadding=\"0.1em\" cellspacing=\"0\">"
58 "\n"
59 "<colgroup>"
60 "<col width=\"55%\"/>"
61 "<col width=\"20%\"/>"
62 "<col width=\"25%\"/>"
63 "</colgroup>"
64 "\n"
65 "<thead>"
66 "<tr>"
67 "<th>File Name</th>"
68 "<th>File Size</th>"
69 "<th>Date</th>"
70 "</tr>"
71 "</thead>"
72 "\n"
73 "<tbody>"
74 "<tr class=\"o\">"
75 "<td><a href=\"../\">Parent directory/</a></td>"
76 "<td>-</td>"
77 "<td>-</td>"
78 "</tr>"
79 ;
80 static const u_char t07_list2[] = ""
81 "</tbody>"
82 "</table>"
83 ;
84 static const u_char t08_foot1[] = ""
85 "</body>"
86 "</html>"
87 ;
88 #define NFI_TEMPLATE_SIZE (0 \
89 + nfi_sizeof_ssz(t05_body2) \
90 + nfi_sizeof_ssz(t06_list1) \
91 + nfi_sizeof_ssz(t07_list2) \
92 + nfi_sizeof_ssz(t08_foot1) \
93 + nfi_sizeof_ssz(t01_head1) \
94 + nfi_sizeof_ssz(t02_head2) \
95 + nfi_sizeof_ssz(t03_head3) \
96 + nfi_sizeof_ssz(t04_body1) \
97 )
0 <!-- var t01_head1 -->
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
3 <html xmlns="http://www.w3.org/1999/xhtml">
4
5 <head>
6 <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
7 <style type="text/css">
8 body,html {
9 background:#fff;
10 font-family:"Bitstream Vera Sans","Lucida Grande",
11 "Lucida Sans Unicode",Lucidux,Verdana,Lucida,sans-serif;
12 }
13 tr.e {
14 background:#f4f4f4;
15 }
16 th,td {
17 padding:0.1em 0.5em;
18 }
19 th {
20 text-align:left;
21 font-weight:bold;
22 background:#eee;
23 border-bottom:1px solid #aaa;
24 }
25 #list {
26 border:1px solid #aaa;
27 width:100%;
28 }
29 a {
30 color:#a33;
31 }
32 a:hover {
33 color:#e33;
34 }
35 </style>
36
37 <!-- var t02_head2 -->
38
39 <title>Index of
40 <!-- var NONE -->
41 /path/to/somewhere
42 <!-- var t03_head3 -->
43 </title>
44
45 </head>
46 <!-- var t04_body1 -->
47 <body>
48 <h1>Index of
49 <!-- var NONE -->
50 /path/to/somewhere
51 <!-- var t05_body2 -->
52 </h1>
53
54 <!-- var t06_list1 -->
55 <table id="list" cellpadding="0.1em" cellspacing="0">
56
57 <colgroup>
58 <col width="55%"/>
59 <col width="20%"/>
60 <col width="25%"/>
61 </colgroup>
62
63 <thead>
64 <tr>
65 <th>File Name</th>
66 <th>File Size</th>
67 <th>Date</th>
68 </tr>
69 </thead>
70
71 <tbody>
72 <tr class="o">
73 <td><a href="../">Parent directory/</a></td>
74 <td>-</td>
75 <td>-</td>
76 </tr>
77 <!-- var NONE -->
78 <tr class="e">
79 <td>test file 1</td>
80 <td>123kB</td>
81 <td>date</td>
82 </tr>
83 <tr class="o">
84 <td>test file 2</td>
85 <td>321MB</td>
86 <td>date</td>
87 </tr>
88 <tr class="e">
89 <td>test file 3</td>
90 <td>666</td>
91 <td>date</td>
92 </tr>
93 <!-- var t07_list2 -->
94 </tbody>
95 </table>
96 <!-- var t08_foot1 -->
97 </body>
98 </html>
159159 --add-module=$(MODULESDIR)/nginx-dav-ext-module \
160160 --add-module=$(MODULESDIR)/nginx-development-kit \
161161 --add-module=$(MODULESDIR)/nginx-echo \
162 --add-module=$(MODULESDIR)/ngx-fancyindex \
162163 --add-module=$(MODULESDIR)/nginx-http-push \
163164 --add-module=$(MODULESDIR)/nginx-lua \
164165 --add-module=$(MODULESDIR)/nginx-upload-progress \