comparison src/http/modules/ngx_http_dav_module.c @ 362:54fad6c4b555 NGINX_0_6_25

nginx 0.6.25 *) Change: now the "server_name_in_redirect" directive is used instead of the "server_name" directive's special "*" parameter. *) Change: now wildcard and regex names can be used as main name in a "server_name" directive. *) Change: the "satisfy_any" directive was replaced by the "satisfy" directive. *) Workaround: old worker processes might hog CPU after reconfiguration if they was run under Linux OpenVZ. *) Feature: the "min_delete_depth" directive. *) Bugfix: the COPY and MOVE methods did not work with single files. *) Bugfix: the ngx_http_gzip_static_module did not allow the ngx_http_dav_module to work; bug appeared in 0.6.23. *) Bugfix: socket leak in HTTPS mode if deferred accept was used. Thanks to Ben Maurer. *) Bugfix: nginx could not be built without PCRE library; bug appeared in 0.6.23.
author Igor Sysoev <http://sysoev.ru>
date Tue, 08 Jan 2008 00:00:00 +0300
parents 9121a0a91f47
children a39aab45a53f
comparison
equal deleted inserted replaced
361:160660bad929 362:54fad6c4b555
19 #define NGX_HTTP_DAV_INFINITY_DEPTH -1 19 #define NGX_HTTP_DAV_INFINITY_DEPTH -1
20 20
21 21
22 typedef struct { 22 typedef struct {
23 ngx_uint_t methods; 23 ngx_uint_t methods;
24 ngx_uint_t access;
25 ngx_uint_t min_delete_depth;
24 ngx_flag_t create_full_put_path; 26 ngx_flag_t create_full_put_path;
25 ngx_uint_t access;
26 } ngx_http_dav_loc_conf_t; 27 } ngx_http_dav_loc_conf_t;
27 28
28 29
29 typedef struct { 30 typedef struct {
30 ngx_str_t path; 31 ngx_str_t path;
35 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); 36 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
36 37
37 static void ngx_http_dav_put_handler(ngx_http_request_t *r); 38 static void ngx_http_dav_put_handler(ngx_http_request_t *r);
38 39
39 static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r); 40 static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r);
40 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); 41 static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r,
42 ngx_str_t *path, ngx_uint_t dir);
41 static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path); 43 static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
42 static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); 44 static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
45 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
43 46
44 static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r, 47 static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r,
45 ngx_http_dav_loc_conf_t *dlcf); 48 ngx_http_dav_loc_conf_t *dlcf);
46 49
47 static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r); 50 static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r);
48 static ngx_int_t ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path); 51 static ngx_int_t ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
49 static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, 52 static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx,
50 ngx_str_t *path); 53 ngx_str_t *path);
51 static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); 54 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
52 55 ngx_str_t *path);
53 static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r, 56 static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from,
54 ngx_str_t *path, ngx_uint_t dir); 57 u_char *to);
58
55 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_depth(ngx_http_request_t *r, ngx_int_t dflt);
56 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, 60 static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
57 ngx_int_t not_found, char *failed, u_char *path); 61 ngx_int_t not_found, char *failed, u_char *path);
58 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); 62 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path);
59 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); 63 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
85 { ngx_string("create_full_put_path"), 89 { ngx_string("create_full_put_path"),
86 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 90 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
87 ngx_conf_set_flag_slot, 91 ngx_conf_set_flag_slot,
88 NGX_HTTP_LOC_CONF_OFFSET, 92 NGX_HTTP_LOC_CONF_OFFSET,
89 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), 93 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
94 NULL },
95
96 { ngx_string("min_delete_depth"),
97 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
98 ngx_conf_set_num_slot,
99 NGX_HTTP_LOC_CONF_OFFSET,
100 offsetof(ngx_http_dav_loc_conf_t, min_delete_depth),
90 NULL }, 101 NULL },
91 102
92 { ngx_string("dav_access"), 103 { ngx_string("dav_access"),
93 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, 104 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
94 ngx_conf_set_access_slot, 105 ngx_conf_set_access_slot,
151 switch (r->method) { 162 switch (r->method) {
152 163
153 case NGX_HTTP_PUT: 164 case NGX_HTTP_PUT:
154 165
155 if (r->uri.data[r->uri.len - 1] == '/') { 166 if (r->uri.data[r->uri.len - 1] == '/') {
156 return NGX_HTTP_BAD_REQUEST; 167 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
168 "can not PUT to a collection");
169 return NGX_HTTP_CONFLICT;
157 } 170 }
158 171
159 r->request_body_in_file_only = 1; 172 r->request_body_in_file_only = 1;
160 r->request_body_in_persistent_file = 1; 173 r->request_body_in_persistent_file = 1;
161 r->request_body_in_clean_file = 1; 174 r->request_body_in_clean_file = 1;
192 205
193 206
194 static void 207 static void
195 ngx_http_dav_put_handler(ngx_http_request_t *r) 208 ngx_http_dav_put_handler(ngx_http_request_t *r)
196 { 209 {
197 char *failed;
198 u_char *name;
199 size_t root; 210 size_t root;
200 time_t date; 211 time_t date;
201 ngx_err_t err;
202 ngx_str_t *temp, path; 212 ngx_str_t *temp, path;
203 ngx_uint_t status, not_found; 213 ngx_uint_t status;
204 ngx_file_info_t fi; 214 ngx_file_info_t fi;
215 ngx_ext_rename_file_t ext;
205 ngx_http_dav_loc_conf_t *dlcf; 216 ngx_http_dav_loc_conf_t *dlcf;
206 217
207 ngx_http_map_uri_to_path(r, &path, &root, 0); 218 ngx_http_map_uri_to_path(r, &path, &root, 0);
208 219
209 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 220 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
232 } 243 }
233 } 244 }
234 245
235 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); 246 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
236 247
237 #if !(NGX_WIN32) 248 ext.access = dlcf->access;
238 249 ext.time = -1;
239 if (ngx_change_file_access(temp->data, dlcf->access) == NGX_FILE_ERROR) { 250 ext.create_path = dlcf->create_full_put_path;
240 err = ngx_errno; 251 ext.delete = 1;
241 not_found = NGX_HTTP_INTERNAL_SERVER_ERROR; 252 ext.log = r->connection->log;
242 failed = ngx_change_file_access_n;
243 name = temp->data;
244
245 goto failed;
246 }
247
248 #endif
249 253
250 if (r->headers_in.date) { 254 if (r->headers_in.date) {
251 date = ngx_http_parse_time(r->headers_in.date->value.data, 255 date = ngx_http_parse_time(r->headers_in.date->value.data,
252 r->headers_in.date->value.len); 256 r->headers_in.date->value.len);
253 257
254 if (date != NGX_ERROR) { 258 if (date != NGX_ERROR) {
255 if (ngx_set_file_time(temp->data, 259 ext.time = date;
256 r->request_body->temp_file->file.fd, date) 260 ext.fd = r->request_body->temp_file->file.fd;
257 != NGX_OK) 261 }
258 { 262 }
259 err = ngx_errno; 263
260 not_found = NGX_HTTP_INTERNAL_SERVER_ERROR; 264 if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) {
261 failed = ngx_set_file_time_n; 265 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
262 name = temp->data; 266 return;
263 267 }
264 goto failed;
265 }
266 }
267 }
268
269 not_found = NGX_HTTP_CONFLICT;
270 failed = ngx_rename_file_n;
271 name = path.data;
272
273 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
274 goto ok;
275 }
276
277 err = ngx_errno;
278
279 if (err == NGX_ENOENT) {
280
281 if (dlcf->create_full_put_path) {
282 err = ngx_create_full_path(path.data, ngx_dir_access(dlcf->access));
283
284 if (err == 0) {
285 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
286 goto ok;
287 }
288
289 err = ngx_errno;
290 }
291 }
292 }
293
294 #if (NGX_WIN32)
295
296 if (err == NGX_EEXIST) {
297 if (ngx_win32_rename_file(temp, &path, r->connection->log) == NGX_OK) {
298
299 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
300 goto ok;
301 }
302 }
303
304 err = ngx_errno;
305 }
306
307 #endif
308
309 failed:
310
311 if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
312 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
313 ngx_delete_file_n " \"%s\" failed",
314 temp->data);
315 }
316
317 ngx_http_finalize_request(r,
318 ngx_http_dav_error(r->connection->log, err,
319 not_found, failed, name));
320
321 return;
322
323 ok:
324 268
325 if (status == NGX_HTTP_CREATED) { 269 if (status == NGX_HTTP_CREATED) {
326 if (ngx_http_dav_location(r, path.data) != NGX_OK) { 270 if (ngx_http_dav_location(r, path.data) != NGX_OK) {
327 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 271 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
328 return; 272 return;
340 284
341 285
342 static ngx_int_t 286 static ngx_int_t
343 ngx_http_dav_delete_handler(ngx_http_request_t *r) 287 ngx_http_dav_delete_handler(ngx_http_request_t *r)
344 { 288 {
345 size_t root;
346 ngx_int_t rc, depth;
347 ngx_uint_t dir;
348 ngx_str_t path;
349 ngx_file_info_t fi;
350
351 if (r->headers_in.content_length_n > 0) {
352 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
353 }
354
355 rc = ngx_http_discard_request_body(r);
356
357 if (rc != NGX_OK) {
358 return rc;
359 }
360
361 ngx_http_map_uri_to_path(r, &path, &root, 0);
362
363 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
364 "http delete filename: \"%s\"", path.data);
365
366 if (ngx_file_info(path.data, &fi) == -1) {
367 return ngx_http_dav_error(r->connection->log, ngx_errno,
368 NGX_HTTP_NOT_FOUND, ngx_file_info_n,
369 path.data);
370 }
371
372 if (ngx_is_dir(&fi)) {
373
374 if (r->uri.data[r->uri.len - 1] != '/') {
375 /* TODO: 301 */
376 return NGX_HTTP_BAD_REQUEST;
377 }
378
379 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
380
381 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
382 return NGX_HTTP_BAD_REQUEST;
383 }
384
385 path.len -= 2; /* omit "/\0" */
386
387 dir = 1;
388
389 } else {
390
391 depth = ngx_http_dav_depth(r, 0);
392
393 if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
394 return NGX_HTTP_BAD_REQUEST;
395 }
396
397 dir = 0;
398 }
399
400 rc = ngx_http_dav_delete_path(r, &path, dir);
401
402 if (rc == NGX_OK) {
403 return NGX_HTTP_NO_CONTENT;
404 }
405
406 return rc;
407 }
408
409
410 static ngx_int_t
411 ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
412 {
413 return NGX_OK;
414 }
415
416
417 static ngx_int_t
418 ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
419 {
420 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
421 "http delete dir: \"%s\"", path->data);
422
423 if (ngx_delete_dir(path->data) == NGX_FILE_ERROR) {
424
425 /* TODO: add to 207 */
426
427 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_dir_n,
428 path->data);
429 }
430
431 return NGX_OK;
432 }
433
434
435 static ngx_int_t
436 ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
437 {
438 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
439 "http delete file: \"%s\"", path->data);
440
441 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
442
443 /* TODO: add to 207 */
444
445 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_file_n,
446 path->data);
447 }
448
449 return NGX_OK;
450 }
451
452
453 static ngx_int_t
454 ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
455 {
456 size_t root;
457 ngx_int_t rc;
458 ngx_str_t path;
459
460 if (r->headers_in.content_length_n > 0) {
461 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
462 }
463
464 rc = ngx_http_discard_request_body(r);
465
466 if (rc != NGX_OK) {
467 return rc;
468 }
469
470 ngx_http_map_uri_to_path(r, &path, &root, 0);
471
472 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
473 "http mkcol path: \"%s\"", path.data);
474
475 if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access))
476 != NGX_FILE_ERROR)
477 {
478 if (ngx_http_dav_location(r, path.data) != NGX_OK) {
479 return NGX_HTTP_INTERNAL_SERVER_ERROR;
480 }
481
482 return NGX_HTTP_CREATED;
483 }
484
485 return ngx_http_dav_error(r->connection->log, ngx_errno,
486 NGX_HTTP_BAD_REQUEST, ngx_create_dir_n,
487 path.data);
488 }
489
490
491 static ngx_int_t
492 ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
493 {
494 u_char *p, *host, *last, ch;
495 size_t root; 289 size_t root;
496 ngx_err_t err; 290 ngx_err_t err;
497 ngx_int_t rc, depth; 291 ngx_int_t rc, depth;
498 ngx_uint_t overwrite, slash; 292 ngx_uint_t i, d, dir;
499 ngx_str_t path, uri; 293 ngx_str_t path;
500 ngx_tree_ctx_t tree;
501 ngx_file_info_t fi; 294 ngx_file_info_t fi;
502 ngx_table_elt_t *dest, *over; 295 ngx_http_dav_loc_conf_t *dlcf;
503 ngx_http_dav_copy_ctx_t copy;
504 296
505 if (r->headers_in.content_length_n > 0) { 297 if (r->headers_in.content_length_n > 0) {
298 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
299 "DELETE with body is unsupported");
506 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; 300 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
507 } 301 }
508 302
509 dest = r->headers_in.destination; 303 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
510 304
511 if (dest == NULL) { 305 if (dlcf->min_delete_depth) {
512 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 306 d = 0;
513 "client sent no \"Destination\" header"); 307
514 return NGX_HTTP_BAD_REQUEST; 308 for (i = 0; i < r->uri.len; /* void */) {
515 } 309 if (r->uri.data[i++] == '/') {
516 310 if (++d >= dlcf->min_delete_depth && i < r->uri.len) {
517 if (dest->value.len < sizeof("http://") - 1 + r->server_name.len + 1) { 311 goto ok;
518 goto invalid_destination;
519 }
520
521 #if (NGX_HTTP_SSL)
522
523 if (r->connection->ssl) {
524 if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1)
525 != 0)
526 {
527 goto invalid_destination;
528 }
529
530 host = dest->value.data + sizeof("https://") - 1;
531
532 } else
533 #endif
534 {
535 if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1)
536 != 0)
537 {
538 goto invalid_destination;
539 }
540
541 host = dest->value.data + sizeof("http://") - 1;
542 }
543
544 if (ngx_strncmp(host, r->server_name.data, r->server_name.len) != 0) {
545 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
546 "Destination URI \"%V\" is handled by "
547 "different repository than the source URI",
548 &dest->value);
549
550 return NGX_HTTP_BAD_REQUEST;
551 }
552
553 last = dest->value.data + dest->value.len;
554
555 for (p = host + r->server_name.len; p < last; p++) {
556 if (*p == '/') {
557 goto destination_done;
558 }
559 }
560
561 invalid_destination:
562
563 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
564 "client sent invalid \"Destination\" header: \"%V\"",
565 &dest->value);
566
567 return NGX_HTTP_BAD_REQUEST;
568
569 destination_done:
570
571 depth = ngx_http_dav_depth(r, 0);
572
573 if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
574 return NGX_HTTP_BAD_REQUEST;
575 }
576
577 over = r->headers_in.overwrite;
578
579 if (over) {
580 if (over->value.len == 1) {
581 ch = over->value.data[0];
582
583 if (ch == 'T' || ch == 't') {
584 overwrite = 1;
585 goto overwrite_done;
586 }
587
588 if (ch == 'F' || ch == 'f') {
589 overwrite = 0;
590 goto overwrite_done;
591 }
592
593 }
594
595 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
596 "client sent invalid \"Overwrite\" header: \"%V\"",
597 &over->value);
598
599 return NGX_HTTP_BAD_REQUEST;
600 }
601
602 overwrite = 1;
603
604 overwrite_done:
605
606 rc = ngx_http_discard_request_body(r);
607
608 if (rc != NGX_OK) {
609 return rc;
610 }
611
612 ngx_http_map_uri_to_path(r, &path, &root, 0);
613
614 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
615 "http copy from: \"%s\"", path.data);
616
617 uri = r->uri;
618
619 r->uri.len = last - p;
620 r->uri.data = p;
621
622 ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
623
624 r->uri = uri;
625
626 copy.path.len--; /* omit "\0" */
627
628 if (copy.path.data[copy.path.len - 1] == '/') {
629 slash = 1;
630 copy.path.len--;
631 copy.path.data[copy.path.len] = '\0';
632
633 } else {
634 slash = 0;
635 }
636
637 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
638 "http copy to: \"%s\"", copy.path.data);
639
640 if (ngx_file_info(copy.path.data, &fi) == -1) {
641 err = ngx_errno;
642
643 if (err != NGX_ENOENT) {
644 return ngx_http_dav_error(r->connection->log, err,
645 NGX_HTTP_NOT_FOUND, ngx_file_info_n,
646 copy.path.data);
647 }
648
649 /* destination does not exist */
650
651 } else {
652
653 /* destination exists */
654
655 if (ngx_is_dir(&fi) && !slash) {
656 return NGX_HTTP_CONFLICT;
657 }
658
659 if (!overwrite) {
660 return NGX_HTTP_PRECONDITION_FAILED;
661 }
662
663 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
664 "http delete: \"%s\"", copy.path.data);
665
666 rc = ngx_http_dav_delete_path(r, &copy.path, ngx_is_dir(&fi));
667
668 if (rc != NGX_OK) {
669 return rc;
670 }
671 }
672
673 if (ngx_file_info(path.data, &fi) == -1) {
674 return ngx_http_dav_error(r->connection->log, ngx_errno,
675 NGX_HTTP_NOT_FOUND, ngx_file_info_n,
676 path.data);
677 }
678
679
680 if (ngx_is_dir(&fi)) {
681
682 if (r->uri.data[r->uri.len - 1] != '/') {
683 /* TODO: 301 */
684 return NGX_HTTP_BAD_REQUEST;
685 }
686
687 path.len -= 2; /* omit "/\0" */
688
689 if (r->method == NGX_HTTP_MOVE) {
690 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
691 return NGX_HTTP_CREATED;
692 }
693 }
694
695 if (ngx_create_dir(copy.path.data, ngx_file_access(&fi))
696 == NGX_FILE_ERROR)
697 {
698 return ngx_http_dav_error(r->connection->log, ngx_errno,
699 NGX_HTTP_NOT_FOUND,
700 ngx_create_dir_n, copy.path.data);
701 }
702
703 copy.len = path.len;
704
705 tree.init_handler = NULL;
706 tree.file_handler = ngx_http_dav_copy_file;
707 tree.pre_tree_handler = ngx_http_dav_copy_dir;
708 tree.post_tree_handler = ngx_http_dav_copy_dir_time;
709 tree.spec_handler = ngx_http_dav_noop;
710 tree.data = &copy;
711 tree.alloc = 0;
712 tree.log = r->connection->log;
713
714 if (ngx_walk_tree(&tree, &path) == NGX_OK) {
715
716 if (r->method == NGX_HTTP_MOVE) {
717 rc = ngx_http_dav_delete_path(r, &path, 1);
718
719 if (rc != NGX_OK) {
720 return rc;
721 } 312 }
722 } 313 }
723 314 }
724 return NGX_HTTP_CREATED; 315
725 } 316 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
317 "insufficient URI depth:%i to DELETE", d);
318 return NGX_HTTP_CONFLICT;
319 }
320
321 ok:
322
323 ngx_http_map_uri_to_path(r, &path, &root, 0);
324
325 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
326 "http delete filename: \"%s\"", path.data);
327
328 if (ngx_file_info(path.data, &fi) == -1) {
329 err = ngx_errno;
330
331 rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND;
332
333 return ngx_http_dav_error(r->connection->log, err,
334 rc, ngx_file_info_n, path.data);
335 }
336
337 if (ngx_is_dir(&fi)) {
338
339 if (r->uri.data[r->uri.len - 1] != '/') {
340 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
341 "DELETE \"%s\" failed", path.data);
342 return NGX_HTTP_CONFLICT;
343 }
344
345 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
346
347 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
348 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
349 "\"Depth\" header must be infinity");
350 return NGX_HTTP_BAD_REQUEST;
351 }
352
353 path.len -= 2; /* omit "/\0" */
354
355 dir = 1;
726 356
727 } else { 357 } else {
728 358
729 if (dest->value.data[dest->value.len - 1] == '/') { 359 /*
360 * we do not need to test (r->uri.data[r->uri.len - 1] == '/')
361 * because ngx_file_info("/file/") returned NGX_ENOTDIR above
362 */
363
364 depth = ngx_http_dav_depth(r, 0);
365
366 if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
367 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
368 "\"Depth\" header must be 0 or infinity");
730 return NGX_HTTP_BAD_REQUEST; 369 return NGX_HTTP_BAD_REQUEST;
731 } 370 }
732 371
733 if (r->method == NGX_HTTP_MOVE) { 372 dir = 0;
734 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { 373 }
735 return NGX_HTTP_NO_CONTENT; 374
736 } 375 rc = ngx_http_dav_delete_path(r, &path, dir);
737 } 376
738 377 if (rc == NGX_OK) {
739 tree.data = &copy; 378 return NGX_HTTP_NO_CONTENT;
740 tree.log = r->connection->log; 379 }
741 380
742 if (ngx_http_dav_copy_file(&tree, &path) != NGX_FILE_ERROR) { 381 return rc;
743
744 if (r->method == NGX_HTTP_MOVE) {
745 rc = ngx_http_dav_delete_path(r, &path, 0);
746
747 if (rc != NGX_OK) {
748 return rc;
749 }
750 }
751
752 return NGX_HTTP_NO_CONTENT;
753 }
754 }
755
756 return NGX_HTTP_INTERNAL_SERVER_ERROR;
757 }
758
759
760 static ngx_int_t
761 ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
762 {
763 u_char *p, *dir;
764 size_t len;
765 ngx_http_dav_copy_ctx_t *copy;
766
767 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
768 "http copy dir: \"%s\"", path->data);
769
770 copy = ctx->data;
771
772 len = copy->path.len + path->len;
773
774 dir = ngx_alloc(len + 1, ctx->log);
775 if (dir == NULL) {
776 return NGX_ABORT;
777 }
778
779 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
780 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
781
782 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
783 "http copy dir to: \"%s\"", dir);
784
785 if (ngx_create_dir(dir, ngx_dir_access(ctx->access)) == NGX_FILE_ERROR) {
786 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_create_dir_n,
787 dir);
788 }
789
790 ngx_free(dir);
791
792 return NGX_OK;
793 }
794
795
796 static ngx_int_t
797 ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path)
798 {
799 u_char *p, *dir;
800 size_t len;
801 ngx_http_dav_copy_ctx_t *copy;
802 #if (WIN32)
803 ngx_fd_t fd;
804 #endif
805
806 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
807 "http copy dir time: \"%s\"", path->data);
808
809 copy = ctx->data;
810
811 len = copy->path.len + path->len;
812
813 dir = ngx_alloc(len + 1, ctx->log);
814 if (dir == NULL) {
815 return NGX_ABORT;
816 }
817
818 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
819 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
820
821 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
822 "http copy dir time to: \"%s\"", dir);
823
824 #if (WIN32)
825
826 fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
827
828 if (fd == NGX_INVALID_FILE) {
829 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir);
830 goto failed;
831 }
832
833 if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) {
834 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
835 ngx_set_file_time_n " \"%s\" failed", dir);
836 }
837
838 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
839 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
840 ngx_close_file_n " \"%s\" failed", dir);
841 }
842
843 failed:
844
845 #else
846
847 if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) {
848 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
849 ngx_set_file_time_n " \"%s\" failed", dir);
850 }
851
852 #endif
853
854 ngx_free(dir);
855
856 return NGX_OK;
857 }
858
859
860 static ngx_int_t
861 ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
862 {
863 u_char *p, *file;
864 size_t len;
865 off_t size;
866 ssize_t n;
867 ngx_fd_t fd, copy_fd;
868 ngx_http_dav_copy_ctx_t *copy;
869 u_char buf[NGX_HTTP_DAV_COPY_BLOCK];
870
871 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
872 "http copy file: \"%s\"", path->data);
873
874 copy = ctx->data;
875
876 len = copy->path.len + path->len;
877
878 file = ngx_alloc(len + 1, ctx->log);
879 if (file == NULL) {
880 return NGX_ABORT;
881 }
882
883 p = ngx_cpymem(file, copy->path.data, copy->path.len);
884 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
885
886 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
887 "http copy file to: \"%s\"", file);
888
889 fd = ngx_open_file(path->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
890
891 if (fd == NGX_INVALID_FILE) {
892 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n,
893 path->data);
894 goto failed;
895 }
896
897 copy_fd = ngx_open_file(file, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
898 ctx->access);
899
900 if (copy_fd == NGX_INVALID_FILE) {
901 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n,
902 file);
903 goto copy_failed;
904 }
905
906 for (size = ctx->size; size > 0; size -= n) {
907
908 n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK);
909
910 if (n == NGX_FILE_ERROR) {
911 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
912 ngx_read_fd_n " \"%s\" failed", path->data);
913 break;
914 }
915
916 if (ngx_write_fd(copy_fd, buf, n) == NGX_FILE_ERROR) {
917 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
918 ngx_write_fd_n " \"%s\" failed", file);
919 }
920 }
921
922 if (ngx_set_file_time(file, copy_fd, ctx->mtime) != NGX_OK) {
923 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
924 ngx_set_file_time_n " \"%s\" failed", file);
925 }
926
927 if (ngx_close_file(copy_fd) == NGX_FILE_ERROR) {
928 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
929 ngx_close_file_n " \"%s\" failed", file);
930 }
931
932 copy_failed:
933
934 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
935 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
936 ngx_close_file_n " \"%s\" failed", path->data);
937 }
938
939 failed:
940
941 ngx_free(file);
942
943 return NGX_OK;
944 } 382 }
945 383
946 384
947 static ngx_int_t 385 static ngx_int_t
948 ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir) 386 ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir)
986 NGX_HTTP_NOT_FOUND, failed, path->data); 424 NGX_HTTP_NOT_FOUND, failed, path->data);
987 } 425 }
988 426
989 427
990 static ngx_int_t 428 static ngx_int_t
429 ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
430 {
431 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
432 "http delete dir: \"%s\"", path->data);
433
434 if (ngx_delete_dir(path->data) == NGX_FILE_ERROR) {
435
436 /* TODO: add to 207 */
437
438 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_dir_n,
439 path->data);
440 }
441
442 return NGX_OK;
443 }
444
445
446 static ngx_int_t
447 ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
448 {
449 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
450 "http delete file: \"%s\"", path->data);
451
452 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
453
454 /* TODO: add to 207 */
455
456 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_file_n,
457 path->data);
458 }
459
460 return NGX_OK;
461 }
462
463
464 static ngx_int_t
465 ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
466 {
467 return NGX_OK;
468 }
469
470
471 static ngx_int_t
472 ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
473 {
474 u_char *p;
475 size_t root;
476 ngx_str_t path;
477
478 if (r->headers_in.content_length_n > 0) {
479 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
480 "MKCOL with body is unsupported");
481 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
482 }
483
484 if (r->uri.data[r->uri.len - 1] != '/') {
485 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
486 "MKCOL can create a collection only");
487 return NGX_HTTP_CONFLICT;
488 }
489
490 p = ngx_http_map_uri_to_path(r, &path, &root, 0);
491
492 *(p - 1) = '\0';
493
494 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
495 "http mkcol path: \"%s\"", path.data);
496
497 if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access))
498 != NGX_FILE_ERROR)
499 {
500 if (ngx_http_dav_location(r, path.data) != NGX_OK) {
501 return NGX_HTTP_INTERNAL_SERVER_ERROR;
502 }
503
504 return NGX_HTTP_CREATED;
505 }
506
507 return ngx_http_dav_error(r->connection->log, ngx_errno,
508 NGX_HTTP_CONFLICT, ngx_create_dir_n, path.data);
509 }
510
511
512 static ngx_int_t
513 ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
514 {
515 u_char *p, *desthost, *last, ch;
516 size_t len, root;
517 ngx_err_t err;
518 ngx_int_t rc, depth;
519 ngx_uint_t overwrite, slash, dir;
520 ngx_str_t path, uri;
521 ngx_tree_ctx_t tree;
522 ngx_file_info_t fi;
523 ngx_table_elt_t *host, *dest, *over;
524 ngx_http_dav_copy_ctx_t copy;
525 ngx_http_dav_loc_conf_t *dlcf;
526
527 if (r->headers_in.content_length_n > 0) {
528 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
529 }
530
531 dest = r->headers_in.destination;
532
533 if (dest == NULL) {
534 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
535 "client sent no \"Destination\" header");
536 return NGX_HTTP_BAD_REQUEST;
537 }
538
539 host = r->headers_in.host;
540
541 if (host == NULL) {
542 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
543 "client sent no \"Host\" header");
544 return NGX_HTTP_BAD_REQUEST;
545 }
546
547 #if (NGX_HTTP_SSL)
548
549 if (r->connection->ssl) {
550 if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1)
551 != 0)
552 {
553 goto invalid_destination;
554 }
555
556 desthost = dest->value.data + sizeof("https://") - 1;
557
558 } else
559 #endif
560 {
561 if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1)
562 != 0)
563 {
564 goto invalid_destination;
565 }
566
567 desthost = dest->value.data + sizeof("http://") - 1;
568 }
569
570 len = r->headers_in.host_name_len;
571
572 if (ngx_strncmp(desthost, host->value.data, len) != 0) {
573 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
574 "\"Destination\" URI \"%V\" is handled by "
575 "different repository than the source URI",
576 &dest->value);
577 return NGX_HTTP_BAD_REQUEST;
578 }
579
580 last = dest->value.data + dest->value.len;
581
582 for (p = desthost + len; p < last; p++) {
583 if (*p == '/') {
584 goto destination_done;
585 }
586 }
587
588 invalid_destination:
589
590 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
591 "client sent invalid \"Destination\" header: \"%V\"",
592 &dest->value);
593 return NGX_HTTP_BAD_REQUEST;
594
595 destination_done:
596
597 if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
598 || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
599 {
600 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
601 "both URI \"%V\" and \"Destination\" URI \"%V\" "
602 "should be either collections or non-collections",
603 &r->uri, &dest->value);
604 return NGX_HTTP_CONFLICT;
605 }
606
607 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
608
609 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
610
611 if (r->method == NGX_HTTP_COPY) {
612 if (depth != 0) {
613 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
614 "\"Depth\" header must be 0 or infinity");
615 return NGX_HTTP_BAD_REQUEST;
616 }
617
618 } else {
619 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
620 "\"Depth\" header must be infinity");
621 return NGX_HTTP_BAD_REQUEST;
622 }
623 }
624
625 over = r->headers_in.overwrite;
626
627 if (over) {
628 if (over->value.len == 1) {
629 ch = over->value.data[0];
630
631 if (ch == 'T' || ch == 't') {
632 overwrite = 1;
633 goto overwrite_done;
634 }
635
636 if (ch == 'F' || ch == 'f') {
637 overwrite = 0;
638 goto overwrite_done;
639 }
640
641 }
642
643 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
644 "client sent invalid \"Overwrite\" header: \"%V\"",
645 &over->value);
646 return NGX_HTTP_BAD_REQUEST;
647 }
648
649 overwrite = 1;
650
651 overwrite_done:
652
653 ngx_http_map_uri_to_path(r, &path, &root, 0);
654
655 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
656 "http copy from: \"%s\"", path.data);
657
658 uri = r->uri;
659
660 r->uri.len = last - p;
661 r->uri.data = p;
662
663 ngx_http_map_uri_to_path(r, &copy.path, &root, 0);
664
665 r->uri = uri;
666
667 copy.path.len--; /* omit "\0" */
668
669 if (copy.path.data[copy.path.len - 1] == '/') {
670 slash = 1;
671 copy.path.len--;
672 copy.path.data[copy.path.len] = '\0';
673
674 } else {
675 slash = 0;
676 }
677
678 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
679 "http copy to: \"%s\"", copy.path.data);
680
681 if (ngx_file_info(copy.path.data, &fi) == -1) {
682 err = ngx_errno;
683
684 if (err != NGX_ENOENT) {
685 return ngx_http_dav_error(r->connection->log, err,
686 NGX_HTTP_NOT_FOUND, ngx_file_info_n,
687 copy.path.data);
688 }
689
690 /* destination does not exist */
691
692 overwrite = 0;
693 dir = 0;
694
695 } else {
696
697 /* destination exists */
698
699 if (ngx_is_dir(&fi) && !slash) {
700 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
701 "\"%V\" could not be %Ved to collection \"%V\"",
702 &r->uri, &r->method_name, &dest->value);
703 return NGX_HTTP_CONFLICT;
704 }
705
706 if (!overwrite) {
707 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST,
708 "\"%s\" could not be created", copy.path.data);
709 return NGX_HTTP_PRECONDITION_FAILED;
710 }
711
712 dir = ngx_is_dir(&fi);
713 }
714
715 if (ngx_file_info(path.data, &fi) == -1) {
716 return ngx_http_dav_error(r->connection->log, ngx_errno,
717 NGX_HTTP_NOT_FOUND, ngx_file_info_n,
718 path.data);
719 }
720
721 if (ngx_is_dir(&fi)) {
722
723 if (r->uri.data[r->uri.len - 1] != '/') {
724 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
725 "\"%V\" is collection", &r->uri);
726 return NGX_HTTP_BAD_REQUEST;
727 }
728
729 if (overwrite) {
730 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
731 "http delete: \"%s\"", copy.path.data);
732
733 rc = ngx_http_dav_delete_path(r, &copy.path, dir);
734
735 if (rc != NGX_OK) {
736 return rc;
737 }
738 }
739 }
740
741 if (ngx_is_dir(&fi)) {
742
743 path.len -= 2; /* omit "/\0" */
744
745 if (r->method == NGX_HTTP_MOVE) {
746 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
747 return NGX_HTTP_CREATED;
748 }
749 }
750
751 if (ngx_create_dir(copy.path.data, ngx_file_access(&fi))
752 == NGX_FILE_ERROR)
753 {
754 return ngx_http_dav_error(r->connection->log, ngx_errno,
755 NGX_HTTP_NOT_FOUND,
756 ngx_create_dir_n, copy.path.data);
757 }
758
759 copy.len = path.len;
760
761 tree.init_handler = NULL;
762 tree.file_handler = ngx_http_dav_copy_tree_file;
763 tree.pre_tree_handler = ngx_http_dav_copy_dir;
764 tree.post_tree_handler = ngx_http_dav_copy_dir_time;
765 tree.spec_handler = ngx_http_dav_noop;
766 tree.data = &copy;
767 tree.alloc = 0;
768 tree.log = r->connection->log;
769
770 if (ngx_walk_tree(&tree, &path) == NGX_OK) {
771
772 if (r->method == NGX_HTTP_MOVE) {
773 rc = ngx_http_dav_delete_path(r, &path, 1);
774
775 if (rc != NGX_OK) {
776 return rc;
777 }
778 }
779
780 return NGX_HTTP_CREATED;
781 }
782
783 } else {
784
785 if (r->method == NGX_HTTP_MOVE) {
786 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
787 return NGX_HTTP_NO_CONTENT;
788 }
789 }
790
791 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
792
793 tree.size = ngx_file_size(&fi);
794 tree.mtime = ngx_file_mtime(&fi);
795 tree.access = dlcf->access;
796 tree.log = r->connection->log;
797
798 if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK)
799 {
800 if (r->method == NGX_HTTP_MOVE) {
801 rc = ngx_http_dav_delete_path(r, &path, 0);
802
803 if (rc != NGX_OK) {
804 return rc;
805 }
806 }
807
808 return NGX_HTTP_NO_CONTENT;
809 }
810 }
811
812 return NGX_HTTP_INTERNAL_SERVER_ERROR;
813 }
814
815
816 static ngx_int_t
817 ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
818 {
819 u_char *p, *dir;
820 size_t len;
821 ngx_http_dav_copy_ctx_t *copy;
822
823 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
824 "http copy dir: \"%s\"", path->data);
825
826 copy = ctx->data;
827
828 len = copy->path.len + path->len;
829
830 dir = ngx_alloc(len + 1, ctx->log);
831 if (dir == NULL) {
832 return NGX_ABORT;
833 }
834
835 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
836 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
837
838 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
839 "http copy dir to: \"%s\"", dir);
840
841 if (ngx_create_dir(dir, ngx_dir_access(ctx->access)) == NGX_FILE_ERROR) {
842 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_create_dir_n,
843 dir);
844 }
845
846 ngx_free(dir);
847
848 return NGX_OK;
849 }
850
851
852 static ngx_int_t
853 ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path)
854 {
855 u_char *p, *dir;
856 size_t len;
857 ngx_http_dav_copy_ctx_t *copy;
858
859 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
860 "http copy dir time: \"%s\"", path->data);
861
862 copy = ctx->data;
863
864 len = copy->path.len + path->len;
865
866 dir = ngx_alloc(len + 1, ctx->log);
867 if (dir == NULL) {
868 return NGX_ABORT;
869 }
870
871 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
872 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
873
874 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
875 "http copy dir time to: \"%s\"", dir);
876
877 #if (NGX_WIN32)
878 {
879 ngx_fd_t fd;
880
881 fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
882
883 if (fd == NGX_INVALID_FILE) {
884 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir);
885 goto failed;
886 }
887
888 if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) {
889 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
890 ngx_set_file_time_n " \"%s\" failed", dir);
891 }
892
893 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
894 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
895 ngx_close_file_n " \"%s\" failed", dir);
896 }
897 }
898
899 failed:
900
901 #else
902
903 if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) {
904 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
905 ngx_set_file_time_n " \"%s\" failed", dir);
906 }
907
908 #endif
909
910 ngx_free(dir);
911
912 return NGX_OK;
913 }
914
915
916 static ngx_int_t
917 ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
918 {
919 u_char *p, *file;
920 size_t len;
921 ngx_http_dav_copy_ctx_t *copy;
922
923 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
924 "http copy file: \"%s\"", path->data);
925
926 copy = ctx->data;
927
928 len = copy->path.len + path->len;
929
930 file = ngx_alloc(len + 1, ctx->log);
931 if (file == NULL) {
932 return NGX_ABORT;
933 }
934
935 p = ngx_cpymem(file, copy->path.data, copy->path.len);
936 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
937
938 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
939 "http copy file to: \"%s\"", file);
940
941 (void) ngx_http_dav_copy_file(ctx, path->data, file);
942
943 ngx_free(file);
944
945 return NGX_OK;
946 }
947
948
949 static ngx_int_t
950 ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to)
951 {
952 off_t size;
953 ssize_t n;
954 ngx_fd_t fd, cfd;
955 ngx_int_t rc;
956 u_char buf[NGX_HTTP_DAV_COPY_BLOCK];
957
958 fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
959
960 if (fd == NGX_INVALID_FILE) {
961 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n,
962 from);
963 return NGX_ERROR;
964 }
965
966 cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN,
967 ctx->access);
968
969 rc = NGX_ERROR;
970
971 if (cfd == NGX_INVALID_FILE) {
972 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to);
973 goto failed;
974 }
975
976 for (size = ctx->size; size > 0; size -= n) {
977
978 n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK);
979
980 if (n == NGX_FILE_ERROR) {
981 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
982 ngx_read_fd_n " \"%s\" failed", from);
983 goto failed;
984 }
985
986 if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) {
987 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
988 ngx_write_fd_n " \"%s\" failed", to);
989 goto failed;
990 }
991 }
992
993 if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) {
994 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
995 ngx_set_file_time_n " \"%s\" failed", to);
996 goto failed;
997 }
998
999 if (ngx_close_file(cfd) == NGX_FILE_ERROR) {
1000 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
1001 ngx_close_file_n " \"%s\" failed", to);
1002 goto failed;
1003 }
1004
1005 rc = NGX_OK;
1006
1007 failed:
1008
1009 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
1010 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
1011 ngx_close_file_n " \"%s\" failed", from);
1012 }
1013
1014 return rc;
1015 }
1016
1017
1018 static ngx_int_t
991 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt) 1019 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
992 { 1020 {
993 ngx_table_elt_t *depth; 1021 ngx_table_elt_t *depth;
994 1022
995 depth = r->headers_in.depth; 1023 depth = r->headers_in.depth;
1110 * set by ngx_pcalloc(): 1138 * set by ngx_pcalloc():
1111 * 1139 *
1112 * conf->methods = 0; 1140 * conf->methods = 0;
1113 */ 1141 */
1114 1142
1143 conf->min_delete_depth = NGX_CONF_UNSET;
1144 conf->access = NGX_CONF_UNSET_UINT;
1115 conf->create_full_put_path = NGX_CONF_UNSET; 1145 conf->create_full_put_path = NGX_CONF_UNSET;
1116 conf->access = NGX_CONF_UNSET_UINT;
1117 1146
1118 return conf; 1147 return conf;
1119 } 1148 }
1120 1149
1121 1150
1126 ngx_http_dav_loc_conf_t *conf = child; 1155 ngx_http_dav_loc_conf_t *conf = child;
1127 1156
1128 ngx_conf_merge_bitmask_value(conf->methods, prev->methods, 1157 ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
1129 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); 1158 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF));
1130 1159
1131 ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path, 1160 ngx_conf_merge_uint_value(conf->min_delete_depth,
1132 0); 1161 prev->min_delete_depth, 0);
1133 1162
1134 ngx_conf_merge_uint_value(conf->access, prev->access, 0600); 1163 ngx_conf_merge_uint_value(conf->access, prev->access, 0600);
1164
1165 ngx_conf_merge_value(conf->create_full_put_path,
1166 prev->create_full_put_path, 0);
1135 1167
1136 return NGX_CONF_OK; 1168 return NGX_CONF_OK;
1137 } 1169 }
1138 1170
1139 1171