Ticket #7: ngx_http_dav_module.c

File ngx_http_dav_module.c, 10.5 KB (added by Marc VERRIERE, 15 years ago)

WebDav module

Line 
1
2/*
3 * Copyright (C) Igor Sysoev
4 */
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8
9#include <ngx_config.h>
10#include <ngx_core.h>
11#include <ngx_http.h>
12#define NGX_HTTP_DAV_COPY_BLOCK 65536
13
14#define NGX_HTTP_DAV_OFF 2
15#define NGX_HTTP_DAV_DEBUG 3
16
17#define NGX_HTTP_DAV_NO_DEPTH -3
18#define NGX_HTTP_DAV_INVALID_DEPTH -2
19#define NGX_HTTP_DAV_INFINITY_DEPTH -1
20
21typedef struct {
22 ngx_uint_t methods;
23 ngx_uint_t access;
24 ngx_uint_t min_delete_depth;
25 ngx_flag_t create_full_put_path;
26} ngx_http_dav_loc_conf_t;
27
28
29typedef struct {
30 ngx_str_t path;
31 size_t len;
32} ngx_http_dav_copy_ctx_t;
33
34
35typedef struct {
36 char *key;
37 char *value;
38} ngx_http_dav_header;
39
40static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
41
42static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
43static ngx_int_t ngx_http_dav_options_handler(ngx_http_request_t *r);
44static void ngx_http_dav_propfind_handler(ngx_http_request_t *r);
45static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
46 void *parent, void *child);
47static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf);
48
49static ngx_conf_bitmask_t ngx_http_dav_methods_mask[] = {
50 { ngx_string("off"), NGX_HTTP_DAV_OFF },
51 { ngx_string("put"), NGX_HTTP_PUT },
52 { ngx_string("delete"), NGX_HTTP_DELETE },
53 { ngx_string("mkcol"), NGX_HTTP_MKCOL },
54 { ngx_string("copy"), NGX_HTTP_COPY },
55 { ngx_string("move"), NGX_HTTP_MOVE },
56
57 { ngx_string("propfind"), NGX_HTTP_PROPFIND },
58 { ngx_string("proppatch"), NGX_HTTP_PROPPATCH },
59 { ngx_string("lock"), NGX_HTTP_LOCK },
60 { ngx_string("unlock"), NGX_HTTP_UNLOCK },
61 { ngx_string("options"), NGX_HTTP_OPTIONS },
62 { ngx_null_string, 0 }
63};
64
65
66static ngx_command_t ngx_http_dav_commands[] = {
67
68 { ngx_string("dav_methods"),
69 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
70 ngx_conf_set_bitmask_slot,
71 NGX_HTTP_LOC_CONF_OFFSET,
72 offsetof(ngx_http_dav_loc_conf_t, methods),
73 &ngx_http_dav_methods_mask },
74
75 { ngx_string("create_full_put_path"),
76 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
77 ngx_conf_set_flag_slot,
78 NGX_HTTP_LOC_CONF_OFFSET,
79 offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
80 NULL },
81
82 { ngx_string("min_delete_depth"),
83 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
84 ngx_conf_set_num_slot,
85 NGX_HTTP_LOC_CONF_OFFSET,
86 offsetof(ngx_http_dav_loc_conf_t, min_delete_depth),
87 NULL },
88
89 { ngx_string("dav_access"),
90 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
91 ngx_conf_set_access_slot,
92 NGX_HTTP_LOC_CONF_OFFSET,
93 offsetof(ngx_http_dav_loc_conf_t, access),
94 NULL },
95
96 ngx_null_command
97};
98
99
100static ngx_http_module_t ngx_http_dav_module_ctx = {
101 NULL, /* preconfiguration */
102 ngx_http_dav_init, /* postconfiguration */
103
104 NULL, /* create main configuration */
105 NULL, /* init main configuration */
106
107 NULL, /* create server configuration */
108 NULL, /* merge server configuration */
109
110 ngx_http_dav_create_loc_conf, /* create location configuration */
111 ngx_http_dav_merge_loc_conf /* merge location configuration */
112};
113
114
115ngx_module_t ngx_http_dav_module = {
116 NGX_MODULE_V1,
117 &ngx_http_dav_module_ctx, /* module context */
118 ngx_http_dav_commands, /* module directives */
119 NGX_HTTP_MODULE, /* module type */
120 NULL, /* init master */
121 NULL, /* init module */
122 NULL, /* init process */
123 NULL, /* init thread */
124 NULL, /* exit thread */
125 NULL, /* exit process */
126 NULL, /* exit master */
127 NGX_MODULE_V1_PADDING
128};
129
130static ngx_int_t
131ngx_http_dav_handler(ngx_http_request_t *r)
132{
133ngx_int_t rc;
134 ngx_http_dav_loc_conf_t *dlcf;
135 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
136 if (!(r->method & dlcf->methods)) {
137 return NGX_DECLINED;
138 }
139
140 switch (r->method) {
141
142 case NGX_HTTP_OPTIONS:
143
144 return ngx_http_dav_options_handler(r);
145
146 case NGX_HTTP_PROPFIND:
147
148 r->request_body_in_file_only = 1;
149 r->request_body_in_persistent_file = 1;
150 r->request_body_in_clean_file = 1;
151 r->request_body_file_group_access = 1;
152 r->request_body_file_log_level = 0;
153 rc = ngx_http_read_client_request_body(r, ngx_http_dav_propfind_handler);
154 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
155 return rc;
156 }
157 return NGX_DONE;
158 }
159
160 return NGX_OK;
161}
162
163u_int
164ngx_http_dav_extra_headers(ngx_http_request_t *r, ngx_http_dav_header headers[]){
165 u_int i;
166 ngx_table_elt_t *head;
167 for(i=0;headers[i].key != NULL;i++){
168 head = ngx_list_push(&r->headers_out.headers);
169 if (head == NULL) return NGX_ERROR;
170 head->hash = 1;
171 head->key.len = strlen(headers[i].key);
172 head->key.data = (u_char *) headers[i].key ;
173 head->value.len = strlen(headers[i].value);
174 head->value.data = (u_char*) headers[i].value;
175 }
176 return NGX_OK;
177}
178
179static ngx_int_t
180ngx_http_dav_send_request(ngx_http_request_t *r, ngx_int_t status, ngx_http_dav_header headers[], u_char *body, size_t size)
181{
182 ngx_int_t rc;
183 ngx_buf_t *b;
184 ngx_chain_t out;
185
186 /* We discard the previous body */
187 rc = ngx_http_discard_request_body(r);
188 if (rc != NGX_OK) {
189 return rc;
190 }
191
192 r->headers_out.status = status;
193 r->headers_out.content_length_n = size;
194
195 /* If there are additionnal headers, we add them */
196 if(headers != NULL) {
197 rc = ngx_http_dav_extra_headers(r, headers);
198 }
199
200 /* If body is empty, we send headers only */
201 if(size == 0){
202 r->header_only = 1;
203 return ngx_http_send_header(r);
204 }
205
206 /* We send the headers */
207 rc = ngx_http_send_header(r);
208 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
209 return rc;
210 }
211
212 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
213 if (b == NULL) {
214 return NGX_HTTP_INTERNAL_SERVER_ERROR;
215 }
216 out.buf = b;
217 out.next = NULL;
218
219 b->pos = body;
220 b->last = body + size;
221 b->memory = 1;
222 b->last_buf = 1;
223
224 /* We send the body */
225 return ngx_http_output_filter(r, &out);
226}
227
228static void
229ngx_http_dav_propfind_handler(ngx_http_request_t *r)
230{
231
232 ngx_http_dav_header headers[] = { { NULL, NULL } };
233
234 ngx_http_dav_send_request(r,NGX_HTTP_OK, headers,
235 (u_char*)"<?xml version=\"1.0\"?>\
236<multistatus xmlns:D:=\"DAV:\"><response><href>/webserv/</href><propstat><prop><getlastmodified>Tue, 16 Aug 2011 9:25:8 GMT</getlastmodified><ressourcetype><collection/></ressourcetype></prop><status>HTTP/1.1 200 OK</status></propstat><propstat><prop><getetag/><getcontentlength/><creationdate/><executable/></prop><status>HTTP/1.1 404 NOT FOUND</status></propstat></response></multistatus>",
237 strlen("<?xml version=\"1.0\"?>\
238<multistatus xmlns:D:=\"DAV:\"><response><href>/webserv/</href><propstat><prop><getlastmodified>Tue, 16 Aug 2011 9:25:8 GMT</getlastmodified><ressourcetype><collection/></ressourcetype></prop><status>HTTP/1.1 200 OK</status></propstat><propstat><prop><getetag/><getcontentlength/><creationdate/><executable/></prop><status>HTTP/1.1 404 NOT FOUND</status></propstat></response></multistatus>"));
239}
240
241
242
243static ngx_int_t
244ngx_http_dav_options_handler(ngx_http_request_t *r)
245{
246 ngx_http_dav_loc_conf_t *dlcf;
247
248 char allowed_methods[256]="";
249
250
251 dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
252 if(dlcf->methods & NGX_HTTP_GET) strcat(allowed_methods,"GET,");
253 if(dlcf->methods & NGX_HTTP_PUT) strcat(allowed_methods,"PUT,");
254 if(dlcf->methods & NGX_HTTP_HEAD) strcat(allowed_methods,"HEAD,");
255 if(dlcf->methods & NGX_HTTP_POST) strcat(allowed_methods,"POST,");
256 if(dlcf->methods & NGX_HTTP_COPY) strcat(allowed_methods,"COPY,");
257 if(dlcf->methods & NGX_HTTP_MOVE) strcat(allowed_methods,"MOVE,");
258 if(dlcf->methods & NGX_HTTP_LOCK) strcat(allowed_methods,"LOCK,");
259 if(dlcf->methods & NGX_HTTP_TRACE) strcat(allowed_methods,"TRACE,");
260 if(dlcf->methods & NGX_HTTP_MKCOL) strcat(allowed_methods,"MKCOL,");
261 if(dlcf->methods & NGX_HTTP_UNLOCK) strcat(allowed_methods,"UNLOCK,");
262 if(dlcf->methods & NGX_HTTP_DELETE) strcat(allowed_methods,"DELETE,");
263 if(dlcf->methods & NGX_HTTP_OPTIONS) strcat(allowed_methods,"OPTIONS,");
264 if(dlcf->methods & NGX_HTTP_PROPFIND) strcat(allowed_methods,"PROPFIND,");
265 if(dlcf->methods & NGX_HTTP_PROPPATCH) strcat(allowed_methods,"PROPPATCH,");
266 allowed_methods[strlen(allowed_methods)-1]='\0';
267
268 ngx_http_dav_header headers[] = {
269 { "Allow", allowed_methods },
270 { "DAV", "1"},
271 { "MS-Author-Via", "DAV" },
272 { "Keep-Alive", "timeout=15, max=100" },
273 { "Content-Type", "httpd/unix-directory" },
274 { NULL, NULL }
275 };
276
277
278 return ngx_http_dav_send_request(r,NGX_HTTP_MULTI_STATUS, headers, (u_char*)NULL, 0);
279}
280
281static void *
282ngx_http_dav_create_loc_conf(ngx_conf_t *cf)
283{
284 ngx_http_dav_loc_conf_t *conf;
285
286 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t));
287 if (conf == NULL) {
288 return NULL;
289 }
290
291 /*
292 * set by ngx_pcalloc():
293 *
294 * conf->methods = 0;
295 */
296
297 conf->min_delete_depth = NGX_CONF_UNSET_UINT;
298 conf->access = NGX_CONF_UNSET_UINT;
299 conf->create_full_put_path = NGX_CONF_UNSET;
300
301 return conf;
302}
303
304
305static char *
306ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
307{
308 ngx_http_dav_loc_conf_t *prev = parent;
309 ngx_http_dav_loc_conf_t *conf = child;
310
311 ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
312 (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF));
313
314 ngx_conf_merge_uint_value(conf->min_delete_depth,
315 prev->min_delete_depth, 0);
316
317 ngx_conf_merge_uint_value(conf->access, prev->access, 0600);
318
319 ngx_conf_merge_value(conf->create_full_put_path,
320 prev->create_full_put_path, 0);
321
322 return NGX_CONF_OK;
323}
324
325
326static ngx_int_t
327ngx_http_dav_init(ngx_conf_t *cf)
328{
329 ngx_http_handler_pt *h;
330 ngx_http_core_main_conf_t *cmcf;
331
332 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
333
334 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
335 if (h == NULL) {
336 return NGX_ERROR;
337 }
338
339 *h = ngx_http_dav_handler;
340
341 return NGX_OK;
342}