Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_dav_module.c @ 4664:356c91151658 stable-1.2
Merge of r4618: rewrite escaping fix (ticket #162).
The following code resulted in incorrect escaping of uri and possible
segfault:
location / {
rewrite ^(.*) $1?c=$1;
return 200 "$uri";
}
If there were arguments in a rewrite's replacement string, and length was
actually calculated (due to duplicate captures as in the example above,
or variables present), the is_args flag was set and incorrectly copied
after length calculation. This resulted in escaping applied to the uri part
of the replacement, resulting in incorrect escaping. Additionally, buffer
was allocated without escaping expected, thus this also resulted in buffer
overrun and possible segfault.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 04 Jun 2012 11:07:19 +0000 |
parents | d620f497c50f |
children | e7467ae41626 |
rev | line source |
---|---|
633 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
633 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
1116 | 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 | |
633 | 22 |
23 typedef struct { | |
24 ngx_uint_t methods; | |
1816 | 25 ngx_uint_t access; |
26 ngx_uint_t min_delete_depth; | |
637 | 27 ngx_flag_t create_full_put_path; |
633 | 28 } ngx_http_dav_loc_conf_t; |
29 | |
30 | |
1116 | 31 typedef struct { |
32 ngx_str_t path; | |
33 size_t len; | |
34 } ngx_http_dav_copy_ctx_t; | |
35 | |
36 | |
633 | 37 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); |
1116 | 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); | |
1820 | 42 static ngx_int_t ngx_http_dav_delete_path(ngx_http_request_t *r, |
43 ngx_str_t *path, ngx_uint_t dir); | |
957 | 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); | |
1820 | 46 static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path); |
1116 | 47 |
48 static ngx_int_t ngx_http_dav_mkcol_handler(ngx_http_request_t *r, | |
49 ngx_http_dav_loc_conf_t *dlcf); | |
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); | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
55 static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
56 ngx_str_t *path); |
1116 | 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, | |
637 | 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); | |
633 | 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); | |
681 | 65 static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf); |
633 | 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 }, | |
637 | 72 { ngx_string("mkcol"), NGX_HTTP_MKCOL }, |
1116 | 73 { ngx_string("copy"), NGX_HTTP_COPY }, |
74 { ngx_string("move"), NGX_HTTP_MOVE }, | |
633 | 75 { ngx_null_string, 0 } |
76 }; | |
77 | |
78 | |
79 static ngx_command_t ngx_http_dav_commands[] = { | |
80 | |
81 { ngx_string("dav_methods"), | |
82 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | |
83 ngx_conf_set_bitmask_slot, | |
84 NGX_HTTP_LOC_CONF_OFFSET, | |
85 offsetof(ngx_http_dav_loc_conf_t, methods), | |
86 &ngx_http_dav_methods_mask }, | |
87 | |
637 | 88 { ngx_string("create_full_put_path"), |
89 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
90 ngx_conf_set_flag_slot, | |
91 NGX_HTTP_LOC_CONF_OFFSET, | |
92 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), | |
93 NULL }, | |
94 | |
1816 | 95 { ngx_string("min_delete_depth"), |
96 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
97 ngx_conf_set_num_slot, | |
98 NGX_HTTP_LOC_CONF_OFFSET, | |
99 offsetof(ngx_http_dav_loc_conf_t, min_delete_depth), | |
100 NULL }, | |
101 | |
669 | 102 { ngx_string("dav_access"), |
675 | 103 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, |
1296
9fcfca54b208
dav_access uses ngx_conf_set_access_slot()
Igor Sysoev <igor@sysoev.ru>
parents:
1289
diff
changeset
|
104 ngx_conf_set_access_slot, |
669 | 105 NGX_HTTP_LOC_CONF_OFFSET, |
1296
9fcfca54b208
dav_access uses ngx_conf_set_access_slot()
Igor Sysoev <igor@sysoev.ru>
parents:
1289
diff
changeset
|
106 offsetof(ngx_http_dav_loc_conf_t, access), |
669 | 107 NULL }, |
108 | |
633 | 109 ngx_null_command |
110 }; | |
111 | |
112 | |
667 | 113 static ngx_http_module_t ngx_http_dav_module_ctx = { |
633 | 114 NULL, /* preconfiguration */ |
681 | 115 ngx_http_dav_init, /* postconfiguration */ |
633 | 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 | |
128 ngx_module_t ngx_http_dav_module = { | |
129 NGX_MODULE_V1, | |
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 */ | |
681 | 134 NULL, /* init module */ |
633 | 135 NULL, /* init process */ |
136 NULL, /* init thread */ | |
137 NULL, /* exit thread */ | |
138 NULL, /* exit process */ | |
139 NULL, /* exit master */ | |
140 NGX_MODULE_V1_PADDING | |
141 }; | |
142 | |
143 | |
144 static ngx_int_t | |
145 ngx_http_dav_handler(ngx_http_request_t *r) | |
146 { | |
147 ngx_int_t rc; | |
148 ngx_http_dav_loc_conf_t *dlcf; | |
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] == '/') { | |
1813
d3f80e0be8fa
change status code and add log message
Igor Sysoev <igor@sysoev.ru>
parents:
1804
diff
changeset
|
161 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
4133
59b99f217c6d
Replaced "can not" with "cannot" and "could not" in a bunch of places.
Ruslan Ermilov <ru@nginx.com>
parents:
3612
diff
changeset
|
162 "cannot PUT to a collection"); |
1813
d3f80e0be8fa
change status code and add log message
Igor Sysoev <igor@sysoev.ru>
parents:
1804
diff
changeset
|
163 return NGX_HTTP_CONFLICT; |
633 | 164 } |
165 | |
166 r->request_body_in_file_only = 1; | |
167 r->request_body_in_persistent_file = 1; | |
1075
4d203f76b757
undo "client_body_in_file_only any"
Igor Sysoev <igor@sysoev.ru>
parents:
1060
diff
changeset
|
168 r->request_body_in_clean_file = 1; |
633 | 169 r->request_body_file_group_access = 1; |
637 | 170 r->request_body_file_log_level = 0; |
633 | 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 | |
1116 | 182 return ngx_http_dav_delete_handler(r); |
637 | 183 |
184 case NGX_HTTP_MKCOL: | |
185 | |
1116 | 186 return ngx_http_dav_mkcol_handler(r, dlcf); |
637 | 187 |
1116 | 188 case NGX_HTTP_COPY: |
637 | 189 |
1116 | 190 return ngx_http_dav_copy_move_handler(r); |
637 | 191 |
1116 | 192 case NGX_HTTP_MOVE: |
637 | 193 |
1116 | 194 return ngx_http_dav_copy_move_handler(r); |
633 | 195 } |
196 | |
197 return NGX_DECLINED; | |
198 } | |
199 | |
200 | |
201 static void | |
202 ngx_http_dav_put_handler(ngx_http_request_t *r) | |
203 { | |
773 | 204 size_t root; |
681 | 205 time_t date; |
637 | 206 ngx_str_t *temp, path; |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
207 ngx_uint_t status; |
637 | 208 ngx_file_info_t fi; |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
209 ngx_ext_rename_file_t ext; |
637 | 210 ngx_http_dav_loc_conf_t *dlcf; |
633 | 211 |
773 | 212 ngx_http_map_uri_to_path(r, &path, &root, 0); |
633 | 213 |
3032
524ba56ba9f7
fix copy destination name length, introduced in r3025
Igor Sysoev <igor@sysoev.ru>
parents:
3024
diff
changeset
|
214 path.len--; |
524ba56ba9f7
fix copy destination name length, introduced in r3025
Igor Sysoev <igor@sysoev.ru>
parents:
3024
diff
changeset
|
215 |
633 | 216 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
217 "http put filename: \"%s\"", path.data); | |
218 | |
219 temp = &r->request_body->temp_file->file.name; | |
220 | |
2782
4bd7825fab80
uniform ngx_file_info() interface with ngx_fd_info()
Igor Sysoev <igor@sysoev.ru>
parents:
2721
diff
changeset
|
221 if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { |
633 | 222 status = NGX_HTTP_CREATED; |
223 | |
224 } else { | |
225 status = NGX_HTTP_NO_CONTENT; | |
663 | 226 |
227 if (ngx_is_dir(&fi)) { | |
228 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, | |
229 "\"%s\" could not be created", path.data); | |
633 | 230 |
663 | 231 if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) { |
232 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | |
233 ngx_delete_file_n " \"%s\" failed", | |
234 temp->data); | |
235 } | |
236 | |
237 ngx_http_finalize_request(r, NGX_HTTP_CONFLICT); | |
238 return; | |
661 | 239 } |
637 | 240 } |
241 | |
669 | 242 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); |
243 | |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
244 ext.access = dlcf->access; |
2394
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
245 ext.path_access = dlcf->access; |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
246 ext.time = -1; |
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
247 ext.create_path = dlcf->create_full_put_path; |
1909 | 248 ext.delete_file = 1; |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
249 ext.log = r->connection->log; |
669 | 250 |
681 | 251 if (r->headers_in.date) { |
252 date = ngx_http_parse_time(r->headers_in.date->value.data, | |
253 r->headers_in.date->value.len); | |
254 | |
255 if (date != NGX_ERROR) { | |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
256 ext.time = date; |
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
257 ext.fd = r->request_body->temp_file->file.fd; |
681 | 258 } |
259 } | |
260 | |
1828
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
261 if (ngx_ext_rename_file(temp, &path, &ext) != NGX_OK) { |
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
262 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1f3c2b6607e0
use ngx_ext_rename_file() in PUT
Igor Sysoev <igor@sysoev.ru>
parents:
1825
diff
changeset
|
263 return; |
637 | 264 } |
265 | |
633 | 266 if (status == NGX_HTTP_CREATED) { |
637 | 267 if (ngx_http_dav_location(r, path.data) != NGX_OK) { |
633 | 268 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
269 return; | |
270 } | |
639 | 271 |
272 r->headers_out.content_length_n = 0; | |
633 | 273 } |
274 | |
275 r->headers_out.status = status; | |
276 r->header_only = 1; | |
277 | |
278 ngx_http_finalize_request(r, ngx_http_send_header(r)); | |
279 return; | |
280 } | |
281 | |
282 | |
637 | 283 static ngx_int_t |
1116 | 284 ngx_http_dav_delete_handler(ngx_http_request_t *r) |
285 { | |
1816 | 286 size_t root; |
287 ngx_err_t err; | |
288 ngx_int_t rc, depth; | |
289 ngx_uint_t i, d, dir; | |
290 ngx_str_t path; | |
291 ngx_file_info_t fi; | |
292 ngx_http_dav_loc_conf_t *dlcf; | |
1116 | 293 |
294 if (r->headers_in.content_length_n > 0) { | |
1815 | 295 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
296 "DELETE with body is unsupported"); | |
1116 | 297 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; |
298 } | |
299 | |
1816 | 300 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); |
301 | |
302 if (dlcf->min_delete_depth) { | |
303 d = 0; | |
304 | |
305 for (i = 0; i < r->uri.len; /* void */) { | |
306 if (r->uri.data[i++] == '/') { | |
307 if (++d >= dlcf->min_delete_depth && i < r->uri.len) { | |
308 goto ok; | |
309 } | |
310 } | |
311 } | |
312 | |
313 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
314 "insufficient URI depth:%i to DELETE", d); | |
315 return NGX_HTTP_CONFLICT; | |
316 } | |
317 | |
318 ok: | |
319 | |
1116 | 320 ngx_http_map_uri_to_path(r, &path, &root, 0); |
321 | |
322 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
323 "http delete filename: \"%s\"", path.data); | |
324 | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
325 if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { |
1815 | 326 err = ngx_errno; |
327 | |
328 rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND; | |
329 | |
330 return ngx_http_dav_error(r->connection->log, err, | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
331 rc, ngx_link_info_n, path.data); |
1116 | 332 } |
333 | |
334 if (ngx_is_dir(&fi)) { | |
335 | |
336 if (r->uri.data[r->uri.len - 1] != '/') { | |
1815 | 337 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EISDIR, |
338 "DELETE \"%s\" failed", path.data); | |
339 return NGX_HTTP_CONFLICT; | |
1116 | 340 } |
341 | |
342 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); | |
343 | |
344 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { | |
1815 | 345 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
346 "\"Depth\" header must be infinity"); | |
1116 | 347 return NGX_HTTP_BAD_REQUEST; |
348 } | |
349 | |
350 path.len -= 2; /* omit "/\0" */ | |
351 | |
352 dir = 1; | |
353 | |
354 } else { | |
355 | |
1823 | 356 /* |
357 * we do not need to test (r->uri.data[r->uri.len - 1] == '/') | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
358 * because ngx_link_info("/file/") returned NGX_ENOTDIR above |
1823 | 359 */ |
360 | |
1116 | 361 depth = ngx_http_dav_depth(r, 0); |
362 | |
363 if (depth != 0 && depth != NGX_HTTP_DAV_INFINITY_DEPTH) { | |
1815 | 364 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
365 "\"Depth\" header must be 0 or infinity"); | |
1116 | 366 return NGX_HTTP_BAD_REQUEST; |
367 } | |
368 | |
369 dir = 0; | |
370 } | |
371 | |
372 rc = ngx_http_dav_delete_path(r, &path, dir); | |
373 | |
374 if (rc == NGX_OK) { | |
375 return NGX_HTTP_NO_CONTENT; | |
376 } | |
377 | |
378 return rc; | |
379 } | |
380 | |
381 | |
382 static ngx_int_t | |
1820 | 383 ngx_http_dav_delete_path(ngx_http_request_t *r, ngx_str_t *path, ngx_uint_t dir) |
1116 | 384 { |
1820 | 385 char *failed; |
386 ngx_tree_ctx_t tree; | |
387 | |
388 if (dir) { | |
389 | |
390 tree.init_handler = NULL; | |
391 tree.file_handler = ngx_http_dav_delete_file; | |
392 tree.pre_tree_handler = ngx_http_dav_noop; | |
393 tree.post_tree_handler = ngx_http_dav_delete_dir; | |
394 tree.spec_handler = ngx_http_dav_delete_file; | |
395 tree.data = NULL; | |
396 tree.alloc = 0; | |
397 tree.log = r->connection->log; | |
398 | |
399 /* TODO: 207 */ | |
400 | |
401 if (ngx_walk_tree(&tree, path) != NGX_OK) { | |
402 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
403 } | |
404 | |
405 if (ngx_delete_dir(path->data) != NGX_FILE_ERROR) { | |
406 return NGX_OK; | |
407 } | |
408 | |
409 failed = ngx_delete_dir_n; | |
410 | |
411 } else { | |
412 | |
413 if (ngx_delete_file(path->data) != NGX_FILE_ERROR) { | |
414 return NGX_OK; | |
415 } | |
416 | |
417 failed = ngx_delete_file_n; | |
418 } | |
419 | |
420 return ngx_http_dav_error(r->connection->log, ngx_errno, | |
421 NGX_HTTP_NOT_FOUND, failed, path->data); | |
1116 | 422 } |
423 | |
424 | |
425 static ngx_int_t | |
426 ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path) | |
427 { | |
428 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
429 "http delete dir: \"%s\"", path->data); | |
430 | |
431 if (ngx_delete_dir(path->data) == NGX_FILE_ERROR) { | |
432 | |
433 /* TODO: add to 207 */ | |
434 | |
435 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_dir_n, | |
436 path->data); | |
437 } | |
438 | |
439 return NGX_OK; | |
440 } | |
441 | |
442 | |
443 static ngx_int_t | |
444 ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) | |
445 { | |
446 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
447 "http delete file: \"%s\"", path->data); | |
448 | |
449 if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { | |
450 | |
451 /* TODO: add to 207 */ | |
452 | |
453 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_delete_file_n, | |
454 path->data); | |
455 } | |
456 | |
457 return NGX_OK; | |
458 } | |
459 | |
460 | |
461 static ngx_int_t | |
1820 | 462 ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) |
463 { | |
464 return NGX_OK; | |
465 } | |
466 | |
467 | |
468 static ngx_int_t | |
1116 | 469 ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf) |
470 { | |
1819
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
471 u_char *p; |
1116 | 472 size_t root; |
473 ngx_str_t path; | |
474 | |
475 if (r->headers_in.content_length_n > 0) { | |
1819
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
476 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
477 "MKCOL with body is unsupported"); |
1116 | 478 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; |
479 } | |
480 | |
1819
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
481 if (r->uri.data[r->uri.len - 1] != '/') { |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
482 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
483 "MKCOL can create a collection only"); |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
484 return NGX_HTTP_CONFLICT; |
1116 | 485 } |
486 | |
1819
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
487 p = ngx_http_map_uri_to_path(r, &path, &root, 0); |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
488 |
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
489 *(p - 1) = '\0'; |
3182
6ddaac3e0bf7
omit '\0' from "Location" header on MKCOL request
Igor Sysoev <igor@sysoev.ru>
parents:
3161
diff
changeset
|
490 r->uri.len--; |
1116 | 491 |
492 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
493 "http mkcol path: \"%s\"", path.data); | |
494 | |
495 if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access)) | |
496 != NGX_FILE_ERROR) | |
497 { | |
498 if (ngx_http_dav_location(r, path.data) != NGX_OK) { | |
499 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
500 } | |
501 | |
502 return NGX_HTTP_CREATED; | |
503 } | |
504 | |
505 return ngx_http_dav_error(r->connection->log, ngx_errno, | |
1819
0f907513dd3c
change status code, add log message, and test collection URI
Igor Sysoev <igor@sysoev.ru>
parents:
1818
diff
changeset
|
506 NGX_HTTP_CONFLICT, ngx_create_dir_n, path.data); |
1116 | 507 } |
508 | |
509 | |
510 static ngx_int_t | |
511 ngx_http_dav_copy_move_handler(ngx_http_request_t *r) | |
512 { | |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
513 u_char *p, *host, *last, ch; |
1804
d457a1576532
several changes in server_name:
Igor Sysoev <igor@sysoev.ru>
parents:
1803
diff
changeset
|
514 size_t len, root; |
1116 | 515 ngx_err_t err; |
516 ngx_int_t rc, depth; | |
3161 | 517 ngx_uint_t overwrite, slash, dir, flags; |
518 ngx_str_t path, uri, duri, args; | |
1116 | 519 ngx_tree_ctx_t tree; |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
520 ngx_copy_file_t cf; |
1116 | 521 ngx_file_info_t fi; |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
522 ngx_table_elt_t *dest, *over; |
2394
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
523 ngx_ext_rename_file_t ext; |
1116 | 524 ngx_http_dav_copy_ctx_t copy; |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
525 ngx_http_dav_loc_conf_t *dlcf; |
1116 | 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 | |
3612
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
539 p = dest->value.data; |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
540 /* there is always '\0' even after empty header value */ |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
541 if (p[0] == '/') { |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
542 last = p + dest->value.len; |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
543 goto destination_done; |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
544 } |
f9a96545fee7
allow Destination URL without host
Igor Sysoev <igor@sysoev.ru>
parents:
3527
diff
changeset
|
545 |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
546 len = r->headers_in.server.len; |
1804
d457a1576532
several changes in server_name:
Igor Sysoev <igor@sysoev.ru>
parents:
1803
diff
changeset
|
547 |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
548 if (len == 0) { |
1804
d457a1576532
several changes in server_name:
Igor Sysoev <igor@sysoev.ru>
parents:
1803
diff
changeset
|
549 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
d457a1576532
several changes in server_name:
Igor Sysoev <igor@sysoev.ru>
parents:
1803
diff
changeset
|
550 "client sent no \"Host\" header"); |
d457a1576532
several changes in server_name:
Igor Sysoev <igor@sysoev.ru>
parents:
1803
diff
changeset
|
551 return NGX_HTTP_BAD_REQUEST; |
1116 | 552 } |
553 | |
554 #if (NGX_HTTP_SSL) | |
555 | |
556 if (r->connection->ssl) { | |
557 if (ngx_strncmp(dest->value.data, "https://", sizeof("https://") - 1) | |
558 != 0) | |
559 { | |
560 goto invalid_destination; | |
561 } | |
562 | |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
563 host = dest->value.data + sizeof("https://") - 1; |
1116 | 564 |
565 } else | |
566 #endif | |
567 { | |
568 if (ngx_strncmp(dest->value.data, "http://", sizeof("http://") - 1) | |
569 != 0) | |
570 { | |
571 goto invalid_destination; | |
572 } | |
573 | |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
574 host = dest->value.data + sizeof("http://") - 1; |
1116 | 575 } |
576 | |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
577 if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) { |
1116 | 578 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
1822
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
579 "\"Destination\" URI \"%V\" is handled by " |
1116 | 580 "different repository than the source URI", |
581 &dest->value); | |
582 return NGX_HTTP_BAD_REQUEST; | |
583 } | |
584 | |
585 last = dest->value.data + dest->value.len; | |
586 | |
2007
b9de93d804ea
*) host in request line has priority
Igor Sysoev <igor@sysoev.ru>
parents:
1909
diff
changeset
|
587 for (p = host + len; p < last; p++) { |
1116 | 588 if (*p == '/') { |
589 goto destination_done; | |
590 } | |
591 } | |
592 | |
593 invalid_destination: | |
594 | |
595 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
596 "client sent invalid \"Destination\" header: \"%V\"", | |
597 &dest->value); | |
598 return NGX_HTTP_BAD_REQUEST; | |
599 | |
600 destination_done: | |
601 | |
3161 | 602 duri.len = last - p; |
603 duri.data = p; | |
604 flags = 0; | |
605 | |
606 if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { | |
607 goto invalid_destination; | |
608 } | |
609 | |
1822
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
610 if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
611 || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
612 { |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
613 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
614 "both URI \"%V\" and \"Destination\" URI \"%V\" " |
1834
aa343f669f11
style fix: remove trailing space
Igor Sysoev <igor@sysoev.ru>
parents:
1831
diff
changeset
|
615 "should be either collections or non-collections", |
1822
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
616 &r->uri, &dest->value); |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
617 return NGX_HTTP_CONFLICT; |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
618 } |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
619 |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
620 depth = ngx_http_dav_depth(r, NGX_HTTP_DAV_INFINITY_DEPTH); |
1116 | 621 |
1822
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
622 if (depth != NGX_HTTP_DAV_INFINITY_DEPTH) { |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
623 |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
624 if (r->method == NGX_HTTP_COPY) { |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
625 if (depth != 0) { |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
626 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
627 "\"Depth\" header must be 0 or infinity"); |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
628 return NGX_HTTP_BAD_REQUEST; |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
629 } |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
630 |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
631 } else { |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
632 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
633 "\"Depth\" header must be infinity"); |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
634 return NGX_HTTP_BAD_REQUEST; |
935427c55e04
test URI/Destination collection/non-collection and Depth
Igor Sysoev <igor@sysoev.ru>
parents:
1821
diff
changeset
|
635 } |
1116 | 636 } |
1174
6be5ee17d80b
style fix: remove trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1116
diff
changeset
|
637 |
1116 | 638 over = r->headers_in.overwrite; |
639 | |
640 if (over) { | |
641 if (over->value.len == 1) { | |
642 ch = over->value.data[0]; | |
643 | |
644 if (ch == 'T' || ch == 't') { | |
645 overwrite = 1; | |
646 goto overwrite_done; | |
647 } | |
648 | |
649 if (ch == 'F' || ch == 'f') { | |
650 overwrite = 0; | |
651 goto overwrite_done; | |
652 } | |
653 | |
654 } | |
655 | |
656 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
657 "client sent invalid \"Overwrite\" header: \"%V\"", | |
658 &over->value); | |
659 return NGX_HTTP_BAD_REQUEST; | |
660 } | |
661 | |
662 overwrite = 1; | |
663 | |
664 overwrite_done: | |
665 | |
666 ngx_http_map_uri_to_path(r, &path, &root, 0); | |
667 | |
668 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
669 "http copy from: \"%s\"", path.data); | |
670 | |
671 uri = r->uri; | |
3161 | 672 r->uri = duri; |
1116 | 673 |
674 ngx_http_map_uri_to_path(r, ©.path, &root, 0); | |
675 | |
676 r->uri = uri; | |
677 | |
678 copy.path.len--; /* omit "\0" */ | |
679 | |
680 if (copy.path.data[copy.path.len - 1] == '/') { | |
681 slash = 1; | |
682 copy.path.len--; | |
683 copy.path.data[copy.path.len] = '\0'; | |
684 | |
685 } else { | |
686 slash = 0; | |
687 } | |
688 | |
689 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
690 "http copy to: \"%s\"", copy.path.data); | |
691 | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
692 if (ngx_link_info(copy.path.data, &fi) == NGX_FILE_ERROR) { |
1116 | 693 err = ngx_errno; |
694 | |
695 if (err != NGX_ENOENT) { | |
696 return ngx_http_dav_error(r->connection->log, err, | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
697 NGX_HTTP_NOT_FOUND, ngx_link_info_n, |
1116 | 698 copy.path.data); |
699 } | |
700 | |
701 /* destination does not exist */ | |
702 | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
703 overwrite = 0; |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
704 dir = 0; |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
705 |
1116 | 706 } else { |
707 | |
708 /* destination exists */ | |
709 | |
710 if (ngx_is_dir(&fi) && !slash) { | |
1824 | 711 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
712 "\"%V\" could not be %Ved to collection \"%V\"", | |
713 &r->uri, &r->method_name, &dest->value); | |
1116 | 714 return NGX_HTTP_CONFLICT; |
715 } | |
716 | |
717 if (!overwrite) { | |
1824 | 718 ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_EEXIST, |
719 "\"%s\" could not be created", copy.path.data); | |
1116 | 720 return NGX_HTTP_PRECONDITION_FAILED; |
721 } | |
722 | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
723 dir = ngx_is_dir(&fi); |
1116 | 724 } |
725 | |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
726 if (ngx_link_info(path.data, &fi) == NGX_FILE_ERROR) { |
1116 | 727 return ngx_http_dav_error(r->connection->log, ngx_errno, |
3501
423ff11e3018
use lstat() for WebDAV DELETE, COPY, and MOVE to handle symlinks
Igor Sysoev <igor@sysoev.ru>
parents:
3182
diff
changeset
|
728 NGX_HTTP_NOT_FOUND, ngx_link_info_n, |
1116 | 729 path.data); |
730 } | |
731 | |
732 if (ngx_is_dir(&fi)) { | |
733 | |
734 if (r->uri.data[r->uri.len - 1] != '/') { | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
735 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
736 "\"%V\" is collection", &r->uri); |
1116 | 737 return NGX_HTTP_BAD_REQUEST; |
738 } | |
739 | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
740 if (overwrite) { |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
741 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
742 "http delete: \"%s\"", copy.path.data); |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
743 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
744 rc = ngx_http_dav_delete_path(r, ©.path, dir); |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
745 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
746 if (rc != NGX_OK) { |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
747 return rc; |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
748 } |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
749 } |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
750 } |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
751 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
752 if (ngx_is_dir(&fi)) { |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
753 |
1116 | 754 path.len -= 2; /* omit "/\0" */ |
755 | |
756 if (r->method == NGX_HTTP_MOVE) { | |
757 if (ngx_rename_file(path.data, copy.path.data) != NGX_FILE_ERROR) { | |
758 return NGX_HTTP_CREATED; | |
759 } | |
760 } | |
761 | |
762 if (ngx_create_dir(copy.path.data, ngx_file_access(&fi)) | |
763 == NGX_FILE_ERROR) | |
764 { | |
765 return ngx_http_dav_error(r->connection->log, ngx_errno, | |
766 NGX_HTTP_NOT_FOUND, | |
767 ngx_create_dir_n, copy.path.data); | |
768 } | |
769 | |
770 copy.len = path.len; | |
771 | |
1769
a35bc4007ec3
tree.init_handler is never called
Igor Sysoev <igor@sysoev.ru>
parents:
1749
diff
changeset
|
772 tree.init_handler = NULL; |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
773 tree.file_handler = ngx_http_dav_copy_tree_file; |
1116 | 774 tree.pre_tree_handler = ngx_http_dav_copy_dir; |
775 tree.post_tree_handler = ngx_http_dav_copy_dir_time; | |
776 tree.spec_handler = ngx_http_dav_noop; | |
777 tree.data = © | |
778 tree.alloc = 0; | |
779 tree.log = r->connection->log; | |
780 | |
781 if (ngx_walk_tree(&tree, &path) == NGX_OK) { | |
782 | |
783 if (r->method == NGX_HTTP_MOVE) { | |
784 rc = ngx_http_dav_delete_path(r, &path, 1); | |
785 | |
786 if (rc != NGX_OK) { | |
787 return rc; | |
788 } | |
789 } | |
790 | |
791 return NGX_HTTP_CREATED; | |
792 } | |
793 | |
794 } else { | |
795 | |
796 if (r->method == NGX_HTTP_MOVE) { | |
2394
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
797 |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
798 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
799 |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
800 ext.access = 0; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
801 ext.path_access = dlcf->access; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
802 ext.time = -1; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
803 ext.create_path = 1; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
804 ext.delete_file = 0; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
805 ext.log = r->connection->log; |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
806 |
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
807 if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { |
1116 | 808 return NGX_HTTP_NO_CONTENT; |
809 } | |
2394
dbe746851b31
use ngx_ext_rename_file() for single file MOVE
Igor Sysoev <igor@sysoev.ru>
parents:
2049
diff
changeset
|
810 |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
811 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
1116 | 812 } |
813 | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
814 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
815 |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
816 cf.size = ngx_file_size(&fi); |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
817 cf.buf_size = 0; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
818 cf.access = dlcf->access; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
819 cf.time = ngx_file_mtime(&fi); |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
820 cf.log = r->connection->log; |
1116 | 821 |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
822 if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { |
1116 | 823 return NGX_HTTP_NO_CONTENT; |
824 } | |
825 } | |
826 | |
827 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
828 } | |
829 | |
830 | |
831 static ngx_int_t | |
832 ngx_http_dav_copy_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path) | |
833 { | |
834 u_char *p, *dir; | |
835 size_t len; | |
836 ngx_http_dav_copy_ctx_t *copy; | |
837 | |
838 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
839 "http copy dir: \"%s\"", path->data); | |
840 | |
841 copy = ctx->data; | |
842 | |
843 len = copy->path.len + path->len; | |
844 | |
845 dir = ngx_alloc(len + 1, ctx->log); | |
846 if (dir == NULL) { | |
847 return NGX_ABORT; | |
848 } | |
849 | |
850 p = ngx_cpymem(dir, copy->path.data, copy->path.len); | |
851 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1); | |
852 | |
853 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
854 "http copy dir to: \"%s\"", dir); | |
855 | |
856 if (ngx_create_dir(dir, ngx_dir_access(ctx->access)) == NGX_FILE_ERROR) { | |
857 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_create_dir_n, | |
858 dir); | |
859 } | |
860 | |
861 ngx_free(dir); | |
862 | |
863 return NGX_OK; | |
864 } | |
865 | |
866 | |
867 static ngx_int_t | |
868 ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path) | |
869 { | |
870 u_char *p, *dir; | |
871 size_t len; | |
872 ngx_http_dav_copy_ctx_t *copy; | |
873 | |
874 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
875 "http copy dir time: \"%s\"", path->data); | |
876 | |
877 copy = ctx->data; | |
878 | |
879 len = copy->path.len + path->len; | |
880 | |
881 dir = ngx_alloc(len + 1, ctx->log); | |
882 if (dir == NULL) { | |
883 return NGX_ABORT; | |
884 } | |
885 | |
886 p = ngx_cpymem(dir, copy->path.data, copy->path.len); | |
887 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1); | |
888 | |
889 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
890 "http copy dir time to: \"%s\"", dir); | |
891 | |
1803
7405719e4848
condition declarations inside blocks update missed in r1705
Igor Sysoev <igor@sysoev.ru>
parents:
1769
diff
changeset
|
892 #if (NGX_WIN32) |
7405719e4848
condition declarations inside blocks update missed in r1705
Igor Sysoev <igor@sysoev.ru>
parents:
1769
diff
changeset
|
893 { |
7405719e4848
condition declarations inside blocks update missed in r1705
Igor Sysoev <igor@sysoev.ru>
parents:
1769
diff
changeset
|
894 ngx_fd_t fd; |
1116 | 895 |
896 fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0); | |
897 | |
898 if (fd == NGX_INVALID_FILE) { | |
899 (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir); | |
900 goto failed; | |
901 } | |
902 | |
903 if (ngx_set_file_time(NULL, fd, 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 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
909 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, | |
910 ngx_close_file_n " \"%s\" failed", dir); | |
911 } | |
1803
7405719e4848
condition declarations inside blocks update missed in r1705
Igor Sysoev <igor@sysoev.ru>
parents:
1769
diff
changeset
|
912 } |
1116 | 913 |
914 failed: | |
915 | |
916 #else | |
917 | |
918 if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) { | |
919 ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, | |
920 ngx_set_file_time_n " \"%s\" failed", dir); | |
921 } | |
922 | |
923 #endif | |
924 | |
925 ngx_free(dir); | |
926 | |
927 return NGX_OK; | |
928 } | |
929 | |
930 | |
931 static ngx_int_t | |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
932 ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) |
1116 | 933 { |
934 u_char *p, *file; | |
935 size_t len; | |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
936 ngx_copy_file_t cf; |
1116 | 937 ngx_http_dav_copy_ctx_t *copy; |
938 | |
939 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
940 "http copy file: \"%s\"", path->data); | |
941 | |
942 copy = ctx->data; | |
943 | |
944 len = copy->path.len + path->len; | |
945 | |
946 file = ngx_alloc(len + 1, ctx->log); | |
947 if (file == NULL) { | |
948 return NGX_ABORT; | |
949 } | |
950 | |
951 p = ngx_cpymem(file, copy->path.data, copy->path.len); | |
952 (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1); | |
953 | |
954 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, | |
955 "http copy file to: \"%s\"", file); | |
956 | |
3024
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
957 cf.size = ctx->size; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
958 cf.buf_size = 0; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
959 cf.access = ctx->access; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
960 cf.time = ctx->mtime; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
961 cf.log = ctx->log; |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
962 |
8101d9101ed8
allow cross device temporary files atomic copying:
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
963 (void) ngx_copy_file(path->data, file, &cf); |
1825
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
964 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
965 ngx_free(file); |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
966 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
967 return NGX_OK; |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
968 } |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
969 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
970 |
2e0fbfef56d4
do not delete target until all tests will be done,
Igor Sysoev <igor@sysoev.ru>
parents:
1824
diff
changeset
|
971 static ngx_int_t |
1116 | 972 ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt) |
973 { | |
974 ngx_table_elt_t *depth; | |
1174
6be5ee17d80b
style fix: remove trailing spaces
Igor Sysoev <igor@sysoev.ru>
parents:
1116
diff
changeset
|
975 |
1116 | 976 depth = r->headers_in.depth; |
977 | |
978 if (depth == NULL) { | |
979 return dflt; | |
980 } | |
981 | |
982 if (depth->value.len == 1) { | |
983 | |
984 if (depth->value.data[0] == '0') { | |
985 return 0; | |
986 } | |
987 | |
988 if (depth->value.data[0] == '1') { | |
989 return 1; | |
990 } | |
991 | |
992 } else { | |
993 | |
994 if (depth->value.len == sizeof("infinity") - 1 | |
995 && ngx_strcmp(depth->value.data, "infinity") == 0) | |
996 { | |
997 return NGX_HTTP_DAV_INFINITY_DEPTH; | |
998 } | |
999 } | |
1000 | |
1001 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1002 "client sent invalid \"Depth\" header: \"%V\"", | |
1003 &depth->value); | |
1004 | |
1005 return NGX_HTTP_DAV_INVALID_DEPTH; | |
1006 } | |
1007 | |
1008 | |
1009 static ngx_int_t | |
1010 ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, | |
637 | 1011 char *failed, u_char *path) |
1012 { | |
1013 ngx_int_t rc; | |
1014 ngx_uint_t level; | |
1015 | |
1016 if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { | |
1017 level = NGX_LOG_ERR; | |
1018 rc = not_found; | |
1019 | |
1020 } else if (err == NGX_EACCES || err == NGX_EPERM) { | |
1021 level = NGX_LOG_ERR; | |
1022 rc = NGX_HTTP_FORBIDDEN; | |
1023 | |
1024 } else if (err == NGX_EEXIST) { | |
1025 level = NGX_LOG_ERR; | |
1026 rc = NGX_HTTP_NOT_ALLOWED; | |
1027 | |
1028 } else if (err == NGX_ENOSPC) { | |
1029 level = NGX_LOG_CRIT; | |
1030 rc = NGX_HTTP_INSUFFICIENT_STORAGE; | |
1031 | |
1032 } else { | |
1033 level = NGX_LOG_CRIT; | |
1034 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1035 } | |
1036 | |
1116 | 1037 ngx_log_error(level, log, err, "%s \"%s\" failed", failed, path); |
637 | 1038 |
1039 return rc; | |
1040 } | |
1041 | |
1042 | |
1043 static ngx_int_t | |
1044 ngx_http_dav_location(ngx_http_request_t *r, u_char *path) | |
1045 { | |
1046 u_char *location; | |
1047 ngx_http_core_loc_conf_t *clcf; | |
1048 | |
1049 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); | |
1050 if (r->headers_out.location == NULL) { | |
1051 return NGX_ERROR; | |
1052 } | |
1053 | |
1054 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
1055 | |
1056 if (!clcf->alias && clcf->root_lengths == NULL) { | |
1057 location = path + clcf->root.len; | |
1058 | |
1059 } else { | |
2049 | 1060 location = ngx_pnalloc(r->pool, r->uri.len); |
637 | 1061 if (location == NULL) { |
1062 return NGX_ERROR; | |
1063 } | |
1064 | |
1065 ngx_memcpy(location, r->uri.data, r->uri.len); | |
1066 } | |
1067 | |
1068 /* | |
1069 * we do not need to set the r->headers_out.location->hash and | |
1070 * r->headers_out.location->key fields | |
1071 */ | |
1072 | |
1073 r->headers_out.location->value.len = r->uri.len; | |
1074 r->headers_out.location->value.data = location; | |
1075 | |
1076 return NGX_OK; | |
1077 } | |
1078 | |
1079 | |
633 | 1080 static void * |
1081 ngx_http_dav_create_loc_conf(ngx_conf_t *cf) | |
1082 { | |
1083 ngx_http_dav_loc_conf_t *conf; | |
1084 | |
1085 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t)); | |
1086 if (conf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2782
diff
changeset
|
1087 return NULL; |
633 | 1088 } |
1089 | |
1090 /* | |
1091 * set by ngx_pcalloc(): | |
1092 * | |
1093 * conf->methods = 0; | |
1094 */ | |
1095 | |
1864
524831ec3e69
fix building by msvc introduced in r1817
Igor Sysoev <igor@sysoev.ru>
parents:
1834
diff
changeset
|
1096 conf->min_delete_depth = NGX_CONF_UNSET_UINT; |
1816 | 1097 conf->access = NGX_CONF_UNSET_UINT; |
637 | 1098 conf->create_full_put_path = NGX_CONF_UNSET; |
1099 | |
633 | 1100 return conf; |
1101 } | |
1102 | |
1103 | |
1104 static char * | |
1105 ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
1106 { | |
1107 ngx_http_dav_loc_conf_t *prev = parent; | |
1108 ngx_http_dav_loc_conf_t *conf = child; | |
1109 | |
1110 ngx_conf_merge_bitmask_value(conf->methods, prev->methods, | |
637 | 1111 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); |
1112 | |
1816 | 1113 ngx_conf_merge_uint_value(conf->min_delete_depth, |
1114 prev->min_delete_depth, 0); | |
633 | 1115 |
669 | 1116 ngx_conf_merge_uint_value(conf->access, prev->access, 0600); |
1117 | |
1816 | 1118 ngx_conf_merge_value(conf->create_full_put_path, |
1119 prev->create_full_put_path, 0); | |
1120 | |
633 | 1121 return NGX_CONF_OK; |
1122 } | |
1123 | |
1124 | |
1125 static ngx_int_t | |
681 | 1126 ngx_http_dav_init(ngx_conf_t *cf) |
633 | 1127 { |
1128 ngx_http_handler_pt *h; | |
1129 ngx_http_core_main_conf_t *cmcf; | |
1130 | |
681 | 1131 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); |
633 | 1132 |
1133 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); | |
1134 if (h == NULL) { | |
1135 return NGX_ERROR; | |
1136 } | |
1137 | |
1138 *h = ngx_http_dav_handler; | |
1139 | |
1140 return NGX_OK; | |
1141 } |