Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_dav_module.c @ 186:54aabf2b0bc6 NGINX_0_3_40
nginx 0.3.40
*) Feature: the ngx_http_dav_module supports the MKCOL method.
*) Feature: the "create_full_put_path" directive.
*) Feature: the "$limit_rate" variable.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 19 Apr 2006 00:00:00 +0400 |
parents | 13710a1813ad |
children | af37b7cb6698 |
comparison
equal
deleted
inserted
replaced
185:a9c5dc369ffe | 186:54aabf2b0bc6 |
---|---|
11 | 11 |
12 #define NGX_HTTP_DAV_OFF 2 | 12 #define NGX_HTTP_DAV_OFF 2 |
13 | 13 |
14 typedef struct { | 14 typedef struct { |
15 ngx_uint_t methods; | 15 ngx_uint_t methods; |
16 ngx_flag_t create_full_put_path; | |
16 } ngx_http_dav_loc_conf_t; | 17 } ngx_http_dav_loc_conf_t; |
17 | 18 |
18 | 19 |
19 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); | 20 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r); |
20 static void ngx_http_dav_put_handler(ngx_http_request_t *r); | 21 static void ngx_http_dav_put_handler(ngx_http_request_t *r); |
22 static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err, | |
23 ngx_int_t not_found, char *failed, u_char *path); | |
24 static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); | |
21 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); | 25 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); |
22 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, | 26 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, |
23 void *parent, void *child); | 27 void *parent, void *child); |
24 static ngx_int_t ngx_http_dav_init(ngx_cycle_t *cycle); | 28 static ngx_int_t ngx_http_dav_init(ngx_cycle_t *cycle); |
25 | 29 |
26 | 30 |
27 static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = { | 31 static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = { |
28 { ngx_string("off"), NGX_HTTP_DAV_OFF }, | 32 { ngx_string("off"), NGX_HTTP_DAV_OFF }, |
29 { ngx_string("put"), NGX_HTTP_PUT }, | 33 { ngx_string("put"), NGX_HTTP_PUT }, |
30 { ngx_string("delete"), NGX_HTTP_DELETE }, | 34 { ngx_string("delete"), NGX_HTTP_DELETE }, |
35 { ngx_string("mkcol"), NGX_HTTP_MKCOL }, | |
31 { ngx_null_string, 0 } | 36 { ngx_null_string, 0 } |
32 }; | 37 }; |
33 | 38 |
34 | 39 |
35 static ngx_command_t ngx_http_dav_commands[] = { | 40 static ngx_command_t ngx_http_dav_commands[] = { |
38 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, | 43 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, |
39 ngx_conf_set_bitmask_slot, | 44 ngx_conf_set_bitmask_slot, |
40 NGX_HTTP_LOC_CONF_OFFSET, | 45 NGX_HTTP_LOC_CONF_OFFSET, |
41 offsetof(ngx_http_dav_loc_conf_t, methods), | 46 offsetof(ngx_http_dav_loc_conf_t, methods), |
42 &ngx_http_dav_methods_mask }, | 47 &ngx_http_dav_methods_mask }, |
48 | |
49 { ngx_string("create_full_put_path"), | |
50 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
51 ngx_conf_set_flag_slot, | |
52 NGX_HTTP_LOC_CONF_OFFSET, | |
53 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path), | |
54 NULL }, | |
43 | 55 |
44 ngx_null_command | 56 ngx_null_command |
45 }; | 57 }; |
46 | 58 |
47 | 59 |
77 | 89 |
78 | 90 |
79 static ngx_int_t | 91 static ngx_int_t |
80 ngx_http_dav_handler(ngx_http_request_t *r) | 92 ngx_http_dav_handler(ngx_http_request_t *r) |
81 { | 93 { |
94 char *failed; | |
82 ngx_int_t rc; | 95 ngx_int_t rc; |
83 ngx_str_t path; | 96 ngx_str_t path; |
97 ngx_file_info_t fi; | |
84 ngx_http_dav_loc_conf_t *dlcf; | 98 ngx_http_dav_loc_conf_t *dlcf; |
85 | 99 |
86 /* TODO: Win32 */ | 100 /* TODO: Win32 */ |
87 if (r->zero_in_uri) { | 101 if (r->zero_in_uri) { |
88 return NGX_DECLINED; | 102 return NGX_DECLINED; |
98 | 112 |
99 case NGX_HTTP_PUT: | 113 case NGX_HTTP_PUT: |
100 | 114 |
101 if (r->uri.data[r->uri.len - 1] == '/') { | 115 if (r->uri.data[r->uri.len - 1] == '/') { |
102 return NGX_DECLINED; | 116 return NGX_DECLINED; |
117 } | |
118 | |
119 if (r->headers_in.content_length_n < 0) { | |
120 return NGX_HTTP_BAD_REQUEST; | |
103 } | 121 } |
104 | 122 |
105 r->request_body_in_file_only = 1; | 123 r->request_body_in_file_only = 1; |
106 r->request_body_in_persistent_file = 1; | 124 r->request_body_in_persistent_file = 1; |
107 r->request_body_delete_incomplete_file = 1; | 125 r->request_body_delete_incomplete_file = 1; |
108 r->request_body_file_group_access = 1; | 126 r->request_body_file_group_access = 1; |
127 r->request_body_file_log_level = 0; | |
109 | 128 |
110 rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler); | 129 rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler); |
111 | 130 |
112 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | 131 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { |
113 return rc; | 132 return rc; |
115 | 134 |
116 return NGX_DONE; | 135 return NGX_DONE; |
117 | 136 |
118 case NGX_HTTP_DELETE: | 137 case NGX_HTTP_DELETE: |
119 | 138 |
120 if (r->uri.data[r->uri.len - 1] == '/') { | 139 if (r->headers_in.content_length_n > 0) { |
121 return NGX_DECLINED; | 140 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; |
141 } | |
142 | |
143 rc = ngx_http_discard_body(r); | |
144 | |
145 if (rc != NGX_OK && rc != NGX_AGAIN) { | |
146 return rc; | |
122 } | 147 } |
123 | 148 |
124 ngx_http_map_uri_to_path(r, &path, 0); | 149 ngx_http_map_uri_to_path(r, &path, 0); |
125 | 150 |
126 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 151 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
127 "http delete filename: \"%s\"", path.data); | 152 "http delete filename: \"%s\"", path.data); |
128 | 153 |
129 if (ngx_delete_file(path.data) == NGX_FILE_ERROR) { | 154 if (ngx_file_info(path.data, &fi) != -1) { |
130 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, | 155 |
131 ngx_delete_file_n " \"%s\" failed", path.data); | 156 if (ngx_is_dir(&fi)) { |
132 | 157 |
133 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 158 if (r->uri.data[r->uri.len - 1] != '/' |
134 } | 159 || r->headers_in.depth == NULL |
135 | 160 || r->headers_in.depth->value.len != sizeof("infinity") - 1 |
136 return NGX_HTTP_NO_CONTENT; | 161 || ngx_strcmp(r->headers_in.depth->value.data, "infinity") |
162 != 0) | |
163 { | |
164 return NGX_HTTP_BAD_REQUEST; | |
165 } | |
166 | |
167 if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) { | |
168 return NGX_HTTP_NO_CONTENT; | |
169 } | |
170 | |
171 failed = ngx_delete_dir_n; | |
172 | |
173 } else { | |
174 | |
175 if (r->uri.data[r->uri.len - 1] == '/') { | |
176 return NGX_HTTP_BAD_REQUEST; | |
177 } | |
178 | |
179 if (r->headers_in.depth | |
180 && r->headers_in.depth->value.len == 1 | |
181 && r->headers_in.depth->value.data[0] == '1') | |
182 { | |
183 return NGX_HTTP_BAD_REQUEST; | |
184 } | |
185 | |
186 if (ngx_delete_file(path.data) != NGX_FILE_ERROR) { | |
187 return NGX_HTTP_NO_CONTENT; | |
188 } | |
189 | |
190 failed = ngx_delete_file_n; | |
191 } | |
192 | |
193 } else { | |
194 failed = ngx_file_info_n; | |
195 } | |
196 | |
197 return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_NOT_FOUND, failed, | |
198 path.data); | |
199 | |
200 case NGX_HTTP_MKCOL: | |
201 | |
202 if (r->uri.data[r->uri.len - 1] != '/') { | |
203 return NGX_DECLINED; | |
204 } | |
205 | |
206 if (r->headers_in.content_length_n > 0) { | |
207 return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; | |
208 } | |
209 | |
210 rc = ngx_http_discard_body(r); | |
211 | |
212 if (rc != NGX_OK && rc != NGX_AGAIN) { | |
213 return rc; | |
214 } | |
215 | |
216 ngx_http_map_uri_to_path(r, &path, 0); | |
217 | |
218 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
219 "http mkcol path: \"%s\"", path.data); | |
220 | |
221 if (ngx_create_dir(path.data) != NGX_FILE_ERROR) { | |
222 if (ngx_http_dav_location(r, path.data) != NGX_OK) { | |
223 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
224 } | |
225 | |
226 return NGX_HTTP_CREATED; | |
227 } | |
228 | |
229 return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_CONFLICT, | |
230 ngx_create_dir_n, path.data); | |
137 } | 231 } |
138 | 232 |
139 return NGX_DECLINED; | 233 return NGX_DECLINED; |
140 } | 234 } |
141 | 235 |
142 | 236 |
143 static void | 237 static void |
144 ngx_http_dav_put_handler(ngx_http_request_t *r) | 238 ngx_http_dav_put_handler(ngx_http_request_t *r) |
145 { | 239 { |
146 u_char *location; | 240 ngx_err_t err; |
147 ngx_err_t err; | 241 ngx_str_t *temp, path; |
148 ngx_str_t *temp, path; | 242 ngx_uint_t status; |
149 ngx_uint_t status; | 243 ngx_file_info_t fi; |
150 ngx_file_info_t fi; | 244 ngx_http_dav_loc_conf_t *dlcf; |
151 ngx_http_core_loc_conf_t *clcf; | |
152 | 245 |
153 ngx_http_map_uri_to_path(r, &path, 0); | 246 ngx_http_map_uri_to_path(r, &path, 0); |
154 | 247 |
155 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 248 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
156 "http put filename: \"%s\"", path.data); | 249 "http put filename: \"%s\"", path.data); |
162 | 255 |
163 } else { | 256 } else { |
164 status = NGX_HTTP_NO_CONTENT; | 257 status = NGX_HTTP_NO_CONTENT; |
165 } | 258 } |
166 | 259 |
260 if (ngx_is_dir(&fi)) { | |
261 ngx_http_finalize_request(r, NGX_HTTP_CONFLICT); | |
262 return; | |
263 } | |
264 | |
167 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { | 265 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { |
168 goto ok; | 266 goto ok; |
169 } | 267 } |
170 | 268 |
171 err = ngx_errno; | 269 err = ngx_errno; |
270 | |
271 if (err == NGX_ENOENT) { | |
272 | |
273 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); | |
274 | |
275 if (dlcf->create_full_put_path) { | |
276 err = ngx_create_full_path(path.data); | |
277 | |
278 if (err == 0) { | |
279 if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { | |
280 goto ok; | |
281 } | |
282 | |
283 err = ngx_errno; | |
284 } | |
285 } | |
286 } | |
172 | 287 |
173 #if (NGX_WIN32) | 288 #if (NGX_WIN32) |
174 | 289 |
175 if (err == NGX_EEXIST) { | 290 if (err == NGX_EEXIST) { |
176 if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) { | 291 if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) { |
183 err = ngx_errno; | 298 err = ngx_errno; |
184 } | 299 } |
185 | 300 |
186 #endif | 301 #endif |
187 | 302 |
188 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, | 303 ngx_http_finalize_request(r, ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT, |
189 ngx_rename_file_n " \"%s\" failed", path.data); | 304 ngx_rename_file_n, |
190 | 305 path.data)); |
191 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
192 return; | 306 return; |
193 | 307 |
194 ok: | 308 ok: |
195 | 309 |
196 if (status == NGX_HTTP_CREATED) { | 310 if (status == NGX_HTTP_CREATED) { |
197 | 311 if (ngx_http_dav_location(r, path.data) != NGX_OK) { |
198 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); | |
199 if (r->headers_out.location == NULL) { | |
200 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | 312 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
201 return; | 313 return; |
202 } | 314 } |
203 | |
204 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
205 | |
206 if (!clcf->alias && clcf->root_lengths == NULL) { | |
207 location = path.data + clcf->root.len; | |
208 | |
209 } else { | |
210 location = ngx_palloc(r->pool, r->uri.len); | |
211 if (location == NULL) { | |
212 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
213 return; | |
214 } | |
215 | |
216 ngx_memcpy(location, r->uri.data, r->uri.len); | |
217 } | |
218 | |
219 /* | |
220 * we do not need to set the r->headers_out.location->hash and | |
221 * r->headers_out.location->key fields | |
222 */ | |
223 | |
224 r->headers_out.location->value.len = r->uri.len; | |
225 r->headers_out.location->value.data = location; | |
226 | |
227 } | 315 } |
228 | 316 |
229 r->headers_out.status = status; | 317 r->headers_out.status = status; |
230 r->header_only = 1; | 318 r->header_only = 1; |
231 | 319 |
232 ngx_http_finalize_request(r, ngx_http_send_header(r)); | 320 ngx_http_finalize_request(r, ngx_http_send_header(r)); |
233 return; | 321 return; |
322 } | |
323 | |
324 | |
325 static ngx_int_t | |
326 ngx_http_dav_error(ngx_http_request_t *r, ngx_err_t err, ngx_int_t not_found, | |
327 char *failed, u_char *path) | |
328 { | |
329 ngx_int_t rc; | |
330 ngx_uint_t level; | |
331 | |
332 if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { | |
333 level = NGX_LOG_ERR; | |
334 rc = not_found; | |
335 | |
336 } else if (err == NGX_EACCES || err == NGX_EPERM) { | |
337 level = NGX_LOG_ERR; | |
338 rc = NGX_HTTP_FORBIDDEN; | |
339 | |
340 } else if (err == NGX_EEXIST) { | |
341 level = NGX_LOG_ERR; | |
342 rc = NGX_HTTP_NOT_ALLOWED; | |
343 | |
344 } else if (err == NGX_ENOSPC) { | |
345 level = NGX_LOG_CRIT; | |
346 rc = NGX_HTTP_INSUFFICIENT_STORAGE; | |
347 | |
348 } else { | |
349 level = NGX_LOG_CRIT; | |
350 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | |
351 } | |
352 | |
353 ngx_log_error(level, r->connection->log, err, | |
354 "%s \"%s\" failed", failed, path); | |
355 | |
356 return rc; | |
357 } | |
358 | |
359 | |
360 static ngx_int_t | |
361 ngx_http_dav_location(ngx_http_request_t *r, u_char *path) | |
362 { | |
363 u_char *location; | |
364 ngx_http_core_loc_conf_t *clcf; | |
365 | |
366 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); | |
367 if (r->headers_out.location == NULL) { | |
368 return NGX_ERROR; | |
369 } | |
370 | |
371 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
372 | |
373 if (!clcf->alias && clcf->root_lengths == NULL) { | |
374 location = path + clcf->root.len; | |
375 | |
376 } else { | |
377 location = ngx_palloc(r->pool, r->uri.len); | |
378 if (location == NULL) { | |
379 return NGX_ERROR; | |
380 } | |
381 | |
382 ngx_memcpy(location, r->uri.data, r->uri.len); | |
383 } | |
384 | |
385 /* | |
386 * we do not need to set the r->headers_out.location->hash and | |
387 * r->headers_out.location->key fields | |
388 */ | |
389 | |
390 r->headers_out.location->value.len = r->uri.len; | |
391 r->headers_out.location->value.data = location; | |
392 | |
393 return NGX_OK; | |
234 } | 394 } |
235 | 395 |
236 | 396 |
237 static void * | 397 static void * |
238 ngx_http_dav_create_loc_conf(ngx_conf_t *cf) | 398 ngx_http_dav_create_loc_conf(ngx_conf_t *cf) |
248 * set by ngx_pcalloc(): | 408 * set by ngx_pcalloc(): |
249 * | 409 * |
250 * conf->methods = 0; | 410 * conf->methods = 0; |
251 */ | 411 */ |
252 | 412 |
413 conf->create_full_put_path = NGX_CONF_UNSET; | |
414 | |
253 return conf; | 415 return conf; |
254 } | 416 } |
255 | 417 |
256 | 418 |
257 static char * | 419 static char * |
259 { | 421 { |
260 ngx_http_dav_loc_conf_t *prev = parent; | 422 ngx_http_dav_loc_conf_t *prev = parent; |
261 ngx_http_dav_loc_conf_t *conf = child; | 423 ngx_http_dav_loc_conf_t *conf = child; |
262 | 424 |
263 ngx_conf_merge_bitmask_value(conf->methods, prev->methods, | 425 ngx_conf_merge_bitmask_value(conf->methods, prev->methods, |
264 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); | 426 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF)); |
427 | |
428 ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path, | |
429 0); | |
265 | 430 |
266 return NGX_CONF_OK; | 431 return NGX_CONF_OK; |
267 } | 432 } |
268 | 433 |
269 | 434 |