static apr_status_t stream_send_data()

in protocols/http2_stream.c [221:313]


static apr_status_t stream_send_data(serf_http2_stream_t *stream,
                                     serf_bucket_t *data)
{
    apr_uint64_t remaining;
    serf_bucket_t *next;
    apr_size_t prefix_len;
    bool end_stream;
    apr_status_t status;

    SERF_H2_assert(stream->status == H2S_OPEN
                   || stream->status == H2S_HALFCLOSED_REMOTE);
    SERF_H2_assert(!stream->data->data_tail || (data ==
                                                stream->data->data_tail));

    /* Sending DATA frames over HTTP/2 is not easy as this usually requires
       handling windowing, priority, etc. This code will improve over time */
    stream->data->data_tail = NULL;

    if (!data)
        remaining = 0;
    else
        remaining = serf_bucket_get_remaining(data);

    /* If the stream decided we are already done */
    if (remaining == 0) {
        if (stream->status == H2S_OPEN)
            stream->status = H2S_HALFCLOSED_LOCAL;
        else
            stream->status = H2S_CLOSED;

        serf_bucket_destroy(data);

        next = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_DATA,
                                               HTTP2_FLAG_END_STREAM,
                                               &stream->streamid,
                                               serf_http2__allocate_stream_id,
                                               stream, 0, stream->alloc);
        return serf_http2__enqueue_frame(stream->h2, next, false);
    }

    prefix_len = serf_http2__alloc_window(stream->h2, stream,
                                          (remaining >= APR_SIZE_MAX)
                                          ? SERF_READ_ALL_AVAIL
                                          : (apr_size_t)remaining);

    if (prefix_len == 0) {
        /* No window left */
        stream->data->data_tail = data;

        /* Write more later */
        serf_http2__ensure_writable(stream);

        return APR_SUCCESS;
    }

    if (prefix_len < remaining) {
        window_allocate_info_t *wai;
        serf_bucket_split_create(&data, &stream->data->data_tail, data,
                                 MIN(prefix_len, 1024), prefix_len);

        wai = serf_bucket_mem_alloc(stream->alloc, sizeof(*wai));
        wai->stream = stream;
        wai->bkt = data;
        wai->allocated = prefix_len;

        data = serf__bucket_event_create(data, wai,
                                         data_write_started,
                                         data_write_done, NULL, stream->alloc);
        end_stream = false;

        serf_http2__ensure_writable(stream);
    }
    else {
        end_stream = true;

        if (stream->status == H2S_OPEN)
            stream->status = H2S_HALFCLOSED_LOCAL;
        else
            stream->status = H2S_CLOSED;
    }

    next = serf__bucket_http2_frame_create(data, HTTP2_FRAME_TYPE_DATA,
                                           end_stream ? HTTP2_FLAG_END_STREAM
                                                      : 0,
                                           &stream->streamid,
                                           serf_http2__allocate_stream_id,
                                           stream, prefix_len,
                                           data->allocator);

    status = serf_http2__enqueue_frame(stream->h2, next, TRUE);

    return status;
}