blob: 68a66657adeaa2543ee1ec0d0a91050fdd257a34 [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __mod_h2__h2_task__
#define __mod_h2__h2_task__
#include <http_core.h>
/**
* A h2_task fakes a HTTP/1.1 request from the data in a HTTP/2 stream
* (HEADER+CONT.+DATA) the module receives.
*
* In order to answer a HTTP/2 stream, we want all Apache httpd infrastructure
* to be involved as usual, as if this stream can as a separate HTTP/1.1
* request. The basic trickery to do so was derived from google's mod_spdy
* source. Basically, we fake a new conn_rec object, even with its own
* socket and give it to ap_process_connection().
*
* Since h2_task instances are executed in separate threads, we may have
* different lifetimes than our h2_stream or h2_session instances. Basically,
* we would like to be as standalone as possible.
*
* Finally, to keep certain connection level filters, such as ourselves and
* especially mod_ssl ones, from messing with our data, we need a filter
* of our own to disble those.
*/
struct h2_bucket_beam;
struct h2_conn;
struct h2_mplx;
struct h2_task;
struct h2_request;
struct h2_response_parser;
struct h2_stream;
struct h2_worker;
typedef struct h2_task h2_task;
struct h2_task {
const char *id;
int stream_id;
conn_rec *c;
apr_pool_t *pool;
const struct h2_request *request;
apr_interval_time_t timeout;
int rst_error; /* h2 related stream abort error */
struct {
struct h2_bucket_beam *beam;
unsigned int eos : 1;
apr_bucket_brigade *bb;
apr_bucket_brigade *bbchunk;
apr_off_t chunked_total;
} input;
struct {
struct h2_bucket_beam *beam;
unsigned int opened : 1;
unsigned int sent_response : 1;
unsigned int copy_files : 1;
struct h2_response_parser *rparser;
apr_bucket_brigade *bb;
apr_size_t max_buffer;
} output;
struct h2_mplx *mplx;
unsigned int filters_set : 1;
unsigned int worker_started : 1; /* h2_worker started processing */
unsigned int redo : 1; /* was throttled, should be restarted later */
int worker_done; /* h2_worker finished */
int done_done; /* task_done has been handled */
apr_time_t started_at; /* when processing started */
apr_time_t done_at; /* when processing was done */
apr_bucket *eor;
};
h2_task *h2_task_create(conn_rec *slave, int stream_id,
const h2_request *req, struct h2_mplx *m,
struct h2_bucket_beam *input,
apr_interval_time_t timeout,
apr_size_t output_max_mem);
void h2_task_destroy(h2_task *task);
apr_status_t h2_task_do(h2_task *task, apr_thread_t *thread, int worker_id);
void h2_task_redo(h2_task *task);
int h2_task_can_redo(h2_task *task);
int h2_task_has_started(h2_task *task);
/**
* Reset the task with the given error code, resets all input/output.
*/
void h2_task_rst(h2_task *task, int error);
void h2_task_register_hooks(void);
/*
* One time, post config initialization.
*/
apr_status_t h2_task_init(apr_pool_t *pool, server_rec *s);
extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_in) *h2_task_logio_add_bytes_in;
extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *h2_task_logio_add_bytes_out;
#endif /* defined(__mod_h2__h2_task__) */