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