apr_status_t h2_to_h1_add_data(h2_to_h1 *to_h1, const char *data, size_t len) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, h2_mplx_get_conn(to_h1->m), "h2_to_h1(%ld-%d): add %ld data bytes", h2_mplx_get_id(to_h1->m), to_h1->stream_id, (long)len); if (to_h1->chunked) { /* if input may have a body and we have not seen any * content-length header, we need to chunk the input data. */ apr_status_t status = apr_brigade_printf(to_h1->bb, NULL, NULL, "%lx\r\n", len); if (status == APR_SUCCESS) { status = h2_to_h1_add_data_raw(to_h1, data, len); if (status == APR_SUCCESS) { status = apr_brigade_puts(to_h1->bb, NULL, NULL, "\r\n"); } } return status; } else { to_h1->remain_len -= len; if (to_h1->remain_len < 0) { ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, h2_mplx_get_conn(to_h1->m), "h2_to_h1(%ld-%d): got %ld more content bytes than announced " "in content-length header: %ld", h2_mplx_get_id(to_h1->m), to_h1->stream_id, (long)to_h1->content_len, -(long)to_h1->remain_len); } return h2_to_h1_add_data_raw(to_h1, data, len); } }
apr_status_t h2_to_h1_end_headers(h2_to_h1 *to_h1, h2_task *task, int eos) { conn_rec *c = h2_mplx_get_conn(to_h1->m); ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_to_h1(%ld-%d): end headers", h2_mplx_get_id(to_h1->m), to_h1->stream_id); if (to_h1->eoh) { return APR_EINVAL; } if (!to_h1->seen_host) { /* Need to add a "Host" header if not already there to * make virtual hosts work correctly. */ if (!to_h1->authority) { return APR_BADARG; } apr_table_set(to_h1->headers, "Host", to_h1->authority); } if (eos && to_h1->chunked) { /* We had chunking figured out, but the EOS is already there. * unmark chunking and set a definitive content-length. */ to_h1->chunked = 0; apr_table_setn(to_h1->headers, "Content-Length", "0"); } else if (to_h1->chunked) { /* We have not seen a content-length. We therefore must * pass any request content in chunked form. */ apr_table_mergen(to_h1->headers, "Transfer-Encoding", "chunked"); } h2_task_set_request(task, to_h1->method, to_h1->path, to_h1->authority, to_h1->headers, eos); to_h1->eoh = 1; if (eos) { apr_status_t status = h2_to_h1_close(to_h1); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_WARNING, status, c, "h2_to_h1(%ld-%d): end headers, eos=%d", h2_mplx_get_id(to_h1->m), to_h1->stream_id, eos); } return status; } return APR_SUCCESS; }
apr_status_t h2_to_h1_flush(h2_to_h1 *to_h1) { apr_status_t status = APR_SUCCESS; if (!APR_BRIGADE_EMPTY(to_h1->bb)) { ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, h2_mplx_get_conn(to_h1->m), "h2_to_h1(%ld-%d): flush request bytes", h2_mplx_get_id(to_h1->m), to_h1->stream_id); status = h2_mplx_in_write(to_h1->m, to_h1->stream_id, to_h1->bb); if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_ERR, status, h2_mplx_get_conn(to_h1->m), "h2_request(%d): pushing request data", to_h1->stream_id); } } return status; }
static h2_stream *resume_on_data(void *ctx, h2_stream *stream) { h2_session *session = (h2_session *)ctx; assert(session); assert(stream); if (h2_stream_is_suspended(stream)) { ap_log_perror(APLOG_MARK, APLOG_DEBUG, 0, stream->pool, "h2_stream(%ld-%d): suspended, checking for DATA", h2_mplx_get_id(stream->m), stream->id); if (h2_mplx_out_has_data_for(stream->m, h2_stream_get_id(stream))) { h2_stream_set_suspended(stream, 0); int rv = nghttp2_session_resume_data(session->ngh2, h2_stream_get_id(stream)); ap_log_cerror(APLOG_MARK, nghttp2_is_fatal(rv)? APLOG_ERR : APLOG_DEBUG, 0, session->c, "h2_stream(%ld-%d): resuming stream %s", session->id, stream->id, nghttp2_strerror(rv)); } } return NULL; }