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