Den mån 8 sep. 2025 kl 00:58 skrev Branko Čibej <[email protected]>:

> On 7. 9. 25 22:38, Daniel Sahlberg wrote:
>
> Den ons 20 aug. 2025 kl 16:43 skrev Branko Čibej <[email protected]>:
>
>> [moved here from users@]
>>
>> On 20. 8. 25 14:29, sebb wrote:
>>
>> svn co --depth=empty https://svn.apache.org/repos/asf/incubator
>>
>>
>>
>> Traced this to svn_ra_serf__expect_empty_body() line 1154; the value
>> returned from serf_bucket_response_get_headers() is 0xf0, clearly wrong,
>> and then serf_bucket_headers_get() crashes. This happens with both serf-1
>> and serf-2 (trunk), could be a bug in Serf, could be something else. Also
>> happens over http://, so it's not something related to OpenSSL (which
>> makes sense).
>>
>> -- Brane
>>
>>
> Hi,
>
> I've spent some time this weekend trying to figure this out. It seems like
> we end up in Subversion's libsvn_ra_serf/update.c in process_buffer with
> at_eof = 0, thus creating an EAGAIN bucket which doesn't have any header,
> thus causing an error later on (as described by Brane above). Thus I'm
> leaning towards a Subversion error rather than an error in Serf.
>
> The call originates in update_delay_handler and it seems that function has
> the proper headers in the request bucket. But it creates a new bucket in
> process_buffer, without attaching the headers. This in turn causes the
> issues in serf_bucket_response_get_headers() since there are no headers to
> get.
>
> I'm a bit at loss here, but it would be fun to be able to follow this to
> the very end so if I may ask the graybeards here to not "just solve it" but
> bear with me and maybe just give me a few pointers on where to look next.
> Even if it is a Doh! moment for someone...
>
>
>
> Never been in that code. If it's a 301, Subversion should handle it, I'm
> almost certain Serf doesn't (which is ... another kind of problem). You're
> sure it behaves as if it received EAGAIN instead of a redirect? I know
> there's code in Subversion that handles redirects, but it's IIRC at a
> higher level where we connect to the repository; not in the edit drive.
>

Well... We end up here (ignore the line numbers, I've added quite a bit of
printf() debug code).

[[[
(gdb) bt
#0  update_delay_handler (request=0x7ffff638a038, response=0x7ffff6392738,
handler_baton=0x7ffff63ad2a0, scratch_pool=0x7ffff6381028) at
subversion/libsvn_ra_serf/update.c:2258
#1  0x00007ffff79b6c36 in handle_response (request=0x7ffff638a038,
response=0x7ffff6392738, handler=0x7ffff63ad1c0,
serf_status=0x7fffffffcbe0, scratch_pool=0x7ffff6381028) at
subversion/libsvn_ra_serf/util.c:1489
#2  0x00007ffff79b6d48 in handle_response_cb (request=0x7ffff638a038,
response=0x7ffff6392738, baton=0x7ffff63ad1c0,
response_pool=0x7ffff6381028) at subversion/libsvn_ra_serf/util.c:1523
#3  0x00007ffff765c94e in serf.process_connection () from
/home/dsg/bin/lib/libserf-1.so.1
#4  0x00007ffff765b21e in serf_event_trigger () from
/home/dsg/bin/lib/libserf-1.so.1
#5  0x00007ffff765b369 in serf_context_run () from
/home/dsg/bin/lib/libserf-1.so.1
#6  0x00007ffff79b599c in svn_ra_serf__context_run (sess=0x7ffff63af250,
waittime_left=0x7fffffffcdd8, scratch_pool=0x7ffff6386028) at
subversion/libsvn_ra_serf/util.c:913
#7  0x00007ffff79b2f55 in process_editor_report (ctx=0x7ffff639c660,
handler=0x7ffff63ad1c0, scratch_pool=0x7ffff63ad028) at
subversion/libsvn_ra_serf/update.c:2434
#8  0x00007ffff79b33e6 in finish_report (report_baton=0x7ffff639c660,
pool=0x7ffff63b1028) at subversion/libsvn_ra_serf/update.c:2509
#9  0x00007ffff7de8da0 in svn_wc_crawl_revisions6 (wc_ctx=0x7ffff63c48a8,
local_abspath=0x7ffff63b1168 "/home/dsg/bin/bin/incubator",
reporter=0x7ffff79cd660 <ra_serf_reporter>, report_baton=0x7ffff639c660,
restore_files=1,
    depth=svn_depth_unknown, honor_depth_exclude=1,
depth_compatibility_trick=0, use_commit_times=0, cancel_func=0x7ffff7ceb065
<check_cancel>, cancel_baton=0x0, notify_func=0x5555555877a5
<svn_cl__check_externals_failed_notify_wrapper>,
    notify_baton=0x7fffffffd700, scratch_pool=0x7ffff63b1028) at
subversion/libsvn_wc/adm_crawler.c:868
#10 0x00007ffff7f9924d in update_internal (result_rev=0x0,
timestamp_sleep=0x7fffffffd5dc, conflicted_paths=0x0,
ra_session_p=0x7fffffffd2d0, local_abspath=0x7ffff63b1168
"/home/dsg/bin/bin/incubator",
    anchor_abspath=0x7ffff63b2f50 "/home/dsg/bin/bin/incubator",
revision=0x7fffffffd360, depth=svn_depth_unknown, depth_is_sticky=0,
ignore_externals=0, allow_unver_obstructions=0, adds_as_modification=1,
notify_summary=1,
    ctx=0x7ffff63c47d8, result_pool=0x7ffff63b1028,
scratch_pool=0x7ffff63b1028) at subversion/libsvn_client/update.c:563
#11 0x00007ffff7f99884 in svn_client__update_internal (result_rev=0x0,
timestamp_sleep=0x7fffffffd5dc, local_abspath=0x7ffff63b1168
"/home/dsg/bin/bin/incubator", revision=0x7fffffffd4e0,
depth=svn_depth_unknown, depth_is_sticky=1,
    ignore_externals=0, allow_unver_obstructions=0, adds_as_modification=1,
make_parents=0, innerupdate=0, ra_session=0x7ffff63af228,
ctx=0x7ffff63c47d8, pool=0x7ffff63b1028) at
subversion/libsvn_client/update.c:702
#12 0x00007ffff7efaf6f in svn_client__checkout_internal (result_rev=0x0,
timestamp_sleep=0x7fffffffd5dc, url=0x7ffff63b34a8 "
http://svn.apache.org/repos/asf/incubator";, local_abspath=0x7ffff63b1168
"/home/dsg/bin/bin/incubator",
    peg_revision=0x7fffffffd6f0, revision=0x7fffffffd6e0,
depth=svn_depth_unknown, ignore_externals=0, allow_unver_obstructions=0,
settings_from_context=0, wc_format_version=0x0,
store_pristine=svn_tristate_unknown,
    ra_session=0x7ffff63af228, ctx=0x7ffff63c47d8,
scratch_pool=0x7ffff63b1028) at subversion/libsvn_client/checkout.c:274
#13 0x00007ffff7efb091 in svn_client_checkout4 (result_rev=0x0,
URL=0x7ffff63b34a8 "http://svn.apache.org/repos/asf/incubator";,
path=0x7ffff63b34f8 "incubator", peg_revision=0x7fffffffd6f0,
revision=0x7fffffffd6e0, depth=svn_depth_unknown,
    ignore_externals=0, allow_unver_obstructions=0, wc_format_version=0x0,
store_pristine=svn_tristate_unknown, ctx=0x7ffff63c47d8,
pool=0x7ffff63b1028) at subversion/libsvn_client/checkout.c:305
#14 0x0000555555567db1 in svn_cl__checkout (os=0x7ffff63c3520,
baton=0x7fffffffd9d0, pool=0x7ffff63c3028) at
subversion/svn/checkout-cmd.c:168
#15 0x000055555559c2c2 in sub_main (exit_code=0x7fffffffdd04, argc=3,
cmdline_argv=0x7fffffffde48, pool=0x7ffff63c3028) at
subversion/svn/svn.c:3365
#16 0x000055555559c64c in main (argc=3, argv=0x7fffffffde48) at
subversion/svn/svn.c:3450
]]]

update_delay_handler has an argument response, a bucket of type RESPONSE,
and I can call serf_bucket_response_get_headers(response) to get a headers
bucket which I can pass to serf_bucket_headers_get and get the headers.

We then get the response (serf_bucket_read) and pass on to process_buffer
which creates a new bucket using svn_ra_serf__create_bucket_with_eagain. (I
think the eagain is a red herring. We seem to read from the
response_body_bucket which is returning 0, ie not APR_STATUS_IS_EOF, so the
udb->report->report_received and at_eof flags are not set to TRUE. But even
if I hard code these to TRUE, process_buffer creates a new bucket with
serf_bucket_simple_create and this STILL doesn't have a request header so
we fail in the same place as before.

It seems Subversion is looking for a redirect on
svn_ra_serf__exchange_capabilities(), which is called really early, in
svn_ra_serf__open(). The server, at that time, isn't sending a 301 (the
actual request is OPTIONS /repos/asf/incubator) so we proceed. Then (much)
later the server sends a 301 on REPORT /repos/asf/!svn/me which we are not
able to handle.

One way to solve this is to check if serf_bucket_response_get_headers find
any header, something like this:

[[[
Index: subversion/libsvn_ra_serf/util.c
===================================================================
--- subversion/libsvn_ra_serf/util.c    (revision 1926872)
+++ subversion/libsvn_ra_serf/util.c    (working copy)
@@ -1139,7 +1139,7 @@ svn_ra_serf__expect_empty_body(serf_request_t *req
 {
   svn_ra_serf__handler_t *handler = baton;
   serf_bucket_t *hdrs;
-  const char *val;
+  const char *val = 0;

   /* This function is just like handle_multistatus_only() except for the
      XML parsing callbacks. We want to look for the -readable element.  */
@@ -1151,7 +1151,8 @@ svn_ra_serf__expect_empty_body(serf_request_t *req
   SVN_ERR_ASSERT(handler->server_error == NULL);

   hdrs = serf_bucket_response_get_headers(response);
-  val = serf_bucket_headers_get(hdrs, "Content-Type");
+  if (hdrs)
+    val = serf_bucket_headers_get(hdrs, "Content-Type");
   if (val
       && (handler->sline.code < 200 || handler->sline.code >= 300)
       && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0)
]]]

The server did actually return Content-Type: text/xml, so technically this
is probably wrong, but the reply body is HTML and I have a feeling it
wouldn't pass XML parsing a little later in the code above. With the change
above we fail with the following error message:
[[[
svn: E175011: Repository moved permanently to '
http://svn.apache.org/repos/asf'
]]]

We should probably come back to OP with a question why they configured the
redirect this way in the first place..

Cheers,
Daniel

Reply via email to