📄 mod_dav.c
字号:
return result; } /* note: doc == NULL if no request body */ if (doc && !dav_validate_root(doc, "options")) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "The \"options\" element was not found."); return HTTP_BAD_REQUEST; } /* determine which providers are available */ dav_level = "1"; if (locks_hooks != NULL) { dav_level = "1,2"; } if (binding_hooks != NULL) dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL); /* ### * MSFT Web Folders chokes if length of DAV header value > 63 characters! * To workaround that, we use separate DAV headers for versioning and * live prop provider namespace URIs. * ### */ apr_table_setn(r->headers_out, "DAV", dav_level); /* * If there is a versioning provider, generate DAV headers * for versioning options. */ if (vsn_hooks != NULL) { (*vsn_hooks->get_vsn_options)(r->pool, &vsn_options); for (t = vsn_options.first; t != NULL; t = t->next) apr_table_addn(r->headers_out, "DAV", t->text); } /* * Gather property set URIs from all the liveprop providers, * and generate a separate DAV header for each URI, to avoid * problems with long header lengths. */ uri_ary = apr_array_make(r->pool, 5, sizeof(const char *)); dav_run_gather_propsets(uri_ary); for (i = 0; i < uri_ary->nelts; ++i) { if (((char **)uri_ary->elts)[i] != NULL) apr_table_addn(r->headers_out, "DAV", ((char **)uri_ary->elts)[i]); } /* this tells MSFT products to skip looking for FrontPage extensions */ apr_table_setn(r->headers_out, "MS-Author-Via", "DAV"); /* * Determine which methods are allowed on the resource. * Three cases: resource is null (3), is lock-null (7.4), or exists. * * All cases support OPTIONS, and if there is a lock provider, LOCK. * (Lock-) null resources also support MKCOL and PUT. * Lock-null supports PROPFIND and UNLOCK. * Existing resources support lots of stuff. */ apr_table_addn(methods, "OPTIONS", ""); /* ### take into account resource type */ switch (dav_get_resource_state(r, resource)) { case DAV_RESOURCE_EXISTS: /* resource exists */ apr_table_addn(methods, "GET", ""); apr_table_addn(methods, "HEAD", ""); apr_table_addn(methods, "POST", ""); apr_table_addn(methods, "DELETE", ""); apr_table_addn(methods, "TRACE", ""); apr_table_addn(methods, "PROPFIND", ""); apr_table_addn(methods, "PROPPATCH", ""); apr_table_addn(methods, "COPY", ""); apr_table_addn(methods, "MOVE", ""); if (!resource->collection) apr_table_addn(methods, "PUT", ""); if (locks_hooks != NULL) { apr_table_addn(methods, "LOCK", ""); apr_table_addn(methods, "UNLOCK", ""); } break; case DAV_RESOURCE_LOCK_NULL: /* resource is lock-null. */ apr_table_addn(methods, "MKCOL", ""); apr_table_addn(methods, "PROPFIND", ""); apr_table_addn(methods, "PUT", ""); if (locks_hooks != NULL) { apr_table_addn(methods, "LOCK", ""); apr_table_addn(methods, "UNLOCK", ""); } break; case DAV_RESOURCE_NULL: /* resource is null. */ apr_table_addn(methods, "MKCOL", ""); apr_table_addn(methods, "PUT", ""); if (locks_hooks != NULL) apr_table_addn(methods, "LOCK", ""); break; default: /* ### internal error! */ break; } /* If there is a versioning provider, add versioning methods */ if (vsn_hooks != NULL) { if (!resource->exists) { if ((*vsn_hooks->versionable)(resource)) apr_table_addn(methods, "VERSION-CONTROL", ""); if (vsn_hooks->can_be_workspace != NULL && (*vsn_hooks->can_be_workspace)(resource)) apr_table_addn(methods, "MKWORKSPACE", ""); if (vsn_hooks->can_be_activity != NULL && (*vsn_hooks->can_be_activity)(resource)) apr_table_addn(methods, "MKACTIVITY", ""); } else if (!resource->versioned) { if ((*vsn_hooks->versionable)(resource)) apr_table_addn(methods, "VERSION-CONTROL", ""); } else if (resource->working) { apr_table_addn(methods, "CHECKIN", ""); /* ### we might not support this DeltaV option */ apr_table_addn(methods, "UNCHECKOUT", ""); } else if (vsn_hooks->add_label != NULL) { apr_table_addn(methods, "CHECKOUT", ""); apr_table_addn(methods, "LABEL", ""); } else { apr_table_addn(methods, "CHECKOUT", ""); } } /* If there is a bindings provider, see if resource is bindable */ if (binding_hooks != NULL && (*binding_hooks->is_bindable)(resource)) { apr_table_addn(methods, "BIND", ""); } /* If there is a search provider, set SEARCH in option */ if (search_hooks != NULL) { apr_table_addn(methods, "SEARCH", ""); } /* Generate the Allow header */ arr = apr_table_elts(methods); elts = (const apr_table_entry_t *)arr->elts; text_size = 0; /* first, compute total length */ for (i = 0; i < arr->nelts; ++i) { if (elts[i].key == NULL) continue; /* add 1 for comma or null */ text_size += strlen(elts[i].key) + 1; } s = allow = apr_palloc(r->pool, text_size); for (i = 0; i < arr->nelts; ++i) { if (elts[i].key == NULL) continue; if (s != allow) *s++ = ','; strcpy(s, elts[i].key); s += strlen(s); } apr_table_setn(r->headers_out, "Allow", allow); /* If there is search set_option_head function, set head */ /* DASL: <DAV:basicsearch> * DASL: <http://foo.bar.com/syntax1> * DASL: <http://akuma.com/syntax2> */ if (search_hooks != NULL && *search_hooks->set_option_head != NULL) { if ((err = (*search_hooks->set_option_head)(r)) != NULL) { return dav_handle_err(r, err, NULL); } } /* if there was no request body, then there is no response body */ if (doc == NULL) { ap_set_content_length(r, 0); /* ### this sends a Content-Type. the default OPTIONS does not. */ /* ### the default (ap_send_http_options) returns OK, but I believe * ### that is because it is the default handler and nothing else * ### will run after the thing. */ return DONE; } /* handle each options request */ for (elem = doc->root->first_child; elem != NULL; elem = elem->next) { /* check for something we recognize first */ int core_option = 0; dav_error *err = NULL; if (elem->ns == APR_XML_NS_DAV_ID) { if (strcmp(elem->name, "supported-method-set") == 0) { err = dav_gen_supported_methods(r, elem, methods, &body); core_option = 1; } else if (strcmp(elem->name, "supported-live-property-set") == 0) { err = dav_gen_supported_live_props(r, resource, elem, &body); core_option = 1; } else if (strcmp(elem->name, "supported-report-set") == 0) { err = dav_gen_supported_reports(r, resource, elem, vsn_hooks, &body); core_option = 1; } } if (err != NULL) return dav_handle_err(r, err, NULL); /* if unrecognized option, pass to versioning provider */ if (!core_option && vsn_hooks != NULL) { if ((err = (*vsn_hooks->get_option)(resource, elem, &body)) != NULL) { return dav_handle_err(r, err, NULL); } } } /* send the options response */ r->status = HTTP_OK; ap_set_content_type(r, DAV_XML_CONTENT_TYPE); /* send the headers and response body */ ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:options-response xmlns:D=\"DAV:\">" DEBUG_CR, r); for (t = body.first; t != NULL; t = t->next) ap_rputs(t->text, r); ap_rputs("</D:options-response>" DEBUG_CR, r); /* we've sent everything necessary to the client. */ return DONE;}static void dav_cache_badprops(dav_walker_ctx *ctx){ const apr_xml_elem *elem; apr_text_header hdr = { 0 }; /* just return if we built the thing already */ if (ctx->propstat_404 != NULL) { return; } apr_text_append(ctx->w.pool, &hdr, "<D:propstat>" DEBUG_CR "<D:prop>" DEBUG_CR); elem = dav_find_child(ctx->doc->root, "prop"); for (elem = elem->first_child; elem; elem = elem->next) { apr_text_append(ctx->w.pool, &hdr, apr_xml_empty_elem(ctx->w.pool, elem)); } apr_text_append(ctx->w.pool, &hdr, "</D:prop>" DEBUG_CR "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR "</D:propstat>" DEBUG_CR); ctx->propstat_404 = hdr.first;}static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype){ dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; dav_propdb *propdb; dav_get_props_result propstats = { 0 }; /* ** Note: ctx->doc can only be NULL for DAV_PROPFIND_IS_ALLPROP. Since ** dav_get_allprops() does not need to do namespace translation, ** we're okay. ** ** Note: we cast to lose the "const". The propdb won't try to change ** the resource, however, since we are opening readonly. */ err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1, ctx->doc ? ctx->doc->namespaces : NULL, &propdb); if (err != NULL) { /* ### do something with err! */ if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) { dav_get_props_result badprops = { 0 }; /* some props were expected on this collection/resource */ dav_cache_badprops(ctx); badprops.propstats = ctx->propstat_404; dav_stream_response(wres, 0, &badprops, ctx->scratchpool); } else { /* no props on this collection/resource */ dav_stream_response(wres, HTTP_OK, NULL, ctx->scratchpool); } apr_pool_clear(ctx->scratchpool); return NULL; } /* ### what to do about closing the propdb on server failure? */ if (ctx->propfind_type == DAV_PROPFIND_IS_PROP) { propstats = dav_get_props(propdb, ctx->doc); } else { dav_prop_insert what = ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP ? DAV_PROP_INSERT_VALUE : DAV_PROP_INSERT_NAME; propstats = dav_get_allprops(propdb, what); } dav_close_propdb(propdb); dav_stream_response(wres, 0, &propstats, ctx->scratchpool); /* at this point, ctx->scratchpool has been used to stream a single response. this function fully controls the pool, and thus has the right to clear it for the next iteration of this callback. */ apr_pool_clear(ctx->scratchpool); return NULL;}/* handle the PROPFIND method */static int dav_method_propfind(request_rec *r){ dav_resource *resource; int depth; dav_error *err; int result; apr_xml_doc *doc; const apr_xml_elem *child; dav_walker_ctx ctx = { { 0 } }; dav_response *multi_status; /* Ask repository module to resolve the resource */ err = dav_get_resource(r, 1 /* label_allowed */, 0 /* use_checked_in */, &resource); if (err != NULL) return dav_handle_err(r, err, NULL); if (dav_get_resource_state(r, resource) == DAV_RESOURCE_NULL) { /* Apache will supply a default error for this. */ return HTTP_NOT_FOUND; } if ((depth = dav_get_depth(r, DAV_INFINITY)) < 0) { /* dav_get_depth() supplies additional information for the * default message. */ return HTTP_BAD_REQUEST; } if (depth == DAV_INFINITY && resource->collection) { dav_dir_conf *conf; conf = (dav_dir_conf *)ap_get_module_config(r->per_dir_config, &dav_module); /* default is to DISALLOW these requests */ if (conf->allow_depthinfinity != DAV_ENABLED_ON) { return dav_error_response(r, HTTP_FORBIDDEN, apr_psprintf(r->pool,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -