blob: 0cc9ae18bf00af5310ae38372cbca2d5d61e5729 [file] [log] [blame]
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001
2/*
3 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_http.h>
11
12
Igor Sysoev54736622007-02-16 12:16:25 +000013#define NGX_HTTP_DAV_OFF 2
14
15
16#define NGX_HTTP_DAV_NO_DEPTH -3
17#define NGX_HTTP_DAV_INVALID_DEPTH -2
18#define NGX_HTTP_DAV_INFINITY_DEPTH -1
19
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000020
21typedef struct {
22 ngx_uint_t methods;
Igor Sysoevb71c6902006-08-04 16:04:04 +000023 ngx_uint_t access;
Igor Sysoev8dd40532007-12-30 11:46:03 +000024 ngx_uint_t min_delete_depth;
25 ngx_flag_t create_full_put_path;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000026} ngx_http_dav_loc_conf_t;
27
28
Igor Sysoev54736622007-02-16 12:16:25 +000029typedef struct {
30 ngx_str_t path;
31 size_t len;
32} ngx_http_dav_copy_ctx_t;
33
34
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000035static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
Igor Sysoev54736622007-02-16 12:16:25 +000036
37static void ngx_http_dav_put_handler(ngx_http_request_t *r);
38
39static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r);
Igor Sysoeva27b0b72008-01-03 19:18:25 +000040static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r,
41 ngx_str_t *path, ngx_uint_t dir);
Igor Sysoev1980cc12006-12-25 12:38:44 +000042static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
43static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
Igor Sysoeva27b0b72008-01-03 19:18:25 +000044static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
Igor Sysoev54736622007-02-16 12:16:25 +000045
46static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r,
47 ngx_http_dav_loc_conf_t *dlcf);
48
49static ngx_int_t ngx_http_dav_copy_move_handler(ngx_http_request_t *r);
50static ngx_int_t ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
51static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx,
52 ngx_str_t *path);
Igor Sysoevcea90342008-01-03 21:44:38 +000053static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
54 ngx_str_t *path);
Igor Sysoev54736622007-02-16 12:16:25 +000055
Igor Sysoev54736622007-02-16 12:16:25 +000056static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
57static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
Igor Sysoev7bdb7202006-04-19 15:30:56 +000058 ngx_int_t not_found, char *failed, u_char *path);
Ruslan Ermilov19532602019-12-16 15:19:01 +030059static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000060static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
61static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
62 void *parent, void *child);
Igor Sysoevda173ab2006-08-30 10:39:17 +000063static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000064
65
66static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = {
67 { ngx_string("off"), NGX_HTTP_DAV_OFF },
68 { ngx_string("put"), NGX_HTTP_PUT },
69 { ngx_string("delete"), NGX_HTTP_DELETE },
Igor Sysoev7bdb7202006-04-19 15:30:56 +000070 { ngx_string("mkcol"), NGX_HTTP_MKCOL },
Igor Sysoev54736622007-02-16 12:16:25 +000071 { ngx_string("copy"), NGX_HTTP_COPY },
72 { ngx_string("move"), NGX_HTTP_MOVE },
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000073 { ngx_null_string, 0 }
74};
75
76
77static ngx_command_t ngx_http_dav_commands[] = {
78
79 { ngx_string("dav_methods"),
80 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
81 ngx_conf_set_bitmask_slot,
82 NGX_HTTP_LOC_CONF_OFFSET,
83 offsetof(ngx_http_dav_loc_conf_t, methods),
84 &ngx_http_dav_methods_mask },
85
Igor Sysoev7bdb7202006-04-19 15:30:56 +000086 { ngx_string("create_full_put_path"),
87 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
88 ngx_conf_set_flag_slot,
89 NGX_HTTP_LOC_CONF_OFFSET,
90 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
91 NULL },
92
Igor Sysoev8dd40532007-12-30 11:46:03 +000093 { ngx_string("min_delete_depth"),
94 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
95 ngx_conf_set_num_slot,
96 NGX_HTTP_LOC_CONF_OFFSET,
97 offsetof(ngx_http_dav_loc_conf_t, min_delete_depth),
98 NULL },
99
Igor Sysoevb71c6902006-08-04 16:04:04 +0000100 { ngx_string("dav_access"),
Igor Sysoevef316432006-08-16 13:09:33 +0000101 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
Igor Sysoev471b92e2007-07-13 08:32:12 +0000102 ngx_conf_set_access_slot,
Igor Sysoevb71c6902006-08-04 16:04:04 +0000103 NGX_HTTP_LOC_CONF_OFFSET,
Igor Sysoev471b92e2007-07-13 08:32:12 +0000104 offsetof(ngx_http_dav_loc_conf_t, access),
Igor Sysoevb71c6902006-08-04 16:04:04 +0000105 NULL },
106
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000107 ngx_null_command
108};
109
110
Igor Sysoev8f125582006-07-28 15:16:17 +0000111static ngx_http_module_t ngx_http_dav_module_ctx = {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000112 NULL, /* preconfiguration */
Igor Sysoevda173ab2006-08-30 10:39:17 +0000113 ngx_http_dav_init, /* postconfiguration */
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000114
115 NULL, /* create main configuration */
116 NULL, /* init main configuration */
117
118 NULL, /* create server configuration */
119 NULL, /* merge server configuration */
120
121 ngx_http_dav_create_loc_conf, /* create location configuration */
122 ngx_http_dav_merge_loc_conf /* merge location configuration */
123};
124
125
126ngx_module_t ngx_http_dav_module = {
127 NGX_MODULE_V1,
128 &ngx_http_dav_module_ctx, /* module context */
129 ngx_http_dav_commands, /* module directives */
130 NGX_HTTP_MODULE, /* module type */
131 NULL, /* init master */
Igor Sysoevda173ab2006-08-30 10:39:17 +0000132 NULL, /* init module */
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000133 NULL, /* init process */
134 NULL, /* init thread */
135 NULL, /* exit thread */
136 NULL, /* exit process */
137 NULL, /* exit master */
138 NGX_MODULE_V1_PADDING
139};
140
141
142static ngx_int_t
143ngx_http_dav_handler(ngx_http_request_t *r)
144{
145 ngx_int_t rc;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000146 ngx_http_dav_loc_conf_t *dlcf;
147
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000148 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
149
150 if (!(r->method & dlcf->methods)) {
151 return NGX_DECLINED;
152 }
153
154 switch (r->method) {
155
156 case NGX_HTTP_PUT:
157
158 if (r->uri.data[r->uri.len - 1] == '/') {
Igor Sysoevab325352007-12-30 09:44:02 +0000159 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Ruslan Ermilova823c552011-09-19 14:48:29 +0000160 "cannot PUT to a collection");
Igor Sysoevab325352007-12-30 09:44:02 +0000161 return NGX_HTTP_CONFLICT;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000162 }
163
Maxim Dounin692ba442016-05-16 20:37:23 +0300164 if (r->headers_in.content_range) {
165 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
166 "PUT with range is unsupported");
167 return NGX_HTTP_NOT_IMPLEMENTED;
168 }
169
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000170 r->request_body_in_file_only = 1;
171 r->request_body_in_persistent_file = 1;
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000172 r->request_body_in_clean_file = 1;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000173 r->request_body_file_group_access = 1;
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000174 r->request_body_file_log_level = 0;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000175
176 rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler);
177
178 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
179 return rc;
180 }
181
182 return NGX_DONE;
183
184 case NGX_HTTP_DELETE:
185
Igor Sysoev54736622007-02-16 12:16:25 +0000186 return ngx_http_dav_delete_handler(r);
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000187
188 case NGX_HTTP_MKCOL:
189
Igor Sysoev54736622007-02-16 12:16:25 +0000190 return ngx_http_dav_mkcol_handler(r, dlcf);
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000191
Igor Sysoev54736622007-02-16 12:16:25 +0000192 case NGX_HTTP_COPY:
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000193
Igor Sysoev54736622007-02-16 12:16:25 +0000194 return ngx_http_dav_copy_move_handler(r);
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000195
Igor Sysoev54736622007-02-16 12:16:25 +0000196 case NGX_HTTP_MOVE:
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000197
Igor Sysoev54736622007-02-16 12:16:25 +0000198 return ngx_http_dav_copy_move_handler(r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000199 }
200
201 return NGX_DECLINED;
202}
203
204
205static void
206ngx_http_dav_put_handler(ngx_http_request_t *r)
207{
Igor Sysoev0e5f86d2006-10-12 13:36:54 +0000208 size_t root;
Igor Sysoevda173ab2006-08-30 10:39:17 +0000209 time_t date;
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000210 ngx_str_t *temp, path;
Igor Sysoev81922512008-01-03 22:18:21 +0000211 ngx_uint_t status;
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000212 ngx_file_info_t fi;
Igor Sysoev81922512008-01-03 22:18:21 +0000213 ngx_ext_rename_file_t ext;
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000214 ngx_http_dav_loc_conf_t *dlcf;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000215
Roman Arutyunyanab9021f2018-02-07 16:44:29 +0300216 if (r->request_body == NULL) {
217 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
218 "PUT request body is unavailable");
219 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
220 return;
221 }
222
223 if (r->request_body->temp_file == NULL) {
224 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
225 "PUT request body must be in a file");
Maxim Dounin248bc412012-11-21 00:51:37 +0000226 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
227 return;
228 }
229
FengGubfa56732014-07-30 14:45:08 +0800230 if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
231 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
232 return;
233 }
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000234
Igor Sysoev9db33c92009-08-20 13:37:26 +0000235 path.len--;
236
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000237 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
238 "http put filename: \"%s\"", path.data);
239
240 temp = &r->request_body->temp_file->file.name;
241
Igor Sysoevef919752009-04-29 19:28:52 +0000242 if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000243 status = NGX_HTTP_CREATED;
244
245 } else {
246 status = NGX_HTTP_NO_CONTENT;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000247
Igor Sysoev1765f472006-07-07 16:33:19 +0000248 if (ngx_is_dir(&fi)) {
249 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
250 "\"%s\" could not be created", path.data);
251
252 if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
253 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
254 ngx_delete_file_n " \"%s\" failed",
255 temp->data);
256 }
257
258 ngx_http_finalize_request(r, NGX_HTTP_CONFLICT);
259 return;
Igor Sysoev3186bf52006-07-03 16:49:20 +0000260 }
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000261 }
262
Igor Sysoevb71c6902006-08-04 16:04:04 +0000263 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
264
Igor Sysoev81922512008-01-03 22:18:21 +0000265 ext.access = dlcf->access;
Igor Sysoev524f54f2008-12-10 14:53:45 +0000266 ext.path_access = dlcf->access;
Igor Sysoev81922512008-01-03 22:18:21 +0000267 ext.time = -1;
268 ext.create_path = dlcf->create_full_put_path;
Igor Sysoev34cec292008-03-03 16:32:16 +0000269 ext.delete_file = 1;
Igor Sysoev81922512008-01-03 22:18:21 +0000270 ext.log = r->connection->log;
Igor Sysoevb71c6902006-08-04 16:04:04 +0000271
Igor Sysoevda173ab2006-08-30 10:39:17 +0000272 if (r->headers_in.date) {
Maxim Dounin1e49bdf2015-06-11 20:42:31 +0300273 date = ngx_parse_http_time(r->headers_in.date->value.data,
Igor Sysoevda173ab2006-08-30 10:39:17 +0000274 r->headers_in.date->value.len);
275
276 if (date != NGX_ERROR) {
Igor Sysoev81922512008-01-03 22:18:21 +0000277 ext.time = date;
278 ext.fd = r->request_body->temp_file->file.fd;
Igor Sysoevda173ab2006-08-30 10:39:17 +0000279 }
280 }
281
Igor Sysoev81922512008-01-03 22:18:21 +0000282 if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) {
283 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
284 return;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000285 }
286
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000287 if (status == NGX_HTTP_CREATED) {
Ruslan Ermilov19532602019-12-16 15:19:01 +0300288 if (ngx_http_dav_location(r) != NGX_OK) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000289 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
290 return;
291 }
Igor Sysoev4ecb4d72006-04-21 12:06:44 +0000292
293 r->headers_out.content_length_n = 0;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000294 }
295
296 r->headers_out.status = status;
297 r->header_only = 1;
298
299 ngx_http_finalize_request(r, ngx_http_send_header(r));
300 return;
301}
302
303
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000304static ngx_int_t
Igor Sysoev54736622007-02-16 12:16:25 +0000305ngx_http_dav_delete_handler(ngx_http_request_t *r)
306{
Igor Sysoev8dd40532007-12-30 11:46:03 +0000307 size_t root;
308 ngx_err_t err;
309 ngx_int_t rc, depth;
310 ngx_uint_t i, d, dir;
311 ngx_str_t path;
312 ngx_file_info_t fi;
313 ngx_http_dav_loc_conf_t *dlcf;
Igor Sysoev54736622007-02-16 12:16:25 +0000314
Maxim Douninf8071d02019-12-23 20:39:27 +0300315 if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
Igor Sysoevb06db422007-12-30 10:24:43 +0000316 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
317 "DELETE with body is unsupported");
Igor Sysoev54736622007-02-16 12:16:25 +0000318 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
319 }
320
Igor Sysoev8dd40532007-12-30 11:46:03 +0000321 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
322
323 if (dlcf->min_delete_depth) {
324 d = 0;
325
326 for (i = 0; i < r->uri.len; /* void */) {
327 if (r->uri.data[i++] == '/') {
328 if (++d >= dlcf->min_delete_depth && i < r->uri.len) {
329 goto ok;
330 }
331 }
332 }
333
334 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
335 "insufficient URI depth:%i to DELETE", d);
336 return NGX_HTTP_CONFLICT;
337 }
338
339ok:
340
FengGubfa56732014-07-30 14:45:08 +0800341 if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
342 return NGX_HTTP_INTERNAL_SERVER_ERROR;
343 }
Igor Sysoev54736622007-02-16 12:16:25 +0000344
345 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
346 "http delete filename: \"%s\"", path.data);
347
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000348 if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) {
Igor Sysoevb06db422007-12-30 10:24:43 +0000349 err = ngx_errno;
350
351 rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND;
352
353 return ngx_http_dav_error(r->connection->log, err,
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000354 rc, ngx_link_info_n, path.data);
Igor Sysoev54736622007-02-16 12:16:25 +0000355 }
356
357 if (ngx_is_dir(&fi)) {
358
359 if (r->uri.data[r->uri.len - 1] != '/') {
Igor Sysoevb06db422007-12-30 10:24:43 +0000360 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR,
361 "DELETE \"%s\" failed", path.data);
362 return NGX_HTTP_CONFLICT;
Igor Sysoev54736622007-02-16 12:16:25 +0000363 }
364
365 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
366
367 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
Igor Sysoevb06db422007-12-30 10:24:43 +0000368 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
369 "\"Depth\" header must be infinity");
Igor Sysoev54736622007-02-16 12:16:25 +0000370 return NGX_HTTP_BAD_REQUEST;
371 }
372
373 path.len -= 2; /* omit "/\0" */
374
375 dir = 1;
376
377 } else {
378
Igor Sysoevac487bf2008-01-03 20:43:12 +0000379 /*
380 * we do not need to test (r->uri.data[r->uri.len - 1] == '/')
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000381 * because ngx_link_info("/file/") returned NGX_ENOTDIR above
Igor Sysoevac487bf2008-01-03 20:43:12 +0000382 */
383
Igor Sysoev54736622007-02-16 12:16:25 +0000384 depth = ngx_http_dav_depth(r, 0);
385
386 if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
Igor Sysoevb06db422007-12-30 10:24:43 +0000387 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
388 "\"Depth\" header must be 0 or infinity");
Igor Sysoev54736622007-02-16 12:16:25 +0000389 return NGX_HTTP_BAD_REQUEST;
390 }
391
392 dir = 0;
393 }
394
395 rc = ngx_http_dav_delete_path(r, &path, dir);
396
397 if (rc == NGX_OK) {
398 return NGX_HTTP_NO_CONTENT;
399 }
400
401 return rc;
402}
403
404
405static ngx_int_t
Igor Sysoeva27b0b72008-01-03 19:18:25 +0000406ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir)
Igor Sysoev54736622007-02-16 12:16:25 +0000407{
Igor Sysoeva27b0b72008-01-03 19:18:25 +0000408 char *failed;
409 ngx_tree_ctx_t tree;
410
411 if (dir) {
412
413 tree.init_handler = NULL;
414 tree.file_handler = ngx_http_dav_delete_file;
415 tree.pre_tree_handler = ngx_http_dav_noop;
416 tree.post_tree_handler = ngx_http_dav_delete_dir;
417 tree.spec_handler = ngx_http_dav_delete_file;
418 tree.data = NULL;
419 tree.alloc = 0;
420 tree.log = r->connection->log;
421
422 /* TODO: 207 */
423
424 if (ngx_walk_tree(&tree, path) != NGX_OK) {
425 return NGX_HTTP_INTERNAL_SERVER_ERROR;
426 }
427
428 if (ngx_delete_dir(path->data) != NGX_FILE_ERROR) {
429 return NGX_OK;
430 }
431
432 failed = ngx_delete_dir_n;
433
434 } else {
435
436 if (ngx_delete_file(path->data) != NGX_FILE_ERROR) {
437 return NGX_OK;
438 }
439
440 failed = ngx_delete_file_n;
441 }
442
443 return ngx_http_dav_error(r->connection->log, ngx_errno,
444 NGX_HTTP_NOT_FOUND, failed, path->data);
Igor Sysoev54736622007-02-16 12:16:25 +0000445}
446
447
448static ngx_int_t
449ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
450{
451 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
452 "http delete dir: \"%s\"", path->data);
453
454 if (ngx_delete_dir(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_dir_n,
459 path->data);
460 }
461
462 return NGX_OK;
463}
464
465
466static ngx_int_t
467ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
468{
469 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
470 "http delete file: \"%s\"", path->data);
471
472 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
473
474 /* TODO: add to 207 */
475
476 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_file_n,
477 path->data);
478 }
479
480 return NGX_OK;
481}
482
483
484static ngx_int_t
Igor Sysoeva27b0b72008-01-03 19:18:25 +0000485ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
486{
487 return NGX_OK;
488}
489
490
491static ngx_int_t
Igor Sysoev54736622007-02-16 12:16:25 +0000492ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
493{
Igor Sysoev369791a2008-01-03 19:13:04 +0000494 u_char *p;
Igor Sysoev54736622007-02-16 12:16:25 +0000495 size_t root;
Igor Sysoev54736622007-02-16 12:16:25 +0000496 ngx_str_t path;
497
Maxim Douninf8071d02019-12-23 20:39:27 +0300498 if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
Igor Sysoev369791a2008-01-03 19:13:04 +0000499 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
500 "MKCOL with body is unsupported");
Igor Sysoev54736622007-02-16 12:16:25 +0000501 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
502 }
503
Igor Sysoev369791a2008-01-03 19:13:04 +0000504 if (r->uri.data[r->uri.len - 1] != '/') {
505 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
506 "MKCOL can create a collection only");
507 return NGX_HTTP_CONFLICT;
Igor Sysoev54736622007-02-16 12:16:25 +0000508 }
509
Igor Sysoev369791a2008-01-03 19:13:04 +0000510 p = ngx_http_map_uri_to_path(r, &path, &root, 0);
FengGubfa56732014-07-30 14:45:08 +0800511 if (p == NULL) {
512 return NGX_HTTP_INTERNAL_SERVER_ERROR;
513 }
Igor Sysoev369791a2008-01-03 19:13:04 +0000514
515 *(p - 1) = '\0';
Igor Sysoev54736622007-02-16 12:16:25 +0000516
517 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
518 "http mkcol path: \"%s\"", path.data);
519
520 if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access))
521 != NGX_FILE_ERROR)
522 {
Ruslan Ermilov19532602019-12-16 15:19:01 +0300523 if (ngx_http_dav_location(r) != NGX_OK) {
Igor Sysoev54736622007-02-16 12:16:25 +0000524 return NGX_HTTP_INTERNAL_SERVER_ERROR;
525 }
526
527 return NGX_HTTP_CREATED;
528 }
529
530 return ngx_http_dav_error(r->connection->log, ngx_errno,
Igor Sysoev369791a2008-01-03 19:13:04 +0000531 NGX_HTTP_CONFLICT, ngx_create_dir_n, path.data);
Igor Sysoev54736622007-02-16 12:16:25 +0000532}
533
534
535static ngx_int_t
536ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
537{
Igor Sysoev5fd09312008-05-15 14:44:47 +0000538 u_char *p, *host, *last, ch;
Igor Sysoev3f24ae22007-12-29 15:30:39 +0000539 size_t len, root;
Igor Sysoev54736622007-02-16 12:16:25 +0000540 ngx_err_t err;
541 ngx_int_t rc, depth;
Igor Sysoeva552ab42009-09-25 09:30:06 +0000542 ngx_uint_t overwrite, slash, dir, flags;
543 ngx_str_t path, uri, duri, args;
Igor Sysoev54736622007-02-16 12:16:25 +0000544 ngx_tree_ctx_t tree;
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000545 ngx_copy_file_t cf;
Igor Sysoev54736622007-02-16 12:16:25 +0000546 ngx_file_info_t fi;
Igor Sysoev5fd09312008-05-15 14:44:47 +0000547 ngx_table_elt_t *dest, *over;
Igor Sysoev524f54f2008-12-10 14:53:45 +0000548 ngx_ext_rename_file_t ext;
Igor Sysoev54736622007-02-16 12:16:25 +0000549 ngx_http_dav_copy_ctx_t copy;
Igor Sysoevcea90342008-01-03 21:44:38 +0000550 ngx_http_dav_loc_conf_t *dlcf;
Igor Sysoev54736622007-02-16 12:16:25 +0000551
Maxim Douninf8071d02019-12-23 20:39:27 +0300552 if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
553 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
554 "COPY and MOVE with body are unsupported");
Igor Sysoev54736622007-02-16 12:16:25 +0000555 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
556 }
557
558 dest = r->headers_in.destination;
559
560 if (dest == NULL) {
561 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
562 "client sent no \"Destination\" header");
563 return NGX_HTTP_BAD_REQUEST;
564 }
565
Igor Sysoev34cd1cc2010-06-10 08:17:16 +0000566 p = dest->value.data;
567 /* there is always '\0' even after empty header value */
568 if (p[0] == '/') {
569 last = p + dest->value.len;
570 goto destination_done;
571 }
572
Igor Sysoev5fd09312008-05-15 14:44:47 +0000573 len = r->headers_in.server.len;
Igor Sysoev3f24ae22007-12-29 15:30:39 +0000574
Igor Sysoev5fd09312008-05-15 14:44:47 +0000575 if (len == 0) {
Igor Sysoev3f24ae22007-12-29 15:30:39 +0000576 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
577 "client sent no \"Host\" header");
578 return NGX_HTTP_BAD_REQUEST;
Igor Sysoev54736622007-02-16 12:16:25 +0000579 }
580
581#if (NGX_HTTP_SSL)
582
583 if (r->connection->ssl) {
584 if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1)
585 != 0)
586 {
587 goto invalid_destination;
588 }
589
Igor Sysoev5fd09312008-05-15 14:44:47 +0000590 host = dest->value.data + sizeof("https://") - 1;
Igor Sysoev54736622007-02-16 12:16:25 +0000591
592 } else
593#endif
594 {
595 if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1)
596 != 0)
597 {
598 goto invalid_destination;
599 }
600
Igor Sysoev5fd09312008-05-15 14:44:47 +0000601 host = dest->value.data + sizeof("http://") - 1;
Igor Sysoev54736622007-02-16 12:16:25 +0000602 }
603
Igor Sysoev5fd09312008-05-15 14:44:47 +0000604 if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) {
Igor Sysoev54736622007-02-16 12:16:25 +0000605 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Igor Sysoev58d04fe2008-01-03 20:09:51 +0000606 "\"Destination\" URI \"%V\" is handled by "
Igor Sysoev54736622007-02-16 12:16:25 +0000607 "different repository than the source URI",
608 &dest->value);
Igor Sysoev54736622007-02-16 12:16:25 +0000609 return NGX_HTTP_BAD_REQUEST;
610 }
611
612 last = dest->value.data + dest->value.len;
613
Igor Sysoev5fd09312008-05-15 14:44:47 +0000614 for (p = host + len; p < last; p++) {
Igor Sysoev54736622007-02-16 12:16:25 +0000615 if (*p == '/') {
616 goto destination_done;
617 }
618 }
619
620invalid_destination:
621
622 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
623 "client sent invalid \"Destination\" header: \"%V\"",
624 &dest->value);
Igor Sysoev54736622007-02-16 12:16:25 +0000625 return NGX_HTTP_BAD_REQUEST;
626
627destination_done:
628
Igor Sysoeva552ab42009-09-25 09:30:06 +0000629 duri.len = last - p;
630 duri.data = p;
Ruslan Ermilov9b4a99c2013-12-23 18:12:03 +0400631 flags = NGX_HTTP_LOG_UNSAFE;
Igor Sysoeva552ab42009-09-25 09:30:06 +0000632
633 if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) {
634 goto invalid_destination;
635 }
636
Igor Sysoev58d04fe2008-01-03 20:09:51 +0000637 if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/')
638 || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/'))
639 {
Ruslan Ermilov2161d8a2016-03-30 11:52:16 +0300640 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
641 "both URI \"%V\" and \"Destination\" URI \"%V\" "
642 "should be either collections or non-collections",
643 &r->uri, &dest->value);
644 return NGX_HTTP_CONFLICT;
Igor Sysoev58d04fe2008-01-03 20:09:51 +0000645 }
Igor Sysoev54736622007-02-16 12:16:25 +0000646
Igor Sysoev58d04fe2008-01-03 20:09:51 +0000647 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH);
648
649 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) {
650
651 if (r->method == NGX_HTTP_COPY) {
652 if (depth != 0) {
653 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
654 "\"Depth\" header must be 0 or infinity");
655 return NGX_HTTP_BAD_REQUEST;
656 }
657
658 } else {
659 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
660 "\"Depth\" header must be infinity");
661 return NGX_HTTP_BAD_REQUEST;
662 }
Igor Sysoev54736622007-02-16 12:16:25 +0000663 }
Igor Sysoev6d939762007-04-19 18:07:39 +0000664
Igor Sysoev54736622007-02-16 12:16:25 +0000665 over = r->headers_in.overwrite;
666
667 if (over) {
668 if (over->value.len == 1) {
669 ch = over->value.data[0];
670
671 if (ch == 'T' || ch == 't') {
672 overwrite = 1;
673 goto overwrite_done;
674 }
675
676 if (ch == 'F' || ch == 'f') {
677 overwrite = 0;
678 goto overwrite_done;
679 }
680
681 }
682
683 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
684 "client sent invalid \"Overwrite\" header: \"%V\"",
685 &over->value);
Igor Sysoev54736622007-02-16 12:16:25 +0000686 return NGX_HTTP_BAD_REQUEST;
687 }
688
689 overwrite = 1;
690
691overwrite_done:
692
FengGubfa56732014-07-30 14:45:08 +0800693 if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
694 return NGX_HTTP_INTERNAL_SERVER_ERROR;
695 }
Igor Sysoev54736622007-02-16 12:16:25 +0000696
697 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
698 "http copy from: \"%s\"", path.data);
699
700 uri = r->uri;
Igor Sysoeva552ab42009-09-25 09:30:06 +0000701 r->uri = duri;
Igor Sysoev54736622007-02-16 12:16:25 +0000702
FengGubfa56732014-07-30 14:45:08 +0800703 if (ngx_http_map_uri_to_path(r, &copy.path, &root, 0) == NULL) {
704 return NGX_HTTP_INTERNAL_SERVER_ERROR;
705 }
Igor Sysoev54736622007-02-16 12:16:25 +0000706
707 r->uri = uri;
708
709 copy.path.len--; /* omit "\0" */
710
711 if (copy.path.data[copy.path.len - 1] == '/') {
712 slash = 1;
713 copy.path.len--;
714 copy.path.data[copy.path.len] = '\0';
715
716 } else {
717 slash = 0;
718 }
719
720 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
721 "http copy to: \"%s\"", copy.path.data);
722
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000723 if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) {
Igor Sysoev54736622007-02-16 12:16:25 +0000724 err = ngx_errno;
725
726 if (err != NGX_ENOENT) {
727 return ngx_http_dav_error(r->connection->log, err,
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000728 NGX_HTTP_NOT_FOUND, ngx_link_info_n,
Igor Sysoev54736622007-02-16 12:16:25 +0000729 copy.path.data);
730 }
731
732 /* destination does not exist */
733
Igor Sysoevcea90342008-01-03 21:44:38 +0000734 overwrite = 0;
735 dir = 0;
736
Igor Sysoev54736622007-02-16 12:16:25 +0000737 } else {
738
739 /* destination exists */
740
741 if (ngx_is_dir(&fi) && !slash) {
Igor Sysoevb98f27d2008-01-03 21:29:01 +0000742 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
743 "\"%V\" could not be %Ved to collection \"%V\"",
744 &r->uri, &r->method_name, &dest->value);
Igor Sysoev54736622007-02-16 12:16:25 +0000745 return NGX_HTTP_CONFLICT;
746 }
747
748 if (!overwrite) {
Igor Sysoevb98f27d2008-01-03 21:29:01 +0000749 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST,
750 "\"%s\" could not be created", copy.path.data);
Igor Sysoev54736622007-02-16 12:16:25 +0000751 return NGX_HTTP_PRECONDITION_FAILED;
752 }
753
Igor Sysoevcea90342008-01-03 21:44:38 +0000754 dir = ngx_is_dir(&fi);
Igor Sysoev54736622007-02-16 12:16:25 +0000755 }
756
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000757 if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) {
Igor Sysoev54736622007-02-16 12:16:25 +0000758 return ngx_http_dav_error(r->connection->log, ngx_errno,
Igor Sysoev3ec15dd2010-04-22 17:15:42 +0000759 NGX_HTTP_NOT_FOUND, ngx_link_info_n,
Igor Sysoev54736622007-02-16 12:16:25 +0000760 path.data);
761 }
762
Igor Sysoev54736622007-02-16 12:16:25 +0000763 if (ngx_is_dir(&fi)) {
764
765 if (r->uri.data[r->uri.len - 1] != '/') {
Igor Sysoevcea90342008-01-03 21:44:38 +0000766 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
767 "\"%V\" is collection", &r->uri);
Igor Sysoev54736622007-02-16 12:16:25 +0000768 return NGX_HTTP_BAD_REQUEST;
769 }
770
Igor Sysoevcea90342008-01-03 21:44:38 +0000771 if (overwrite) {
772 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
773 "http delete: \"%s\"", copy.path.data);
774
775 rc = ngx_http_dav_delete_path(r, &copy.path, dir);
776
777 if (rc != NGX_OK) {
778 return rc;
779 }
780 }
781 }
782
783 if (ngx_is_dir(&fi)) {
784
Igor Sysoev54736622007-02-16 12:16:25 +0000785 path.len -= 2; /* omit "/\0" */
786
787 if (r->method == NGX_HTTP_MOVE) {
788 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) {
789 return NGX_HTTP_CREATED;
790 }
791 }
792
793 if (ngx_create_dir(copy.path.data, ngx_file_access(&fi))
794 == NGX_FILE_ERROR)
795 {
796 return ngx_http_dav_error(r->connection->log, ngx_errno,
797 NGX_HTTP_NOT_FOUND,
798 ngx_create_dir_n, copy.path.data);
799 }
800
801 copy.len = path.len;
802
Igor Sysoev465a5ff2007-12-21 17:50:49 +0000803 tree.init_handler = NULL;
Igor Sysoevcea90342008-01-03 21:44:38 +0000804 tree.file_handler = ngx_http_dav_copy_tree_file;
Igor Sysoev54736622007-02-16 12:16:25 +0000805 tree.pre_tree_handler = ngx_http_dav_copy_dir;
806 tree.post_tree_handler = ngx_http_dav_copy_dir_time;
807 tree.spec_handler = ngx_http_dav_noop;
808 tree.data = &copy;
809 tree.alloc = 0;
810 tree.log = r->connection->log;
811
812 if (ngx_walk_tree(&tree, &path) == NGX_OK) {
813
814 if (r->method == NGX_HTTP_MOVE) {
815 rc = ngx_http_dav_delete_path(r, &path, 1);
816
817 if (rc != NGX_OK) {
818 return rc;
819 }
820 }
821
822 return NGX_HTTP_CREATED;
823 }
824
825 } else {
826
Igor Sysoev54736622007-02-16 12:16:25 +0000827 if (r->method == NGX_HTTP_MOVE) {
Igor Sysoev524f54f2008-12-10 14:53:45 +0000828
829 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
830
831 ext.access = 0;
832 ext.path_access = dlcf->access;
833 ext.time = -1;
834 ext.create_path = 1;
835 ext.delete_file = 0;
Igor Sysoev524f54f2008-12-10 14:53:45 +0000836 ext.log = r->connection->log;
837
838 if (ngx_ext_rename_file(&path, &copy.path, &ext) == NGX_OK) {
Igor Sysoev54736622007-02-16 12:16:25 +0000839 return NGX_HTTP_NO_CONTENT;
840 }
Igor Sysoev524f54f2008-12-10 14:53:45 +0000841
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000842 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev54736622007-02-16 12:16:25 +0000843 }
844
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000845 cf.size = ngx_file_size(&fi);
846 cf.buf_size = 0;
Maxim Dounin93a65532018-08-01 02:12:21 +0300847 cf.access = ngx_file_access(&fi);
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000848 cf.time = ngx_file_mtime(&fi);
849 cf.log = r->connection->log;
Igor Sysoev54736622007-02-16 12:16:25 +0000850
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000851 if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) {
Igor Sysoev54736622007-02-16 12:16:25 +0000852 return NGX_HTTP_NO_CONTENT;
853 }
854 }
855
856 return NGX_HTTP_INTERNAL_SERVER_ERROR;
857}
858
859
860static ngx_int_t
861ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
862{
863 u_char *p, *dir;
864 size_t len;
865 ngx_http_dav_copy_ctx_t *copy;
866
867 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
868 "http copy dir: \"%s\"", path->data);
869
870 copy = ctx->data;
871
872 len = copy->path.len + path->len;
873
874 dir = ngx_alloc(len + 1, ctx->log);
875 if (dir == NULL) {
876 return NGX_ABORT;
877 }
878
879 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
880 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
881
882 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
883 "http copy dir to: \"%s\"", dir);
884
885 if (ngx_create_dir(dir, ngx_dir_access(ctx->access)) == NGX_FILE_ERROR) {
886 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_create_dir_n,
887 dir);
888 }
889
890 ngx_free(dir);
891
892 return NGX_OK;
893}
894
895
896static ngx_int_t
897ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path)
898{
899 u_char *p, *dir;
900 size_t len;
901 ngx_http_dav_copy_ctx_t *copy;
Igor Sysoev54736622007-02-16 12:16:25 +0000902
903 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
904 "http copy dir time: \"%s\"", path->data);
905
906 copy = ctx->data;
907
908 len = copy->path.len + path->len;
909
910 dir = ngx_alloc(len + 1, ctx->log);
911 if (dir == NULL) {
912 return NGX_ABORT;
913 }
914
915 p = ngx_cpymem(dir, copy->path.data, copy->path.len);
916 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
917
918 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
919 "http copy dir time to: \"%s\"", dir);
920
Igor Sysoev5dff77a2007-12-29 13:55:10 +0000921#if (NGX_WIN32)
922 {
923 ngx_fd_t fd;
Igor Sysoev54736622007-02-16 12:16:25 +0000924
925 fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0);
926
927 if (fd == NGX_INVALID_FILE) {
928 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir);
929 goto failed;
930 }
931
932 if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) {
933 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
934 ngx_set_file_time_n " \"%s\" failed", dir);
935 }
936
937 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
938 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
939 ngx_close_file_n " \"%s\" failed", dir);
940 }
Igor Sysoev5dff77a2007-12-29 13:55:10 +0000941 }
Igor Sysoev54736622007-02-16 12:16:25 +0000942
943failed:
944
945#else
946
947 if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) {
948 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno,
949 ngx_set_file_time_n " \"%s\" failed", dir);
950 }
951
952#endif
953
954 ngx_free(dir);
955
956 return NGX_OK;
957}
958
959
960static ngx_int_t
Igor Sysoevcea90342008-01-03 21:44:38 +0000961ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
Igor Sysoev54736622007-02-16 12:16:25 +0000962{
963 u_char *p, *file;
964 size_t len;
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000965 ngx_copy_file_t cf;
Igor Sysoev54736622007-02-16 12:16:25 +0000966 ngx_http_dav_copy_ctx_t *copy;
Igor Sysoev54736622007-02-16 12:16:25 +0000967
968 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
969 "http copy file: \"%s\"", path->data);
970
971 copy = ctx->data;
972
973 len = copy->path.len + path->len;
974
975 file = ngx_alloc(len + 1, ctx->log);
976 if (file == NULL) {
977 return NGX_ABORT;
978 }
979
980 p = ngx_cpymem(file, copy->path.data, copy->path.len);
981 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1);
982
983 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
984 "http copy file to: \"%s\"", file);
985
Igor Sysoevb7a09c52009-08-12 12:05:33 +0000986 cf.size = ctx->size;
987 cf.buf_size = 0;
988 cf.access = ctx->access;
989 cf.time = ctx->mtime;
990 cf.log = ctx->log;
991
992 (void) ngx_copy_file(path->data, file, &cf);
Igor Sysoevcea90342008-01-03 21:44:38 +0000993
994 ngx_free(file);
995
996 return NGX_OK;
997}
998
999
1000static ngx_int_t
Igor Sysoev54736622007-02-16 12:16:25 +00001001ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt)
1002{
1003 ngx_table_elt_t *depth;
Igor Sysoev6d939762007-04-19 18:07:39 +00001004
Igor Sysoev54736622007-02-16 12:16:25 +00001005 depth = r->headers_in.depth;
1006
1007 if (depth == NULL) {
1008 return dflt;
1009 }
1010
1011 if (depth->value.len == 1) {
1012
1013 if (depth->value.data[0] == '0') {
1014 return 0;
1015 }
1016
1017 if (depth->value.data[0] == '1') {
1018 return 1;
1019 }
1020
1021 } else {
1022
1023 if (depth->value.len == sizeof("infinity") - 1
1024 && ngx_strcmp(depth->value.data, "infinity") == 0)
1025 {
1026 return NGX_HTTP_DAV_INFINITY_DEPTH;
1027 }
1028 }
1029
1030 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1031 "client sent invalid \"Depth\" header: \"%V\"",
1032 &depth->value);
1033
1034 return NGX_HTTP_DAV_INVALID_DEPTH;
1035}
1036
1037
1038static ngx_int_t
1039ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found,
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001040 char *failed, u_char *path)
1041{
1042 ngx_int_t rc;
1043 ngx_uint_t level;
1044
1045 if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) {
1046 level = NGX_LOG_ERR;
1047 rc = not_found;
1048
1049 } else if (err == NGX_EACCES || err == NGX_EPERM) {
1050 level = NGX_LOG_ERR;
1051 rc = NGX_HTTP_FORBIDDEN;
1052
1053 } else if (err == NGX_EEXIST) {
1054 level = NGX_LOG_ERR;
1055 rc = NGX_HTTP_NOT_ALLOWED;
1056
1057 } else if (err == NGX_ENOSPC) {
1058 level = NGX_LOG_CRIT;
1059 rc = NGX_HTTP_INSUFFICIENT_STORAGE;
1060
1061 } else {
1062 level = NGX_LOG_CRIT;
1063 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
1064 }
1065
Igor Sysoev54736622007-02-16 12:16:25 +00001066 ngx_log_error(level, log, err, "%s \"%s\" failed", failed, path);
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001067
1068 return rc;
1069}
1070
1071
1072static ngx_int_t
Ruslan Ermilov19532602019-12-16 15:19:01 +03001073ngx_http_dav_location(ngx_http_request_t *r)
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001074{
Ruslan Ermilov0c5e1102021-05-24 21:55:20 +03001075 u_char *p;
1076 size_t len;
1077 uintptr_t escape;
1078
Ruslan Ermilov8ca190c2016-12-22 11:58:52 +03001079 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001080 if (r->headers_out.location == NULL) {
1081 return NGX_ERROR;
1082 }
1083
Ruslan Ermilov8ca190c2016-12-22 11:58:52 +03001084 r->headers_out.location->hash = 1;
1085 ngx_str_set(&r->headers_out.location->key, "Location");
Ruslan Ermilov0c5e1102021-05-24 21:55:20 +03001086
1087 escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI);
1088
1089 if (escape) {
1090 len = r->uri.len + escape;
1091
1092 p = ngx_pnalloc(r->pool, len);
1093 if (p == NULL) {
1094 ngx_http_clear_location(r);
1095 return NGX_ERROR;
1096 }
1097
1098 r->headers_out.location->value.len = len;
1099 r->headers_out.location->value.data = p;
1100
1101 ngx_escape_uri(p, r->uri.data, r->uri.len, NGX_ESCAPE_URI);
1102
1103 } else {
1104 r->headers_out.location->value = r->uri;
1105 }
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001106
1107 return NGX_OK;
1108}
1109
1110
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001111static void *
1112ngx_http_dav_create_loc_conf(ngx_conf_t *cf)
1113{
1114 ngx_http_dav_loc_conf_t *conf;
1115
1116 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t));
1117 if (conf == NULL) {
Igor Sysoev260c4322009-06-02 16:09:44 +00001118 return NULL;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001119 }
1120
1121 /*
1122 * set by ngx_pcalloc():
1123 *
1124 * conf->methods = 0;
1125 */
1126
Igor Sysoevfa0d3e12008-01-22 15:16:38 +00001127 conf->min_delete_depth = NGX_CONF_UNSET_UINT;
Igor Sysoevb71c6902006-08-04 16:04:04 +00001128 conf->access = NGX_CONF_UNSET_UINT;
Igor Sysoev8dd40532007-12-30 11:46:03 +00001129 conf->create_full_put_path = NGX_CONF_UNSET;
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001130
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001131 return conf;
1132}
1133
1134
1135static char *
1136ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1137{
1138 ngx_http_dav_loc_conf_t *prev = parent;
1139 ngx_http_dav_loc_conf_t *conf = child;
1140
1141 ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
Igor Sysoev7bdb7202006-04-19 15:30:56 +00001142 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF));
1143
Igor Sysoev8dd40532007-12-30 11:46:03 +00001144 ngx_conf_merge_uint_value(conf->min_delete_depth,
1145 prev->min_delete_depth, 0);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001146
Igor Sysoevb71c6902006-08-04 16:04:04 +00001147 ngx_conf_merge_uint_value(conf->access, prev->access, 0600);
1148
Igor Sysoev8dd40532007-12-30 11:46:03 +00001149 ngx_conf_merge_value(conf->create_full_put_path,
1150 prev->create_full_put_path, 0);
1151
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001152 return NGX_CONF_OK;
1153}
1154
1155
1156static ngx_int_t
Igor Sysoevda173ab2006-08-30 10:39:17 +00001157ngx_http_dav_init(ngx_conf_t *cf)
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001158{
1159 ngx_http_handler_pt *h;
1160 ngx_http_core_main_conf_t *cmcf;
1161
Igor Sysoevda173ab2006-08-30 10:39:17 +00001162 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +00001163
1164 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
1165 if (h == NULL) {
1166 return NGX_ERROR;
1167 }
1168
1169 *h = ngx_http_dav_handler;
1170
1171 return NGX_OK;
1172}