📄 mod_dav.c
字号:
/* 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", ""); } /* Generate the Allow header */ arr = apr_table_elts(methods); elts = (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 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 == AP_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) { 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; r->content_type = 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 ap_xml_elem *elem; ap_text_header hdr = { 0 }; /* just return if we built the thing already */ if (ctx->propstat_404 != NULL) { return; } ap_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) { ap_text_append(ctx->w.pool, &hdr, ap_xml_empty_elem(ctx->w.pool, elem)); } ap_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_add_response(wres, 0, &badprops); } else { /* no props on this collection/resource */ dav_add_response(wres, HTTP_OK, NULL); } 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_add_response(wres, 0, &propstats); return NULL;}/* handle the PROPFIND method */static int dav_method_propfind(request_rec *r){ dav_resource *resource; int depth; dav_error *err; int result; ap_xml_doc *doc; const ap_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, "PROPFIND requests with a " "Depth of \"infinity\" are " "not allowed for %s.", ap_escape_html(r->pool, r->uri))); } } if ((result = ap_xml_parse_input(r, &doc)) != OK) { return result; } /* note: doc == NULL if no request body */ if (doc && !dav_validate_root(doc, "propfind")) { /* This supplies additional information for the default message. */ ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "The \"propfind\" element was not found."); return HTTP_BAD_REQUEST; } /* ### validate that only one of these three elements is present */ if (doc == NULL || (child = dav_find_child(doc->root, "allprop")) != NULL) { /* note: no request body implies allprop */ ctx.propfind_type = DAV_PROPFIND_IS_ALLPROP; } else if ((child = dav_find_child(doc->root, "propname")) != NULL) { ctx.propfind_type = DAV_PROPFIND_IS_PROPNAME; } else if ((child = dav_find_child(doc->root, "prop")) != NULL) { ctx.propfind_type = DAV_PROPFIND_IS_PROP; } else { /* "propfind" element must have one of the above three children */ /* This supplies additional information for the default message. */ ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "The \"propfind\" element does not contain one of " "the required child elements (the specific command)."); return HTTP_BAD_REQUEST; } ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; ctx.w.func = dav_propfind_walker; ctx.w.walk_ctx = &ctx; ctx.w.pool = r->pool; ctx.w.root = resource; ctx.doc = doc; ctx.r = r; /* ### should open read-only */ if ((err = dav_open_lockdb(r, 0, &ctx.w.lockdb)) != NULL) { err = dav_push_error(r->pool, err->status, 0, "The lock database could not be opened, " "preventing access to the various lock " "properties for the PROPFIND.", err); return dav_handle_err(r, err, NULL); } if (ctx.w.lockdb != NULL) { /* if we have a lock database, then we can walk locknull resources */ ctx.w.walk_type |= DAV_WALKTYPE_LOCKNULL; } err = (*resource->hooks->walk)(&ctx.w, depth, &multi_status); if (ctx.w.lockdb != NULL) { (*ctx.w.lockdb->hooks->close_lockdb)(ctx.w.lockdb); } if (err != NULL) { /* ### add a higher-level description? */ return dav_handle_err(r, err, NULL); } /* return a 207 (Multi-Status) response now. */ /* if a 404 was generated for an HREF, then we need to spit out the * doc's namespaces for use by the 404. Note that <response> elements * will override these ns0, ns1, etc, but NOT within the <response> * scope for the badprops. */ /* NOTE: propstat_404 != NULL implies doc != NULL */ if (ctx.propstat_404 != NULL) { dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, doc->namespaces); } else { dav_send_multistatus(r, HTTP_MULTI_STATUS, multi_status, NULL); } /* the response has been sent. */ return DONE;}static ap_text * dav_failed_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx){ ap_text_header hdr = { 0 }; int i = prop_ctx->nelts; dav_prop_ctx *ctx = (dav_prop_ctx *)prop_ctx->elts; dav_error *err424_set = NULL; dav_error *err424_delete = NULL; const char *s; /* ### might be nice to sort by status code and description *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -