summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_task.h
blob: ab6a7469bc3164ee84d61e75cac3924e57b721d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* 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 recieves.
 *
 * 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_req_engine;
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 frozen         : 1;
    unsigned int thawed         : 1;
    unsigned int worker_started : 1; /* h2_worker started processing */
    unsigned int worker_done    : 1; /* h2_worker finished */
    
    apr_time_t started_at;           /* when processing started */
    apr_time_t done_at;              /* when processing was done */
    apr_bucket *eor;
    
    struct h2_req_engine *engine;   /* engine hosted by this task */
    struct h2_req_engine *assigned; /* engine that task has been assigned to */
};

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);

/**
 * 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 intialization.
 */
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;

apr_status_t h2_task_freeze(h2_task *task);
apr_status_t h2_task_thaw(h2_task *task);
int h2_task_has_thawed(h2_task *task);

#endif /* defined(__mod_h2__h2_task__) */