Hi all, I recently asked the author of mod_dav_acl whether they would donate their apr and apr-util patches to the APR project, and (in the following message) they said yes.
Regards, Graham -- > Begin forwarded message: > > From: Graham Leggett <minf...@sharp.fm> > Subject: Fwd: DAV Option Patch > Date: 31 May 2016 at 1:30:48 AM SAST > To: Jari Urpalainen <jari.urpalai...@nokia.com> > > Hi Jari, > > A while ago there was an effort to get the outstanding patches from > mod_caldav applied to Apache httpd, and we got most of them in. > > I have noticed two patches were missed from mod_dav_acl, which were the > following for apr and apr-util. Are you able to confirm whether the > permission you obtained below to submit httpd-2.2.8-ju.patch to the ASF under > the Apache Licence extended to these two patches as well? > > If so, I’d like to get them into APR and APR-util. > > Regards, > Graham > --
apr-1.2.7-ju1.patch
Description: Binary data
apr-util-1.3.9-ju.patch
Description: Binary data
> >> Begin forwarded message: >> >> From: Jari Urpalainen <jari.urpalai...@nokia.com> >> Subject: Re: DAV Option Patch >> Date: 16 September 2009 at 12:03:49 PM SAST >> To: ext Joe Orton <jor...@redhat.com> >> Cc: ext Graham Leggett <minf...@sharp.fm>, "d...@httpd.apache.org" >> <d...@httpd.apache.org> >> Reply-To: d...@httpd.apache.org >> >> On Wed, 2009-09-16 at 11:39 +0200, ext Joe Orton wrote: >>> On Wed, Sep 16, 2009 at 10:09:23AM +0300, Jari Urpalainen wrote: >>>> I'll assume that you don't need here the content which is included >>>> within mod_dav_acl package at sf.net ? Otherwise you are certainly free >>>> to use it anyways you like. Patch contains mostly some "hooks" to >>>> mod_dav, but since i'm not that familiar with apr & apache code, you can >>>> certainly improve things. For dav_acl, caldav and carddav modules (the >>>> latter of which i just recently submitted), only similar kind of things >>>> are needed, so you can change the api freely as long as the >>>> functionality remains. I do have some cycles to update my modules >>>> accordingly. What comes to having included these with httpd, I'm in the >>>> process of asking permission from my company the change the license to >>>> APL >>> >>> If you can submit the patches to the ASF under the Apache Software >>> License, it is sufficient for you to send them to this mailing list - >>> that counts as a "contribution to the ASF". >>> >>> If you can do that, we can then include the patches in the tree, but if >>> your employer owns the copyright to the patches, then be sure you are >>> authorized to submit the code under that license first. >>> >>> Regards, Joe >> >> Ok, here's the patch (which I'm authorized to submit). And yes you can >> apply the Apache License, Version 2.0 or what is the official name. >> >> thanks Jari
diff -Naur httpd-2.2.8/modules/dav/fs/repos.c httpd-2.2.8-ju/modules/dav/fs/repos.c --- httpd-2.2.8/modules/dav/fs/repos.c 2008-06-04 10:53:04.000000000 +0300 +++ httpd-2.2.8-ju/modules/dav/fs/repos.c 2008-07-02 10:17:47.000000000 +0300 @@ -46,6 +46,7 @@ apr_pool_t *pool; /* memory storage pool associated with request */ const char *pathname; /* full pathname to resource */ apr_finfo_t finfo; /* filesystem info */ + request_rec *r; }; /* private context for doing a filesystem walk */ @@ -200,6 +201,11 @@ ** ** PRIVATE REPOSITORY FUNCTIONS */ +request_rec *dav_fs_get_request_rec(const dav_resource *resource) +{ + return resource->info->r; +} + apr_pool_t *dav_fs_pool(const dav_resource *resource) { return resource->info->pool; @@ -638,6 +644,7 @@ /* Create private resource context descriptor */ ctx = apr_pcalloc(r->pool, sizeof(*ctx)); ctx->finfo = r->finfo; + ctx->r = r; /* ### this should go away */ ctx->pool = r->pool; @@ -1775,17 +1782,13 @@ if (!resource->exists) return apr_pstrdup(ctx->pool, ""); + { + request_rec *r = ctx->r; - if (ctx->finfo.filetype != 0) { - return apr_psprintf(ctx->pool, "\"%" APR_UINT64_T_HEX_FMT "-%" - APR_UINT64_T_HEX_FMT "-%" APR_UINT64_T_HEX_FMT "\"", - (apr_uint64_t) ctx->finfo.inode, - (apr_uint64_t) ctx->finfo.size, - (apr_uint64_t) ctx->finfo.mtime); - } - - return apr_psprintf(ctx->pool, "\"%" APR_UINT64_T_HEX_FMT "\"", - (apr_uint64_t) ctx->finfo.mtime); + r->mtime = ctx->finfo.mtime; + r->finfo = ctx->finfo; + return ap_make_etag(r, 0); + } } static const dav_hooks_repository dav_hooks_repository_fs = @@ -1812,6 +1815,9 @@ dav_fs_remove_resource, dav_fs_walk, dav_fs_getetag, + dav_fs_get_request_rec, + dav_fs_pathname, + NULL }; static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, diff -Naur httpd-2.2.8/modules/dav/main/mod_dav.c httpd-2.2.8-ju/modules/dav/main/mod_dav.c --- httpd-2.2.8/modules/dav/main/mod_dav.c 2008-06-04 10:53:04.000000000 +0300 +++ httpd-2.2.8-ju/modules/dav/main/mod_dav.c 2008-07-02 10:24:09.000000000 +0300 @@ -57,6 +57,8 @@ #include "http_request.h" #include "util_script.h" +#include "ap_provider.h" + #include "mod_dav.h" @@ -79,6 +81,8 @@ const char *dir; int locktimeout; int allow_depthinfinity; + int acl_checking; + int etag_response; } dav_dir_conf; @@ -195,10 +199,18 @@ newconf->dir = DAV_INHERIT_VALUE(parent, child, dir); newconf->allow_depthinfinity = DAV_INHERIT_VALUE(parent, child, allow_depthinfinity); + newconf->acl_checking = DAV_INHERIT_VALUE(parent, child, acl_checking); + newconf->etag_response = DAV_INHERIT_VALUE(parent, child, etag_response); return newconf; } +DAV_DECLARE(const char *) dav_get_provider_name(request_rec *r) +{ + dav_dir_conf *conf = ap_get_module_config(r->per_dir_config, &dav_module); + return conf ? conf->provider_name : NULL; +} + static const dav_provider *dav_get_provider(request_rec *r) { dav_dir_conf *conf; @@ -287,6 +299,30 @@ } /* + * Command handler for the DAVACL directive, which is FLAG. + */ +static const char *dav_cmd_acl_checking(cmd_parms *cmd, void *config, + int arg) +{ + dav_dir_conf *conf = (dav_dir_conf *)config; + + conf->acl_checking = arg; + return NULL; +} + +/* + * Command handler for the DAVETagResponse directive, which is FLAG. + */ +static const char *dav_cmd_etag_response(cmd_parms *cmd, void *config, + int arg) +{ + dav_dir_conf *conf = (dav_dir_conf *)config; + + conf->etag_response = arg; + return NULL; +} + +/* * Command handler for DAVMinTimeout directive, which is TAKE1 */ static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config, @@ -361,18 +397,35 @@ ap_rputs(" xmlns:m=\"http://apache.org/dav/xmlns\"", r); } - if (err->namespace != NULL) { - ap_rprintf(r, - " xmlns:C=\"%s\">" DEBUG_CR - "<C:%s/>" DEBUG_CR, - err->namespace, err->tagname); - } + if (err->childtags) { + if (err->namespace != NULL) { + ap_rprintf(r, + " xmlns:C=\"%s\">" DEBUG_CR + "<C:%s>%s</C:%s>" DEBUG_CR, + err->namespace, + err->tagname, err->childtags, err->tagname); + } + else { + ap_rprintf(r, + ">" DEBUG_CR + "<D:%s>%s<D:%s>" DEBUG_CR, + err->tagname, err->childtags, err->tagname); + + } + } else { - ap_rprintf(r, - ">" DEBUG_CR - "<D:%s/>" DEBUG_CR, err->tagname); + if (err->namespace != NULL) { + ap_rprintf(r, + " xmlns:C=\"%s\">" DEBUG_CR + "<C:%s/>" DEBUG_CR, + err->namespace, err->tagname); + } + else { + ap_rprintf(r, + ">" DEBUG_CR + "<D:%s/>" DEBUG_CR, err->tagname); + } } - /* here's our mod_dav specific tag: */ if (err->desc != NULL) { ap_rprintf(r, @@ -423,7 +476,7 @@ [Presumably the <multistatus> tag has already been written; this routine is shared by dav_send_multistatus and dav_stream_response.] */ -static void dav_send_one_response(dav_response *response, +void dav_send_one_response(dav_response *response, apr_bucket_brigade *bb, ap_filter_t *output, apr_pool_t *pool) @@ -485,9 +538,9 @@ response and write <multistatus> tag into BB, destined for R->output_filters. Use xml NAMESPACES in initial tag, if non-NULL. */ -static void dav_begin_multistatus(apr_bucket_brigade *bb, - request_rec *r, int status, - apr_array_header_t *namespaces) +void dav_begin_multistatus(apr_bucket_brigade *bb, + request_rec *r, int status, + apr_array_header_t *namespaces) { /* Set the correct status and Content-Type */ r->status = status; @@ -510,8 +563,8 @@ } /* Finish a multistatus response started by dav_begin_multistatus: */ -static apr_status_t dav_finish_multistatus(request_rec *r, - apr_bucket_brigade *bb) +apr_status_t dav_finish_multistatus(request_rec *r, + apr_bucket_brigade *bb) { apr_bucket *b; @@ -525,9 +578,9 @@ return ap_pass_brigade(r->output_filters, bb); } -static void dav_send_multistatus(request_rec *r, int status, - dav_response *first, - apr_array_header_t *namespaces) +void dav_send_multistatus(request_rec *r, int status, + dav_response *first, + apr_array_header_t *namespaces) { apr_pool_t *subpool; apr_bucket_brigade *bb = apr_brigade_create(r->pool, @@ -587,8 +640,8 @@ * - repos_hooks->copy_resource * - vsn_hooks->update */ -static int dav_handle_err(request_rec *r, dav_error *err, - dav_response *response) +int dav_handle_err(request_rec *r, dav_error *err, + dav_response *response) { /* log the errors */ dav_log_err(r, err, APLOG_ERR); @@ -621,11 +674,25 @@ int replaced) { const char *body; + dav_dir_conf *conf; if (locn == NULL) { locn = r->uri; } + /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */ + conf = ap_get_module_config(r->per_dir_config, &dav_module); + + /* added ETag response ... vlv disabled as well ! */ + if (conf->etag_response) { + char *vlv = r->vlist_validator; + r->vlist_validator = NULL; + apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool); + r->mtime = r->finfo.mtime; + ap_set_etag(r); + r->vlist_validator = vlv; + } + /* did the target resource already exist? */ if (replaced) { /* Apache will supply a default message */ @@ -634,12 +701,10 @@ /* Per HTTP/1.1, S10.2.2: add a Location header to contain the * URI that was created. */ - + /* Convert locn to an absolute URI, and return in Location header */ apr_table_setn(r->headers_out, "Location", ap_construct_url(r->pool, locn, r)); - /* ### insert an ETag header? see HTTP/1.1 S10.2.2 */ - /* Apache doesn't allow us to set a variable body for HTTP_CREATED, so * we must manufacture the entire response. */ body = apr_psprintf(r->pool, "%s %s has been created.", @@ -647,6 +712,7 @@ return dav_error_response(r, HTTP_CREATED, body); } + /* ### move to dav_util? */ DAV_DECLARE(int) dav_get_depth(request_rec *r, int def_depth) { @@ -711,7 +777,7 @@ dav_dir_conf *conf; const char *label = NULL; dav_error *err; - + /* if the request target can be overridden, get any target selector */ if (label_allowed) { label = apr_table_get(r->headers_in, "label"); @@ -745,6 +811,12 @@ * add it now */ dav_add_vary_header(r, r, *res_p); + /* if acls checking -> check if allowed method excluding propfind */ + if (conf->acl_checking && + ((*res_p)->acl_hooks = dav_get_acl_hooks()) && + (err = (*res_p)->acl_hooks->acl_check_method(r, *res_p))) + return err; + return NULL; } @@ -1092,11 +1164,16 @@ return dav_handle_err(r, err, NULL); } } - + /* NOTE: WebDAV spec, S8.7.1 states properties should be unaffected */ /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS); + int rc = dav_created(r, NULL, "Resource", resource_state == DAV_RESOURCE_EXISTS); + + if (resource->acl_hooks) + resource->acl_hooks->acl_post_processing(r, resource, r->status == HTTP_CREATED); + + return rc; } @@ -1245,6 +1322,9 @@ dav_log_err(r, err, APLOG_WARNING); } + if (resource->acl_hooks) + resource->acl_hooks->acl_post_processing(r, resource, 0); + /* ### HTTP_NO_CONTENT if no body, HTTP_OK if there is a body (some day) */ /* Apache will supply a default error for this. */ @@ -1609,6 +1689,27 @@ if (binding_hooks != NULL) dav_level = apr_pstrcat(r->pool, dav_level, ",bindings", NULL); + { /* DAV header additions registered by external modules */ + int i; + apr_array_header_t *extensions = + ap_list_provider_names(r->pool, DAV_OPTIONS_EXTENSION_GROUP, "0"); + ap_list_provider_names_t *entry = + (ap_list_provider_names_t *)extensions->elts; + + for (i = 0; i < extensions->nelts; i++, entry++) { + const dav_hooks_options *options = + dav_get_options_hooks(entry->provider_name); + + if (options && options->dav_header) { + apr_text_header hoptions = { 0 }; + + options->dav_header(r, resource, &hoptions); + for (t = hoptions.first; t && t->text; t = t->next) + dav_level = apr_pstrcat(r->pool, dav_level, ",", t->text, NULL); + } + } + } + /* ### * MSFT Web Folders chokes if length of DAV header value > 63 characters! * To workaround that, we use separate DAV headers for versioning and @@ -1670,7 +1771,7 @@ apr_table_addn(methods, "COPY", ""); apr_table_addn(methods, "MOVE", ""); - if (!resource->collection) + /* if (!resource->collection) */ apr_table_addn(methods, "PUT", ""); if (locks_hooks != NULL) { @@ -1752,6 +1853,27 @@ apr_table_addn(methods, "SEARCH", ""); } + { /* additional methods registered by external modules */ + int i; + apr_array_header_t *extensions = + ap_list_provider_names(r->pool, DAV_OPTIONS_EXTENSION_GROUP, "0"); + ap_list_provider_names_t *entry = + (ap_list_provider_names_t *)extensions->elts; + + for (i = 0; i < extensions->nelts; i++, entry++) { + const dav_hooks_options *options = + dav_get_options_hooks(entry->provider_name); + + if (options && options->dav_method) { + apr_text_header hoptions = { 0 }; + + options->dav_method(r, resource, &hoptions); + for (t = hoptions.first; t && t->text; t = t->next) + apr_table_addn(methods, t->text, ""); + } + } + } + /* Generate the Allow header */ arr = apr_table_elts(methods); elts = (const apr_table_entry_t *)arr->elts; @@ -2023,7 +2145,12 @@ "the required child elements (the specific command)."); return HTTP_BAD_REQUEST; } - + if (resource->acl_hooks && + (ctx.propfind_type == DAV_PROPFIND_IS_PROPNAME || + ctx.propfind_type == DAV_PROPFIND_IS_ALLPROP) && + (err = resource->acl_hooks->acl_check_read(r, resource))) + return dav_handle_err(r, err, NULL); + ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; ctx.w.func = dav_propfind_walker; ctx.w.walk_ctx = &ctx; @@ -2088,8 +2215,8 @@ return DONE; } -static apr_text * dav_failed_proppatch(apr_pool_t *p, - apr_array_header_t *prop_ctx) +apr_text * dav_failed_proppatch(apr_pool_t *p, + apr_array_header_t *prop_ctx) { apr_text_header hdr = { 0 }; int i = prop_ctx->nelts; @@ -2149,7 +2276,7 @@ return hdr.first; } -static apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx) +apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx) { apr_text_header hdr = { 0 }; int i = prop_ctx->nelts; @@ -2370,6 +2497,9 @@ dav_send_multistatus(r, HTTP_MULTI_STATUS, &resp, doc->namespaces); + if (resource->acl_hooks) + resource->acl_hooks->acl_post_processing(r, resource, 0); + /* the response has been sent. */ return DONE; } @@ -2546,8 +2676,14 @@ } } + /* return an appropriate response (HTTP_CREATED) */ - return dav_created(r, NULL, "Collection", 0); + int rc = dav_created(r, NULL, "Collection", 0); + + if (resource->acl_hooks) + resource->acl_hooks->acl_post_processing(r, resource, r->status == 201); + + return rc; } /* handle the COPY and MOVE methods */ @@ -2949,9 +3085,16 @@ } } + /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, lookup.rnew->uri, "Destination", - resnew_state == DAV_RESOURCE_EXISTS); + int rc = dav_created(r, lookup.rnew->uri, "Destination", + resnew_state == DAV_RESOURCE_EXISTS); + + if (resource->acl_hooks) + resource->acl_hooks->acl_post_processing(r, is_move ? resource : resnew, + r->status == 201); + + return rc; } /* dav_method_lock: Handler to implement the DAV LOCK method @@ -4816,6 +4959,16 @@ ACCESS_CONF|RSRC_CONF, "allow Depth infinity PROPFIND requests"), + /* per directory/location, or per server */ + AP_INIT_FLAG("DAVETagResponse", dav_cmd_etag_response, NULL, + ACCESS_CONF|RSRC_CONF, + "response with ETag for dav_created"), + + /* per directory/location, or per server */ + AP_INIT_FLAG("DAVACL", dav_cmd_acl_checking, NULL, + ACCESS_CONF|RSRC_CONF, + "Access Control List as per rfc3744"), + { NULL } }; diff -Naur httpd-2.2.8/modules/dav/main/mod_dav.h httpd-2.2.8-ju/modules/dav/main/mod_dav.h --- httpd-2.2.8/modules/dav/main/mod_dav.h 2007-01-15 15:01:50.000000000 +0200 +++ httpd-2.2.8-ju/modules/dav/main/mod_dav.h 2008-07-01 19:56:18.000000000 +0300 @@ -46,7 +46,7 @@ #define DAV_VERSION AP_SERVER_BASEREVISION #define DAV_XML_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?>" -#define DAV_XML_CONTENT_TYPE "text/xml; charset=\"utf-8\"" +#define DAV_XML_CONTENT_TYPE "application/xml; charset=\"utf-8\"" #define DAV_READ_BLOCKSIZE 2048 /* used for reading input blocks */ @@ -128,10 +128,13 @@ const char *namespace; /* [optional] namespace of error */ const char *tagname; /* name of error-tag */ + const char *childtags; /* error-tag may have children */ + struct dav_error *prev; /* previous error (in stack) */ } dav_error; + /* ** Create a new error structure. save_errno will be filled with the current ** errno value. @@ -349,6 +352,10 @@ ** baselined = 0 ** working = 0 */ + +typedef struct dav_hooks_acl dav_hooks_acl; + + typedef struct dav_resource { dav_resource_type type; @@ -381,6 +388,11 @@ long as the dav_resource structure. */ apr_pool_t *pool; + /* acl hooks */ + const dav_hooks_acl *acl_hooks; + + void *ctx; /* additional parameter */ + } dav_resource; /* @@ -648,6 +660,8 @@ const dav_provider *hooks); DAV_DECLARE(const dav_provider *) dav_lookup_provider(const char *name); +DAV_DECLARE(const char *) dav_get_provider_name(request_rec *r); + /* ### deprecated */ #define DAV_GET_HOOKS_PROPDB(r) dav_get_propdb_hooks(r) @@ -1935,6 +1949,12 @@ /* Get the entity tag for a resource */ const char * (*getetag)(const dav_resource *resource); + /* return request record */ + request_rec * (*get_request_rec)(const dav_resource *resource); + + /* return path */ + const char * (*get_pathname)(const dav_resource *resource); + /* ** If a provider needs a context to associate with this hooks structure, ** then this field may be used. In most cases, it will just be NULL. @@ -2419,6 +2439,106 @@ const dav_hooks_liveprop *provider; /* the provider defining this prop */ } dav_elem_private; + +/* -------------------------------------------------------------------- +** +** DAV ACL HOOKS +*/ + +struct dav_hooks_acl +{ + dav_error * (*acl_check_method)(request_rec *r, + const dav_resource *resource); + + dav_error * (*acl_check_read)(request_rec *r, + const dav_resource *resource); + + dav_error * (*acl_check_prop)(request_rec *r, + const dav_resource *resource, + const dav_prop_name *name, + dav_prop_insert what); + + void (*acl_post_processing)(request_rec *r, + const dav_resource *resource, + int fStoreOwner); + void *ctx; +}; + + +DAV_DECLARE(void) dav_acl_register_hooks(apr_pool_t *p, + const dav_hooks_acl *acl); + +DAV_DECLARE(const dav_hooks_acl *) dav_get_acl_hooks(); + +/* moved some nice functions to public */ +extern void dav_begin_multistatus(apr_bucket_brigade *bb, + request_rec *r, int status, + apr_array_header_t *namespaces); +extern void dav_send_one_response(dav_response *response, + apr_bucket_brigade *bb, + ap_filter_t *output, + apr_pool_t *pool); +extern apr_status_t dav_finish_multistatus(request_rec *r, + apr_bucket_brigade *bb); +extern void dav_send_multistatus(request_rec *r, int status, + dav_response *first, + apr_array_header_t *namespaces); +extern int dav_handle_err(request_rec *r, dav_error *err, + dav_response *response); +extern apr_text * dav_failed_proppatch(apr_pool_t *p, + apr_array_header_t *prop_ctx); +extern apr_text * dav_success_proppatch(apr_pool_t *p, apr_array_header_t *prop_ctx); + + +/* -------------------------------------------------------------------- +** +** DAV RESOURCE TYPE HOOKS +*/ + +typedef struct dav_hooks_resource +{ + int (*get_resource_type)(const dav_resource *resource, + const char **name, + const char **uri); + + void *ctx; +} dav_hooks_resource; + +#define DAV_RESOURCE_GROUP "dav_resource" + +DAV_DECLARE(void) dav_resource_register_hooks(apr_pool_t *p, + const char *name, + const dav_hooks_resource *provider); + +DAV_DECLARE(const dav_hooks_resource *) dav_get_resource_hooks(const char *name); + + +/* -------------------------------------------------------------------- +** +** DAV OPTIONS HOOKS +*/ +#define DAV_OPTIONS_EXTENSION_GROUP "dav_options" + +typedef struct dav_hooks_options +{ + dav_error* (*dav_header)(request_rec *r, + const dav_resource *resource, + apr_text_header *phdr); + + dav_error* (*dav_method)(request_rec *r, + const dav_resource *resource, + apr_text_header *phdr); + + void *ctx; +} dav_hooks_options; + +extern DAV_DECLARE(const dav_hooks_options *) dav_get_options_hooks(const char *name); + +extern DAV_DECLARE(void) dav_options_register_hooks(apr_pool_t *p, + const char *name, + const dav_hooks_options *provider); + + #ifdef __cplusplus } #endif diff -Naur httpd-2.2.8/modules/dav/main/props.c httpd-2.2.8-ju/modules/dav/main/props.c --- httpd-2.2.8/modules/dav/main/props.c 2007-01-15 15:01:50.000000000 +0200 +++ httpd-2.2.8-ju/modules/dav/main/props.c 2008-06-06 08:02:11.000000000 +0300 @@ -538,7 +538,7 @@ propdb->ns_xlate = ns_xlate; propdb->db_hooks = DAV_GET_HOOKS_PROPDB(r); - + propdb->lockdb = lockdb; /* always defer actual open, to avoid expense of accessing db @@ -617,7 +617,14 @@ found_contentlang = 1; } } - + /* check for possible acl restrictions */ + if (propdb->resource->acl_hooks && + propdb->resource->acl_hooks->acl_check_prop(propdb->r, + propdb->resource, + &name, + what)) { + goto next_key; + } if (what == DAV_PROP_INSERT_VALUE) { dav_error *err; int found; @@ -700,6 +707,7 @@ 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_not_auth = { 0 }; apr_text_header hdr_ns = { 0 }; int have_good = 0; dav_get_props_result result = { 0 }; @@ -707,6 +715,11 @@ dav_xmlns_info *xi; int xi_filled = 0; + /* check for possible acl restrictions */ + dav_error *err_read = propdb->resource->acl_hooks ? + propdb->resource->acl_hooks->acl_check_read(propdb->r, + propdb->resource) : NULL; + /* ### NOTE: we should pass in TWO buffers -- one for keys, one for the marks */ @@ -729,7 +742,7 @@ 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. @@ -746,6 +759,32 @@ if (priv->propid != DAV_PROPID_CORE_UNKNOWN) { + /* check for possible acl restrictions + * ask for each live prop separately (e.g. read-acl privilege) */ + if (propdb->resource->acl_hooks) { + 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; + + if (propdb->resource->acl_hooks-> + acl_check_prop(propdb->r, propdb->resource, + &name, + DAV_PROP_INSERT_VALUE)) { + + if (hdr_not_auth.first == NULL) { + apr_text_append(propdb->p, &hdr_not_auth, + "<D:propstat>" DEBUG_CR + "<D:prop>" DEBUG_CR); + } + if (!name.ns) + name.ns = ""; + dav_output_prop_name(propdb->p, &name, xi, &hdr_not_auth); + continue; + } + } + /* 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) { @@ -783,7 +822,7 @@ 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 @@ -811,6 +850,19 @@ name.ns = APR_XML_GET_URI_ITEM(propdb->ns_xlate, elem->ns); name.name = elem->name; + /* check for possible acl restrictions */ + if (err_read) { + if (hdr_not_auth.first == NULL) { + apr_text_append(propdb->p, &hdr_not_auth, + "<D:propstat>" DEBUG_CR + "<D:prop>" DEBUG_CR); + } + if (!name.ns) + name.ns = ""; + dav_output_prop_name(propdb->p, &name, xi, &hdr_not_auth); + continue; + } + /* only bother to look if a database exists */ if (propdb->db != NULL) { int found; @@ -874,6 +926,21 @@ } } + if (hdr_not_auth.first != NULL) { + apr_text_append(propdb->p, &hdr_not_auth, + "</D:prop>" DEBUG_CR + "<D:status>HTTP/1.1 403 Forbidden</D:status>" DEBUG_CR + "</D:propstat>" DEBUG_CR); + + if (!have_good && !hdr_bad.first) + result.propstats = hdr_not_auth.first; + else if (hdr_bad.first != NULL) + hdr_bad.last->next = hdr_not_auth.first; + else + hdr_good.last->next = hdr_not_auth.first; + + } + /* add in all the various namespaces, and return them */ dav_xmlns_generate(xi, &hdr_ns); result.xmlns = hdr_ns.first; diff -Naur httpd-2.2.8/modules/dav/main/providers.c httpd-2.2.8-ju/modules/dav/main/providers.c --- httpd-2.2.8/modules/dav/main/providers.c 2007-01-15 15:01:50.000000000 +0200 +++ httpd-2.2.8-ju/modules/dav/main/providers.c 2008-06-06 08:02:11.000000000 +0300 @@ -31,3 +31,41 @@ { return ap_lookup_provider(DAV_PROVIDER_GROUP, name, "0"); } + +DAV_DECLARE(void) dav_acl_register_hooks(apr_pool_t *p, + const dav_hooks_acl *provider) +{ + ap_register_provider(p, DAV_PROVIDER_GROUP, "acl", "0", provider); +} + +DAV_DECLARE(const dav_hooks_acl *) dav_get_acl_hooks() +{ + return ap_lookup_provider(DAV_PROVIDER_GROUP, "acl", "0"); +} + +DAV_DECLARE(void) dav_options_register_hooks(apr_pool_t *p, + const char *name, + const dav_hooks_options *provider) +{ + ap_register_provider(p, DAV_OPTIONS_EXTENSION_GROUP, name, "0", provider); +} + +DAV_DECLARE(const dav_hooks_options *) dav_get_options_hooks(const char *name) +{ + return ap_lookup_provider(DAV_OPTIONS_EXTENSION_GROUP, name, "0"); +} + +DAV_DECLARE(void) dav_resource_register_hooks(apr_pool_t *p, + const char *name, + const dav_hooks_resource *provider) +{ + ap_register_provider(p, DAV_RESOURCE_GROUP, name, "0", provider); +} + +DAV_DECLARE(const dav_hooks_resource *) dav_get_resource_hooks(const char *name) +{ + return ap_lookup_provider(DAV_RESOURCE_GROUP, name, "0"); +} + + + diff -Naur httpd-2.2.8/modules/dav/main/std_liveprop.c httpd-2.2.8-ju/modules/dav/main/std_liveprop.c --- httpd-2.2.8/modules/dav/main/std_liveprop.c 2007-01-15 15:01:50.000000000 +0200 +++ httpd-2.2.8-ju/modules/dav/main/std_liveprop.c 2008-06-06 08:02:11.000000000 +0300 @@ -17,6 +17,7 @@ #include "httpd.h" #include "util_xml.h" #include "apr_strings.h" +#include "ap_provider.h" #include "mod_dav.h" @@ -59,7 +60,7 @@ int propid, dav_prop_insert what, apr_text_header *phdr) { - const char *value; + const char *value = NULL; const char *s; apr_pool_t *p = resource->pool; const dav_liveprop_spec *info; @@ -68,32 +69,63 @@ switch (propid) { case DAV_PROPID_resourcetype: + + { /* additional type info provided by external modules ? */ + int i; + + apr_array_header_t *extensions = + ap_list_provider_names(p, DAV_RESOURCE_GROUP, "0"); + ap_list_provider_names_t *entry = + (ap_list_provider_names_t *)extensions->elts; + + for (i = 0; i < extensions->nelts; i++, entry++) { + const dav_hooks_resource *res_hooks = + dav_get_resource_hooks(entry->provider_name); + const char *name = NULL, *uri = NULL; + + if (!res_hooks || !res_hooks->get_resource_type) + continue; + + if (!res_hooks->get_resource_type(resource, &name, &uri) && + name) { + + if (!uri || !strcasecmp(uri, "DAV:")) + value = apr_pstrcat(p, value ? value : "", + "<D:", name, "/>", NULL); + else + value = apr_pstrcat(p, value ? value : "", + "<x:", name, + " xmlns:x=\"", uri, + "\"/>", NULL); + } + } + } switch (resource->type) { case DAV_RESOURCE_TYPE_VERSION: if (resource->baselined) { - value = "<D:baseline/>"; + value = apr_pstrcat(p, value ? value : "", "<D:baseline/>", NULL); break; } /* fall through */ case DAV_RESOURCE_TYPE_REGULAR: case DAV_RESOURCE_TYPE_WORKING: if (resource->collection) { - value = "<D:collection/>"; + value = apr_pstrcat(p, value ? value : "", "<D:collection/>", NULL); } else { /* ### should we denote lock-null resources? */ - - value = ""; /* becomes: <D:resourcetype/> */ + if (value == NULL) + value = ""; /* becomes: <D:resourcetype/> */ } break; case DAV_RESOURCE_TYPE_HISTORY: - value = "<D:version-history/>"; + value = apr_pstrcat(p, value ? value : "", "<D:version-history/>", NULL); break; case DAV_RESOURCE_TYPE_WORKSPACE: - value = "<D:collection/>"; + value = apr_pstrcat(p, value ? value : "", "<D:collection/>", NULL); break; case DAV_RESOURCE_TYPE_ACTIVITY: - value = "<D:activity/>"; + value = apr_pstrcat(p, value ? value : "", "<D:activity/>", NULL); break; default: diff -Naur httpd-2.2.8/modules/http/http_etag.c httpd-2.2.8-ju/modules/http/http_etag.c --- httpd-2.2.8/modules/http/http_etag.c 2008-06-04 10:53:04.000000000 +0300 +++ httpd-2.2.8-ju/modules/http/http_etag.c 2008-06-06 08:02:11.000000000 +0300 @@ -100,7 +100,12 @@ * be modified again later in the second, and the validation * would be incorrect. */ - if ((r->request_time - r->mtime > (1 * APR_USEC_PER_SEC)) && + if ( +#if 0 + imo weak etags are bogus + (r->request_time - r->mtime > (1 * APR_USEC_PER_SEC)) && +#endif + !force_weak) { weak = NULL; weak_len = 0;
> >> >