| 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 |
|
|---|
| 21 | typedef 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 |
|
|---|
| 29 | typedef struct {
|
|---|
| 30 | ngx_str_t path;
|
|---|
| 31 | size_t len;
|
|---|
| 32 | } ngx_http_dav_copy_ctx_t;
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 | typedef struct {
|
|---|
| 36 | char *key;
|
|---|
| 37 | char *value;
|
|---|
| 38 | } ngx_http_dav_header;
|
|---|
| 39 |
|
|---|
| 40 | static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
|
|---|
| 41 |
|
|---|
| 42 | static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
|
|---|
| 43 | static ngx_int_t ngx_http_dav_options_handler(ngx_http_request_t *r);
|
|---|
| 44 | static void ngx_http_dav_propfind_handler(ngx_http_request_t *r);
|
|---|
| 45 | static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
|
|---|
| 46 | void *parent, void *child);
|
|---|
| 47 | static ngx_int_t ngx_http_dav_init(ngx_conf_t *cf);
|
|---|
| 48 |
|
|---|
| 49 | static 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 |
|
|---|
| 66 | static 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 |
|
|---|
| 100 | static 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 |
|
|---|
| 115 | ngx_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 |
|
|---|
| 130 | static ngx_int_t
|
|---|
| 131 | ngx_http_dav_handler(ngx_http_request_t *r)
|
|---|
| 132 | {
|
|---|
| 133 | ngx_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 |
|
|---|
| 163 | u_int
|
|---|
| 164 | ngx_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 |
|
|---|
| 179 | static ngx_int_t
|
|---|
| 180 | ngx_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 |
|
|---|
| 228 | static void
|
|---|
| 229 | ngx_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 |
|
|---|
| 243 | static ngx_int_t
|
|---|
| 244 | ngx_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 |
|
|---|
| 281 | static void *
|
|---|
| 282 | ngx_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 |
|
|---|
| 305 | static char *
|
|---|
| 306 | ngx_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 |
|
|---|
| 326 | static ngx_int_t
|
|---|
| 327 | ngx_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 | }
|
|---|