Mailing List Archive

MS-WDV (was Re: Help with buckets)
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
manu@netbsd.org
Re: MS-WDV (was Re: Help with buckets) [ In reply to ]
On Fri, Dec 02, 2022 at 08:53:07AM +0000, Emmanuel Dreyfus wrote:
> 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.

Hi Emmanuel,

That's a very weird protocol design, wow. Have you tested this with a
long PROPFIND response? It needs to buffer the entire response in the
output brigade to work out the length in the "multipart" prefix, but
mod_dav will flush output brigades down the filter chain regularly
during the multistatus response processing.

I think this might need to do something more complex, maybe running the
PROPFIND in a subrequest properly and capturing (buffering) the output
in a custom filter, rather than using the mod_dav internal API directly.
Have you tried using ap_sub_req_method_uri()? Not sure this has been
tried before with mod_dav so might well be something I'm missing.

Regards, Joe
Re: MS-WDV (was Re: Help with buckets) [ In reply to ]
On Fri, Dec 02, 2022 at 03:17:05PM +0000, Joe Orton wrote:
> I think this might need to do something more complex, maybe running the
> PROPFIND in a subrequest properly and capturing (buffering) the output
> in a custom filter, rather than using the mod_dav internal API directly.
> Have you tried using ap_sub_req_method_uri()? Not sure this has been
> tried before with mod_dav so might well be something I'm missing.

I can try that, but whatever the method is, we need to produce the
propfind data before sending its size.

I see two unsatisfying alternatives:

1) produce propfind data in a buffer, output the size, then the buffer

2) produce propfind data, discarding it as it comes but coutning its size,
then output the size, and produce the propfind data a second time.

First approach wastes memory, second approach wastes CPU. And second approach
needs a mechanism to ensure propfind data does not change between the two
times it is produced. I am not sure that can be guaranteed.

--
Emmanuel Dreyfus
manu@netbsd.org
Re: MS-WDV (was Re: Help with buckets) [ In reply to ]
On 12/2/22 4:42 PM, Emmanuel Dreyfus wrote:
> On Fri, Dec 02, 2022 at 03:17:05PM +0000, Joe Orton wrote:
>> I think this might need to do something more complex, maybe running the
>> PROPFIND in a subrequest properly and capturing (buffering) the output
>> in a custom filter, rather than using the mod_dav internal API directly.
>> Have you tried using ap_sub_req_method_uri()? Not sure this has been
>> tried before with mod_dav so might well be something I'm missing.
>
> I can try that, but whatever the method is, we need to produce the
> propfind data before sending its size.
>
> I see two unsatisfying alternatives:
>
> 1) produce propfind data in a buffer, output the size, then the buffer
>
> 2) produce propfind data, discarding it as it comes but coutning its size,
> then output the size, and produce the propfind data a second time.
>
> First approach wastes memory, second approach wastes CPU. And second approach
> needs a mechanism to ensure propfind data does not change between the two
> times it is produced. I am not sure that can be guaranteed.

I think we cannot guarantee this, which leaves us with 1.

Regards

RĂ¼diger
Re: MS-WDV (was Re: Help with buckets) [ In reply to ]
On Fri, Dec 02, 2022 at 03:17:05PM +0000, Joe Orton wrote:
> I think this might need to do something more complex, maybe running the
> PROPFIND in a subrequest properly and capturing (buffering) the output
> in a custom filter, rather than using the mod_dav internal API directly.
> Have you tried using ap_sub_req_method_uri()? Not sure this has been
> tried before with mod_dav so might well be something I'm missing.

I did it the way you suggested. The patch gets huge, I just send the
reelvant bits. Does it looks good to you?

In register_hooks() I have
ap_register_output_filter("DAV_MSEXT_OUT", dav_msext_output, NULL,
AP_FTYPE_RESOURCE);
Then:

static apr_status_t dav_msext_output(ap_filter_t *f,
apr_bucket_brigade *bb)
{
apr_bucket_brigade *bbsub = f->ctx;
apr_bucket *b;

b = APR_BRIGADE_FIRST(bb);
while (b != APR_BRIGADE_SENTINEL(bb)) {
apr_bucket *nb;
if (APR_BUCKET_IS_EOS(b))
break;

nb = APR_BUCKET_NEXT(b);
APR_BUCKET_REMOVE(b);
APR_BRIGADE_INSERT_TAIL(bbsub, b);
b = nb;
}

return ap_pass_brigade(f->next, bb);
}

static void dav_msdavext_combined_propfind(request_rec *r)
{
apr_bucket_brigade *bbsub;
apr_bucket_brigade *bb;
ap_filter_t *f;
apr_bucket *b;
request_rec *rr = NULL;
apr_off_t length;

bbsub = apr_brigade_create(r->pool, r->output_filters->c->bucket_alloc);

rr = ap_sub_req_method_uri("PROPFIND", r->uri, r, r->output_filters);
if (!rr || rr->status != HTTP_OK)
goto out;

f = ap_add_output_filter("DAV_MSEXT_OUT", bbsub, rr, rr->connection);
if (!f)
goto out;

if (ap_run_sub_req(rr) != OK)
goto out;

ap_remove_output_filter(f);

if (apr_brigade_length(bbsub, 1, &length) != APR_SUCCESS)
goto out;

bb = apr_brigade_create(r->pool,r->output_filters->c->bucket_alloc);

apr_brigade_printf(bb, NULL, NULL,
"%016" APR_UINT64_T_HEX_FMT, length);

APR_BRIGADE_CONCAT(bb, bbsub);

ap_destroy_sub_req(rr);
rr = NULL;

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);

/* plain GET rocessing happens afterward */
out:
if (rr)
ap_destroy_sub_req(rr);

return;
}


--
Emmanuel Dreyfus
manu@netbsd.org