/* * Callback when nghttp2 wants to send bytes back to the client. */ static ssize_t send_cb(nghttp2_session *ngh2, const uint8_t *data, size_t length, int flags, void *userp) { h2_session *session = (h2_session *)userp; apr_status_t status; (void)ngh2; (void)flags; status = h2_conn_io_write(&session->io, (const char *)data, length); if (status == APR_SUCCESS) { return length; } if (APR_STATUS_IS_EAGAIN(status)) { return NGHTTP2_ERR_WOULDBLOCK; } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c, "h2_session: send error"); return h2_session_status_from_apr_status(status); }
/* * Callback when nghttp2 wants to send bytes back to the client. */ static ssize_t send_cb(nghttp2_session *ngh2, const uint8_t *data, size_t length, int flags, void *userp) { h2_session *session = (h2_session *)userp; if (session->aborted) { return NGHTTP2_ERR_CALLBACK_FAILURE; } size_t written = 0; apr_status_t status = h2_conn_io_write(&session->io, (const char*)data, length, &written); if (status == APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, session->c, "h2_session: callback send write %d bytes", (int)written); return written; } else if (status == APR_EAGAIN || status == APR_TIMEUP) { return NGHTTP2_ERR_WOULDBLOCK; } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, session->c, "h2_session: send error"); return h2_session_status_from_apr_status(status); }
static apr_status_t send_data(h2_session *session, const char *data, apr_size_t length) { return h2_conn_io_write(&session->io, data, length); }
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); }
static apr_status_t pass_data(void *ctx, const char *data, apr_size_t length) { return h2_conn_io_write(&((h2_session*)ctx)->io, data, length); }