Mercurial > hg > nginx
annotate src/http/modules/ngx_http_dav_module.c @ 921:cba27113c33c
DELETE may not have the "Depth" header
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Thu, 14 Dec 2006 22:12:42 +0000 |
parents | da097813ff2e |
children | 7ea5db4c06cb |
rev | line source |
---|---|
633 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 #define NGX_HTTP_DAV_OFF 2 | |
13 | |
14 typedef struct { | |
15 ngx_uint_t methods; | |
637 | 16 ngx_flag_t create_full_put_path; |
669 | 17 ngx_uint_t access; |
633 | 18 } ngx_http_dav_loc_conf_t; |
19 | |
20 | |
21 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); | |
22 static void ngx_http_dav_put_handler(ngx_http_request_t *r); | |
637 | 23 static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err, |
24 ngx_int_t not_found, char *failed, u_char *path); | |
25 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); | |
669 | 26 static char *ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, |
27 void *conf); | |
633 | 28 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); |
29 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, | |
30 void *parent, void *child); | |
681 | 31 static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf); |
633 | 32 |
33 | |
34 static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = { | |
35 { ngx_string("off"), NGX_HTTP_DAV_OFF }, | |
36 { ngx_string("put"), NGX_HTTP_PUT }, | |
37 { ngx_string("delete"), NGX_HTTP_DELETE }, | |
637 | 38 { ngx_string("mkcol"), NGX_HTTP_MKCOL }, |
633 | 39 { ngx_null_string, 0 } |
40 }; | |
41 | |
42 | |
43 static ngx_command_t ngx_http_dav_commands[] = { | |
44 | |
45 { ngx_string("dav_methods"), | |
46 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
47 ngx_conf_set_bitmask_slot, | |
48 NGX_HTTP_LOC_CONF_OFFSET, | |
49 offsetof(ngx_http_dav_loc_conf_t, methods), | |
50 &ngx_http_dav_methods_mask }, | |
51 | |
637 | 52 { ngx_string("create_full_put_path"), |
53 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
54 ngx_conf_set_flag_slot, | |
55 NGX_HTTP_LOC_CONF_OFFSET, | |
56 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), | |
57 NULL }, | |
58 | |
669 | 59 { ngx_string("dav_access"), |
675 | 60 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, |
669 | 61 ngx_http_dav_access, |
62 NGX_HTTP_LOC_CONF_OFFSET, | |
63 0, | |
64 NULL }, | |
65 | |
633 | 66 ngx_null_command |
67 }; | |
68 | |
69 | |
667 | 70 static ngx_http_module_t ngx_http_dav_module_ctx = { |
633 | 71 NULL, /* preconfiguration */ |
681 | 72 ngx_http_dav_init, /* postconfiguration */ |
633 | 73 |
74 NULL, /* create main configuration */ | |
75 NULL, /* init main configuration */ | |
76 | |
77 NULL, /* create server configuration */ | |
78 NULL, /* merge server configuration */ | |
79 | |
80 ngx_http_dav_create_loc_conf, /* create location configuration */ | |
81 ngx_http_dav_merge_loc_conf /* merge location configuration */ | |
82 }; | |
83 | |
84 | |
85 ngx_module_t ngx_http_dav_module = { | |
86 NGX_MODULE_V1, | |
87 &ngx_http_dav_module_ctx, /* module context */ | |
88 ngx_http_dav_commands, /* module directives */ | |
89 NGX_HTTP_MODULE, /* module type */ | |
90 NULL, /* init master */ | |
681 | 91 NULL, /* init module */ |
633 | 92 NULL, /* init process */ |
93 NULL, /* init thread */ | |
94 NULL, /* exit thread */ | |
95 NULL, /* exit process */ | |
96 NULL, /* exit master */ | |
97 NGX_MODULE_V1_PADDING | |
98 }; | |
99 | |
100 | |
101 static ngx_int_t | |
102 ngx_http_dav_handler(ngx_http_request_t *r) | |
103 { | |
637 | 104 char *failed; |
773 | 105 size_t root; |
633 | 106 ngx_int_t rc; |
107 ngx_str_t path; | |
637 | 108 ngx_file_info_t fi; |
921
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
109 ngx_table_elt_t *depth; |
633 | 110 ngx_http_dav_loc_conf_t *dlcf; |
111 | |
112 /* TODO: Win32 */ | |
113 if (r->zero_in_uri) { | |
114 return NGX_DECLINED; | |
115 } | |
116 | |
117 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); | |
118 | |
119 if (!(r->method & dlcf->methods)) { | |
120 return NGX_DECLINED; | |
121 } | |
122 | |
123 switch (r->method) { | |
124 | |
125 case NGX_HTTP_PUT: | |
126 | |
127 if (r->uri.data[r->uri.len - 1] == '/') { | |
128 return NGX_DECLINED; | |
129 } | |
130 | |
131 r->request_body_in_file_only = 1; | |
132 r->request_body_in_persistent_file = 1; | |
133 r->request_body_delete_incomplete_file = 1; | |
134 r->request_body_file_group_access = 1; | |
637 | 135 r->request_body_file_log_level = 0; |
633 | 136 |
137 rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler); | |
138 | |
139 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | |
140 return rc; | |
141 } | |
142 | |
143 return NGX_DONE; | |
144 | |
145 case NGX_HTTP_DELETE: | |
146 | |
637 | 147 if (r->headers_in.content_length_n > 0) { |
148 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; | |
149 } | |
150 | |
151 rc = ngx_http_discard_body(r); | |
152 | |
153 if (rc != NGX_OK && rc != NGX_AGAIN) { | |
154 return rc; | |
633 | 155 } |
156 | |
773 | 157 ngx_http_map_uri_to_path(r, &path, &root, 0); |
633 | 158 |
159 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
160 "http delete filename: \"%s\"", path.data); | |
161 | |
637 | 162 if (ngx_file_info(path.data, &fi) != -1) { |
163 | |
164 if (ngx_is_dir(&fi)) { | |
165 | |
921
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
166 if (r->uri.data[r->uri.len - 1] != '/') { |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
167 return NGX_HTTP_BAD_REQUEST; |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
168 } |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
169 |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
170 depth = r->headers_in.depth; |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
171 |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
172 if (depth |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
173 && (depth->value.len != sizeof("infinity") - 1 |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
174 || ngx_strcmp(depth->value.data, "infinity") != 0)) |
637 | 175 { |
176 return NGX_HTTP_BAD_REQUEST; | |
177 } | |
178 | |
179 if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) { | |
180 return NGX_HTTP_NO_CONTENT; | |
181 } | |
182 | |
183 failed = ngx_delete_dir_n; | |
184 | |
185 } else { | |
633 | 186 |
637 | 187 if (r->uri.data[r->uri.len - 1] == '/') { |
188 return NGX_HTTP_BAD_REQUEST; | |
189 } | |
190 | |
921
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
191 depth = r->headers_in.depth; |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
192 |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
193 if (depth |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
194 && depth->value.len == 1 |
cba27113c33c
DELETE may not have the "Depth" header
Igor Sysoev <igor@sysoev.ru>
parents:
920
diff
changeset
|
195 && depth->value.data[0] == '1') |
637 | 196 { |
197 return NGX_HTTP_BAD_REQUEST; | |
198 } | |
199 | |
200 if (ngx_delete_file(path.data) != NGX_FILE_ERROR) { | |
201 return NGX_HTTP_NO_CONTENT; | |
202 } | |
203 | |
204 failed = ngx_delete_file_n; | |
205 } | |
206 | |
207 } else { | |
208 failed = ngx_file_info_n; | |
633 | 209 } |
210 | |
637 | 211 return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_NOT_FOUND, failed, |
212 path.data); | |
213 | |
214 case NGX_HTTP_MKCOL: | |
215 | |
216 if (r->uri.data[r->uri.len - 1] != '/') { | |
217 return NGX_DECLINED; | |
218 } | |
219 | |
220 if (r->headers_in.content_length_n > 0) { | |
221 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; | |
222 } | |
223 | |
224 rc = ngx_http_discard_body(r); | |
225 | |
226 if (rc != NGX_OK && rc != NGX_AGAIN) { | |
227 return rc; | |
228 } | |
229 | |
773 | 230 ngx_http_map_uri_to_path(r, &path, &root, 0); |
637 | 231 |
232 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
233 "http mkcol path: \"%s\"", path.data); | |
234 | |
669 | 235 if (ngx_create_dir(path.data, dlcf->access) != NGX_FILE_ERROR) { |
637 | 236 if (ngx_http_dav_location(r, path.data) != NGX_OK) { |
237 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
238 } | |
239 | |
240 return NGX_HTTP_CREATED; | |
241 } | |
242 | |
243 return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_CONFLICT, | |
244 ngx_create_dir_n, path.data); | |
633 | 245 } |
246 | |
247 return NGX_DECLINED; | |
248 } | |
249 | |
250 | |
251 static void | |
252 ngx_http_dav_put_handler(ngx_http_request_t *r) | |
253 { | |
669 | 254 char *failed; |
255 u_char *name; | |
773 | 256 size_t root; |
681 | 257 time_t date; |
637 | 258 ngx_err_t err; |
259 ngx_str_t *temp, path; | |
260 ngx_uint_t status; | |
261 ngx_file_info_t fi; | |
262 ngx_http_dav_loc_conf_t *dlcf; | |
633 | 263 |
773 | 264 ngx_http_map_uri_to_path(r, &path, &root, 0); |
633 | 265 |
266 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
267 "http put filename: \"%s\"", path.data); | |
268 | |
269 temp = &r->request_body->temp_file->file.name; | |
270 | |
271 if (ngx_file_info(path.data, &fi) == -1) { | |
272 status = NGX_HTTP_CREATED; | |
273 | |
274 } else { | |
275 status = NGX_HTTP_NO_CONTENT; | |
663 | 276 |
277 if (ngx_is_dir(&fi)) { | |
278 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, | |
279 "\"%s\" could not be created", path.data); | |
633 | 280 |
663 | 281 if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { |
282 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
283 ngx_delete_file_n " \"%s\" failed", | |
284 temp->data); | |
285 } | |
286 | |
287 ngx_http_finalize_request(r, NGX_HTTP_CONFLICT); | |
288 return; | |
661 | 289 } |
637 | 290 } |
291 | |
669 | 292 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); |
293 | |
294 #if !(NGX_WIN32) | |
295 | |
296 if (ngx_change_file_access(temp->data, dlcf->access & ~0111) | |
297 == NGX_FILE_ERROR) | |
298 { | |
299 err = ngx_errno; | |
300 failed = ngx_change_file_access_n; | |
301 name = temp->data; | |
302 | |
303 goto failed; | |
304 } | |
305 | |
306 #endif | |
307 | |
681 | 308 if (r->headers_in.date) { |
309 date = ngx_http_parse_time(r->headers_in.date->value.data, | |
310 r->headers_in.date->value.len); | |
311 | |
312 if (date != NGX_ERROR) { | |
313 if (ngx_set_file_time(temp->data, | |
314 r->request_body->temp_file->file.fd, date) | |
315 != NGX_OK) | |
316 { | |
317 err = ngx_errno; | |
318 failed = ngx_set_file_time_n; | |
319 name = temp->data; | |
320 | |
321 goto failed; | |
322 } | |
323 } | |
324 } | |
325 | |
669 | 326 failed = ngx_rename_file_n; |
327 name = path.data; | |
328 | |
633 | 329 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { |
330 goto ok; | |
331 } | |
332 | |
333 err = ngx_errno; | |
334 | |
637 | 335 if (err == NGX_ENOENT) { |
336 | |
337 if (dlcf->create_full_put_path) { | |
669 | 338 err = ngx_create_full_path(path.data, dlcf->access); |
637 | 339 |
340 if (err == 0) { | |
341 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { | |
342 goto ok; | |
343 } | |
344 | |
345 err = ngx_errno; | |
346 } | |
347 } | |
348 } | |
349 | |
633 | 350 #if (NGX_WIN32) |
351 | |
352 if (err == NGX_EEXIST) { | |
353 if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) { | |
354 | |
355 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { | |
356 goto ok; | |
357 } | |
358 } | |
359 | |
360 err = ngx_errno; | |
361 } | |
362 | |
681 | 363 #endif |
669 | 364 |
365 failed: | |
366 | |
661 | 367 if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { |
368 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
369 ngx_delete_file_n " \"%s\" failed", | |
370 temp->data); | |
371 } | |
372 | |
669 | 373 ngx_http_finalize_request(r, |
374 ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT, failed, name)); | |
375 | |
633 | 376 return; |
377 | |
378 ok: | |
379 | |
380 if (status == NGX_HTTP_CREATED) { | |
637 | 381 if (ngx_http_dav_location(r, path.data) != NGX_OK) { |
633 | 382 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
383 return; | |
384 } | |
639 | 385 |
386 r->headers_out.content_length_n = 0; | |
633 | 387 } |
388 | |
389 r->headers_out.status = status; | |
390 r->header_only = 1; | |
391 | |
392 ngx_http_finalize_request(r, ngx_http_send_header(r)); | |
393 return; | |
394 } | |
395 | |
396 | |
637 | 397 static ngx_int_t |
398 ngx_http_dav_error(ngx_http_request_t *r, ngx_err_t err, ngx_int_t not_found, | |
399 char *failed, u_char *path) | |
400 { | |
401 ngx_int_t rc; | |
402 ngx_uint_t level; | |
403 | |
404 if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { | |
405 level = NGX_LOG_ERR; | |
406 rc = not_found; | |
407 | |
408 } else if (err == NGX_EACCES || err == NGX_EPERM) { | |
409 level = NGX_LOG_ERR; | |
410 rc = NGX_HTTP_FORBIDDEN; | |
411 | |
412 } else if (err == NGX_EEXIST) { | |
413 level = NGX_LOG_ERR; | |
414 rc = NGX_HTTP_NOT_ALLOWED; | |
415 | |
416 } else if (err == NGX_ENOSPC) { | |
417 level = NGX_LOG_CRIT; | |
418 rc = NGX_HTTP_INSUFFICIENT_STORAGE; | |
419 | |
420 } else { | |
421 level = NGX_LOG_CRIT; | |
422 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
423 } | |
424 | |
425 ngx_log_error(level, r->connection->log, err, | |
426 "%s \"%s\" failed", failed, path); | |
427 | |
428 return rc; | |
429 } | |
430 | |
431 | |
432 static ngx_int_t | |
433 ngx_http_dav_location(ngx_http_request_t *r, u_char *path) | |
434 { | |
435 u_char *location; | |
436 ngx_http_core_loc_conf_t *clcf; | |
437 | |
438 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); | |
439 if (r->headers_out.location == NULL) { | |
440 return NGX_ERROR; | |
441 } | |
442 | |
443 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
444 | |
445 if (!clcf->alias && clcf->root_lengths == NULL) { | |
446 location = path + clcf->root.len; | |
447 | |
448 } else { | |
449 location = ngx_palloc(r->pool, r->uri.len); | |
450 if (location == NULL) { | |
451 return NGX_ERROR; | |
452 } | |
453 | |
454 ngx_memcpy(location, r->uri.data, r->uri.len); | |
455 } | |
456 | |
457 /* | |
458 * we do not need to set the r->headers_out.location->hash and | |
459 * r->headers_out.location->key fields | |
460 */ | |
461 | |
462 r->headers_out.location->value.len = r->uri.len; | |
463 r->headers_out.location->value.data = location; | |
464 | |
465 return NGX_OK; | |
466 } | |
467 | |
468 | |
669 | 469 static char * |
470 ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
471 { | |
472 ngx_http_dav_loc_conf_t *lcf = conf; | |
473 | |
474 u_char *p; | |
475 ngx_str_t *value; | |
476 ngx_uint_t i, right, shift; | |
477 | |
478 if (lcf->access != NGX_CONF_UNSET_UINT) { | |
479 return "is duplicate"; | |
480 } | |
481 | |
482 value = cf->args->elts; | |
483 | |
484 lcf->access = 0700; | |
485 | |
920 | 486 for (i = 1; i < cf->args->nelts; i++) { |
669 | 487 |
488 p = value[i].data; | |
489 | |
490 if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) { | |
491 shift = 6; | |
492 p += sizeof("user:") - 1; | |
493 | |
494 } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) { | |
495 shift = 3; | |
496 p += sizeof("group:") - 1; | |
497 | |
498 } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) { | |
499 shift = 0; | |
500 p += sizeof("all:") - 1; | |
501 | |
502 } else { | |
503 goto invalid; | |
504 } | |
505 | |
506 if (ngx_strcmp(p, "rw") == 0) { | |
507 right = 7; | |
508 | |
509 } else if (ngx_strcmp(p, "r") == 0) { | |
510 right = 5; | |
511 | |
512 } else { | |
513 goto invalid; | |
514 } | |
515 | |
516 lcf->access += right << shift; | |
517 } | |
518 | |
519 return NGX_CONF_OK; | |
520 | |
521 invalid: | |
522 | |
523 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
524 "invalid value \"%V\"", &value[i]); | |
525 return NGX_CONF_ERROR; | |
526 } | |
527 | |
528 | |
633 | 529 static void * |
530 ngx_http_dav_create_loc_conf(ngx_conf_t *cf) | |
531 { | |
532 ngx_http_dav_loc_conf_t *conf; | |
533 | |
534 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t)); | |
535 if (conf == NULL) { | |
536 return NGX_CONF_ERROR; | |
537 } | |
538 | |
539 /* | |
540 * set by ngx_pcalloc(): | |
541 * | |
542 * conf->methods = 0; | |
543 */ | |
544 | |
637 | 545 conf->create_full_put_path = NGX_CONF_UNSET; |
669 | 546 conf->access = NGX_CONF_UNSET_UINT; |
637 | 547 |
633 | 548 return conf; |
549 } | |
550 | |
551 | |
552 static char * | |
553 ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
554 { | |
555 ngx_http_dav_loc_conf_t *prev = parent; | |
556 ngx_http_dav_loc_conf_t *conf = child; | |
557 | |
558 ngx_conf_merge_bitmask_value(conf->methods, prev->methods, | |
637 | 559 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); |
560 | |
561 ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path, | |
562 0); | |
633 | 563 |
669 | 564 ngx_conf_merge_uint_value(conf->access, prev->access, 0600); |
565 | |
633 | 566 return NGX_CONF_OK; |
567 } | |
568 | |
569 | |
570 static ngx_int_t | |
681 | 571 ngx_http_dav_init(ngx_conf_t *cf) |
633 | 572 { |
573 ngx_http_handler_pt *h; | |
574 ngx_http_core_main_conf_t *cmcf; | |
575 | |
681 | 576 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); |
633 | 577 |
578 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); | |
579 if (h == NULL) { | |
580 return NGX_ERROR; | |
581 } | |
582 | |
583 *h = ngx_http_dav_handler; | |
584 | |
585 return NGX_OK; | |
586 } |