static apr_status_t serf_fcgi_frame_refill()

in buckets/fcgi_buckets.c [657:765]


static apr_status_t serf_fcgi_frame_refill(serf_bucket_t *bucket)
{
    fcgi_frame_ctx_t *ctx = bucket->data;
    apr_status_t status;
    serf_bucket_t *head = NULL;
    apr_size_t payload;

    if (ctx->at_eof)
        return APR_EOF;

    if (!ctx->agg)
        ctx->agg = serf_bucket_aggregate_create(bucket->allocator);

    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,
                                 1, 0xFFFF);

        remaining = serf_bucket_get_remaining(head);
        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[SERF__STD_IOV_COUNT];
            int vecs_used;

            status = serf_bucket_read_iovec(head, 0xFFF0, COUNT_OF(vecs),
                                            vecs, &vecs_used);

            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_t *tmp;

                tmp = serf_bucket_iovec_create(vecs, vecs_used, bucket->allocator);
                payload = (apr_size_t)serf_bucket_get_remaining(ctx->agg);

                tmp = serf__bucket_event_create(tmp, head, NULL, NULL,
                                                destroy_bucket, bucket->allocator);

                serf_bucket_aggregate_append(ctx->agg, tmp);
            }
            else
                payload = 0;
        }

        if (!payload && !ctx->send_eof)
            return APR_SUCCESS;
    }
    else
    {
        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 %"
              APR_SIZE_T_FMT "\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);
    ctx->record_data[2] = (ctx->stream_id >> 8);
    ctx->record_data[3] = (ctx->stream_id & 0xFF);
    ctx->record_data[4] = (payload >> 8) & 0xFF;
    ctx->record_data[5] = (payload & 0xFF);
    ctx->record_data[6] = 0; /* padding */
    ctx->record_data[7] = 0; /* reserved */

    serf_bucket_aggregate_prepend(ctx->agg,
                                  serf_bucket_simple_create(ctx->record_data,
                                                            FCGI_RECORD_SIZE,
                                                            NULL, NULL,
                                                            bucket->allocator));
    return APR_SUCCESS;
}