Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_dav_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 #define NGX_HTTP_DAV_COPY_BLOCK 65536
14 
15 #define NGX_HTTP_DAV_OFF 2
16 
17 
18 #define NGX_HTTP_DAV_NO_DEPTH -3
19 #define NGX_HTTP_DAV_INVALID_DEPTH -2
20 #define NGX_HTTP_DAV_INFINITY_DEPTH -1
21 
22 
23 typedef struct {
29 
30 
31 typedef struct {
33  size_t len;
35 
36 
37 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
38 
39 static void ngx_http_dav_put_handler(ngx_http_request_t *r);
40 
41 static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r);
42 static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r,
43  ngx_str_t *path, ngx_uint_t dir);
44 static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
45 static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
46 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
47 
48 static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r,
50 
51 static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r);
52 static ngx_int_t ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
53 static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx,
54  ngx_str_t *path);
55 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
56  ngx_str_t *path);
57 
58 static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
59 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
60  ngx_int_t not_found, char *failed, u_char *path);
61 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path);
62 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
63 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
64  void *parent, void *child);
65 static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf);
66 
67 
68 static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = {
69  { ngx_string("off"), NGX_HTTP_DAV_OFF },
70  { ngx_string("put"), NGX_HTTP_PUT },
71  { ngx_string("delete"), NGX_HTTP_DELETE },
72  { ngx_string("mkcol"), NGX_HTTP_MKCOL },
73  { ngx_string("copy"), NGX_HTTP_COPY },
74  { ngx_string("move"), NGX_HTTP_MOVE },
75  { ngx_null_string, 0 }
76 };
77 
78 
79 static ngx_command_t ngx_http_dav_commands[] = {
80 
81  { ngx_string("dav_methods"),
85  offsetof(ngx_http_dav_loc_conf_t, methods),
86  &ngx_http_dav_methods_mask },
87 
88  { ngx_string("create_full_put_path"),
92  offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
93  NULL },
94 
95  { ngx_string("min_delete_depth"),
99  offsetof(ngx_http_dav_loc_conf_t, min_delete_depth),
100  NULL },
101 
102  { ngx_string("dav_access"),
106  offsetof(ngx_http_dav_loc_conf_t, access),
107  NULL },
108 
110 };
111 
112 
113 static ngx_http_module_t ngx_http_dav_module_ctx = {
114  NULL, /* preconfiguration */
115  ngx_http_dav_init, /* postconfiguration */
116 
117  NULL, /* create main configuration */
118  NULL, /* init main configuration */
119 
120  NULL, /* create server configuration */
121  NULL, /* merge server configuration */
122 
123  ngx_http_dav_create_loc_conf, /* create location configuration */
124  ngx_http_dav_merge_loc_conf /* merge location configuration */
125 };
126 
127 
130  &ngx_http_dav_module_ctx, /* module context */
131  ngx_http_dav_commands, /* module directives */
132  NGX_HTTP_MODULE, /* module type */
133  NULL, /* init master */
134  NULL, /* init module */
135  NULL, /* init process */
136  NULL, /* init thread */
137  NULL, /* exit thread */
138  NULL, /* exit process */
139  NULL, /* exit master */
141 };
142 
143 
144 static ngx_int_t
145 ngx_http_dav_handler(ngx_http_request_t *r)
146 {
147  ngx_int_t rc;
149 
150  dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
151 
152  if (!(r->method & dlcf->methods)) {
153  return NGX_DECLINED;
154  }
155 
156  switch (r->method) {
157 
158  case NGX_HTTP_PUT:
159 
160  if (r->uri.data[r->uri.len - 1] == '/') {
162  "cannot PUT to a collection");
163  return NGX_HTTP_CONFLICT;
164  }
165 
171 
172  rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler);
173 
174  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
175  return rc;
176  }
177 
178  return NGX_DONE;
179 
180  case NGX_HTTP_DELETE:
181 
182  return ngx_http_dav_delete_handler(r);
183 
184  case NGX_HTTP_MKCOL:
185 
186  return ngx_http_dav_mkcol_handler(r, dlcf);
187 
188  case NGX_HTTP_COPY:
189 
190  return ngx_http_dav_copy_move_handler(r);
191 
192  case NGX_HTTP_MOVE:
193 
194  return ngx_http_dav_copy_move_handler(r);
195  }
196 
197  return NGX_DECLINED;
198 }
199 
200 
201 static void
202 ngx_http_dav_put_handler(ngx_http_request_t *r)
203 {
204  size_t root;
205  time_t date;
206  ngx_str_t *temp, path;
207  ngx_uint_t status;
208  ngx_file_info_t fi;
211 
212  if (r->request_body == NULL || r->request_body->temp_file == NULL) {
214  return;
215  }
216 
217  ngx_http_map_uri_to_path(r, &path, &root, 0);
218 
219  path.len--;
220 
222  "http put filename: \"%s\"", path.data);
223 
224  temp = &r->request_body->temp_file->file.name;
225 
226  if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
227  status = NGX_HTTP_CREATED;
228 
229  } else {
230  status = NGX_HTTP_NO_CONTENT;
231 
232  if (ngx_is_dir(&fi)) {
234  "\"%s\" could not be created", path.data);
235 
236  if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
238  ngx_delete_file_n " \"%s\" failed",
239  temp->data);
240  }
241 
243  return;
244  }
245  }
246 
247  dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
248 
249  ext.access = dlcf->access;
250  ext.path_access = dlcf->access;
251  ext.time = -1;
252  ext.create_path = dlcf->create_full_put_path;
253  ext.delete_file = 1;
254  ext.log = r->connection->log;
255 
256  if (r->headers_in.date) {
257  date = ngx_http_parse_time(r->headers_in.date->value.data,
258  r->headers_in.date->value.len);
259 
260  if (date != NGX_ERROR) {
261  ext.time = date;
262  ext.fd = r->request_body->temp_file->file.fd;
263  }
264  }
265 
266  if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) {
268  return;
269  }
270 
271  if (status == NGX_HTTP_CREATED) {
272  if (ngx_http_dav_location(r, path.data) != NGX_OK) {
274  return;
275  }
276 
278  }
279 
280  r->headers_out.status = status;
281  r->header_only = 1;
282 
284  return;
285 }
286 
287 
288 static ngx_int_t
289 ngx_http_dav_delete_handler(ngx_http_request_t *r)
290 {
291  size_t root;
292  ngx_err_t err;
293  ngx_int_t rc, depth;
294  ngx_uint_t i, d, dir;
295  ngx_str_t path;
296  ngx_file_info_t fi;
298 
299  if (r->headers_in.content_length_n > 0) {
301  "DELETE with body is unsupported");
303  }
304 
305  dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
306 
307  if (dlcf->min_delete_depth) {
308  d = 0;
309 
310  for (i = 0; i < r->uri.len; /* void */) {
311  if (r->uri.data[i++] == '/') {
312  if (++d >= dlcf->min_delete_depth && i < r->uri.len) {
313  goto ok;
314  }
315  }
316  }
317 
319  "insufficient URI depth:%i to DELETE", d);
320  return NGX_HTTP_CONFLICT;
321  }
322 
323 ok:
324 
325  ngx_http_map_uri_to_path(r, &path, &root, 0);
326 
328  "http delete filename: \"%s\"", path.data);
329 
330  if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) {
331  err = ngx_errno;
332 
334 
335  return ngx_http_dav_error(r->connection->log, err,
336  rc, ngx_link_info_n, path.data);
337  }
338 
339  if (ngx_is_dir(&fi)) {
340 
341  if (r->uri.data[r->uri.len - 1] != '/') {
343  "DELETE \"%s\" failed", path.data);
344  return NGX_HTTP_CONFLICT;
345  }
346 
347  depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
348 
349  if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
351  "\"Depth\" header must be infinity");
352  return NGX_HTTP_BAD_REQUEST;
353  }
354 
355  path.len -= 2; /* omit "/\0" */
356 
357  dir = 1;
358 
359  } else {
360 
361  /*
362  * we do not need to test (r->uri.data[r->uri.len - 1] == '/')
363  * because ngx_link_info("/file/") returned NGX_ENOTDIR above
364  */
365 
366  depth = ngx_http_dav_depth(r, 0);
367 
368  if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
370  "\"Depth\" header must be 0 or infinity");
371  return NGX_HTTP_BAD_REQUEST;
372  }
373 
374  dir = 0;
375  }
376 
377  rc = ngx_http_dav_delete_path(r, &path, dir);
378 
379  if (rc == NGX_OK) {
380  return NGX_HTTP_NO_CONTENT;
381  }
382 
383  return rc;
384 }
385 
386 
387 static ngx_int_t
388 ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir)
389 {
390  char *failed;
391  ngx_tree_ctx_t tree;
392 
393  if (dir) {
394 
395  tree.init_handler = NULL;
396  tree.file_handler = ngx_http_dav_delete_file;
397  tree.pre_tree_handler = ngx_http_dav_noop;
398  tree.post_tree_handler = ngx_http_dav_delete_dir;
399  tree.spec_handler = ngx_http_dav_delete_file;
400  tree.data = NULL;
401  tree.alloc = 0;
402  tree.log = r->connection->log;
403 
404  /* TODO: 207 */
405 
406  if (ngx_walk_tree(&tree, path) != NGX_OK) {
408  }
409 
410  if (ngx_delete_dir(path->data) != NGX_FILE_ERROR) {
411  return NGX_OK;
412  }
413 
414  failed = ngx_delete_dir_n;
415 
416  } else {
417 
418  if (ngx_delete_file(path->data) != NGX_FILE_ERROR) {
419  return NGX_OK;
420  }
421 
422  failed = ngx_delete_file_n;
423  }
424 
425  return ngx_http_dav_error(r->connection->log, ngx_errno,
426  NGX_HTTP_NOT_FOUND, failed, path->data);
427 }
428 
429 
430 static ngx_int_t
431 ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
432 {
434  "http delete dir: \"%s\"", path->data);
435 
436  if (ngx_delete_dir(path->data) == NGX_FILE_ERROR) {
437 
438  /* TODO: add to 207 */
439 
440  (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_dir_n,
441  path->data);
442  }
443 
444  return NGX_OK;
445 }
446 
447 
448 static ngx_int_t
449 ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
450 {
452  "http delete file: \"%s\"", path->data);
453 
454  if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
455 
456  /* TODO: add to 207 */
457 
458  (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_file_n,
459  path->data);
460  }
461 
462  return NGX_OK;
463 }
464 
465 
466 static ngx_int_t
467 ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
468 {
469  return NGX_OK;
470 }
471 
472 
473 static ngx_int_t
474 ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
475 {
476  u_char *p;
477  size_t root;
478  ngx_str_t path;
479 
480  if (r->headers_in.content_length_n > 0) {
482  "MKCOL with body is unsupported");
484  }
485 
486  if (r->uri.data[r->uri.len - 1] != '/') {
488  "MKCOL can create a collection only");
489  return NGX_HTTP_CONFLICT;
490  }
491 
492  p = ngx_http_map_uri_to_path(r, &path, &root, 0);
493 
494  *(p - 1) = '\0';
495  r->uri.len--;
496 
498  "http mkcol path: \"%s\"", path.data);
499 
500  if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access))
501  != NGX_FILE_ERROR)
502  {
503  if (ngx_http_dav_location(r, path.data) != NGX_OK) {
505  }
506 
507  return NGX_HTTP_CREATED;
508  }
509 
510  return ngx_http_dav_error(r->connection->log, ngx_errno,
512 }
513 
514 
515 static ngx_int_t
516 ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
517 {
518  u_char *p, *host, *last, ch;
519  size_t len, root;
520  ngx_err_t err;
521  ngx_int_t rc, depth;
522  ngx_uint_t overwrite, slash, dir, flags;
523  ngx_str_t path, uri, duri, args;
524  ngx_tree_ctx_t tree;
525  ngx_copy_file_t cf;
526  ngx_file_info_t fi;
527  ngx_table_elt_t *dest, *over;
531 
532  if (r->headers_in.content_length_n > 0) {
534  }
535 
536  dest = r->headers_in.destination;
537 
538  if (dest == NULL) {
540  "client sent no \"Destination\" header");
541  return NGX_HTTP_BAD_REQUEST;
542  }
543 
544  p = dest->value.data;
545  /* there is always '\0' even after empty header value */
546  if (p[0] == '/') {
547  last = p + dest->value.len;
548  goto destination_done;
549  }
550 
551  len = r->headers_in.server.len;
552 
553  if (len == 0) {
555  "client sent no \"Host\" header");
556  return NGX_HTTP_BAD_REQUEST;
557  }
558 
559 #if (NGX_HTTP_SSL)
560 
561  if (r->connection->ssl) {
562  if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1)
563  != 0)
564  {
565  goto invalid_destination;
566  }
567 
568  host = dest->value.data + sizeof("https://") - 1;
569 
570  } else
571 #endif
572  {
573  if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1)
574  != 0)
575  {
576  goto invalid_destination;
577  }
578 
579  host = dest->value.data + sizeof("http://") - 1;
580  }
581 
582  if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) {
584  "\"Destination\" URI \"%V\" is handled by "
585  "different repository than the source URI",
586  &dest->value);
587  return NGX_HTTP_BAD_REQUEST;
588  }
589 
590  last = dest->value.data + dest->value.len;
591 
592  for (p = host + len; p < last; p++) {
593  if (*p == '/') {
594  goto destination_done;
595  }
596  }
597 
598 invalid_destination:
599 
601  "client sent invalid \"Destination\" header: \"%V\"",
602  &dest->value);
603  return NGX_HTTP_BAD_REQUEST;
604 
605 destination_done:
606 
607  duri.len = last - p;
608  duri.data = p;
609  flags = 0;
610 
611  if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
612  goto invalid_destination;
613  }
614 
615  if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
616  || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
617  {
619  "both URI \"%V\" and \"Destination\" URI \"%V\" "
620  "should be either collections or non-collections",
621  &r->uri, &dest->value);
622  return NGX_HTTP_CONFLICT;
623  }
624 
625  depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
626 
627  if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
628 
629  if (r->method == NGX_HTTP_COPY) {
630  if (depth != 0) {
632  "\"Depth\" header must be 0 or infinity");
633  return NGX_HTTP_BAD_REQUEST;
634  }
635 
636  } else {
638  "\"Depth\" header must be infinity");
639  return NGX_HTTP_BAD_REQUEST;
640  }
641  }
642 
643  over = r->headers_in.overwrite;
644 
645  if (over) {
646  if (over->value.len == 1) {
647  ch = over->value.data[0];
648 
649  if (ch == 'T' || ch == 't') {
650  overwrite = 1;
651  goto overwrite_done;
652  }
653 
654  if (ch == 'F' || ch == 'f') {
655  overwrite = 0;
656  goto overwrite_done;
657  }
658 
659  }
660 
662  "client sent invalid \"Overwrite\" header: \"%V\"",
663  &over->value);
664  return NGX_HTTP_BAD_REQUEST;
665  }
666 
667  overwrite = 1;
668 
669 overwrite_done:
670 
671  ngx_http_map_uri_to_path(r, &path, &root, 0);
672 
674  "http copy from: \"%s\"", path.data);
675 
676  uri = r->uri;
677  r->uri = duri;
678 
679  ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
680 
681  r->uri = uri;
682 
683  copy.path.len--; /* omit "\0" */
684 
685  if (copy.path.data[copy.path.len - 1] == '/') {
686  slash = 1;
687  copy.path.len--;
688  copy.path.data[copy.path.len] = '\0';
689 
690  } else {
691  slash = 0;
692  }
693 
695  "http copy to: \"%s\"", copy.path.data);
696 
697  if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) {
698  err = ngx_errno;
699 
700  if (err != NGX_ENOENT) {
701  return ngx_http_dav_error(r->connection->log, err,
703  copy.path.data);
704  }
705 
706  /* destination does not exist */
707 
708  overwrite = 0;
709  dir = 0;
710 
711  } else {
712 
713  /* destination exists */
714 
715  if (ngx_is_dir(&fi) && !slash) {
717  "\"%V\" could not be %Ved to collection \"%V\"",
718  &r->uri, &r->method_name, &dest->value);
719  return NGX_HTTP_CONFLICT;
720  }
721 
722  if (!overwrite) {
724  "\"%s\" could not be created", copy.path.data);
726  }
727 
728  dir = ngx_is_dir(&fi);
729  }
730 
731  if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) {
732  return ngx_http_dav_error(r->connection->log, ngx_errno,
734  path.data);
735  }
736 
737  if (ngx_is_dir(&fi)) {
738 
739  if (r->uri.data[r->uri.len - 1] != '/') {
741  "\"%V\" is collection", &r->uri);
742  return NGX_HTTP_BAD_REQUEST;
743  }
744 
745  if (overwrite) {
747  "http delete: \"%s\"", copy.path.data);
748 
749  rc = ngx_http_dav_delete_path(r, &copy.path, dir);
750 
751  if (rc != NGX_OK) {
752  return rc;
753  }
754  }
755  }
756 
757  if (ngx_is_dir(&fi)) {
758 
759  path.len -= 2; /* omit "/\0" */
760 
761  if (r->method == NGX_HTTP_MOVE) {
762  if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
763  return NGX_HTTP_CREATED;
764  }
765  }
766 
767  if (ngx_create_dir(copy.path.data, ngx_file_access(&fi))
768  == NGX_FILE_ERROR)
769  {
770  return ngx_http_dav_error(r->connection->log, ngx_errno,
772  ngx_create_dir_n, copy.path.data);
773  }
774 
775  copy.len = path.len;
776 
777  tree.init_handler = NULL;
778  tree.file_handler = ngx_http_dav_copy_tree_file;
779  tree.pre_tree_handler = ngx_http_dav_copy_dir;
780  tree.post_tree_handler = ngx_http_dav_copy_dir_time;
781  tree.spec_handler = ngx_http_dav_noop;
782  tree.data = &copy;
783  tree.alloc = 0;
784  tree.log = r->connection->log;
785 
786  if (ngx_walk_tree(&tree, &path) == NGX_OK) {
787 
788  if (r->method == NGX_HTTP_MOVE) {
789  rc = ngx_http_dav_delete_path(r, &path, 1);
790 
791  if (rc != NGX_OK) {
792  return rc;
793  }
794  }
795 
796  return NGX_HTTP_CREATED;
797  }
798 
799  } else {
800 
801  if (r->method == NGX_HTTP_MOVE) {
802 
803  dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
804 
805  ext.access = 0;
806  ext.path_access = dlcf->access;
807  ext.time = -1;
808  ext.create_path = 1;
809  ext.delete_file = 0;
810  ext.log = r->connection->log;
811 
812  if (ngx_ext_rename_file(&path, &copy.path, &ext) == NGX_OK) {
813  return NGX_HTTP_NO_CONTENT;
814  }
815 
817  }
818 
819  dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
820 
821  cf.size = ngx_file_size(&fi);
822  cf.buf_size = 0;
823  cf.access = dlcf->access;
824  cf.time = ngx_file_mtime(&fi);
825  cf.log = r->connection->log;
826 
827  if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) {
828  return NGX_HTTP_NO_CONTENT;
829  }
830  }
831 
833 }
834 
835 
836 static ngx_int_t
837 ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
838 {
839  u_char *p, *dir;
840  size_t len;
842 
844  "http copy dir: \"%s\"", path->data);
845 
846  copy = ctx->data;
847 
848  len = copy->path.len + path->len;
849 
850  dir = ngx_alloc(len + 1, ctx->log);
851  if (dir == NULL) {
852  return NGX_ABORT;
853  }
854 
855  p = ngx_cpymem(dir, copy->path.data, copy->path.len);
856  (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
857 
859  "http copy dir to: \"%s\"", dir);
860 
861  if (ngx_create_dir(dir, ngx_dir_access(ctx->access)) == NGX_FILE_ERROR) {
862  (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_create_dir_n,
863  dir);
864  }
865 
866  ngx_free(dir);
867 
868  return NGX_OK;
869 }
870 
871 
872 static ngx_int_t
873 ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path)
874 {
875  u_char *p, *dir;
876  size_t len;
878 
880  "http copy dir time: \"%s\"", path->data);
881 
882  copy = ctx->data;
883 
884  len = copy->path.len + path->len;
885 
886  dir = ngx_alloc(len + 1, ctx->log);
887  if (dir == NULL) {
888  return NGX_ABORT;
889  }
890 
891  p = ngx_cpymem(dir, copy->path.data, copy->path.len);
892  (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
893 
895  "http copy dir time to: \"%s\"", dir);
896 
897 #if (NGX_WIN32)
898  {
899  ngx_fd_t fd;
900 
902 
903  if (fd == NGX_INVALID_FILE) {
904  (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir);
905  goto failed;
906  }
907 
908  if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) {
910  ngx_set_file_time_n " \"%s\" failed", dir);
911  }
912 
913  if (ngx_close_file(fd) == NGX_FILE_ERROR) {
915  ngx_close_file_n " \"%s\" failed", dir);
916  }
917  }
918 
919 failed:
920 
921 #else
922 
923  if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) {
925  ngx_set_file_time_n " \"%s\" failed", dir);
926  }
927 
928 #endif
929 
930  ngx_free(dir);
931 
932  return NGX_OK;
933 }
934 
935 
936 static ngx_int_t
937 ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
938 {
939  u_char *p, *file;
940  size_t len;
941  ngx_copy_file_t cf;
943 
945  "http copy file: \"%s\"", path->data);
946 
947  copy = ctx->data;
948 
949  len = copy->path.len + path->len;
950 
951  file = ngx_alloc(len + 1, ctx->log);
952  if (file == NULL) {
953  return NGX_ABORT;
954  }
955 
956  p = ngx_cpymem(file, copy->path.data, copy->path.len);
957  (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
958 
960  "http copy file to: \"%s\"", file);
961 
962  cf.size = ctx->size;
963  cf.buf_size = 0;
964  cf.access = ctx->access;
965  cf.time = ctx->mtime;
966  cf.log = ctx->log;
967 
968  (void) ngx_copy_file(path->data, file, &cf);
969 
970  ngx_free(file);
971 
972  return NGX_OK;
973 }
974 
975 
976 static ngx_int_t
977 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
978 {
979  ngx_table_elt_t *depth;
980 
981  depth = r->headers_in.depth;
982 
983  if (depth == NULL) {
984  return dflt;
985  }
986 
987  if (depth->value.len == 1) {
988 
989  if (depth->value.data[0] == '0') {
990  return 0;
991  }
992 
993  if (depth->value.data[0] == '1') {
994  return 1;
995  }
996 
997  } else {
998 
999  if (depth->value.len == sizeof("infinity") - 1
1000  && ngx_strcmp(depth->value.data, "infinity") == 0)
1001  {
1003  }
1004  }
1005 
1007  "client sent invalid \"Depth\" header: \"%V\"",
1008  &depth->value);
1009 
1011 }
1012 
1013 
1014 static ngx_int_t
1015 ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found,
1016  char *failed, u_char *path)
1017 {
1018  ngx_int_t rc;
1019  ngx_uint_t level;
1020 
1021  if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) {
1022  level = NGX_LOG_ERR;
1023  rc = not_found;
1024 
1025  } else if (err == NGX_EACCES || err == NGX_EPERM) {
1026  level = NGX_LOG_ERR;
1027  rc = NGX_HTTP_FORBIDDEN;
1028 
1029  } else if (err == NGX_EEXIST) {
1030  level = NGX_LOG_ERR;
1031  rc = NGX_HTTP_NOT_ALLOWED;
1032 
1033  } else if (err == NGX_ENOSPC) {
1034  level = NGX_LOG_CRIT;
1036 
1037  } else {
1038  level = NGX_LOG_CRIT;
1040  }
1041 
1042  ngx_log_error(level, log, err, "%s \"%s\" failed", failed, path);
1043 
1044  return rc;
1045 }
1046 
1047 
1048 static ngx_int_t
1049 ngx_http_dav_location(ngx_http_request_t *r, u_char *path)
1050 {
1051  u_char *location;
1053 
1055  if (r->headers_out.location == NULL) {
1056  return NGX_ERROR;
1057  }
1058 
1060 
1061  if (!clcf->alias && clcf->root_lengths == NULL) {
1062  location = path + clcf->root.len;
1063 
1064  } else {
1065  location = ngx_pnalloc(r->pool, r->uri.len);
1066  if (location == NULL) {
1067  return NGX_ERROR;
1068  }
1069 
1070  ngx_memcpy(location, r->uri.data, r->uri.len);
1071  }
1072 
1073  /*
1074  * we do not need to set the r->headers_out.location->hash and
1075  * r->headers_out.location->key fields
1076  */
1077 
1078  r->headers_out.location->value.len = r->uri.len;
1079  r->headers_out.location->value.data = location;
1080 
1081  return NGX_OK;
1082 }
1083 
1084 
1085 static void *
1086 ngx_http_dav_create_loc_conf(ngx_conf_t *cf)
1087 {
1089 
1090  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t));
1091  if (conf == NULL) {
1092  return NULL;
1093  }
1094 
1095  /*
1096  * set by ngx_pcalloc():
1097  *
1098  * conf->methods = 0;
1099  */
1100 
1102  conf->access = NGX_CONF_UNSET_UINT;
1104 
1105  return conf;
1106 }
1107 
1108 
1109 static char *
1110 ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1111 {
1112  ngx_http_dav_loc_conf_t *prev = parent;
1113  ngx_http_dav_loc_conf_t *conf = child;
1114 
1117 
1119  prev->min_delete_depth, 0);
1120 
1121  ngx_conf_merge_uint_value(conf->access, prev->access, 0600);
1122 
1124  prev->create_full_put_path, 0);
1125 
1126  return NGX_CONF_OK;
1127 }
1128 
1129 
1130 static ngx_int_t
1131 ngx_http_dav_init(ngx_conf_t *cf)
1132 {
1135 
1137 
1139  if (h == NULL) {
1140  return NGX_ERROR;
1141  }
1142 
1143  *h = ngx_http_dav_handler;
1144 
1145  return NGX_OK;
1146 }