/* convert the whole document to EBCDIC */ APU_DECLARE(apr_status_t) apr_xml_parser_convert_doc(apr_pool_t *pool, apr_xml_doc *pdoc, apr_xlate_t *convset) { apr_status_t status; /* Don't convert the namespaces: they are constant! */ if (pdoc->namespaces != NULL) { int i; apr_array_header_t *namespaces; namespaces = apr_array_make(pool, pdoc->namespaces->nelts, sizeof(const char *)); if (namespaces == NULL) return APR_ENOMEM; for (i = 0; i < pdoc->namespaces->nelts; i++) { apr_size_t inbytes_left, outbytes_left; char *ptr = (char *) APR_XML_GET_URI_ITEM(pdoc->namespaces, i); ptr = apr_pstrdup(pool, ptr); if ( ptr == NULL) return APR_ENOMEM; inbytes_left = outbytes_left = strlen(ptr); status = apr_xlate_conv_buffer(convset, ptr, &inbytes_left, ptr, &outbytes_left); if (status) { return status; } apr_xml_insert_uri(namespaces, ptr); } pdoc->namespaces = namespaces; } return apr_xml_parser_convert_elem(pdoc->root, convset); }
/* return the URI's (existing) index, or insert it and return a new index */ APU_DECLARE(int) apr_xml_insert_uri(apr_array_header_t *uri_array, const char *uri) { int i; const char **pelt; /* never insert an empty URI; this index is always APR_XML_NS_NONE */ if (*uri == '\0') return APR_XML_NS_NONE; for (i = uri_array->nelts; i--;) { if (strcmp(uri, APR_XML_GET_URI_ITEM(uri_array, i)) == 0) return i; } pelt = apr_array_push(uri_array); *pelt = uri; /* assume uri is const or in a pool */ return uri_array->nelts - 1; }
static void dav_find_liveprop(dav_propdb *propdb, apr_xml_elem *elem) { const char *ns_uri; dav_elem_private *priv = elem->priv; const dav_hooks_liveprop *hooks; if (elem->ns == APR_XML_NS_NONE) ns_uri = NULL; else if (elem->ns == APR_XML_NS_DAV_ID) ns_uri = "DAV:"; else ns_uri = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); priv->propid = dav_find_liveprop_provider(propdb, ns_uri, elem->name, &hooks); /* ### this test seems redundant... */ if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { priv->provider = hooks; } }
DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx) { dav_propdb *propdb = ctx->propdb; dav_error *err = NULL; dav_elem_private *priv = ctx->prop->priv; ctx->rollback = apr_pcalloc(propdb->p, sizeof(*ctx->rollback)); if (ctx->is_liveprop) { err = (*priv->provider->patch_exec)(propdb->resource, ctx->prop, ctx->operation, ctx->liveprop_ctx, &ctx->rollback->liveprop); } else { dav_prop_name name; if (ctx->prop->ns == APR_XML_NS_NONE) name.ns = ""; else name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, ctx->prop->ns); name.name = ctx->prop->name; /* save the old value so that we can do a rollback. */ if ((err = (*propdb->db_hooks ->get_rollback)(propdb->db, &name, &ctx->rollback->deadprop)) != NULL) goto error; if (ctx->operation == DAV_PROP_OP_SET) { /* Note: propdb->mapping was set in dav_prop_validate() */ err = (*propdb->db_hooks->store)(propdb->db, &name, ctx->prop, propdb->mapping); /* ** If an error occurred, then assume that we didn't change the ** value. Remove the rollback item so that we don't try to set ** its value during the rollback. */ /* ### euh... where is the removal? */ } else if (ctx->operation == DAV_PROP_OP_DELETE) { /* ** Delete the property. Ignore errors -- the property is there, or ** we are deleting it for a second time. */ /* ### but what about other errors? */ (void) (*propdb->db_hooks->remove)(propdb->db, &name); } } error: /* push a more specific error here */ if (err != NULL) { /* ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen ** any errors at this point. */ ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_PROP_EXEC, "Could not execute PROPPATCH.", err); } }
DAV_DECLARE(dav_get_props_result) dav_get_props(dav_propdb *propdb, apr_xml_doc *doc) { const dav_hooks_db *db_hooks = propdb->db_hooks; apr_xml_elem *elem = dav_find_child(doc->root, "prop"); apr_text_header hdr_good = { 0 }; apr_text_header hdr_bad = { 0 }; apr_text_header hdr_ns = { 0 }; int have_good = 0; dav_get_props_result result = { 0 }; char *marks_liveprop; dav_xmlns_info *xi; int xi_filled = 0; /* ### NOTE: we should pass in TWO buffers -- one for keys, one for the marks */ /* we will ALWAYS provide a "good" result, even if it is EMPTY */ apr_text_append(propdb->p, &hdr_good, "<D:propstat>" DEBUG_CR "<D:prop>" DEBUG_CR); /* ### the marks should be in a buffer! */ /* allocate zeroed-memory for the marks. These marks indicate which liveprop namespaces we've generated into the output xmlns buffer */ /* same for the liveprops */ marks_liveprop = apr_pcalloc(propdb->p, dav_get_liveprop_ns_count() + 1); xi = dav_xmlns_create(propdb->p); for (elem = elem->first_child; elem; elem = elem->next) { dav_elem_private *priv; dav_error *err; dav_prop_insert inserted; dav_prop_name name; /* ** First try live property providers; if they don't handle ** the property, then try looking it up in the propdb. */ if (elem->priv == NULL) { elem->priv = apr_pcalloc(propdb->p, sizeof(*priv)); } priv = elem->priv; /* 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) { /* insert the property. returns 1 if an insertion was done. */ 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 == DAV_PROP_INSERT_VALUE) { have_good = 1; /* ** Add the liveprop's namespace URIs. Note that provider==NULL ** for core properties. */ if (priv->provider != NULL) { const char * const * scan_ns_uri; for (scan_ns_uri = priv->provider->namespace_uris; *scan_ns_uri != NULL; ++scan_ns_uri) { long ns; ns = dav_get_liveprop_ns_index(*scan_ns_uri); if (marks_liveprop[ns]) continue; marks_liveprop[ns] = 1; dav_insert_xmlns(propdb->p, "lp", ns, *scan_ns_uri, &hdr_ns); } } /* property added. move on to the next property. */ continue; } else if (inserted == DAV_PROP_INSERT_NOTDEF) { /* nothing to do. fall thru to allow property to be handled as a dead property */ } #if DAV_DEBUG else { #if 0 /* ### need to change signature to return an error */ return dav_new_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, 0, 0, "INTERNAL DESIGN ERROR: insert_liveprop " "did not insert what was asked for."); #endif } #endif } /* The property wasn't a live property, so look in the dead property database. */ /* 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 (elem->ns == APR_XML_NS_NONE) name.ns = ""; else name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); name.name = elem->name; /* only bother to look if a database exists */ if (propdb->db != NULL) { int found; if ((err = (*db_hooks->output_value)(propdb->db, &name, xi, &hdr_good, &found)) != NULL) { /* ### what to do? continue doesn't seem right... */ continue; } if (found) { have_good = 1; /* if we haven't added the db's namespaces, then do so... */ if (!xi_filled) { (void) (*db_hooks->define_namespaces)(propdb->db, xi); xi_filled = 1; } continue; } } /* not found as a live OR dead property. add a record to the "bad" propstats */ /* make sure we've started our "bad" propstat */ if (hdr_bad.first == NULL) { apr_text_append(propdb->p, &hdr_bad, "<D:propstat>" DEBUG_CR "<D:prop>" DEBUG_CR); } /* output this property's name (into the bad propstats) */ dav_output_prop_name(propdb->p, &name, xi, &hdr_bad); } apr_text_append(propdb->p, &hdr_good, "</D:prop>" DEBUG_CR "<D:status>HTTP/1.1 200 OK</D:status>" DEBUG_CR "</D:propstat>" DEBUG_CR); /* default to start with the good */ result.propstats = hdr_good.first; /* we may not have any "bad" results */ if (hdr_bad.first != NULL) { /* "close" the bad propstat */ apr_text_append(propdb->p, &hdr_bad, "</D:prop>" DEBUG_CR "<D:status>HTTP/1.1 404 Not Found</D:status>" DEBUG_CR "</D:propstat>" DEBUG_CR); /* if there are no good props, then just return the bad */ if (!have_good) { result.propstats = hdr_bad.first; } else { /* hook the bad propstat to the end of the good one */ hdr_good.last->next = hdr_bad.first; } } /* add in all the various namespaces, and return them */ dav_xmlns_generate(xi, &hdr_ns); result.xmlns = hdr_ns.first; return result; }
DAV_DECLARE_NONSTD(void) dav_prop_exec(dav_prop_ctx *ctx) { dav_propdb *propdb = ctx->propdb; dav_error *err = NULL; dav_elem_private *priv = ctx->prop->priv; const dav_hooks_acl *acl_hooks = dav_get_acl_hooks(ctx->r); dav_prop_name name; ctx->rollback = apr_pcalloc(propdb->p, sizeof(*ctx->rollback)); if (ctx->prop->ns == APR_XML_NS_NONE) name.ns = ""; else name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, ctx->prop->ns); name.name = ctx->prop->name; if (ctx->is_liveprop) { err = (*priv->provider->patch_exec)(propdb->resource, ctx->prop, ctx->operation, ctx->liveprop_ctx, &ctx->rollback->liveprop); } else { /* save the old value so that we can do a rollback. */ if ((err = (*propdb->db_hooks ->get_rollback)(propdb->db, &name, &ctx->rollback->deadprop)) != NULL) goto error; if (ctx->operation == DAV_PROP_OP_SET) { /* Note: propdb->mapping was set in dav_prop_validate() */ err = (*propdb->db_hooks->store)(propdb->db, &name, ctx->prop, propdb->mapping); /* ** If an error occurred, then assume that we didn't change the ** value. Remove the rollback item so that we don't try to set ** its value during the rollback. */ /* ### euh... where is the removal? */ } else if (ctx->operation == DAV_PROP_OP_DELETE) { /* ** Delete the property. Ignore errors -- the property is there, or ** we are deleting it for a second time. */ /* ### but what about other errors? */ (void) (*propdb->db_hooks->remove)(propdb->db, &name); } } if(acl_hooks) { /* update any DAV:property ACE(s) that depend on this property */ const char *newval = dav_xml_get_cdata(dav_find_child(ctx->prop, "href"), propdb->p, 1); /* @NOTE: works only in presence of transactions, * currently no rollback state being stored for ACE changes */ /* assuming cdata is NULL for D:remove prop elem */ if(newval) (*acl_hooks->update_principal_property_aces)( (dav_resource *)propdb->resource, &name, newval); } error: /* push a more specific error here */ if (err != NULL) { if (err->status == HTTP_CONFLICT) { /* semantics of the value are not appropriate for the property */ ctx->err = err; } else { /* ** Use HTTP_INTERNAL_SERVER_ERROR because we shouldn't have seen ** any other errors at this point. */ ctx->err = dav_push_error(propdb->p, HTTP_INTERNAL_SERVER_ERROR, DAV_ERR_PROP_EXEC, "Could not execute PROPPATCH.", err); } } }
static char *write_elem(char *s, const apr_xml_elem *elem, int style, apr_array_header_t *namespaces, int *ns_map) { const apr_xml_elem *child; apr_size_t len; int ns; if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) { int empty = APR_XML_ELEM_IS_EMPTY(elem); const apr_xml_attr *attr; if (elem->ns == APR_XML_NS_NONE) { len = sprintf(s, "<%s", elem->name); } else { ns = ns_map ? ns_map[elem->ns] : elem->ns; len = sprintf(s, "<ns%d:%s", ns, elem->name); } s += len; for (attr = elem->attr; attr; attr = attr->next) { if (attr->ns == APR_XML_NS_NONE) len = sprintf(s, " %s=\"%s\"", attr->name, attr->value); else { ns = ns_map ? ns_map[attr->ns] : attr->ns; len = sprintf(s, " ns%d:%s=\"%s\"", ns, attr->name, attr->value); } s += len; } /* add the xml:lang value if necessary */ if (elem->lang != NULL && (style == APR_XML_X2T_FULL_NS_LANG || elem->parent == NULL || elem->lang != elem->parent->lang)) { len = sprintf(s, " xml:lang=\"%s\"", elem->lang); s += len; } /* add namespace definitions, if required */ if (style == APR_XML_X2T_FULL_NS_LANG) { int i; for (i = namespaces->nelts; i--;) { len = sprintf(s, " xmlns:ns%d=\"%s\"", i, APR_XML_GET_URI_ITEM(namespaces, i)); s += len; } } /* no more to do. close it up and go. */ if (empty) { *s++ = '/'; *s++ = '>'; return s; } /* just close it */ *s++ = '>'; } else if (style == APR_XML_X2T_LANG_INNER) { /* prepend the xml:lang value */ if (elem->lang != NULL) { len = strlen(elem->lang); memcpy(s, elem->lang, len); s += len; } *s++ = '\0'; } s = write_text(s, elem->first_cdata.first); for (child = elem->first_child; child; child = child->next) { s = write_elem(s, child, APR_XML_X2T_FULL, NULL, ns_map); s = write_text(s, child->following_cdata.first); } if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) { if (elem->ns == APR_XML_NS_NONE) { len = sprintf(s, "</%s>", elem->name); } else { ns = ns_map ? ns_map[elem->ns] : elem->ns; len = sprintf(s, "</ns%d:%s>", ns, elem->name); } s += len; } return s; }
static apr_size_t elem_size(const apr_xml_elem *elem, int style, apr_array_header_t *namespaces, int *ns_map) { apr_size_t size; if (style == APR_XML_X2T_FULL || style == APR_XML_X2T_FULL_NS_LANG) { const apr_xml_attr *attr; size = 0; if (style == APR_XML_X2T_FULL_NS_LANG) { int i; /* ** The outer element will contain xmlns:ns%d="%s" attributes ** and an xml:lang attribute, if applicable. */ for (i = namespaces->nelts; i--;) { /* compute size of: ' xmlns:ns%d="%s"' */ size += (9 + APR_XML_NS_LEN(i) + 2 + strlen(APR_XML_GET_URI_ITEM(namespaces, i)) + 1); } if (elem->lang != NULL) { /* compute size of: ' xml:lang="%s"' */ size += 11 + strlen(elem->lang) + 1; } } if (elem->ns == APR_XML_NS_NONE) { /* compute size of: <%s> */ size += 1 + strlen(elem->name) + 1; } else { int ns = ns_map ? ns_map[elem->ns] : elem->ns; /* compute size of: <ns%d:%s> */ size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(elem->name) + 1; } if (APR_XML_ELEM_IS_EMPTY(elem)) { /* insert a closing "/" */ size += 1; } else { /* * two of above plus "/": * <ns%d:%s> ... </ns%d:%s> * OR <%s> ... </%s> */ size = 2 * size + 1; } for (attr = elem->attr; attr; attr = attr->next) { if (attr->ns == APR_XML_NS_NONE) { /* compute size of: ' %s="%s"' */ size += 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1; } else { /* compute size of: ' ns%d:%s="%s"' */ int ns = ns_map ? ns_map[attr->ns] : attr->ns; size += 3 + APR_XML_NS_LEN(ns) + 1 + strlen(attr->name) + 2 + strlen(attr->value) + 1; } } /* ** If the element has an xml:lang value that is *different* from ** its parent, then add the thing in: ' xml:lang="%s"'. ** ** NOTE: we take advantage of the pointer equality established by ** the parsing for "inheriting" the xml:lang values from parents. */ if (elem->lang != NULL && (elem->parent == NULL || elem->lang != elem->parent->lang)) { size += 11 + strlen(elem->lang) + 1; } } else if (style == APR_XML_X2T_LANG_INNER) { /* * This style prepends the xml:lang value plus a null terminator. * If a lang value is not present, then we insert a null term. */ size = elem->lang ? strlen(elem->lang) + 1 : 1; } else size = 0; size += text_size(elem->first_cdata.first); for (elem = elem->first_child; elem; elem = elem->next) { /* the size of the child element plus the CDATA that follows it */ size += (elem_size(elem, APR_XML_X2T_FULL, NULL, ns_map) + text_size(elem->following_cdata.first)); } return size; }