Hello I made some progress with the combined GET+PROPFIND specified by MS-WDV (for a summary, see https://lists.apache.org/thread/57s1vvl6k9qpdv5ym7mtcl29bd933w7k )
Attached is the diff against trunk, form comments. -- Emmanuel Dreyfus m...@netbsd.org
Index: dav/main/mod_dav.c =================================================================== --- dav/main/mod_dav.c (revision 1905652) +++ dav/main/mod_dav.c (working copy) @@ -84,7 +84,7 @@ int locktimeout; int allow_depthinfinity; int allow_lockdiscovery; - + int enable_msext; } dav_dir_conf; /* per-server configuration */ @@ -206,6 +206,8 @@ allow_depthinfinity); newconf->allow_lockdiscovery = DAV_INHERIT_VALUE(parent, child, allow_lockdiscovery); + newconf->enable_msext = DAV_INHERIT_VALUE(parent, child, + enable_msext); return newconf; } @@ -319,6 +321,20 @@ } /* + * Command handler for the DAVmsExt directive, which is FLAG. + */ +static const char *dav_cmd_davmsext(cmd_parms *cmd, void *config, int arg) +{ + dav_dir_conf *conf = (dav_dir_conf *)config; + + if (arg) + conf->enable_msext = DAV_ENABLED_ON; + else + conf->enable_msext = DAV_ENABLED_OFF; + return NULL; +} + +/* * Command handler for DAVMinTimeout directive, which is TAKE1 */ static const char *dav_cmd_davmintimeout(cmd_parms *cmd, void *config, @@ -558,10 +574,17 @@ DAV_DECLARE(apr_status_t) dav_finish_multistatus(request_rec *r, apr_bucket_brigade *bb) { + ap_fputs(r->output_filters, bb, "</D:multistatus>" DEBUG_CR); + + return OK; +} + + +/* Send the response to the first filter */ +static apr_status_t dav_pass_brigade(request_rec *r, apr_bucket_brigade *bb) +{ apr_bucket *b; - ap_fputs(r->output_filters, bb, "</D:multistatus>" DEBUG_CR); - /* indicate the end of the response body */ b = apr_bucket_eos_create(r->connection->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); @@ -590,6 +613,7 @@ apr_pool_destroy(subpool); dav_finish_multistatus(r, bb); + dav_pass_brigade(r, bb); } /* @@ -1691,6 +1715,7 @@ /* handle the OPTIONS method */ static int dav_method_options(request_rec *r) { + dav_dir_conf *conf; const dav_hooks_locks *locks_hooks = DAV_GET_HOOKS_LOCKS(r); const dav_hooks_vsn *vsn_hooks = DAV_GET_HOOKS_VSN(r); const dav_hooks_binding *binding_hooks = DAV_GET_HOOKS_BINDING(r); @@ -1801,6 +1826,11 @@ /* this tells MSFT products to skip looking for FrontPage extensions */ apr_table_setn(r->headers_out, "MS-Author-Via", "DAV"); + /* MS-WDV extensions */ + conf = ap_get_module_config(r->per_dir_config, &dav_module); + if (conf && conf->enable_msext == DAV_ENABLED_ON) + apr_table_setn(r->headers_out, "X-MSDAVEXT", "1"); + /* * Determine which methods are allowed on the resource. * Three cases: resource is null (3), is lock-null (7.4), or exists. @@ -2146,7 +2176,7 @@ } /* handle the PROPFIND method */ -static int dav_method_propfind(request_rec *r) +static int dav_method_propfind(request_rec *r, apr_bucket_brigade *bb) { dav_resource *resource; int depth; @@ -2237,7 +2267,10 @@ ctx.doc = doc; ctx.r = r; - ctx.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + if (bb) + ctx.bb = bb; + else + ctx.bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); apr_pool_create(&ctx.scratchpool, r->pool); apr_pool_tag(ctx.scratchpool, "mod_dav-scratch"); @@ -2288,6 +2321,8 @@ } dav_finish_multistatus(r, ctx.bb); + if (!bb) + dav_pass_brigade(r, ctx.bb); /* the response has been sent. */ return DONE; @@ -4965,12 +5000,70 @@ return dav_created(r, lookup.rnew->unparsed_uri, "Binding", 0); } +static void dav_msdavext_combined(request_rec *r) +{ + dav_dir_conf *conf; + const char *msdavext_hdr; + apr_bucket_brigade *bb; + apr_bucket *b; + request_rec *rr = NULL; + apr_off_t length; + char buf[16+1]; /* +1 for trailing \0 */ + if (r->main) + goto out; + + if (r->method_number != M_GET && r->method_number != M_POST) + goto out; + + conf = ap_get_module_config(r->per_dir_config, &dav_module); + if (conf->enable_msext != DAV_ENABLED_ON) + goto out; + + msdavext_hdr = apr_table_get(r->headers_in, "X-MSDAVEXT"); + if (msdavext_hdr == NULL || strcmp(msdavext_hdr, "PROPFIND") !=0) + goto out; + + bb = apr_brigade_create(r->pool,r->output_filters->c->bucket_alloc); + if (dav_method_propfind(r, bb) != DONE) + goto out; + + if (apr_brigade_length(bb, 1, &length) != APR_SUCCESS) + goto out; + + b = apr_bucket_transient_create(buf, 16, + r->output_filters->c->bucket_alloc); + (void)apr_snprintf(buf, sizeof(buf), + "%016" APR_UINT64_T_HEX_FMT, (uint64_t)length); + APR_BRIGADE_INSERT_HEAD(bb, b); + + rr = ap_sub_req_lookup_uri(r->uri, r, r->output_filters); + if (!rr || rr->status != HTTP_OK || rr->filename == NULL || + rr->finfo.filetype != APR_REG) + goto out; + + apr_brigade_printf(bb, NULL, NULL, + "%016" APR_UINT64_T_HEX_FMT, rr->finfo.size); + + ap_set_content_type(r, "multipart/MSDAVEXTPrefixEncoded"); + + ap_pass_brigade(r->output_filters, bb); + +out: + if (rr) + ap_destroy_sub_req(rr); + + return; +} + /* * Response handler for DAV resources */ static int dav_handler(request_rec *r) { + /* MS-WDV extensions */ + dav_msdavext_combined(r); + if (strcmp(r->handler, DAV_HANDLER_NAME) != 0) return DECLINED; @@ -5063,7 +5156,7 @@ } if (r->method_number == M_PROPFIND) { - return dav_method_propfind(r); + return dav_method_propfind(r, NULL); } if (r->method_number == M_PROPPATCH) { @@ -5248,6 +5341,11 @@ ACCESS_CONF|RSRC_CONF, "allow lock discovery by PROPFIND requests"), + /* per directory/location, or per server */ + AP_INIT_FLAG("DAVMSext", dav_cmd_davmsext, NULL, + ACCESS_CONF|RSRC_CONF, + "Enable MS-WDV extensions"), + { NULL } };