summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_session.h
blob: fbddfdd2a36ad32d9b57b4cc1b147b3ec2231854 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/* 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_session__
#define __mod_h2__h2_session__

#include "h2_c1_io.h"

/**
 * A HTTP/2 connection, a session with a specific client.
 * 
 * h2_session sits on top of a httpd conn_rec* instance and takes complete
 * control of the connection data. It receives protocol frames from the
 * client. For new HTTP/2 streams it creates secondary connections
 * to execute the requests in h2 workers.
 */

#include "h2.h"

struct apr_thread_mutext_t;
struct apr_thread_cond_t;
struct h2_ctx;
struct h2_config;
struct h2_ihash_t;
struct h2_mplx;
struct h2_priority;
struct h2_push;
struct h2_push_diary;
struct h2_session;
struct h2_stream;
struct h2_stream_monitor;
struct h2_workers;

struct nghttp2_session;

typedef enum {
    H2_SESSION_EV_INIT,             /* session was initialized */
    H2_SESSION_EV_INPUT_PENDING,    /* c1 input may have data pending */
    H2_SESSION_EV_INPUT_EXHAUSTED,  /* c1 input exhausted */
    H2_SESSION_EV_LOCAL_GOAWAY,     /* we send a GOAWAY */
    H2_SESSION_EV_REMOTE_GOAWAY,    /* remote send us a GOAWAY */
    H2_SESSION_EV_CONN_ERROR,       /* connection error */
    H2_SESSION_EV_PROTO_ERROR,      /* protocol error */
    H2_SESSION_EV_CONN_TIMEOUT,     /* connection timeout */
    H2_SESSION_EV_NGH2_DONE,        /* nghttp2 wants neither read nor write anything */
    H2_SESSION_EV_MPM_STOPPING,     /* the process is stopping */
    H2_SESSION_EV_PRE_CLOSE,        /* connection will close after this */
    H2_SESSION_EV_NO_MORE_STREAMS,  /* no more streams to process */
} h2_session_event_t;

typedef struct h2_session {
    int child_num;                  /* child number this session runs in */
    apr_uint32_t id;                /* identifier of this session, unique per child */
    conn_rec *c1;                   /* the main connection this session serves */
    request_rec *r;                 /* the request that started this in case
                                     * of 'h2c', NULL otherwise */
    server_rec *s;                  /* server/vhost we're starting on */
    apr_pool_t *pool;               /* pool to use in session */
    struct h2_mplx *mplx;           /* multiplexer for stream data */
    struct h2_workers *workers;     /* for executing streams */
    struct h2_c1_io_in_ctx_t *cin;  /* connection input filter context */
    h2_c1_io io;                    /* io on httpd conn filters */
    unsigned int padding_max;       /* max number of padding bytes */
    int padding_always;             /* padding has precedence over I/O optimizations */
    struct nghttp2_session *ngh2;   /* the nghttp2 session (internal use) */

    h2_session_state state;         /* state session is in */
    
    h2_session_props local;         /* properties of local session */
    h2_session_props remote;        /* properites of remote session */
    
    unsigned int reprioritize  : 1; /* scheduled streams priority changed */
    unsigned int flush         : 1; /* flushing output necessary */
    apr_interval_time_t  wait_us;   /* timeout during BUSY_WAIT state, micro secs */
    
    struct h2_push_diary *push_diary; /* remember pushes, avoid duplicates */
    
    struct h2_stream_monitor *monitor;/* monitor callbacks for streams */
    unsigned int open_streams;      /* number of streams processing */

    unsigned int streams_done;      /* number of http/2 streams handled */
    unsigned int responses_submitted; /* number of http/2 responses submitted */
    unsigned int streams_reset;     /* number of http/2 streams reset by client */
    unsigned int pushes_promised;   /* number of http/2 push promises submitted */
    unsigned int pushes_submitted;  /* number of http/2 pushed responses submitted */
    unsigned int pushes_reset;      /* number of http/2 pushed reset by client */
    
    apr_size_t frames_received;     /* number of http/2 frames received */
    apr_size_t frames_sent;         /* number of http/2 frames sent */
    
    apr_size_t max_stream_count;    /* max number of open streams */
    apr_size_t max_stream_mem;      /* max buffer memory for a single stream */
    
    apr_size_t idle_frames;         /* number of rcvd frames that kept session in idle state */
    apr_interval_time_t idle_delay; /* Time we delay processing rcvd frames in idle state */
    
    apr_bucket_brigade *bbtmp;      /* brigade for keeping temporary data */

    char status[64];                /* status message for scoreboard */
    int last_status_code;           /* the one already reported */
    const char *last_status_msg;    /* the one already reported */

    int input_flushed;              /* stream input was flushed */
    struct h2_iqueue *out_c1_blocked;  /* all streams with output blocked on c1 buffer full */
    struct h2_iqueue *ready_to_process;  /* all streams ready for processing */

} h2_session;

const char *h2_session_state_str(h2_session_state state);

/**
 * Create a new h2_session for the given connection.
 * The session will apply the configured parameter.
 * @param psession pointer receiving the created session on success or NULL
 * @param c       the connection to work on
 * @param r       optional request when protocol was upgraded
 * @param cfg     the module config to apply
 * @param workers the worker pool to use
 * @return the created session
 */
apr_status_t h2_session_create(h2_session **psession,
                               conn_rec *c, request_rec *r, server_rec *, 
                               struct h2_workers *workers);

void h2_session_event(h2_session *session, h2_session_event_t ev, 
                      int err, const char *msg);

/**
 * Process the given HTTP/2 session until it is ended or a fatal
 * error occurred.
 *
 * @param session the sessionm to process
 */
apr_status_t h2_session_process(h2_session *session, int async);

/**
 * Last chance to do anything before the connection is closed.
 */
apr_status_t h2_session_pre_close(h2_session *session, int async);

/**
 * Called when a serious error occurred and the session needs to terminate
 * without further connection io.
 * @param session the session to abort
 * @param reason  the apache status that caused the abort
 */
void h2_session_abort(h2_session *session, apr_status_t reason);

/**
 * Returns if client settings have push enabled.
 * @param != 0 iff push is enabled in client settings
 */
int h2_session_push_enabled(h2_session *session);

/**
 * Submit a push promise on the stream and schedule the new steam for
 * processing..
 * 
 * @param session the session to work in
 * @param is the stream initiating the push
 * @param push the push to promise
 * @return the new promised stream or NULL
 */
struct h2_stream *h2_session_push(h2_session *session, 
                                  struct h2_stream *is, struct h2_push *push);

apr_status_t h2_session_set_prio(h2_session *session, 
                                 struct h2_stream *stream, 
                                 const struct h2_priority *prio);

/**
 * Dispatch a event happending during session processing.
 * @param session the sessiont
 * @param ev the event that happened
 * @param arg integer argument (event type dependant)
 * @param msg destriptive message
 */
void h2_session_dispatch_event(h2_session *session, h2_session_event_t ev,
                               int arg, const char *msg);


#define H2_SSSN_MSG(s, msg)     \
    "h2_session(%d-%lu,%s,%d): "msg, s->child_num, (unsigned long)s->id, \
                            h2_session_state_str(s->state), \
                            s->open_streams

#define H2_SSSN_LOG(aplogno, s, msg)    aplogno H2_SSSN_MSG(s, msg)

#define H2_SSSN_STRM_MSG(s, stream_id, msg)     \
    "h2_stream(%d-%lu-%d): "msg, s->child_num, (unsigned long)s->id, stream_id

#endif /* defined(__mod_h2__h2_session__) */