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