Author: rhuijben Date: Wed Nov 18 01:09:20 2015 New Revision: 1714914 URL: http://svn.apache.org/viewvc?rev=1714914&view=rev Log: Resolve several issues in the fcgi frame bucket, to avoid generating unneeded following frames when done.
* buckets/fcgi_buckets.c (fcgi_frame_ctx_t): Add config. (destroy_bucket): New function. (serf_fcgi_frame_refill): Handle several corner cases. Log written records. (serf_fcgi_frame_read, serf_fcgi_frame_read_iovec, serf_fcgi_frame_peek): Handle eof as success in some cases. (serf_fcgi_frame_set_config): Store config. * protocols/fcgi_stream.c (fcgi_stream_enqueue_response): Send reason after status. Schedule end of request record too. * test/serf_httpd.c (main): Support multiple levels of logging via multiple -v arguments. Modified: serf/trunk/buckets/fcgi_buckets.c serf/trunk/protocols/fcgi_stream.c serf/trunk/test/serf_httpd.c Modified: serf/trunk/buckets/fcgi_buckets.c URL: http://svn.apache.org/viewvc/serf/trunk/buckets/fcgi_buckets.c?rev=1714914&r1=1714913&r2=1714914&view=diff ============================================================================== --- serf/trunk/buckets/fcgi_buckets.c (original) +++ serf/trunk/buckets/fcgi_buckets.c Wed Nov 18 01:09:20 2015 @@ -610,6 +610,8 @@ typedef struct fcgi_frame_ctx_t bool send_eof; bool at_eof; + serf_config_t *config; + char record_data[FCGI_RECORD_SIZE]; } fcgi_frame_ctx_t; @@ -636,6 +638,14 @@ serf__bucket_fcgi_frame_create(serf_buck return serf_bucket_create(&serf_bucket_type__fcgi_frame, alloc, ctx); } +static apr_status_t destroy_bucket(void *baton, + apr_uint64_t bytes_read) +{ + serf_bucket_t *head = baton; + serf_bucket_destroy(head); + return APR_SUCCESS; +} + static apr_status_t serf_fcgi_frame_refill(serf_bucket_t *bucket) { fcgi_frame_ctx_t *ctx = bucket->data; @@ -652,24 +662,29 @@ static apr_status_t serf_fcgi_frame_refi if (!ctx->stream) { payload = 0; + ctx->at_eof = true; + + if (ctx->send_stream && !ctx->send_eof) + return APR_EOF; } else if (ctx->send_stream) { apr_uint64_t remaining; + serf_bucket_split_create(&head, &ctx->stream, ctx->stream, - 8192, 0xFFF0); /* Some guesses */ + 1, 0xFFFF); remaining = serf_bucket_get_remaining(head); - if (remaining != SERF_LENGTH_UNKNOWN) { - serf_bucket_aggregate_append(ctx->agg, head); - payload = (apr_size_t)remaining; - } - else if (remaining == 0) + if (remaining == 0) { payload = 0; serf_bucket_destroy(head); ctx->at_eof = true; } + else if (remaining != SERF_LENGTH_UNKNOWN) { + serf_bucket_aggregate_append(ctx->agg, head); + payload = (apr_size_t)remaining; + } else { struct iovec vecs[IOV_MAX]; @@ -680,30 +695,25 @@ static apr_status_t serf_fcgi_frame_refi if (SERF_BUCKET_READ_ERROR(status)) return status; + else if (!APR_STATUS_IS_EOF(status)) { + /* No get_remaining()... then the split screen should stop + directly when done reading this amount of vecs */ + return SERF_ERROR_TRUNCATED_STREAM; + } if (vecs_used) { - serf_bucket_aggregate_append_iovec(ctx->agg, vecs, vecs_used); + serf_bucket_t *tmp; + + tmp = serf_bucket_iovec_create(vecs, vecs_used, bucket->allocator); payload = (apr_size_t)serf_bucket_get_remaining(ctx->agg); - if (APR_STATUS_IS_EOF(status)) { - /* Keep head alive by appending it to the aggregate */ - serf_bucket_aggregate_append(ctx->agg, head); - } - else { - /* Write a new record for the remaining part of head :( */ - serf_bucket_aggregate_append(ctx->agg, - serf__bucket_fcgi_frame_create(head, ctx->stream_id, - ctx->frame_type, - true /* send_as_stream */, - false /* send_eof */, - bucket->allocator)); - } + tmp = serf__bucket_event_create(tmp, head, NULL, NULL, + destroy_bucket, bucket->allocator); + + serf_bucket_aggregate_append(ctx->agg, tmp); } else payload = 0; - - if (APR_STATUS_IS_EOF(status)) - ctx->at_eof = true; } if (!payload && !ctx->send_eof) @@ -711,9 +721,22 @@ static apr_status_t serf_fcgi_frame_refi } else { - abort(); /* ### TODO */ + apr_uint64_t remaining = serf_bucket_get_remaining(ctx->stream); + + if (remaining >= 0xFFFF) + abort(); /* Impossible (or unimplemented yet) */ + + payload = (apr_size_t)remaining; + ctx->at_eof = true; + + serf_bucket_aggregate_append(ctx->agg, ctx->stream); + ctx->stream = NULL; } + serf__log(LOGLVL_DEBUG, LOGCOMP_CONN, __FILE__, ctx->config, + "Generating 0x%x frame on stream 0x%x of size 0x%x\n", + ctx->frame_type, ctx->stream_id, payload); + /* Create FCGI record */ ctx->record_data[0] = (ctx->frame_type >> 8); ctx->record_data[1] = (ctx->frame_type & 0xFF); @@ -745,6 +768,8 @@ static apr_status_t serf_fcgi_frame_read if (!APR_STATUS_IS_EOF(status)) return status; + else if (*len) + return APR_SUCCESS; } status = serf_fcgi_frame_refill(bucket); @@ -776,6 +801,8 @@ static apr_status_t serf_fcgi_frame_read if (!APR_STATUS_IS_EOF(status)) return status; + else if (*vecs_used) + return APR_SUCCESS; } status = serf_fcgi_frame_refill(bucket); @@ -805,6 +832,8 @@ static apr_status_t serf_fcgi_frame_peek if (!APR_STATUS_IS_EOF(status)) return status; + else if (*len) + return APR_SUCCESS; } status = serf_fcgi_frame_refill(bucket); @@ -843,6 +872,8 @@ static apr_status_t serf_fcgi_frame_set_ { fcgi_frame_ctx_t *ctx = bucket->data; + ctx->config = config; + if (!ctx->agg) ctx->agg = serf_bucket_aggregate_create(bucket->allocator); serf_bucket_set_config(ctx->agg, config); Modified: serf/trunk/protocols/fcgi_stream.c URL: http://svn.apache.org/viewvc/serf/trunk/protocols/fcgi_stream.c?rev=1714914&r1=1714913&r2=1714914&view=diff ============================================================================== --- serf/trunk/protocols/fcgi_stream.c (original) +++ serf/trunk/protocols/fcgi_stream.c Wed Nov 18 01:09:20 2015 @@ -111,7 +111,9 @@ fcgi_stream_enqueue_response(serf_incomi tmp = SERF_BUCKET_SIMPLE_STRING("Status: ", alloc); serf_bucket_aggregate_append(agg, tmp); - tmp = serf_bucket_simple_copy_create(linebuf->line + 9, 3, alloc); + /* Skip "HTTP/1.1 " but send status and reason */ + tmp = serf_bucket_simple_copy_create(linebuf->line + 9, linebuf->used - 9, + alloc); serf_bucket_aggregate_append(agg, tmp); serf_bucket_mem_free(alloc, linebuf); @@ -120,12 +122,27 @@ fcgi_stream_enqueue_response(serf_incomi serf_bucket_aggregate_append(agg, response_bkt); - return serf_fcgi__enqueue_frame( + /* Send response over STDOUT, closing stdout when done */ + status = serf_fcgi__enqueue_frame( stream->fcgi, serf__bucket_fcgi_frame_create(agg, stream->streamid, FCGI_FRAMETYPE(FCGI_V1, FCGI_STDOUT), - true, true, + true, false, + alloc), false); + if (status) + return status; + + /* As we don't use STDERR we don't have to close it either */ + + /* Send end of request: FCGI_REQUEST_COMPLETE, exit code 0 */ + tmp = SERF_BUCKET_SIMPLE_STRING_LEN("\0\0\0\0\0\0\0\0", 8, alloc); + status = serf_fcgi__enqueue_frame( + stream->fcgi, + serf__bucket_fcgi_frame_create(tmp, stream->streamid, + FCGI_FRAMETYPE(FCGI_V1, FCGI_END_REQUEST), + false, false, alloc), true); + return status; } static apr_status_t Modified: serf/trunk/test/serf_httpd.c URL: http://svn.apache.org/viewvc/serf/trunk/test/serf_httpd.c?rev=1714914&r1=1714913&r2=1714914&view=diff ============================================================================== --- serf/trunk/test/serf_httpd.c (original) +++ serf/trunk/test/serf_httpd.c Wed Nov 18 01:09:20 2015 @@ -151,7 +151,7 @@ static apr_status_t request_generate_res serf_bucket_t *tmp; #define CRLF "\r\n" - tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 OK" CRLF, alloc); + tmp = SERF_BUCKET_SIMPLE_STRING("HTTP/1.1 200 BOE" CRLF, alloc); serf_bucket_aggregate_append(agg, tmp); tmp = SERF_BUCKET_SIMPLE_STRING("Content-Type: text/plain" CRLF, alloc); @@ -454,11 +454,18 @@ int main(int argc, const char **argv) if (verbose) { serf_log_output_t *output; apr_status_t status; + apr_uint32_t level; + + level = SERF_LOG_WARNING; + if (verbose >= 3) + level = SERF_LOG_DEBUG; + else if (verbose >= 2) + level = SERF_LOG_INFO; status = serf_logging_create_stream_output( &output, context, - SERF_LOG_INFO, + level, SERF_LOGCOMP_ALL_MSG & ~(SERF_LOGCOMP_RAWMSG | SERF_LOGCOMP_SSLMSG), SERF_LOG_DEFAULT_LAYOUT, stderr,