1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef __mod_h2__h2_session__
18 #define __mod_h2__h2_session__
19 
20 #include "h2_c1_io.h"
21 
22 /**
23  * A HTTP/2 connection, a session with a specific client.
24  *
25  * h2_session sits on top of a httpd conn_rec* instance and takes complete
26  * control of the connection data. It receives protocol frames from the
27  * client. For new HTTP/2 streams it creates secondary connections
28  * to execute the requests in h2 workers.
29  */
30 
31 #include "h2.h"
32 
33 struct apr_thread_mutext_t;
34 struct apr_thread_cond_t;
35 struct h2_ctx;
36 struct h2_config;
37 struct h2_ihash_t;
38 struct h2_mplx;
39 struct h2_priority;
40 struct h2_push;
41 struct h2_push_diary;
42 struct h2_session;
43 struct h2_stream;
44 struct h2_stream_monitor;
45 struct h2_workers;
46 
47 struct nghttp2_session;
48 
49 typedef enum {
50     H2_SESSION_EV_INIT,             /* session was initialized */
51     H2_SESSION_EV_INPUT_PENDING,    /* c1 input may have data pending */
52     H2_SESSION_EV_INPUT_EXHAUSTED,  /* c1 input exhausted */
53     H2_SESSION_EV_LOCAL_GOAWAY,     /* we send a GOAWAY */
54     H2_SESSION_EV_REMOTE_GOAWAY,    /* remote send us a GOAWAY */
55     H2_SESSION_EV_CONN_ERROR,       /* connection error */
56     H2_SESSION_EV_PROTO_ERROR,      /* protocol error */
57     H2_SESSION_EV_CONN_TIMEOUT,     /* connection timeout */
58     H2_SESSION_EV_NGH2_DONE,        /* nghttp2 wants neither read nor write anything */
59     H2_SESSION_EV_MPM_STOPPING,     /* the process is stopping */
60     H2_SESSION_EV_PRE_CLOSE,        /* connection will close after this */
61     H2_SESSION_EV_NO_MORE_STREAMS,  /* no more streams to process */
62 } h2_session_event_t;
63 
64 typedef struct h2_session {
65     long id;                        /* identifier of this session, unique
66                                      * inside a httpd process */
67     conn_rec *c1;                   /* the main connection this session serves */
68     request_rec *r;                 /* the request that started this in case
69                                      * of 'h2c', NULL otherwise */
70     server_rec *s;                  /* server/vhost we're starting on */
71     apr_pool_t *pool;               /* pool to use in session */
72     struct h2_mplx *mplx;           /* multiplexer for stream data */
73     struct h2_workers *workers;     /* for executing streams */
74     struct h2_c1_io_in_ctx_t *cin;  /* connection input filter context */
75     h2_c1_io io;                    /* io on httpd conn filters */
76     int padding_max;                /* max number of padding bytes */
77     int padding_always;             /* padding has precedence over I/O optimizations */
78     struct nghttp2_session *ngh2;   /* the nghttp2 session (internal use) */
79 
80     h2_session_state state;         /* state session is in */
81 
82     h2_session_props local;         /* properties of local session */
83     h2_session_props remote;        /* properites of remote session */
84 
85     unsigned int reprioritize  : 1; /* scheduled streams priority changed */
86     unsigned int flush         : 1; /* flushing output necessary */
87     apr_interval_time_t  wait_us;   /* timeout during BUSY_WAIT state, micro secs */
88 
89     struct h2_push_diary *push_diary; /* remember pushes, avoid duplicates */
90 
91     struct h2_stream_monitor *monitor;/* monitor callbacks for streams */
92     int open_streams;               /* number of streams processing */
93 
94     int streams_done;               /* number of http/2 streams handled */
95     int responses_submitted;        /* number of http/2 responses submitted */
96     int streams_reset;              /* number of http/2 streams reset by client */
97     int pushes_promised;            /* number of http/2 push promises submitted */
98     int pushes_submitted;           /* number of http/2 pushed responses submitted */
99     int pushes_reset;               /* number of http/2 pushed reset by client */
100 
101     apr_size_t frames_received;     /* number of http/2 frames received */
102     apr_size_t frames_sent;         /* number of http/2 frames sent */
103 
104     apr_size_t max_stream_count;    /* max number of open streams */
105     apr_size_t max_stream_mem;      /* max buffer memory for a single stream */
106 
107     apr_size_t idle_frames;         /* number of rcvd frames that kept session in idle state */
108     apr_interval_time_t idle_delay; /* Time we delay processing rcvd frames in idle state */
109 
110     apr_bucket_brigade *bbtmp;      /* brigade for keeping temporary data */
111 
112     char status[64];                /* status message for scoreboard */
113     int last_status_code;           /* the one already reported */
114     const char *last_status_msg;    /* the one already reported */
115 
116     struct h2_iqueue *in_pending;   /* all streams with input pending */
117     struct h2_iqueue *out_c1_blocked;  /* all streams with output blocked on c1 buffer full */
118     struct h2_iqueue *ready_to_process;  /* all streams ready for processing */
119 
120 } h2_session;
121 
122 const char *h2_session_state_str(h2_session_state state);
123 
124 /**
125  * Create a new h2_session for the given connection.
126  * The session will apply the configured parameter.
127  * @param psession pointer receiving the created session on success or NULL
128  * @param c       the connection to work on
129  * @param r       optional request when protocol was upgraded
130  * @param cfg     the module config to apply
131  * @param workers the worker pool to use
132  * @return the created session
133  */
134 apr_status_t h2_session_create(h2_session **psession,
135                                conn_rec *c, request_rec *r, server_rec *,
136                                struct h2_workers *workers);
137 
138 void h2_session_event(h2_session *session, h2_session_event_t ev,
139                       int err, const char *msg);
140 
141 /**
142  * Process the given HTTP/2 session until it is ended or a fatal
143  * error occurred.
144  *
145  * @param session the sessionm to process
146  */
147 apr_status_t h2_session_process(h2_session *session, int async);
148 
149 /**
150  * Last chance to do anything before the connection is closed.
151  */
152 apr_status_t h2_session_pre_close(h2_session *session, int async);
153 
154 /**
155  * Called when a serious error occurred and the session needs to terminate
156  * without further connection io.
157  * @param session the session to abort
158  * @param reason  the apache status that caused the abort
159  */
160 void h2_session_abort(h2_session *session, apr_status_t reason);
161 
162 /**
163  * Returns if client settings have push enabled.
164  * @param != 0 iff push is enabled in client settings
165  */
166 int h2_session_push_enabled(h2_session *session);
167 
168 /**
169  * Submit a push promise on the stream and schedule the new steam for
170  * processing..
171  *
172  * @param session the session to work in
173  * @param is the stream initiating the push
174  * @param push the push to promise
175  * @return the new promised stream or NULL
176  */
177 struct h2_stream *h2_session_push(h2_session *session,
178                                   struct h2_stream *is, struct h2_push *push);
179 
180 apr_status_t h2_session_set_prio(h2_session *session,
181                                  struct h2_stream *stream,
182                                  const struct h2_priority *prio);
183 
184 /**
185  * Dispatch a event happending during session processing.
186  * @param session the sessiont
187  * @param ev the event that happened
188  * @param arg integer argument (event type dependant)
189  * @param msg destriptive message
190  */
191 void h2_session_dispatch_event(h2_session *session, h2_session_event_t ev,
192                                int arg, const char *msg);
193 
194 
195 #define H2_SSSN_MSG(s, msg)     \
196     "h2_session(%ld,%s,%d): "msg, s->id, h2_session_state_str(s->state), \
197                             s->open_streams
198 
199 #define H2_SSSN_LOG(aplogno, s, msg)    aplogno H2_SSSN_MSG(s, msg)
200 
201 #endif /* defined(__mod_h2__h2_session__) */
202