You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by gs...@apache.org on 2001/01/20 03:00:01 UTC
cvs commit: httpd-2.0/modules/dav/main mod_dav.c mod_dav.h props.c std_liveprop.c
gstein 01/01/19 18:00:01
Modified: modules/dav/fs repos.c repos.h
modules/dav/main mod_dav.c mod_dav.h props.c std_liveprop.c
Log:
- 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 <jv...@rational.com>
Reviewed by: Greg Stein
Revision Changes Path
1.42 +17 -14 httpd-2.0/modules/dav/fs/repos.c
Index: repos.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/fs/repos.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -u -r1.41 -r1.42
--- repos.c 2001/01/12 12:18:10 1.41
+++ repos.c 2001/01/20 02:00:00 1.42
@@ -1717,12 +1717,11 @@
};
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 @@
/* 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, "<lp%d:%s>%s</lp%d:%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, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
- which = DAV_PROP_INSERT_NAME;
+ }
+ else {
+ /* assert: what == DAV_PROP_INSERT_SUPPORTED */
+ s = apr_psprintf(p, "<supported-live-property name=\"%s\""
+ " namespace=\"%s\" xmlns=\"DAV:\"/>" 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 @@
}
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_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 @@
** 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 */
1.13 +1 -1 httpd-2.0/modules/dav/fs/repos.h
Index: repos.h
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/fs/repos.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -u -r1.12 -r1.13
--- repos.h 2000/11/27 12:54:08 1.12
+++ repos.h 2001/01/20 02:00:00 1.13
@@ -103,7 +103,7 @@
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);
1.38 +446 -88 httpd-2.0/modules/dav/main/mod_dav.c
Index: mod_dav.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/main/mod_dav.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -u -r1.37 -r1.38
--- mod_dav.c 2001/01/19 07:04:17 1.37
+++ mod_dav.c 2001/01/20 02:00:01 1.38
@@ -1261,6 +1261,244 @@
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, "<D:supported-method-set>" 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,
+ "<D:supported-method D:name=\"%s\"/>" 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,
+ "<D:supported-method D:name=\"%s\"/>" DEBUG_CR,
+ name);
+ ap_text_append(r->pool, body, s);
+ }
+ }
+ }
+ }
+
+ ap_text_append(r->pool, body, "</D:supported-method-set>" 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, "<D:supported-live-property-set>" 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, "</D:supported-live-property-set>" 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, "<D:supported-report-set>" 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,
+ "<D:supported-report D:name=\"%s\" D:namespace=\"%s\"/>" 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,
+ "<D:supported-report D:name=\"%s\" D:namespace=\"%s\"/>" DEBUG_CR,
+ rp->name, rp->nmspace);
+ ap_text_append(r->pool, body, s);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ap_text_append(r->pool, body, "</D:supported-report-set>" DEBUG_CR);
+ return NULL;
+}
+
/* handle the OPTIONS method */
static int dav_method_options(request_rec *r)
{
@@ -1268,153 +1506,271 @@
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)
- 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);
+ 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", "");
+ }
}
/* 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);
+
+ /* send the 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);
- /* ### 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. */
+ ap_rputs("</D:options-response>" DEBUG_CR, r);
/* we've sent everything necessary to the client. */
return DONE;
@@ -1489,8 +1845,10 @@
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 @@
(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));
1.37 +63 -28 httpd-2.0/modules/dav/main/mod_dav.h
Index: mod_dav.h
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/main/mod_dav.h,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -u -r1.36 -r1.37
--- mod_dav.h 2001/01/19 07:04:17 1.36
+++ mod_dav.h 2001/01/20 02:00:01 1.37
@@ -489,6 +489,25 @@
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
+ <DAV:supported-live-property> 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, 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 @@
** 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 @@
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 @@
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_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 @@
** they define the functionality needed to implement "core" versioning.
*/
- /* Return supported versioning level
- * for the Versioning header
- */
- const char * (*get_vsn_header)(void);
+ /* 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.
+ */
+ 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 @@
** 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 ###
1.22 +232 -156 httpd-2.0/modules/dav/main/props.c
Index: props.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/main/props.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -u -r1.21 -r1.22
--- props.c 2001/01/19 07:04:17 1.21
+++ props.c 2001/01/20 02:00:01 1.22
@@ -324,46 +324,60 @@
}
#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;
+
+ *provider = NULL;
- if (elem->ns == AP_XML_NS_DAV_ID) {
+ 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;
}
+
+ /* no provider for this property */
+ return DAV_PROPID_CORE_UNKNOWN;
+}
- priv->propid = DAV_PROPID_CORE_UNKNOWN;
- /* priv->provider == NULL */
+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 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 @@
break;
}
- case DAV_PROPID_CORE_UNKNOWN:
default:
/* fall through to interpret as a dead property */
break;
@@ -500,7 +513,15 @@
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,
+ "<D:supported-live-property D:name=\"%s\"/>" 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, "<D:%s>%s</D:%s>" DEBUG_CR,
name, value, name);
@@ -511,7 +532,7 @@
}
ap_text_append(propdb->p, phdr, s);
- *inserted = 1;
+ *inserted = what;
}
return NULL;
@@ -519,26 +540,23 @@
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_propdb **p_propdb)
{
dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb));
- dav_error *err;
*p_propdb = NULL;
@@ -931,12 +948,10 @@
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 @@
(*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 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,
- "<D:propstat>" DEBUG_CR
- "<D:prop>" 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;
-
- /* 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;
+ /* generate all the namespaces that are in the propdb */
+ dav_get_propdb_xmlns(propdb, &hdr_ns);
- /*
- ** We also look for <DAV:getcontenttype> and
- ** <DAV:getcontentlanguage>. 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 {
- colon = strchr(key.dptr + 2, ':');
- }
+ /* initialize the result with some start tags... */
+ ap_text_append(propdb->p, &hdr,
+ "<D:propstat>" DEBUG_CR
+ "<D:prop>" DEBUG_CR);
+
+ /* if there ARE properties, then scan them */
+ if (propdb->db != NULL) {
+ dav_datum key;
+ int dav_id = dav_find_dav_id(propdb);
+
+ (void) (*db_hooks->firstkey)(propdb->db, &key);
+ while (key.dptr) {
+ dav_datum prevkey;
+
+ /* 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 <DAV:getcontenttype> and
+ ** <DAV:getcontentlanguage>. 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 @@
(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,
- "</D:prop>" DEBUG_CR
- "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
- "</D:propstat>" 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,
+ "</D:prop>" DEBUG_CR
+ "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR
+ "</D:propstat>" DEBUG_CR);
+ }
result.propstats = hdr.first;
result.xmlns = hdr_ns.first;
@@ -1114,6 +1142,7 @@
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 @@
"<D:propstat>" DEBUG_CR
"<D:prop>" 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 @@
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;
-
- /*
- ** 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);
+ dav_error *err;
+ dav_prop_insert inserted;
+ int is_liveprop = 0;
- /* 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 @@
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 */
@@ -1280,6 +1332,30 @@
result.xmlns = hdr_ns.first;
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)
1.4 +11 -74 httpd-2.0/modules/dav/main/std_liveprop.c
Index: std_liveprop.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/dav/main/std_liveprop.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -u -r1.3 -r1.4
--- std_liveprop.c 2000/11/27 12:54:28 1.3
+++ std_liveprop.c 2001/01/20 02:00:01 1.4
@@ -82,10 +82,6 @@
{ 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 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 @@
}
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 @@
/* assert: info != NULL && info->name != NULL */
- if (insvalue && *value != '\0') {
+ if (what == DAV_PROP_INSERT_SUPPORTED) {
+ s = apr_psprintf(p, "<supported-live-property name=\"%s\""
+ " namespace=\"%s\" xmlns=\"DAV:\"/>" DEBUG_CR,
+ info->name, dav_core_namespace_uris[info->ns]);
+ }
+ else if (what == DAV_PROP_INSERT_VALUE && *value != '\0') {
s = apr_psprintf(p, "<lp%d:%s>%s</lp%d:%s>" DEBUG_CR,
global_ns, info->name, value, global_ns, info->name);
- which = DAV_PROP_INSERT_VALUE;
}
else {
s = apr_psprintf(p, "<lp%d:%s/>" 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 @@
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)