| /* 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" | |
| #include "h2_util.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_EV_BAD_CLIENT, /* client misbehaving badly */ | |
| } 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. | |
| * c1-thread only: written via | |
| * h2_mplx_c1_stream_cleanup() on H2_SS_CLEANUP | |
| * and read throughout h2_session_process(), | |
| * all on the c1 connection thread. An async | |
| * MPM (e.g. motorz) re-dispatches c1 to a | |
| * fresh worker between events -- successive, | |
| * never concurrent -- so no atomics/volatile | |
| * are needed; the MPM pollset handoff | |
| * establishes the happens-before. Decrements | |
| * to 0 only after each stream's c2 has | |
| * finished and flushed; the graceful-GOAWAY | |
| * drain in h2_session_process() relies on | |
| * this (see h2_session_ev_remote_goaway). */ | |
| 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 */ | |
| unsigned int max_stream_errors; /* max client stream errors tolerated */ | |
| unsigned int stream_errors; /* number of stream errors 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 max_data_frame_len; /* max amount of bytes for a single DATA frame */ | |
| 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_hd_scratch hd_scratch; | |
| } 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 | |
| * @param async if mpm is async | |
| * @param pkeepalive on return, != 0 if connection to be put into keepalive | |
| * behaviour and timouts | |
| */ | |
| apr_status_t h2_session_process(h2_session *session, int async, int *pkeepalive); | |
| /** | |
| * 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__) */ |