|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include <assert.h>
|
|
Packit |
90a5c9 |
#include <stddef.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include <apr_atomic.h>
|
|
Packit |
90a5c9 |
#include <apr_strings.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include <httpd.h>
|
|
Packit |
90a5c9 |
#include <http_core.h>
|
|
Packit |
90a5c9 |
#include <http_connection.h>
|
|
Packit |
90a5c9 |
#include <http_protocol.h>
|
|
Packit |
90a5c9 |
#include <http_request.h>
|
|
Packit |
90a5c9 |
#include <http_log.h>
|
|
Packit |
90a5c9 |
#include <http_vhost.h>
|
|
Packit |
90a5c9 |
#include <util_filter.h>
|
|
Packit |
90a5c9 |
#include <ap_mpm.h>
|
|
Packit |
90a5c9 |
#include <mod_core.h>
|
|
Packit |
90a5c9 |
#include <scoreboard.h>
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "h2_private.h"
|
|
Packit |
90a5c9 |
#include "h2.h"
|
|
Packit |
90a5c9 |
#include "h2_bucket_beam.h"
|
|
Packit |
90a5c9 |
#include "h2_conn.h"
|
|
Packit |
90a5c9 |
#include "h2_config.h"
|
|
Packit |
90a5c9 |
#include "h2_ctx.h"
|
|
Packit |
90a5c9 |
#include "h2_from_h1.h"
|
|
Packit |
90a5c9 |
#include "h2_h2.h"
|
|
Packit |
90a5c9 |
#include "h2_mplx.h"
|
|
Packit |
90a5c9 |
#include "h2_request.h"
|
|
Packit |
90a5c9 |
#include "h2_headers.h"
|
|
Packit |
90a5c9 |
#include "h2_session.h"
|
|
Packit |
90a5c9 |
#include "h2_stream.h"
|
|
Packit |
90a5c9 |
#include "h2_task.h"
|
|
Packit |
90a5c9 |
#include "h2_util.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void H2_TASK_OUT_LOG(int lvl, h2_task *task, apr_bucket_brigade *bb,
|
|
Packit |
90a5c9 |
const char *tag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (APLOG_C_IS_LEVEL(task->c, lvl)) {
|
|
Packit |
90a5c9 |
conn_rec *c = task->c;
|
|
Packit |
90a5c9 |
char buffer[4 * 1024];
|
|
Packit |
90a5c9 |
const char *line = "(null)";
|
|
Packit |
90a5c9 |
apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
len = h2_util_bb_print(buffer, bmax, tag, "", bb);
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, lvl, 0, c, "bb_dump(%s): %s",
|
|
Packit |
90a5c9 |
task->id, len? buffer : line);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* task input handling
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int input_ser_header(void *ctx, const char *name, const char *value)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_task *task = ctx;
|
|
Packit |
90a5c9 |
apr_brigade_printf(task->input.bb, NULL, NULL, "%s: %s\r\n", name, value);
|
|
Packit |
90a5c9 |
return 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* task output handling
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t open_output(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03348)
|
|
Packit |
90a5c9 |
"h2_task(%s): open output to %s %s %s",
|
|
Packit |
90a5c9 |
task->id, task->request->method,
|
|
Packit |
90a5c9 |
task->request->authority,
|
|
Packit |
90a5c9 |
task->request->path);
|
|
Packit |
90a5c9 |
task->output.opened = 1;
|
|
Packit |
90a5c9 |
return h2_mplx_out_open(task->mplx, task->stream_id, task->output.beam);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t send_out(h2_task *task, apr_bucket_brigade* bb, int block)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_off_t written, left;
|
|
Packit |
90a5c9 |
apr_status_t status;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_brigade_length(bb, 0, &written);
|
|
Packit |
90a5c9 |
H2_TASK_OUT_LOG(APLOG_TRACE2, task, bb, "h2_task send_out");
|
|
Packit |
90a5c9 |
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(before)");
|
|
Packit |
90a5c9 |
/* engines send unblocking */
|
|
Packit |
90a5c9 |
status = h2_beam_send(task->output.beam, bb,
|
|
Packit |
90a5c9 |
block? APR_BLOCK_READ : APR_NONBLOCK_READ);
|
|
Packit |
90a5c9 |
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "send_out(after)");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EAGAIN(status)) {
|
|
Packit |
90a5c9 |
apr_brigade_length(bb, 0, &left);
|
|
Packit |
90a5c9 |
written -= left;
|
|
Packit |
90a5c9 |
status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (status == APR_SUCCESS) {
|
|
Packit |
90a5c9 |
if (h2_task_logio_add_bytes_out) {
|
|
Packit |
90a5c9 |
h2_task_logio_add_bytes_out(task->c, written);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, task->c,
|
|
Packit |
90a5c9 |
"h2_task(%s): send_out done", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, task->c,
|
|
Packit |
90a5c9 |
"h2_task(%s): send_out (%ld bytes)",
|
|
Packit |
90a5c9 |
task->id, (long)written);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Bring the data from the brigade (which represents the result of the
|
|
Packit |
90a5c9 |
* request_rec out filter chain) into the h2_mplx for further sending
|
|
Packit |
90a5c9 |
* on the master connection.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t slave_out(h2_task *task, ap_filter_t* f,
|
|
Packit |
90a5c9 |
apr_bucket_brigade* bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_bucket *b;
|
|
Packit |
90a5c9 |
apr_status_t rv = APR_SUCCESS;
|
|
Packit |
90a5c9 |
int flush = 0, blocking;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (task->frozen) {
|
|
Packit |
90a5c9 |
h2_util_bb_log(task->c, task->stream_id, APLOG_TRACE2,
|
|
Packit |
90a5c9 |
"frozen task output write, ignored", bb);
|
|
Packit |
90a5c9 |
while (!APR_BRIGADE_EMPTY(bb)) {
|
|
Packit |
90a5c9 |
b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
if (AP_BUCKET_IS_EOR(b)) {
|
|
Packit |
90a5c9 |
APR_BUCKET_REMOVE(b);
|
|
Packit |
90a5c9 |
task->eor = b;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
apr_bucket_delete(b);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
send:
|
|
Packit |
90a5c9 |
/* we send block once we opened the output, so someone is there
|
|
Packit |
90a5c9 |
* reading it *and* the task is not assigned to a h2_req_engine */
|
|
Packit |
90a5c9 |
blocking = (!task->assigned && task->output.opened);
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(bb);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(bb);
|
|
Packit |
90a5c9 |
b = APR_BUCKET_NEXT(b)) {
|
|
Packit |
90a5c9 |
if (APR_BUCKET_IS_FLUSH(b) || APR_BUCKET_IS_EOS(b) || AP_BUCKET_IS_EOR(b)) {
|
|
Packit |
90a5c9 |
flush = 1;
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (task->output.bb && !APR_BRIGADE_EMPTY(task->output.bb)) {
|
|
Packit |
90a5c9 |
/* still have data buffered from previous attempt.
|
|
Packit |
90a5c9 |
* setaside and append new data and try to pass the complete data */
|
|
Packit |
90a5c9 |
if (!APR_BRIGADE_EMPTY(bb)) {
|
|
Packit |
90a5c9 |
if (APR_SUCCESS != (rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool))) {
|
|
Packit |
90a5c9 |
goto out;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = send_out(task, task->output.bb, blocking);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* no data buffered previously, pass brigade directly */
|
|
Packit |
90a5c9 |
rv = send_out(task, bb, blocking);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == rv && !APR_BRIGADE_EMPTY(bb)) {
|
|
Packit |
90a5c9 |
/* output refused to buffer it all, time to open? */
|
|
Packit |
90a5c9 |
if (!task->output.opened && APR_SUCCESS == (rv = open_output(task))) {
|
|
Packit |
90a5c9 |
/* Make another attempt to send the data. With the output open,
|
|
Packit |
90a5c9 |
* the call might be blocking and send all data, so we do not need
|
|
Packit |
90a5c9 |
* to save the brigade */
|
|
Packit |
90a5c9 |
goto send;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (blocking && flush) {
|
|
Packit |
90a5c9 |
/* Need to keep on doing this. */
|
|
Packit |
90a5c9 |
goto send;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == rv) {
|
|
Packit |
90a5c9 |
/* could not write all, buffer the rest */
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, task->c, APLOGNO(03405)
|
|
Packit |
90a5c9 |
"h2_slave_out(%s): saving brigade", task->id);
|
|
Packit |
90a5c9 |
ap_assert(NULL);
|
|
Packit |
90a5c9 |
rv = ap_save_brigade(f, &task->output.bb, &bb, task->pool);
|
|
Packit |
90a5c9 |
flush = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == rv && !task->output.opened && flush) {
|
|
Packit |
90a5c9 |
/* got a flush or could not write all, time to tell someone to read */
|
|
Packit |
90a5c9 |
rv = open_output(task);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
out:
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, task->c,
|
|
Packit |
90a5c9 |
"h2_slave_out(%s): slave_out leave", task->id);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t output_finish(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (!task->output.opened) {
|
|
Packit |
90a5c9 |
return open_output(task);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* task slave connection filters
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t h2_filter_slave_in(ap_filter_t* f,
|
|
Packit |
90a5c9 |
apr_bucket_brigade* bb,
|
|
Packit |
90a5c9 |
ap_input_mode_t mode,
|
|
Packit |
90a5c9 |
apr_read_type_e block,
|
|
Packit |
90a5c9 |
apr_off_t readbytes)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_task *task;
|
|
Packit |
90a5c9 |
apr_status_t status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
apr_bucket *b, *next;
|
|
Packit |
90a5c9 |
apr_off_t bblen;
|
|
Packit |
90a5c9 |
const int trace1 = APLOGctrace1(f->c);
|
|
Packit |
90a5c9 |
apr_size_t rmax = ((readbytes <= APR_SIZE_MAX)?
|
|
Packit |
90a5c9 |
(apr_size_t)readbytes : APR_SIZE_MAX);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
task = h2_ctx_cget_task(f->c);
|
|
Packit |
90a5c9 |
ap_assert(task);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): read, mode=%d, block=%d, readbytes=%ld",
|
|
Packit |
90a5c9 |
task->id, mode, block, (long)readbytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (mode == AP_MODE_INIT) {
|
|
Packit |
90a5c9 |
return ap_get_brigade(f->c->input_filters, bb, mode, block, readbytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (f->c->aborted) {
|
|
Packit |
90a5c9 |
return APR_ECONNABORTED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!task->input.bb) {
|
|
Packit |
90a5c9 |
return APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Cleanup brigades from those nasty 0 length non-meta buckets
|
|
Packit |
90a5c9 |
* that apr_brigade_split_line() sometimes produces. */
|
|
Packit |
90a5c9 |
for (b = APR_BRIGADE_FIRST(task->input.bb);
|
|
Packit |
90a5c9 |
b != APR_BRIGADE_SENTINEL(task->input.bb); b = next) {
|
|
Packit |
90a5c9 |
next = APR_BUCKET_NEXT(b);
|
|
Packit |
90a5c9 |
if (b->length == 0 && !APR_BUCKET_IS_METADATA(b)) {
|
|
Packit |
90a5c9 |
apr_bucket_delete(b);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
while (APR_BRIGADE_EMPTY(task->input.bb)) {
|
|
Packit |
90a5c9 |
/* Get more input data for our request. */
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): get more data from mplx, block=%d, "
|
|
Packit |
90a5c9 |
"readbytes=%ld", task->id, block, (long)readbytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (task->input.beam) {
|
|
Packit |
90a5c9 |
status = h2_beam_receive(task->input.beam, task->input.bb, block,
|
|
Packit |
90a5c9 |
128*1024);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
status = APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): read returned", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (APR_STATUS_IS_EAGAIN(status)
|
|
Packit |
90a5c9 |
&& (mode == AP_MODE_GETLINE || block == APR_BLOCK_READ)) {
|
|
Packit |
90a5c9 |
/* chunked input handling does not seem to like it if we
|
|
Packit |
90a5c9 |
* return with APR_EAGAIN from a GETLINE read...
|
|
Packit |
90a5c9 |
* upload 100k test on test-ser.example.org hangs */
|
|
Packit |
90a5c9 |
status = APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (APR_STATUS_IS_EOF(status)) {
|
|
Packit |
90a5c9 |
break;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
h2_util_bb_log(f->c, task->stream_id, APLOG_TRACE2,
|
|
Packit |
90a5c9 |
"input.beam recv raw", task->input.bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (h2_task_logio_add_bytes_in) {
|
|
Packit |
90a5c9 |
apr_brigade_length(bb, 0, &bblen);
|
|
Packit |
90a5c9 |
h2_task_logio_add_bytes_in(f->c, bblen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Nothing there, no more data to get. Return APR_EAGAIN on
|
|
Packit |
90a5c9 |
* speculative reads, this is ap_check_pipeline()'s trick to
|
|
Packit |
90a5c9 |
* see if the connection needs closing. */
|
|
Packit |
90a5c9 |
if (status == APR_EOF && APR_BRIGADE_EMPTY(task->input.bb)) {
|
|
Packit |
90a5c9 |
return (mode == AP_MODE_SPECULATIVE)? APR_EAGAIN : APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
h2_util_bb_log(f->c, task->stream_id, APLOG_TRACE2,
|
|
Packit |
90a5c9 |
"task_input.bb", task->input.bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (APR_BRIGADE_EMPTY(task->input.bb)) {
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): no data", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return (block == APR_NONBLOCK_READ)? APR_EAGAIN : APR_EOF;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (mode == AP_MODE_EXHAUSTIVE) {
|
|
Packit |
90a5c9 |
/* return all we have */
|
|
Packit |
90a5c9 |
APR_BRIGADE_CONCAT(bb, task->input.bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (mode == AP_MODE_READBYTES) {
|
|
Packit |
90a5c9 |
status = h2_brigade_concat_length(bb, task->input.bb, rmax);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (mode == AP_MODE_SPECULATIVE) {
|
|
Packit |
90a5c9 |
status = h2_brigade_copy_length(bb, task->input.bb, rmax);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (mode == AP_MODE_GETLINE) {
|
|
Packit |
90a5c9 |
/* we are reading a single LF line, e.g. the HTTP headers.
|
|
Packit |
90a5c9 |
* this has the nasty side effect to split the bucket, even
|
|
Packit |
90a5c9 |
* though it ends with CRLF and creates a 0 length bucket */
|
|
Packit |
90a5c9 |
status = apr_brigade_split_line(bb, task->input.bb, block,
|
|
Packit |
90a5c9 |
HUGE_STRING_LEN);
|
|
Packit |
90a5c9 |
if (APLOGctrace1(f->c)) {
|
|
Packit |
90a5c9 |
char buffer[1024];
|
|
Packit |
90a5c9 |
apr_size_t len = sizeof(buffer)-1;
|
|
Packit |
90a5c9 |
apr_brigade_flatten(bb, buffer, &len;;
|
|
Packit |
90a5c9 |
buffer[len] = 0;
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): getline: %s",
|
|
Packit |
90a5c9 |
task->id, buffer);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* Hmm, well. There is mode AP_MODE_EATCRLF, but we chose not
|
|
Packit |
90a5c9 |
* to support it. Seems to work. */
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_ERR, APR_ENOTIMPL, f->c,
|
|
Packit |
90a5c9 |
APLOGNO(03472)
|
|
Packit |
90a5c9 |
"h2_slave_in(%s), unsupported READ mode %d",
|
|
Packit |
90a5c9 |
task->id, mode);
|
|
Packit |
90a5c9 |
status = APR_ENOTIMPL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (trace1) {
|
|
Packit |
90a5c9 |
apr_brigade_length(bb, 0, &bblen);
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, f->c,
|
|
Packit |
90a5c9 |
"h2_slave_in(%s): %ld data bytes", task->id, (long)bblen);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t h2_filter_slave_output(ap_filter_t* filter,
|
|
Packit |
90a5c9 |
apr_bucket_brigade* brigade)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_task *task = h2_ctx_cget_task(filter->c);
|
|
Packit |
90a5c9 |
apr_status_t status;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(task);
|
|
Packit |
90a5c9 |
status = slave_out(task, filter, brigade);
|
|
Packit |
90a5c9 |
if (status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
h2_task_rst(task, H2_ERR_INTERNAL_ERROR);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t h2_filter_parse_h1(ap_filter_t* f, apr_bucket_brigade* bb)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_task *task = h2_ctx_cget_task(f->c);
|
|
Packit |
90a5c9 |
apr_status_t status;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(task);
|
|
Packit |
90a5c9 |
/* There are cases where we need to parse a serialized http/1.1
|
|
Packit |
90a5c9 |
* response. One example is a 100-continue answer in serialized mode
|
|
Packit |
90a5c9 |
* or via a mod_proxy setup */
|
|
Packit |
90a5c9 |
while (bb && !task->output.sent_response) {
|
|
Packit |
90a5c9 |
status = h2_from_h1_parse_response(task, f, bb);
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, f->c,
|
|
Packit |
90a5c9 |
"h2_task(%s): parsed response", task->id);
|
|
Packit |
90a5c9 |
if (APR_BRIGADE_EMPTY(bb) || status != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return status;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return ap_pass_brigade(f->next, bb);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* task things
|
|
Packit |
90a5c9 |
******************************************************************************/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_task_can_redo(h2_task *task) {
|
|
Packit |
90a5c9 |
if (task->input.beam && h2_beam_was_received(task->input.beam)) {
|
|
Packit |
90a5c9 |
/* cannot repeat that. */
|
|
Packit |
90a5c9 |
return 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return (!strcmp("GET", task->request->method)
|
|
Packit |
90a5c9 |
|| !strcmp("HEAD", task->request->method)
|
|
Packit |
90a5c9 |
|| !strcmp("OPTIONS", task->request->method));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_task_redo(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
task->rst_error = 0;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_task_rst(h2_task *task, int error)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
task->rst_error = error;
|
|
Packit |
90a5c9 |
if (task->input.beam) {
|
|
Packit |
90a5c9 |
h2_beam_leave(task->input.beam);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (!task->worker_done) {
|
|
Packit |
90a5c9 |
h2_beam_abort(task->output.beam);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (task->c) {
|
|
Packit |
90a5c9 |
task->c->aborted = 1;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*******************************************************************************
|
|
Packit |
90a5c9 |
* Register various hooks
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static const char *const mod_ssl[] = { "mod_ssl.c", NULL};
|
|
Packit |
90a5c9 |
static int h2_task_pre_conn(conn_rec* c, void *arg);
|
|
Packit |
90a5c9 |
static int h2_task_process_conn(conn_rec* c);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_in) *h2_task_logio_add_bytes_in;
|
|
Packit |
90a5c9 |
APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *h2_task_logio_add_bytes_out;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_task_register_hooks(void)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* This hook runs on new connections before mod_ssl has a say.
|
|
Packit |
90a5c9 |
* Its purpose is to prevent mod_ssl from touching our pseudo-connections
|
|
Packit |
90a5c9 |
* for streams.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
ap_hook_pre_connection(h2_task_pre_conn,
|
|
Packit |
90a5c9 |
NULL, mod_ssl, APR_HOOK_FIRST);
|
|
Packit |
90a5c9 |
/* When the connection processing actually starts, we might
|
|
Packit |
90a5c9 |
* take over, if the connection is for a task.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
ap_hook_process_connection(h2_task_process_conn,
|
|
Packit |
90a5c9 |
NULL, NULL, APR_HOOK_FIRST);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_register_input_filter("H2_SLAVE_IN", h2_filter_slave_in,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_NETWORK);
|
|
Packit |
90a5c9 |
ap_register_output_filter("H2_SLAVE_OUT", h2_filter_slave_output,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_NETWORK);
|
|
Packit |
90a5c9 |
ap_register_output_filter("H2_PARSE_H1", h2_filter_parse_h1,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_NETWORK);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_register_input_filter("H2_REQUEST", h2_filter_request_in,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_PROTOCOL);
|
|
Packit |
90a5c9 |
ap_register_output_filter("H2_RESPONSE", h2_filter_headers_out,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_PROTOCOL);
|
|
Packit |
90a5c9 |
ap_register_output_filter("H2_TRAILERS_OUT", h2_filter_trailers_out,
|
|
Packit |
90a5c9 |
NULL, AP_FTYPE_PROTOCOL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* post config init */
|
|
Packit |
90a5c9 |
apr_status_t h2_task_init(apr_pool_t *pool, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_task_logio_add_bytes_in = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_in);
|
|
Packit |
90a5c9 |
h2_task_logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int h2_task_pre_conn(conn_rec* c, void *arg)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_ctx *ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!c->master) {
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx = h2_ctx_get(c, 0);
|
|
Packit |
90a5c9 |
(void)arg;
|
|
Packit |
90a5c9 |
if (h2_ctx_is_task(ctx)) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c,
|
|
Packit |
90a5c9 |
"h2_h2, pre_connection, found stream task");
|
|
Packit |
90a5c9 |
ap_add_input_filter("H2_SLAVE_IN", NULL, NULL, c);
|
|
Packit |
90a5c9 |
ap_add_output_filter("H2_PARSE_H1", NULL, NULL, c);
|
|
Packit |
90a5c9 |
ap_add_output_filter("H2_SLAVE_OUT", NULL, NULL, c);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_task *h2_task_create(conn_rec *slave, int stream_id,
|
|
Packit |
90a5c9 |
const h2_request *req, h2_mplx *m,
|
|
Packit |
90a5c9 |
h2_bucket_beam *input,
|
|
Packit |
90a5c9 |
apr_interval_time_t timeout,
|
|
Packit |
90a5c9 |
apr_size_t output_max_mem)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
apr_pool_t *pool;
|
|
Packit |
90a5c9 |
h2_task *task;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(slave);
|
|
Packit |
90a5c9 |
ap_assert(req);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_pool_create(&pool, slave->pool);
|
|
Packit |
90a5c9 |
task = apr_pcalloc(pool, sizeof(h2_task));
|
|
Packit |
90a5c9 |
if (task == NULL) {
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
task->id = "000";
|
|
Packit |
90a5c9 |
task->stream_id = stream_id;
|
|
Packit |
90a5c9 |
task->c = slave;
|
|
Packit |
90a5c9 |
task->mplx = m;
|
|
Packit |
90a5c9 |
task->pool = pool;
|
|
Packit |
90a5c9 |
task->request = req;
|
|
Packit |
90a5c9 |
task->timeout = timeout;
|
|
Packit |
90a5c9 |
task->input.beam = input;
|
|
Packit |
90a5c9 |
task->output.max_buffer = output_max_mem;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return task;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
void h2_task_destroy(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (task->output.beam) {
|
|
Packit |
90a5c9 |
h2_beam_log(task->output.beam, task->c, APLOG_TRACE2, "task_destroy");
|
|
Packit |
90a5c9 |
h2_beam_destroy(task->output.beam);
|
|
Packit |
90a5c9 |
task->output.beam = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (task->eor) {
|
|
Packit |
90a5c9 |
apr_bucket_destroy(task->eor);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (task->pool) {
|
|
Packit |
90a5c9 |
apr_pool_destroy(task->pool);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
conn_rec *c;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_assert(task);
|
|
Packit |
90a5c9 |
c = task->c;
|
|
Packit |
90a5c9 |
task->worker_started = 1;
|
|
Packit |
90a5c9 |
task->started_at = apr_time_now();
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (c->master) {
|
|
Packit |
90a5c9 |
/* Each conn_rec->id is supposed to be unique at a point in time. Since
|
|
Packit |
90a5c9 |
* some modules (and maybe external code) uses this id as an identifier
|
|
Packit |
90a5c9 |
* for the request_rec they handle, it needs to be unique for slave
|
|
Packit |
90a5c9 |
* connections also.
|
|
Packit |
90a5c9 |
* The connection id is generated by the MPM and most MPMs use the formula
|
|
Packit |
90a5c9 |
* id := (child_num * max_threads) + thread_num
|
|
Packit |
90a5c9 |
* which means that there is a maximum id of about
|
|
Packit |
90a5c9 |
* idmax := max_child_count * max_threads
|
|
Packit |
90a5c9 |
* If we assume 2024 child processes with 2048 threads max, we get
|
|
Packit |
90a5c9 |
* idmax ~= 2024 * 2048 = 2 ** 22
|
|
Packit |
90a5c9 |
* On 32 bit systems, we have not much space left, but on 64 bit systems
|
|
Packit |
90a5c9 |
* (and higher?) we can use the upper 32 bits without fear of collision.
|
|
Packit |
90a5c9 |
* 32 bits is just what we need, since a connection can only handle so
|
|
Packit |
90a5c9 |
* many streams.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
int slave_id, free_bits;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
task->id = apr_psprintf(task->pool, "%ld-%d", c->master->id,
|
|
Packit |
90a5c9 |
task->stream_id);
|
|
Packit |
90a5c9 |
if (sizeof(unsigned long) >= 8) {
|
|
Packit |
90a5c9 |
free_bits = 32;
|
|
Packit |
90a5c9 |
slave_id = task->stream_id;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
/* Assume we have a more limited number of threads/processes
|
|
Packit |
90a5c9 |
* and h2 workers on a 32-bit system. Use the worker instead
|
|
Packit |
90a5c9 |
* of the stream id. */
|
|
Packit |
90a5c9 |
free_bits = 8;
|
|
Packit |
90a5c9 |
slave_id = worker_id;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
task->c->id = (c->master->id << free_bits)^slave_id;
|
|
Packit |
90a5c9 |
c->keepalive = AP_CONN_KEEPALIVE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_beam_create(&task->output.beam, c->pool, task->stream_id, "output",
|
|
Packit |
90a5c9 |
H2_BEAM_OWNER_SEND, 0, task->timeout);
|
|
Packit |
90a5c9 |
if (!task->output.beam) {
|
|
Packit |
90a5c9 |
return APR_ENOMEM;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_beam_buffer_size_set(task->output.beam, task->output.max_buffer);
|
|
Packit |
90a5c9 |
h2_beam_send_from(task->output.beam, task->pool);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_ctx_create_for(c, task);
|
|
Packit |
90a5c9 |
apr_table_setn(c->notes, H2_TASK_ID_NOTE, task->id);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_slave_run_pre_connection(c, ap_get_conn_socket(c));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
task->input.bb = apr_brigade_create(task->pool, c->bucket_alloc);
|
|
Packit |
90a5c9 |
if (task->request->serialize) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): serialize request %s %s",
|
|
Packit |
90a5c9 |
task->id, task->request->method, task->request->path);
|
|
Packit |
90a5c9 |
apr_brigade_printf(task->input.bb, NULL,
|
|
Packit |
90a5c9 |
NULL, "%s %s HTTP/1.1\r\n",
|
|
Packit |
90a5c9 |
task->request->method, task->request->path);
|
|
Packit |
90a5c9 |
apr_table_do(input_ser_header, task, task->request->headers, NULL);
|
|
Packit |
90a5c9 |
apr_brigade_puts(task->input.bb, NULL, NULL, "\r\n");
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): process connection", task->id);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
task->c->current_thread = thread;
|
|
Packit |
90a5c9 |
ap_run_process_connection(c);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (task->frozen) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): process_conn returned frozen task",
|
|
Packit |
90a5c9 |
task->id);
|
|
Packit |
90a5c9 |
/* cleanup delayed */
|
|
Packit |
90a5c9 |
return APR_EAGAIN;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): processing done", task->id);
|
|
Packit |
90a5c9 |
return output_finish(task);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static apr_status_t h2_task_process_request(h2_task *task, conn_rec *c)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
const h2_request *req = task->request;
|
|
Packit |
90a5c9 |
conn_state_t *cs = c->cs;
|
|
Packit |
90a5c9 |
request_rec *r;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): create request_rec", task->id);
|
|
Packit |
90a5c9 |
r = h2_request_create_rec(req, c);
|
|
Packit |
90a5c9 |
if (r && (r->status == HTTP_OK)) {
|
|
Packit |
90a5c9 |
/* set timeouts for virtual host of request */
|
|
Packit |
90a5c9 |
if (task->timeout != r->server->timeout) {
|
|
Packit |
90a5c9 |
task->timeout = r->server->timeout;
|
|
Packit |
90a5c9 |
h2_beam_timeout_set(task->output.beam, task->timeout);
|
|
Packit |
90a5c9 |
if (task->input.beam) {
|
|
Packit |
90a5c9 |
h2_beam_timeout_set(task->input.beam, task->timeout);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (cs) {
|
|
Packit |
90a5c9 |
cs->state = CONN_STATE_HANDLER;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): start process_request", task->id);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* Add the raw bytes of the request (e.g. header frame lengths to
|
|
Packit |
90a5c9 |
* the logio for this request. */
|
|
Packit |
90a5c9 |
if (req->raw_bytes && h2_task_logio_add_bytes_in) {
|
|
Packit |
90a5c9 |
h2_task_logio_add_bytes_in(c, req->raw_bytes);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_process_request(r);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (task->frozen) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): process_request frozen", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): process_request done", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* After the call to ap_process_request, the
|
|
Packit |
90a5c9 |
* request pool may have been deleted. We set
|
|
Packit |
90a5c9 |
* r=NULL here to ensure that any dereference
|
|
Packit |
90a5c9 |
* of r that might be added later in this function
|
|
Packit |
90a5c9 |
* will result in a segfault immediately instead
|
|
Packit |
90a5c9 |
* of nondeterministic failures later.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (cs)
|
|
Packit |
90a5c9 |
cs->state = CONN_STATE_WRITE_COMPLETION;
|
|
Packit |
90a5c9 |
r = NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (!r) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): create request_rec failed, r=NULL", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s): create request_rec failed, r->status=%d",
|
|
Packit |
90a5c9 |
task->id, r->status);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static int h2_task_process_conn(conn_rec* c)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
h2_ctx *ctx;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!c->master) {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ctx = h2_ctx_get(c, 0);
|
|
Packit |
90a5c9 |
if (h2_ctx_is_task(ctx)) {
|
|
Packit |
90a5c9 |
if (!ctx->task->request->serialize) {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_h2, processing request directly");
|
|
Packit |
90a5c9 |
h2_task_process_request(ctx->task, c);
|
|
Packit |
90a5c9 |
return DONE;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"h2_task(%s), serialized handling", ctx->task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c,
|
|
Packit |
90a5c9 |
"slave_conn(%ld): has no task", c->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_task_freeze(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (!task->frozen) {
|
|
Packit |
90a5c9 |
task->frozen = 1;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03406)
|
|
Packit |
90a5c9 |
"h2_task(%s), frozen", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_task_thaw(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (task->frozen) {
|
|
Packit |
90a5c9 |
task->frozen = 0;
|
|
Packit |
90a5c9 |
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, task->c, APLOGNO(03407)
|
|
Packit |
90a5c9 |
"h2_task(%s), thawed", task->id);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
task->thawed = 1;
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int h2_task_has_thawed(h2_task *task)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
return task->thawed;
|
|
Packit |
90a5c9 |
}
|