apr_status_t h2_stream_readx(h2_stream *stream, h2_io_data_cb *cb, void *ctx, apr_off_t *plen, int *peos) { apr_status_t status = APR_SUCCESS; apr_table_t *trailers = NULL; const char *src; H2_STREAM_OUT(APLOG_TRACE2, stream, "h2_stream readx_pre"); if (stream->rst_error) { return APR_ECONNRESET; } *peos = 0; if (!APR_BRIGADE_EMPTY(stream->bbout)) { apr_off_t origlen = *plen; src = "stream"; status = h2_util_bb_readx(stream->bbout, cb, ctx, plen, peos); if (status == APR_SUCCESS && !*peos && !*plen) { apr_brigade_cleanup(stream->bbout); *plen = origlen; return h2_stream_readx(stream, cb, ctx, plen, peos); } } else { src = "mplx"; status = h2_mplx_out_readx(stream->session->mplx, stream->id, cb, ctx, plen, peos, &trailers); } if (trailers && stream->response) { ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, stream->session->c, "h2_stream(%ld-%d): readx, saving trailers", stream->session->id, stream->id); h2_response_set_trailers(stream->response, trailers); } if (status == APR_SUCCESS && !*peos && !*plen) { status = APR_EAGAIN; } H2_STREAM_OUT(APLOG_TRACE2, stream, "h2_stream readx_post"); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, stream->session->c, "h2_stream(%ld-%d): readx %s, len=%ld eos=%d", stream->session->id, stream->id, src, (long)*plen, *peos); H2_STREAM_OUT(APLOG_TRACE2, stream, "h2_stream readx_post"); return status; }
apr_status_t h2_stream_readx(h2_stream *stream, h2_io_data_cb *cb, void *ctx, apr_size_t *plen, int *peos) { apr_status_t status = APR_SUCCESS; const char *src; if (stream->rst_error) { return APR_ECONNRESET; } *peos = 0; if (!APR_BRIGADE_EMPTY(stream->bbout)) { apr_size_t origlen = *plen; src = "stream"; status = h2_util_bb_readx(stream->bbout, cb, ctx, plen, peos); if (status == APR_SUCCESS && !*peos && !*plen) { apr_brigade_cleanup(stream->bbout); *plen = origlen; return h2_stream_readx(stream, cb, ctx, plen, peos); } } else { src = "mplx"; status = h2_mplx_out_readx(stream->session->mplx, stream->id, cb, ctx, plen, peos); } if (status == APR_SUCCESS && !*peos && !*plen) { status = APR_EAGAIN; } ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, stream->session->c, "h2_stream(%ld-%d): readx %s, len=%ld eos=%d", stream->session->id, stream->id, src, (long)*plen, *peos); return status; }
static int on_send_data_cb(nghttp2_session *ngh2, nghttp2_frame *frame, const uint8_t *framehd, size_t length, nghttp2_data_source *source, void *userp) { apr_status_t status = APR_SUCCESS; h2_session *session = (h2_session *)userp; int stream_id = (int)frame->hd.stream_id; const unsigned char padlen = frame->data.padlen; int eos; h2_stream *stream; (void)ngh2; (void)source; if (session->aborted) { return NGHTTP2_ERR_CALLBACK_FAILURE; } stream = h2_stream_set_get(session->streams, stream_id); if (!stream) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_NOTFOUND, session->c, APLOGNO(02924) "h2_stream(%ld-%d): send_data", session->id, (int)stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; } status = send_data(session, (const char *)framehd, 9); if (status == APR_SUCCESS) { if (padlen) { status = send_data(session, (const char *)&padlen, 1); } if (status == APR_SUCCESS) { apr_size_t len = length; status = h2_stream_readx(stream, pass_data, session, &len, &eos); if (status == APR_SUCCESS && len != length) { status = APR_EINVAL; } } if (status == APR_SUCCESS && padlen) { if (padlen) { char pad[256]; memset(pad, 0, padlen); status = send_data(session, pad, padlen); } } } if (status == APR_SUCCESS) { return 0; } else if (status != APR_EOF) { ap_log_cerror(APLOG_MARK, APLOG_ERR, status, session->c, APLOGNO(02925) "h2_stream(%ld-%d): failed send_data_cb", session->id, (int)stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; } return h2_session_status_from_apr_status(status); }
static int on_send_data_cb(nghttp2_session *ngh2, nghttp2_frame *frame, const uint8_t *framehd, size_t length, nghttp2_data_source *source, void *userp) { apr_status_t status = APR_SUCCESS; h2_session *session = (h2_session *)userp; int stream_id = (int)frame->hd.stream_id; const unsigned char padlen = frame->data.padlen; int eos; h2_stream *stream; (void)ngh2; (void)source; if (session->aborted) { return NGHTTP2_ERR_CALLBACK_FAILURE; } stream = h2_stream_set_get(session->streams, stream_id); if (!stream) { ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_NOTFOUND, session->c, APLOGNO(02924) "h2_stream(%ld-%d): send_data", session->id, (int)stream_id); return NGHTTP2_ERR_CALLBACK_FAILURE; } ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, session->c, "h2_stream(%ld-%d): send_data_cb for %ld bytes", session->id, (int)stream_id, (long)length); if (h2_conn_io_is_buffered(&session->io)) { status = h2_conn_io_write(&session->io, (const char *)framehd, 9); if (status == APR_SUCCESS) { if (padlen) { status = h2_conn_io_write(&session->io, (const char *)&padlen, 1); } if (status == APR_SUCCESS) { apr_size_t len = length; status = h2_stream_readx(stream, pass_data, session, &len, &eos); if (status == APR_SUCCESS && len != length) { status = APR_EINVAL; } } if (status == APR_SUCCESS && padlen) { if (padlen) { status = h2_conn_io_write(&session->io, immortal_zeros, padlen); } } } } else { apr_bucket *b; char *header = apr_pcalloc(stream->pool, 10); memcpy(header, (const char *)framehd, 9); if (padlen) { header[9] = (char)padlen; } b = apr_bucket_pool_create(header, padlen? 10 : 9, stream->pool, session->c->bucket_alloc); status = h2_conn_io_writeb(&session->io, b); if (status == APR_SUCCESS) { apr_size_t len = length; status = h2_stream_read_to(stream, session->io.output, &len, &eos); session->io.unflushed = 1; if (status == APR_SUCCESS && len != length) { status = APR_EINVAL; } } if (status == APR_SUCCESS && padlen) { b = apr_bucket_immortal_create(immortal_zeros, padlen, session->c->bucket_alloc); status = h2_conn_io_writeb(&session->io, b); } } if (status == APR_SUCCESS) { stream->data_frames_sent++; h2_conn_io_consider_flush(&session->io); return 0; } else { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c, APLOGNO(02925) "h2_stream(%ld-%d): failed send_data_cb", session->id, (int)stream_id); } return h2_session_status_from_apr_status(status); }