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