[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: ra_serf infinite loop with mod_ssl and mod_deflate

From: Philip Martin <philip.martin_at_wandisco.com>
Date: Tue, 11 Nov 2014 18:28:53 +0000

Philip Martin <philip_at_codematters.co.uk> writes:

> Philip Martin <philip.martin_at_wandisco.com> writes:
>
>> handle_fetch (request=0x7ffff3e56038, response=0x7ffff3e918b8,
>> handler_baton=0x7ffff3e611e0, pool=0x7ffff3e6d028)
>> at ../src/subversion/libsvn_ra_serf/update.c:1152
>> 1152 if (SERF_BUCKET_READ_ERROR(status))
>> (gdb) p status
>> $13 = 0
>
> So that's what happens when I interrupt the infinite loop, i.e. long
> after the first failure to read from the socket. If I catch the first
> socket read error then serf does supply an error to ra_serf:

I can reproduce over plain HTTP without mod_ssl -

  - the closed socket causes apr_socket_recv() to returns APR_EOF
  - APR_EOF gets returned to serf_deflate_read()
  - APR_EOF gets stored in deflate_context_t->stream_status
  - serf_deflate_read() returns APR_SUCCESS
  - serf_response_read() returns APR_SUCCESS

The ra_serf infinite loop is calling serf_response_read() which calls
serf_deflate_read() which keeps converting APR_EOF into APR_SUCCESS:

serf_deflate_read (bucket=0x7ffff3e8f4b8, requested=8000, data=0x7fffffffd460,
    len=0x7fffffffd458) at buckets/deflate_buckets.c:143
143 deflate_context_t *ctx = bucket->data;
(gdb) n
150 switch (ctx->state) {
(gdb) p ctx->stream_status
$24 = 70014
(gdb) n
224 status = serf_bucket_read(ctx->inflate_stream, requested, data,
(gdb)
226 if (SERF_BUCKET_READ_ERROR(status)) {
(gdb)
230 if (APR_STATUS_IS_EOF(status)) {
(gdb)
231 status = ctx->stream_status;
(gdb)
232 if (APR_STATUS_IS_EOF(status)) {
(gdb)
237 status = APR_SUCCESS;
(gdb)
240 if (*len != 0) {
(gdb)
251 if (ctx->zstream.avail_in == 0) {
(gdb)
255 ctx->stream_status = serf_bucket_read(ctx->stream,
(gdb)
260 if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) {
(gdb)
264 if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) {
(gdb)
271 ctx->zstream.next_in = (unsigned char*)private_data;
(gdb)
272 ctx->zstream.avail_in = private_len;
(gdb)
277 zRC = inflate(&ctx->zstream, Z_NO_FLUSH);
(gdb)
281 if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) {
(gdb)
283 ctx->zstream.next_out = ctx->buffer;
(gdb)
284 private_len = ctx->bufferSize - ctx->zstream.avail_out;
(gdb)
286 ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer,
(gdb)
290 tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer,
(gdb)
293 serf_bucket_aggregate_append(ctx->inflate_stream, tmp);
(gdb)
294 ctx->zstream.avail_out = ctx->bufferSize;
(gdb)
295 break;
(gdb)
352 status = serf_bucket_read(ctx->inflate_stream, requested, data,
(gdb)
355 if (APR_STATUS_IS_EOF(status)) {
(gdb) p status
$25 = 70014
(gdb) n
356 status = ctx->stream_status;
(gdb)
359 if (zRC != Z_STREAM_END)
(gdb)
360 return APR_SUCCESS;

-- 
Philip Martin | Subversion Committer
WANdisco // *Non-Stop Data*
serf
Received on 2014-11-11 19:30:09 CET

This is an archived mail posted to the Subversion Dev mailing list.