summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_session.h
blob: 3fd3088a0fd134353e6d28cf93fdf320b0b08b64 (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
206
207
208
209
210
211
212
/* 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_conn_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 h2_task(s) that are sent
 * via callback to a dispatcher (see h2_conn.c).
 * h2_session keeps h2_io's for each ongoing stream which buffer the
 * payload for that stream.
 *
 * New incoming HEADER frames are converted into a h2_stream+h2_task instance
 * that both represent a HTTP/2 stream, but may have separate lifetimes. This
 * allows h2_task to be scheduled in other threads without semaphores
 * all over the place. It allows task memory to be freed independent of
 * session lifetime and sessions may close down while tasks are still running.
 *
 *
 */

#include "h2.h"

struct apr_thread_mutext_t;
struct apr_thread_cond_t;
struct h2_ctx;
struct h2_config;
struct h2_filter_cin;
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_task;
struct h2_workers;

struct nghttp2_session;

typedef enum {
    H2_SESSION_EV_INIT,             /* session was initialized */
    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_NO_IO,            /* nothing has been read or written */
    H2_SESSION_EV_FRAME_RCVD,       /* a frame has been received */
    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_STREAM_CHANGE,    /* a stream (state/input/output) changed */
} h2_session_event_t;

typedef struct h2_session {
    long id;                        /* identifier of this session, unique
                                     * inside a httpd process */
    conn_rec *c;                    /* the 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 stream tasks */
    struct h2_filter_cin *cin;      /* connection input filter context */
    h2_conn_io io;                  /* io on httpd conn filters */
    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 */
    unsigned int have_read     : 1; /* session has read client data */
    unsigned int have_written  : 1; /* session did write data to client */
    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 */
    int open_streams;               /* number of client streams open */
    int unsent_submits;             /* number of submitted, but not yet written responses. */
    int unsent_promises;            /* number of submitted, but not yet written push promises */
                                         
    int responses_submitted;        /* number of http/2 responses submitted */
    int streams_reset;              /* number of http/2 streams reset by client */
    int pushes_promised;            /* number of http/2 push promises submitted */
    int pushes_submitted;           /* number of http/2 pushed responses submitted */
    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_time_t idle_until;          /* Time we shut down due to sheer boredom */
    apr_time_t idle_sync_until;     /* Time we sync wait until keepalive handling kicks in */
    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 */
    struct apr_thread_cond_t *iowait; /* our cond when trywaiting for 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 */
    
    struct h2_iqueue *in_pending;   /* all streams with input pending */
    struct h2_iqueue *in_process;   /* all streams ready for processing on a secondary */

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

/**
 * Close and deallocate the given session.
 */
void h2_session_close(h2_session *session);

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

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

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

#endif /* defined(__mod_h2__h2_session__) */