From: Greg Stein Date: Sat, 20 Jan 2001 02:00:01 +0000 (+0000) Subject: - implement DeltaV OPTIONS extensions X-Git-Tag: APACHE_2_0_BETA_CANDIDATE_1~153 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b30a67812fd44d75f28d737e937195658075dc45;p=thirdparty%2Fapache%2Fhttpd.git - implement DeltaV OPTIONS extensions - let live prop providers get first crack at PROPFIND - work around MS Web Folders limit on DAV header length Submitted by: John Vasta Reviewed by: Greg Stein git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@87752 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 8ee5e839845..913067d591f 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -1717,12 +1717,11 @@ static const dav_hooks_repository dav_hooks_repository_fs = }; static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, - int propid, int insvalue, + int propid, dav_prop_insert what, ap_text_header *phdr) { const char *value; const char *s; - dav_prop_insert which; apr_pool_t *p = resource->info->pool; const dav_liveprop_spec *info; int global_ns; @@ -1806,19 +1805,23 @@ static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, /* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */ - if (insvalue) { + if (what == DAV_PROP_INSERT_VALUE) { s = apr_psprintf(p, "%s" DEBUG_CR, global_ns, info->name, value, global_ns, info->name); - which = DAV_PROP_INSERT_VALUE; } - else { + else if (what == DAV_PROP_INSERT_NAME) { s = apr_psprintf(p, "" DEBUG_CR, global_ns, info->name); - which = DAV_PROP_INSERT_NAME; + } + else { + /* assert: what == DAV_PROP_INSERT_SUPPORTED */ + s = apr_psprintf(p, "" DEBUG_CR, + info->name, dav_fs_namespace_uris[info->ns]); } ap_text_append(p, phdr, s); - /* we inserted a name or value (this prop is done) */ - return which; + /* we inserted what was asked for */ + return what; } static int dav_fs_is_writable(const dav_resource *resource, int propid) @@ -2010,7 +2013,7 @@ int dav_fs_find_liveprop(const dav_resource *resource, } void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr) + dav_prop_insert what, ap_text_header *phdr) { /* don't insert any liveprops if this isn't "our" resource */ if (resource->hooks != &dav_hooks_repository_fs) @@ -2027,13 +2030,13 @@ void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, } (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate, - insvalue, phdr); + what, phdr); (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength, - insvalue, phdr); + what, phdr); (void) dav_fs_insert_prop(resource, DAV_PROPID_getlastmodified, - insvalue, phdr); + what, phdr); (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag, - insvalue, phdr); + what, phdr); #ifndef WIN32 /* @@ -2042,7 +2045,7 @@ void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, ** well not even call it. */ (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable, - insvalue, phdr); + what, phdr); #endif /* ### we know the others aren't defined as liveprops */ diff --git a/modules/dav/fs/repos.h b/modules/dav/fs/repos.h index cfdd9dbc535..904ea3882a7 100644 --- a/modules/dav/fs/repos.h +++ b/modules/dav/fs/repos.h @@ -103,7 +103,7 @@ int dav_fs_find_liveprop(const dav_resource *resource, const char *ns_uri, const char *name, const dav_hooks_liveprop **hooks); void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr); + dav_prop_insert what, ap_text_header *phdr); void dav_fs_register(apr_pool_t *p); diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index 1657c163a81..3fe03d223be 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -1261,6 +1261,244 @@ static int dav_method_delete(request_rec *r) return HTTP_NO_CONTENT; } +/* generate DAV:supported-method-set OPTIONS response */ +static dav_error *dav_gen_supported_methods(request_rec *r, + const ap_xml_elem *elem, + const apr_table_t *methods, + ap_text_header *body) +{ + apr_array_header_t *arr; + apr_table_entry_t *elts; + ap_xml_elem *child; + ap_xml_attr *attr; + char *s; + int i; + + ap_text_append(r->pool, body, "" DEBUG_CR); + + if (elem->first_child == NULL) { + /* show all supported methods */ + arr = apr_table_elts(methods); + elts = (apr_table_entry_t *) arr->elts; + + for (i = 0; i < arr->nelts; ++i) { + if (elts[i].key == NULL) + continue; + s = apr_psprintf(r->pool, + "" DEBUG_CR, + elts[i].key); + ap_text_append(r->pool, body, s); + } + } + else { + /* check for support of specific methods */ + for (child = elem->first_child; child != NULL; child = child->next) { + if (child->ns == AP_XML_NS_DAV_ID + && strcmp(child->name, "supported-method") == 0) { + const char *name = NULL; + + /* go through attributes to find method name */ + for (attr = child->attr; attr != NULL; attr = attr->next) { + if (attr->ns == AP_XML_NS_DAV_ID + && strcmp(attr->name, "name") == 0) + name = attr->value; + } + + if (name == NULL) { + return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, + "A DAV:supported-method element " + "does not have a \"name\" attribute"); + } + + /* see if method is supported */ + if (apr_table_get(methods, name) != NULL) { + s = apr_psprintf(r->pool, + "" DEBUG_CR, + name); + ap_text_append(r->pool, body, s); + } + } + } + } + + ap_text_append(r->pool, body, "" DEBUG_CR); + return NULL; +} + +/* generate DAV:supported-live-property-set OPTIONS response */ +static dav_error *dav_gen_supported_live_props(request_rec *r, + const dav_resource *resource, + const ap_xml_elem *elem, + ap_text_header *body) +{ + dav_lockdb *lockdb; + dav_propdb *propdb; + ap_xml_elem *child; + ap_xml_attr *attr; + dav_error *err; + + /* open lock database, to report on supported lock properties */ + /* ### should open read-only */ + if ((err = dav_open_lockdb(r, 0, &lockdb)) != NULL) { + return dav_push_error(r->pool, err->status, 0, + "The lock database could not be opened, " + "preventing report of supported lock properties.", + err); + } + + /* open the property database (readonly) for the resource */ + if ((err = dav_open_propdb(r, lockdb, + (dav_resource *)resource, 1, + NULL, &propdb)) != NULL) { + if (lockdb != NULL) + (*lockdb->hooks->close_lockdb)(lockdb); + + return dav_push_error(r->pool, err->status, 0, + "The property database could not be opened, " + "preventing report of supported properties.", + err); + } + + ap_text_append(r->pool, body, "" DEBUG_CR); + + if (elem->first_child == NULL) { + /* show all supported live properties */ + dav_get_props_result props = dav_get_allprops(propdb, DAV_PROP_INSERT_SUPPORTED); + body->last->next = props.propstats; + while (body->last->next != NULL) + body->last = body->last->next; + } + else { + /* check for support of specific live property */ + for (child = elem->first_child; child != NULL; child = child->next) { + if (child->ns == AP_XML_NS_DAV_ID + && strcmp(child->name, "supported-live-property") == 0) { + const char *name = NULL; + const char *nmspace = NULL; + + /* go through attributes to find name and namespace */ + for (attr = child->attr; attr != NULL; attr = attr->next) { + if (attr->ns == AP_XML_NS_DAV_ID) { + if (strcmp(attr->name, "name") == 0) + name = attr->value; + else if (strcmp(attr->name, "namespace") == 0) + nmspace = attr->value; + } + } + + if (name == NULL) { + err = dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, + "A DAV:supported-live-property element " + "does not have a \"name\" attribute"); + break; + } + + /* default namespace to DAV: */ + if (nmspace == NULL) + nmspace = "DAV:"; + + /* check for support of property */ + dav_get_liveprop_supported(propdb, nmspace, name, body); + } + } + } + + ap_text_append(r->pool, body, "" DEBUG_CR); + + dav_close_propdb(propdb); + + if (lockdb != NULL) + (*lockdb->hooks->close_lockdb)(lockdb); + + return err; +} + +/* generate DAV:supported-report-set OPTIONS response */ +static dav_error *dav_gen_supported_reports(request_rec *r, + const dav_resource *resource, + const ap_xml_elem *elem, + const dav_hooks_vsn *vsn_hooks, + ap_text_header *body) +{ + ap_xml_elem *child; + ap_xml_attr *attr; + dav_error *err; + char *s; + + ap_text_append(r->pool, body, "" DEBUG_CR); + + if (vsn_hooks != NULL) { + const dav_report_elem *reports; + const dav_report_elem *rp; + + if ((err = (*vsn_hooks->avail_reports)(resource, &reports)) != NULL) { + return dav_push_error(r->pool, err->status, 0, + "DAV:supported-report-set could not be determined " + "due to a problem fetching the available reports " + "for this resource.", + err); + } + + if (reports != NULL) { + if (elem->first_child == NULL) { + /* show all supported reports */ + for (rp = reports; rp->nmspace != NULL; ++rp) { + /* Note: we presume reports->namespace is properly XML/URL quoted */ + s = apr_psprintf(r->pool, + "" DEBUG_CR, + rp->name, rp->nmspace); + ap_text_append(r->pool, body, s); + } + } + else { + /* check for support of specific report */ + for (child = elem->first_child; child != NULL; child = child->next) { + if (child->ns == AP_XML_NS_DAV_ID + && strcmp(child->name, "supported-report") == 0) { + const char *name = NULL; + const char *nmspace = NULL; + + /* go through attributes to find name and namespace */ + for (attr = child->attr; attr != NULL; attr = attr->next) { + if (attr->ns == AP_XML_NS_DAV_ID) { + if (strcmp(attr->name, "name") == 0) + name = attr->value; + else if (strcmp(attr->name, "namespace") == 0) + nmspace = attr->value; + } + } + + if (name == NULL) { + return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, + "A DAV:supported-report element " + "does not have a \"name\" attribute"); + } + + /* default namespace to DAV: */ + if (nmspace == NULL) + nmspace = "DAV:"; + + for (rp = reports; rp->nmspace != NULL; ++rp) { + if (strcmp(name, rp->name) == 0 + && strcmp(nmspace, rp->nmspace) == 0) { + /* Note: we presume reports->nmspace is properly XML/URL quoted */ + s = apr_psprintf(r->pool, + "" DEBUG_CR, + rp->name, rp->nmspace); + ap_text_append(r->pool, body, s); + break; + } + } + } + } + } + } + } + + ap_text_append(r->pool, body, "" DEBUG_CR); + return NULL; +} + /* handle the OPTIONS method */ static int dav_method_options(request_rec *r) { @@ -1268,153 +1506,271 @@ static int dav_method_options(request_rec *r) const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r); dav_resource *resource; - const char *options; const char *dav_level; - const char *vsn_level; + char *allow; + char *s; + apr_array_header_t *arr; + apr_table_entry_t *elts; + apr_table_t *methods = apr_make_table(r->pool, 12); + ap_text_header vsn_options = { 0 }; + ap_text_header body = { 0 }; + ap_text *t; + int text_size; int result; + int i; apr_array_header_t *uri_ary; - const char *uris; - - /* per HTTP/1.1 S9.2, we can discard this body */ - if ((result = ap_discard_request_body(r)) != OK) { - return result; - } - - /* no body */ - ap_set_content_length(r, 0); + ap_xml_doc *doc; + const ap_xml_elem *elem; /* resolve the resource */ result = dav_get_resource(r, 0 /*target_allowed*/, NULL, &resource); if (result != OK) return result; + /* parse any request body */ + if ((result = ap_xml_parse_input(r, &doc)) != OK) { + return result; + } + /* note: doc == NULL if no request body */ + + if (doc && !dav_validate_root(doc, "options")) { + ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, + "The \"options\" element was not found."); + return HTTP_BAD_REQUEST; + } + /* determine which providers are available */ dav_level = "1"; - vsn_level = NULL; if (locks_hooks != NULL) { dav_level = "1,2"; } - if (vsn_hooks != NULL - && (vsn_level = (*vsn_hooks->get_vsn_header)()) != NULL) { - dav_level = apr_pstrcat(r->pool, dav_level, ",", vsn_level, NULL); + 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 */ + /* + ** 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_make_array(r->pool, 5, sizeof(const char *)); dav_run_gather_propsets(uri_ary); - uris = apr_array_pstrcat(r->pool, uri_ary, ','); - if (*uris) { - dav_level = apr_pstrcat(r->pool, dav_level, ",", uris, NULL); + 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 LOCK. + ** All cases support OPTIONS, and if there is a lock provider, LOCK. ** (Lock-) null resources also support MKCOL and PUT. - ** Lock-null support PROPFIND and UNLOCK. + ** 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 */ - if (resource->collection) { - options = apr_pstrcat(r->pool, - "OPTIONS, " - "GET, HEAD, POST, DELETE, TRACE, " - "PROPFIND, PROPPATCH, COPY, MOVE", - locks_hooks != NULL ? ", LOCK, UNLOCK" : "", - NULL); - } - else { - /* files also support PUT */ - options = apr_pstrcat(r->pool, - "OPTIONS, " - "GET, HEAD, POST, DELETE, TRACE, " - "PROPFIND, PROPPATCH, COPY, MOVE, PUT", - locks_hooks != NULL ? ", LOCK, UNLOCK" : "", - NULL); - } - break; + 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. */ - options = apr_pstrcat(r->pool, "OPTIONS, MKCOL, PUT, PROPFIND", - locks_hooks != NULL ? ", LOCK, UNLOCK" : "", - NULL); - break; + 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. */ - options = apr_pstrcat(r->pool, "OPTIONS, MKCOL, PUT", - locks_hooks != NULL ? ", LOCK" : "", - NULL); - break; + apr_table_addn(methods, "MKCOL", ""); + apr_table_addn(methods, "PUT", ""); + + if (locks_hooks != NULL) + apr_table_addn(methods, "LOCK", ""); + + break; default: /* ### internal error! */ - options = "OPTIONS"; break; } - /* If there is a versioning provider, add versioning options */ + /* If there is a versioning provider, add versioning methods */ if (vsn_hooks != NULL) { - const char *vsn_options = NULL; - if (!resource->exists) { - int vsn_control = (*vsn_hooks->versionable)(resource); - int mkworkspace = vsn_hooks->can_be_workspace != NULL - && (*vsn_hooks->can_be_workspace)(resource); + if ((*vsn_hooks->versionable)(resource)) + apr_table_addn(methods, "VERSION-CONTROL", ""); - if (vsn_control && mkworkspace) { - vsn_options = ", VERSION-CONTROL, MKWORKSPACE"; - } - else if (vsn_control) - vsn_options = ", VERSION-CONTROL"; - else if (mkworkspace) { - vsn_options = ", MKWORKSPACE"; - } + if (vsn_hooks->can_be_workspace != NULL + && (*vsn_hooks->can_be_workspace)(resource)) + apr_table_addn(methods, "MKWORKSPACE", ""); } else if (!resource->versioned) { - if ((*vsn_hooks->versionable)(resource)) { - vsn_options = ", VERSION-CONTROL"; - } + if ((*vsn_hooks->versionable)(resource)) + apr_table_addn(methods, "VERSION-CONTROL", ""); + } + else if (resource->working) { + apr_table_addn(methods, "CHECKIN", ""); + 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", ""); } - else if (resource->working) - vsn_options = ", CHECKIN, UNCHECKOUT"; - else if (vsn_hooks->add_label != NULL) - vsn_options = ", CHECKOUT, LABEL"; - else - vsn_options = ", CHECKOUT"; - - if (vsn_options != NULL) - options = apr_pstrcat(r->pool, options, vsn_options, NULL); } /* If there is a bindings provider, see if resource is bindable */ - if (binding_hooks != NULL) { - dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL); - if ((*binding_hooks->is_bindable)(resource)) - options = apr_pstrcat(r->pool, options, ", BIND", NULL); + if (binding_hooks != NULL + && (*binding_hooks->is_bindable)(resource)) { + apr_table_addn(methods, "BIND", ""); } - apr_table_setn(r->headers_out, "Allow", options); - apr_table_setn(r->headers_out, "DAV", dav_level); + /* 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; - /* ### this will send a Content-Type. the default OPTIONS does not. */ + 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 will send a Content-Type. the default OPTIONS does not. */ + ap_send_http_header(r); + + /* ### 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 */ ap_send_http_header(r); - /* ### 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. */ + /* send the response body */ + ap_rputs(DAV_XML_HEADER DEBUG_CR + "" DEBUG_CR, r); + + for (t = body.first; t != NULL; t = t->next) + ap_rputs(t->text, r); + + ap_rputs("" DEBUG_CR, r); /* we've sent everything necessary to the client. */ return DONE; @@ -1489,8 +1845,10 @@ static dav_error * dav_propfind_walker(dav_walk_resource *wres, int calltype) propstats = dav_get_props(propdb, ctx->doc); } else { - propstats = dav_get_allprops(propdb, - ctx->propfind_type == DAV_PROPFIND_IS_ALLPROP); + 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); @@ -4073,5 +4431,5 @@ APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(dav, DAV, int, find_liveprop, (resource, ns_uri, name, hooks), 0); APR_IMPLEMENT_EXTERNAL_HOOK_VOID(dav, DAV, insert_all_liveprops, (request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr), - (r, resource, insvalue, phdr)); + dav_prop_insert what, ap_text_header *phdr), + (r, resource, what, phdr)); diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index dce73ff8f9e..a58bb8acce0 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -489,6 +489,25 @@ typedef struct dav_lookup_result dav_lookup_uri(const char *uri, request_rec *r); +/* defines type of property info a provider is to return */ +typedef enum { + DAV_PROP_INSERT_NOTDEF, /* property is defined by this provider, + but nothing was inserted because the + (live) property is not defined for this + resource (it may be present as a dead + property). */ + DAV_PROP_INSERT_NOTSUPP, /* property is recognized by this provider, + * but it is not supported, and cannot be + * treated as a dead property */ + DAV_PROP_INSERT_NAME, /* a property name (empty elem) was + inserted into the text block */ + DAV_PROP_INSERT_VALUE, /* a property name/value pair was inserted + into the text block */ + DAV_PROP_INSERT_SUPPORTED /* a supported live property was added to + the text block as a + element */ +} dav_prop_insert; + /* ### this stuff is private to dav/fs/repos.c; move it... */ /* format a time string (buf must be at least DAV_TIMEBUF_SIZE chars) */ #define DAV_STYLE_ISO8601 1 @@ -578,7 +597,7 @@ APR_DECLARE_EXTERNAL_HOOK(dav, DAV, int, find_liveprop, */ APR_DECLARE_EXTERNAL_HOOK(dav, DAV, void, insert_all_liveprops, (request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr)) + dav_prop_insert what, ap_text_header *phdr)) /* ### make this internal to mod_dav.c ? */ #define DAV_KEY_RESOURCE "dav-resource" @@ -670,35 +689,36 @@ dav_error * dav_get_locktoken_list(request_rec *r, dav_locktoken_list **ltl); ** LIVE PROPERTY HANDLING */ -typedef enum { - DAV_PROP_INSERT_NOTDEF, /* property is defined by this provider, - but nothing was inserted because the - (live) property is not defined for this - resource (it may be present as a dead - property). */ - DAV_PROP_INSERT_NAME, /* a property name (empty elem) was - inserted into the text block */ - DAV_PROP_INSERT_VALUE /* a property name/value pair was inserted - into the text block */ -} dav_prop_insert; - /* opaque type for PROPPATCH rollback information */ typedef struct dav_liveprop_rollback dav_liveprop_rollback; struct dav_hooks_liveprop { /* - ** Insert a property name/value into a text block. The property to - ** insert is identified by the propid value. If insvalue is true, - ** then the property's value should be inserted; otherwise, an empty - ** element (ie. just the prop's name) should be inserted. + ** Insert property information into a text block. The property to + ** insert is identified by the propid value. The information to insert + ** is identified by the "what" argument, as follows: + ** DAV_PROP_INSERT_NAME + ** property name, as an empty XML element + ** DAV_PROP_INSERT_VALUE + ** property name/value, as an XML element + ** DAV_PROP_INSERT_SUPPORTED + ** if the property is defined on the resource, then + ** a DAV:supported-live-property element, as defined + ** by the DeltaV extensions to RFC2518. + ** + ** Providers should return DAV_PROP_INSERT_NOTDEF if they do not define + ** the specified propid, but allow the property to be handled as a + ** dead property. If a provider recognizes, but does not support, + ** a property, and does not want it handled as a dead property, it should + ** return DAV_PROP_INSERT_NOTSUPP. ** ** Returns one of DAV_PROP_INSERT_* based on what happened. ** ** ### we may need more context... ie. the lock database */ dav_prop_insert (*insert_prop)(const dav_resource *resource, - int propid, int insvalue, + int propid, dav_prop_insert what, ap_text_header *phdr); /* @@ -840,7 +860,7 @@ int dav_core_find_liveprop(const dav_resource *resource, const dav_hooks_liveprop **hooks); void dav_core_insert_all_liveprops(request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr); + dav_prop_insert what, ap_text_header *phdr); void dav_core_register_uris(apr_pool_t *p); @@ -880,9 +900,6 @@ enum { DAV_PROPID_resourcetype, DAV_PROPID_source, DAV_PROPID_supportedlock, - DAV_PROPID_supported_method_set, /* from DeltaV I-D */ - DAV_PROPID_supported_live_property_set, /* from DeltaV I-D */ - DAV_PROPID_supported_report_set, /* from DeltaV I-D */ /* DeltaV properties (from the I-D) */ DAV_PROPID_activity_collection_set, @@ -1351,7 +1368,13 @@ dav_get_props_result dav_get_props( dav_get_props_result dav_get_allprops( dav_propdb *db, - int getvals); + dav_prop_insert what); + +void dav_get_liveprop_supported( + dav_propdb *propdb, + const char *ns_uri, + const char *propname, + ap_text_header *body); /* ** 3-phase property modification. @@ -1851,10 +1874,22 @@ struct dav_hooks_vsn ** they define the functionality needed to implement "core" versioning. */ - /* Return supported versioning level - * for the Versioning header + /* Return supported versioning options. + * Each dav_text item in the list will be returned as a separate + * DAV header. Providers are advised to limit the length of an + * individual text item to 63 characters, to conform to the limit + * used by MS Web Folders. + */ + void (*get_vsn_options)(apr_pool_t *p, ap_text_header *phdr); + + /* Get the value of a specific option for an OPTIONS request. + * The option being requested is given by the parsed XML + * element object "elem". The value of the option should be + * appended to the "option" text object. */ - const char * (*get_vsn_header)(void); + dav_error * (*get_option)(const dav_resource *resource, + const ap_xml_elem *elem, + ap_text_header *option); /* Put a resource under version control. If the resource already * exists unversioned, then it becomes the initial version of the @@ -1947,7 +1982,7 @@ struct dav_hooks_vsn ** must be passed to this routine. ** ** The dav_xml_doc structure contains the parsed report request - ** body. The report response is generated into the dav_text_header + ** body. The report response is generated into the ap_text_header ** structure. ** ** ### shouldn't generate large responses to memory ### diff --git a/modules/dav/main/props.c b/modules/dav/main/props.c index 2278bedf9be..e529deac3b2 100644 --- a/modules/dav/main/props.c +++ b/modules/dav/main/props.c @@ -324,46 +324,60 @@ static const char *dav_get_ns_table_uri(dav_propdb *propdb, int ns) } #endif -static void dav_find_liveprop(dav_propdb *propdb, ap_xml_elem *elem) +static int dav_find_liveprop_provider(dav_propdb *propdb, + const char *ns_uri, + const char *propname, + const dav_hooks_liveprop **provider) { int propid; - const char *ns_uri; - dav_elem_private *priv = elem->private; - const dav_hooks_liveprop *hooks; - if (elem->ns == AP_XML_NS_DAV_ID) { + *provider = NULL; + + if (ns_uri == NULL) { + /* policy: liveprop providers cannot define no-namespace properties */ + return DAV_PROPID_CORE_UNKNOWN; + } + else if (strcmp(ns_uri, "DAV:") == 0) { const char * const *p = dav_core_props; for (propid = DAV_PROPID_CORE; *p != NULL; ++p, ++propid) - if (strcmp(elem->name, *p) == 0) { - priv->propid = propid; - /* priv->provider == NULL */ - return; + if (strcmp(propname, *p) == 0) { + return propid; } /* didn't find it. fall thru. a provider can define DAV: props */ } - else if (elem->ns == AP_XML_NS_NONE) { - /* policy: liveprop providers cannot define no-namespace properties */ - priv->propid = DAV_PROPID_CORE_UNKNOWN; - /* priv->provider == NULL */ - return; - } - - /* get the URI for the element's namespace id */ - ns_uri = AP_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); /* is there a liveprop provider for this property? */ - propid = dav_run_find_liveprop(propdb->resource, ns_uri, elem->name, - &hooks); + propid = dav_run_find_liveprop(propdb->resource, ns_uri, propname, + provider); if (propid != 0) { - priv->propid = propid; - priv->provider = hooks; - return; + return propid; } - priv->propid = DAV_PROPID_CORE_UNKNOWN; - /* priv->provider == NULL */ + /* no provider for this property */ + return DAV_PROPID_CORE_UNKNOWN; +} + +static void dav_find_liveprop(dav_propdb *propdb, ap_xml_elem *elem) +{ + const char *ns_uri; + dav_elem_private *priv = elem->private; + const dav_hooks_liveprop *hooks; + + + if (elem->ns == AP_XML_NS_NONE) + ns_uri = NULL; + else if (elem->ns == AP_XML_NS_DAV_ID) + ns_uri = "DAV:"; + else + ns_uri = AP_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); + + priv->propid = dav_find_liveprop_provider(propdb, ns_uri, elem->name, + &hooks); + if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { + priv->provider = hooks; + } } /* is the live property read/write? */ @@ -415,14 +429,14 @@ static void dav_do_prop_subreq(dav_propdb *propdb) static dav_error * dav_insert_coreprop(dav_propdb *propdb, int propid, const char *name, - int getvals, + dav_prop_insert what, ap_text_header *phdr, - int *inserted) + dav_prop_insert *inserted) { const char *value = NULL; dav_error *err; - *inserted = 0; + *inserted = DAV_PROP_INSERT_NOTDEF; /* fast-path the common case */ if (propid == DAV_PROPID_CORE_UNKNOWN) @@ -490,7 +504,6 @@ static dav_error * dav_insert_coreprop(dav_propdb *propdb, break; } - case DAV_PROPID_CORE_UNKNOWN: default: /* fall through to interpret as a dead property */ break; @@ -500,7 +513,15 @@ static dav_error * dav_insert_coreprop(dav_propdb *propdb, if (value != NULL) { const char *s; - if (getvals && *value != '\0') { + if (what == DAV_PROP_INSERT_SUPPORTED) { + /* use D: prefix to refer to the DAV: namespace URI, + * and let the namespace attribute default to "DAV:" + */ + s = apr_psprintf(propdb->p, + "" DEBUG_CR, + name); + } + else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') { /* use D: prefix to refer to the DAV: namespace URI */ s = apr_psprintf(propdb->p, "%s" DEBUG_CR, name, value, name); @@ -511,7 +532,7 @@ static dav_error * dav_insert_coreprop(dav_propdb *propdb, } ap_text_append(propdb->p, phdr, s); - *inserted = 1; + *inserted = what; } return NULL; @@ -519,26 +540,23 @@ static dav_error * dav_insert_coreprop(dav_propdb *propdb, static dav_error * dav_insert_liveprop(dav_propdb *propdb, const ap_xml_elem *elem, - int getvals, + dav_prop_insert what, ap_text_header *phdr, - int *inserted) + dav_prop_insert *inserted) { - dav_prop_insert pi; dav_elem_private *priv = elem->private; - *inserted = 0; + *inserted = DAV_PROP_INSERT_NOTDEF; if (priv->provider == NULL) { /* this is a "core" property that we define */ return dav_insert_coreprop(propdb, priv->propid, elem->name, - getvals, phdr, inserted); + what, phdr, inserted); } /* ask the provider (that defined this prop) to insert the prop */ - pi = (*priv->provider->insert_prop)(propdb->resource, priv->propid, - getvals, phdr); - if (pi != DAV_PROP_INSERT_NOTDEF) - *inserted = 1; + *inserted = (*priv->provider->insert_prop)(propdb->resource, priv->propid, + what, phdr); return NULL; } @@ -909,7 +927,6 @@ dav_error *dav_open_propdb(request_rec *r, dav_lockdb *lockdb, dav_propdb **p_propdb) { dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb)); - dav_error *err; *p_propdb = NULL; @@ -931,12 +948,10 @@ dav_error *dav_open_propdb(request_rec *r, dav_lockdb *lockdb, propdb->lockdb = lockdb; - if (!ro) { - propdb->deferred = 1; - } - else if ((err = dav_really_open_db(propdb, 1 /* ro */)) != NULL) { - return err; - } + /* always defer actual open, to avoid expense of accessing db + * when only live properties are involved + */ + propdb->deferred = 1; /* ### what to do about closing the propdb on server failure? */ @@ -975,7 +990,7 @@ void dav_close_propdb(dav_propdb *propdb) (*propdb->db_hooks->close)(propdb->db); } -dav_get_props_result dav_get_allprops(dav_propdb *propdb, int getvals) +dav_get_props_result dav_get_allprops(dav_propdb *propdb, dav_prop_insert what) { const dav_hooks_db *db_hooks = propdb->db_hooks; ap_text_header hdr = { 0 }; @@ -983,101 +998,111 @@ dav_get_props_result dav_get_allprops(dav_propdb *propdb, int getvals) dav_get_props_result result = { 0 }; int found_contenttype = 0; int found_contentlang = 0; - int unused_inserted; + dav_prop_insert unused_inserted; - /* generate all the namespaces that are in the propdb */ - dav_get_propdb_xmlns(propdb, &hdr_ns); - - /* initialize the result with some start tags... */ - ap_text_append(propdb->p, &hdr, - "" DEBUG_CR - "" DEBUG_CR); - - /* if there ARE properties, then scan them */ - if (propdb->db != NULL) { - dav_datum key; - int dav_id = dav_find_dav_id(propdb); + /* if not just getting supported live properties, + * scan all properties in the dead prop database + */ + if (what != DAV_PROP_INSERT_SUPPORTED) { + if (propdb->deferred) { + /* ### what to do with db open error? */ + (void) dav_really_open_db(propdb, 1 /*ro*/); + } - (void) (*db_hooks->firstkey)(propdb->db, &key); - while (key.dptr) { - dav_datum prevkey; + /* generate all the namespaces that are in the propdb */ + dav_get_propdb_xmlns(propdb, &hdr_ns); - /* any keys with leading capital letters should be skipped - (real keys start with a number or a colon) */ - if (*key.dptr >= 'A' && *key.dptr <= 'Z') - goto next_key; + /* initialize the result with some start tags... */ + ap_text_append(propdb->p, &hdr, + "" DEBUG_CR + "" DEBUG_CR); - /* - ** We also look for and - ** . If they are not stored as dead - ** properties, then we need to perform a subrequest to get - ** their values (if any). - */ - if (dav_id != -1 - && *key.dptr != ':' - && dav_id == atoi(key.dptr)) { + /* if there ARE properties, then scan them */ + if (propdb->db != NULL) { + dav_datum key; + int dav_id = dav_find_dav_id(propdb); - const char *colon; + (void) (*db_hooks->firstkey)(propdb->db, &key); + while (key.dptr) { + dav_datum prevkey; - /* find the colon */ - if ( key.dptr[1] == ':' ) { - colon = key.dptr + 1; - } - else { - colon = strchr(key.dptr + 2, ':'); - } + /* any keys with leading capital letters should be skipped + (real keys start with a number or a colon) */ + if (*key.dptr >= 'A' && *key.dptr <= 'Z') + goto next_key; - if (colon[1] == 'g') { - if (strcmp(colon + 1, "getcontenttype") == 0) { - found_contenttype = 1; + /* + ** We also look for and + ** . If they are not stored as dead + ** properties, then we need to perform a subrequest to get + ** their values (if any). + */ + if (dav_id != -1 + && *key.dptr != ':' + && dav_id == atoi(key.dptr)) { + + const char *colon; + + /* find the colon */ + if ( key.dptr[1] == ':' ) { + colon = key.dptr + 1; } - else if (strcmp(colon + 1, "getcontentlanguage") == 0) { - found_contentlang = 1; + else { + colon = strchr(key.dptr + 2, ':'); } - } - } - if (getvals) { - dav_datum value; + if (colon[1] == 'g') { + if (strcmp(colon + 1, "getcontenttype") == 0) { + found_contenttype = 1; + } + else if (strcmp(colon + 1, "getcontentlanguage") == 0) { + found_contentlang = 1; + } + } + } - (void) (*db_hooks->fetch)(propdb->db, key, &value); - if (value.dptr == NULL) { - /* ### anything better to do? */ - /* ### probably should enter a 500 error */ - goto next_key; - } + if (what == DAV_PROP_INSERT_VALUE) { + dav_datum value; - /* put the prop name and value into the result */ - dav_append_prop(propdb, key.dptr, value.dptr, &hdr); + (void) (*db_hooks->fetch)(propdb->db, key, &value); + if (value.dptr == NULL) { + /* ### anything better to do? */ + /* ### probably should enter a 500 error */ + goto next_key; + } - (*db_hooks->freedatum)(propdb->db, value); - } - else { - /* simple, empty element if a value isn't needed */ - dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr); + /* put the prop name and value into the result */ + dav_append_prop(propdb, key.dptr, value.dptr, &hdr); + + (*db_hooks->freedatum)(propdb->db, value); + } + else { + /* simple, empty element if a value isn't needed */ + dav_append_prop(propdb, key.dptr, DAV_EMPTY_VALUE, &hdr); + } + + next_key: + prevkey = key; + (void) (*db_hooks->nextkey)(propdb->db, &key); + (*db_hooks->freedatum)(propdb->db, prevkey); } + } - next_key: - prevkey = key; - (void) (*db_hooks->nextkey)(propdb->db, &key); - (*db_hooks->freedatum)(propdb->db, prevkey); - } + /* add namespaces for all the liveprop providers */ + dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns); } - /* add namespaces for all the liveprop providers */ - dav_add_all_liveprop_xmlns(propdb->p, &hdr_ns); - /* ask the liveprop providers to insert their properties */ - dav_run_insert_all_liveprops(propdb->r, propdb->resource, getvals, &hdr); + dav_run_insert_all_liveprops(propdb->r, propdb->resource, what, &hdr); /* insert the standard properties */ /* ### should be handling the return errors here */ (void)dav_insert_coreprop(propdb, DAV_PROPID_CORE_supportedlock, "supportedlock", - getvals, &hdr, &unused_inserted); + what, &hdr, &unused_inserted); (void)dav_insert_coreprop(propdb, DAV_PROPID_CORE_lockdiscovery, "lockdiscovery", - getvals, &hdr, &unused_inserted); + what, &hdr, &unused_inserted); /* if we didn't find these, then do the whole subreq thing. */ if (!found_contenttype) { @@ -1085,21 +1110,24 @@ dav_get_props_result dav_get_allprops(dav_propdb *propdb, int getvals) (void)dav_insert_coreprop(propdb, DAV_PROPID_CORE_getcontenttype, "getcontenttype", - getvals, &hdr, &unused_inserted); + what, &hdr, &unused_inserted); } if (!found_contentlang) { /* ### should be handling the return error here */ (void)dav_insert_coreprop(propdb, DAV_PROPID_CORE_getcontentlanguage, "getcontentlanguage", - getvals, &hdr, &unused_inserted); + what, &hdr, &unused_inserted); } - /* terminate the result */ - ap_text_append(propdb->p, &hdr, - "" DEBUG_CR - "HTTP/1.1 200 OK" DEBUG_CR - "" DEBUG_CR); + /* if not just reporting on supported live props, + * terminate the result */ + if (what != DAV_PROP_INSERT_SUPPORTED) { + ap_text_append(propdb->p, &hdr, + "" DEBUG_CR + "HTTP/1.1 200 OK" DEBUG_CR + "" DEBUG_CR); + } result.propstats = hdr.first; result.xmlns = hdr_ns.first; @@ -1114,6 +1142,7 @@ dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) ap_text_header hdr_bad = { 0 }; ap_text_header hdr_ns = { 0 }; int have_good = 0; + int propdb_xmlns_done = 0; dav_get_props_result result = { 0 }; char *marks_input; char *marks_liveprop; @@ -1126,9 +1155,6 @@ dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) "" DEBUG_CR "" DEBUG_CR); - /* generate all the namespaces that are in the propdb */ - dav_get_propdb_xmlns(propdb, &hdr_ns); - /* ### the marks should be in a buffer! */ /* allocate zeroed-memory for the marks. These marks indicate which input namespaces we've generated into the output xmlns buffer */ @@ -1138,45 +1164,37 @@ dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1); for (elem = elem->first_child; elem; elem = elem->next) { - dav_datum key; + dav_datum key = { 0 }; dav_datum value = { 0 }; dav_elem_private *priv; + dav_error *err; + dav_prop_insert inserted; + int is_liveprop = 0; - /* - ** Note: the key may be NULL if we have no properties that are in - ** a namespace that matches the requested prop's namespace. - */ - key = dav_gdbm_key(propdb, elem); - - /* fetch IF we have a db and a key. otherwise, value is NULL */ - if (propdb->db != NULL && key.dptr != NULL) { - (void) (*db_hooks->fetch)(propdb->db, key, &value); - } + /* + ** First try live property providers; if they don't handle + ** the property, then try looking it up in the propdb. + */ if (elem->private == NULL) { elem->private = apr_pcalloc(propdb->p, sizeof(*priv)); } priv = elem->private; - /* - ** If we did not find the property in the database, then it may - ** be a liveprop that we can handle specially. - */ - if (value.dptr == NULL) { - dav_error *err; - int inserted; + /* cache the propid; dav_get_props() could be called many times */ + if (priv->propid == 0) + dav_find_liveprop(propdb, elem); - /* cache the propid; dav_get_props() could be called many times */ - if (priv->propid == 0) - dav_find_liveprop(propdb, elem); + if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { + is_liveprop = 1; /* insert the property. returns 1 if an insertion was done. */ - if ((err = dav_insert_liveprop(propdb, elem, 1, &hdr_good, - &inserted)) != NULL) { + if ((err = dav_insert_liveprop(propdb, elem, DAV_PROP_INSERT_VALUE, + &hdr_good, &inserted)) != NULL) { /* ### need to propagate the error to the caller... */ /* ### skip it for now, as if nothing was inserted */ } - if (inserted) { + if (inserted == DAV_PROP_INSERT_VALUE) { have_good = 1; /* @@ -1203,7 +1221,41 @@ dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) continue; } - } + else if (inserted == DAV_PROP_INSERT_NOTDEF) { + /* allow property to be handled as a dead property */ + is_liveprop = 0; + } + } + + /* + ** If not handled as a live property, look in the dead property database + */ + if (!is_liveprop) { + /* make sure propdb is really open */ + if (propdb->deferred) { + /* ### what to do with db open error? */ + (void) dav_really_open_db(propdb, 1 /*ro*/); + } + + /* if not done yet, + * generate all the namespaces that are in the propdb + */ + if (!propdb_xmlns_done) { + dav_get_propdb_xmlns(propdb, &hdr_ns); + propdb_xmlns_done = 1; + } + + /* + ** Note: the key may be NULL if we have no properties that are in + ** a namespace that matches the requested prop's namespace. + */ + key = dav_gdbm_key(propdb, elem); + + /* fetch IF we have a db and a key. otherwise, value is NULL */ + if (propdb->db != NULL && key.dptr != NULL) { + (void) (*db_hooks->fetch)(propdb->db, key, &value); + } + } if (value.dptr == NULL) { /* not found. add a record to the "bad" propstats */ @@ -1282,6 +1334,30 @@ dav_get_props_result dav_get_props(dav_propdb *propdb, ap_xml_doc *doc) return result; } +void dav_get_liveprop_supported(dav_propdb *propdb, + const char *ns_uri, + const char *propname, + ap_text_header *body) +{ + int propid; + const dav_hooks_liveprop *hooks; + + propid = dav_find_liveprop_provider(propdb, ns_uri, propname, &hooks); + + if (propid != DAV_PROPID_CORE_UNKNOWN) { + if (hooks == NULL) { + /* this is a "core" property that we define */ + dav_prop_insert unused_inserted; + dav_insert_coreprop(propdb, propid, propname, + DAV_PROP_INSERT_SUPPORTED, body, &unused_inserted); + } + else { + (*hooks->insert_prop)(propdb->resource, propid, + DAV_PROP_INSERT_SUPPORTED, body); + } + } +} + void dav_prop_validate(dav_prop_ctx *ctx) { dav_propdb *propdb = ctx->propdb; diff --git a/modules/dav/main/std_liveprop.c b/modules/dav/main/std_liveprop.c index 8ae1782ebde..01b6b925af9 100644 --- a/modules/dav/main/std_liveprop.c +++ b/modules/dav/main/std_liveprop.c @@ -82,10 +82,6 @@ static const dav_liveprop_spec dav_core_props[] = { 0, "displayname", DAV_PROPID_displayname, 1 }, { 0, "resourcetype", DAV_PROPID_resourcetype, 0 }, { 0, "source", DAV_PROPID_source, 1 }, - { 0, "supported-live-property-set", - DAV_PROPID_supported_live_property_set, 0 }, - { 0, "supported-method-set", DAV_PROPID_supported_method_set, 0 }, - { 0, "supported-report-set", DAV_PROPID_supported_report_set, 0 }, { 0 } /* sentinel */ }; @@ -98,12 +94,11 @@ static const dav_liveprop_group dav_core_liveprop_group = }; static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, - int propid, int insvalue, + int propid, dav_prop_insert what, ap_text_header *phdr) { const char *value; const char *s; - dav_prop_insert which; apr_pool_t *p = resource->pool; const dav_liveprop_spec *info; int global_ns; @@ -145,60 +140,6 @@ static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, } break; - case DAV_PROPID_supported_live_property_set: - /* ### insert all live property names ### */ - return DAV_PROP_INSERT_NOTDEF; - break; - - case DAV_PROPID_supported_method_set: - /* ### leverage code from dav_method_options ### */ - return DAV_PROP_INSERT_NOTDEF; - break; - - case DAV_PROPID_supported_report_set: -#if 0 - { - /* ### where to get "r" ??? */ - const dav_hooks_vsn *vsn_hooks = dav_get_vsn_hooks(r); - - if (vsn_hooks != NULL) { - const dav_report_elem *reports; - dav_error *err; - - if ((err = (*vsn_hooks->avail_reports)(resource, - &reports)) != NULL) { - err = dav_push_error(p, err->status, 0, - "DAV:supported-report-set could not " - "be determined due to a problem " - "fetching the available reports " - "for this resource.", - err); - /* ### can't return err... sigh. punt for now. */ - return DAV_PROP_INSERT_NOTDEF; - } - - value = ""; - - if (reports == NULL) { - /* no reports are defined. break with value="" */ - break; - } - - for (; reports->nmspace != NULL; ++reports) { - /* Note: presume reports->namespace is XML/URL quoted */ - const char *v = apr_psprintf(p, "<%s xmlns=\"%s\"/>" DEBUG_CR, - reports->name, reports->nmspace); - - /* This isn't very memory-efficient, but there should only - be a small number of reports */ - value = apr_pstrcat(p, value, v, NULL); - } - } - break; - } -#endif - /* above code disabled. FALLTHROUGH */ - case DAV_PROPID_comment: case DAV_PROPID_creator_displayname: case DAV_PROPID_displayname: @@ -218,19 +159,22 @@ static dav_prop_insert dav_core_insert_prop(const dav_resource *resource, /* assert: info != NULL && info->name != NULL */ - if (insvalue && *value != '\0') { + if (what == DAV_PROP_INSERT_SUPPORTED) { + s = apr_psprintf(p, "" DEBUG_CR, + info->name, dav_core_namespace_uris[info->ns]); + } + else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') { s = apr_psprintf(p, "%s" DEBUG_CR, global_ns, info->name, value, global_ns, info->name); - which = DAV_PROP_INSERT_VALUE; } else { s = apr_psprintf(p, "" DEBUG_CR, global_ns, info->name); - which = DAV_PROP_INSERT_NAME; } ap_text_append(p, phdr, s); - /* we inserted a name or value (this prop is done) */ - return which; + /* we inserted what was asked for */ + return what; } static int dav_core_is_writable(const dav_resource *resource, int propid) @@ -271,17 +215,10 @@ int dav_core_find_liveprop(const dav_resource *resource, void dav_core_insert_all_liveprops(request_rec *r, const dav_resource *resource, - int insvalue, ap_text_header *phdr) + dav_prop_insert what, ap_text_header *phdr) { (void) dav_core_insert_prop(resource, DAV_PROPID_resourcetype, - insvalue, phdr); - (void) dav_core_insert_prop(resource, - DAV_PROPID_supported_live_property_set, - insvalue, phdr); - (void) dav_core_insert_prop(resource, DAV_PROPID_supported_method_set, - insvalue, phdr); - (void) dav_core_insert_prop(resource, DAV_PROPID_supported_report_set, - insvalue, phdr); + what, phdr); } void dav_core_register_uris(apr_pool_t *p)