summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_stream.h
diff options
context:
space:
mode:
Diffstat (limited to 'modules/http2/h2_stream.h')
-rw-r--r--modules/http2/h2_stream.h326
1 files changed, 326 insertions, 0 deletions
diff --git a/modules/http2/h2_stream.h b/modules/http2/h2_stream.h
new file mode 100644
index 0000000..695d56a
--- /dev/null
+++ b/modules/http2/h2_stream.h
@@ -0,0 +1,326 @@
+/* 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_stream__
+#define __mod_h2__h2_stream__
+
+#include <http_protocol.h>
+
+#include "h2.h"
+#include "h2_headers.h"
+
+/**
+ * A HTTP/2 stream, e.g. a client request+response in HTTP/1.1 terms.
+ *
+ * A stream always belongs to a h2_session, the one managing the
+ * connection to the client. The h2_session writes to the h2_stream,
+ * adding HEADERS and DATA and finally an EOS. When headers are done,
+ * h2_stream is scheduled for handling, which is expected to produce
+ * h2_headers/RESPONSE buckets.
+ *
+ * The h2_headers may be followed by more h2_headers (interim responses) and
+ * by DATA frames read from the h2_stream until EOS is reached. Trailers
+ * are send when a last h2_headers is received. This always closes the stream
+ * output.
+ */
+
+struct h2_mplx;
+struct h2_priority;
+struct h2_request;
+struct h2_session;
+struct h2_bucket_beam;
+
+typedef struct h2_stream h2_stream;
+
+typedef void h2_stream_state_cb(void *ctx, h2_stream *stream);
+typedef void h2_stream_event_cb(void *ctx, h2_stream *stream,
+ h2_stream_event_t ev);
+
+/**
+ * Callback structure for events and stream state transisitions
+ */
+typedef struct h2_stream_monitor {
+ void *ctx;
+ h2_stream_state_cb *on_state_enter; /* called when a state is entered */
+ h2_stream_state_cb *on_state_invalid; /* called when an invalid state change
+ was detected */
+ h2_stream_event_cb *on_state_event; /* called right before the given event
+ result in a new stream state */
+ h2_stream_event_cb *on_event; /* called for events that do not
+ trigger a state change */
+} h2_stream_monitor;
+
+struct h2_stream {
+ int id; /* http2 stream identifier */
+ int initiated_on; /* initiating stream id (PUSH) or 0 */
+ apr_pool_t *pool; /* the memory pool for this stream */
+ struct h2_session *session; /* the session this stream belongs to */
+ h2_stream_state_t state; /* state of this stream */
+
+ apr_time_t created; /* when stream was created */
+
+ const struct h2_request *request; /* the request made in this stream */
+ struct h2_request *rtmp; /* request being assembled */
+ apr_table_t *trailers_in; /* optional, incoming trailers */
+ int request_headers_added; /* number of request headers added */
+
+#if AP_HAS_RESPONSE_BUCKETS
+ ap_bucket_response *response; /* the final, non-interim response or NULL */
+#else
+ struct h2_headers *response; /* the final, non-interim response or NULL */
+#endif
+
+ struct h2_bucket_beam *input;
+ apr_bucket_brigade *in_buffer;
+ int in_window_size;
+ apr_time_t in_last_write;
+
+ struct h2_bucket_beam *output;
+ apr_bucket_brigade *out_buffer;
+
+ int rst_error; /* stream error for RST_STREAM */
+ unsigned int aborted : 1; /* was aborted */
+ unsigned int scheduled : 1; /* stream has been scheduled */
+ unsigned int input_closed : 1; /* no more request data/trailers coming */
+ unsigned int push_policy; /* which push policy to use for this request */
+ unsigned int sent_trailers : 1; /* trailers have been submitted */
+ unsigned int output_eos : 1; /* output EOS in buffer/sent */
+
+ conn_rec *c2; /* connection processing stream */
+
+ const h2_priority *pref_priority; /* preferred priority for this stream */
+ apr_off_t out_frames; /* # of frames sent out */
+ apr_off_t out_frame_octets; /* # of RAW frame octets sent out */
+ apr_off_t out_data_frames; /* # of DATA frames sent */
+ apr_off_t out_data_octets; /* # of DATA octets (payload) sent */
+ apr_off_t in_data_frames; /* # of DATA frames received */
+ apr_off_t in_data_octets; /* # of DATA octets (payload) received */
+ apr_off_t in_trailer_octets; /* # of HEADER octets (payload) received in trailers */
+
+ h2_stream_monitor *monitor; /* optional monitor for stream states */
+};
+
+
+#define H2_STREAM_RST(s, def) (s->rst_error? s->rst_error : (def))
+
+/**
+ * Create a stream in H2_SS_IDLE state.
+ * @param id the stream identifier
+ * @param pool the memory pool to use for this stream
+ * @param session the session this stream belongs to
+ * @param monitor an optional monitor to be called for events and
+ * state transisitions
+ * @param initiated_on the id of the stream this one was initiated on (PUSH)
+ *
+ * @return the newly opened stream
+ */
+h2_stream *h2_stream_create(int id, apr_pool_t *pool,
+ struct h2_session *session,
+ h2_stream_monitor *monitor,
+ int initiated_on);
+
+/**
+ * Destroy memory pool if still owned by the stream.
+ */
+void h2_stream_destroy(h2_stream *stream);
+
+/**
+ * Perform any late initialization before stream starts processing.
+ */
+apr_status_t h2_stream_prepare_processing(h2_stream *stream);
+
+/*
+ * Set a new monitor for this stream, replacing any existing one. Can
+ * be called with NULL to have no monitor installed.
+ */
+void h2_stream_set_monitor(h2_stream *stream, h2_stream_monitor *monitor);
+
+/**
+ * Dispatch (handle) an event on the given stream.
+ * @param stream the streama the event happened on
+ * @param ev the type of event
+ */
+void h2_stream_dispatch(h2_stream *stream, h2_stream_event_t ev);
+
+/**
+ * Determine if stream is at given state.
+ * @param stream the stream to check
+ * @param state the state to look for
+ * @return != 0 iff stream is at given state.
+ */
+int h2_stream_is_at(const h2_stream *stream, h2_stream_state_t state);
+
+/**
+ * Determine if stream is reached given state or is past this state.
+ * @param stream the stream to check
+ * @param state the state to look for
+ * @return != 0 iff stream is at or past given state.
+ */
+int h2_stream_is_at_or_past(const h2_stream *stream, h2_stream_state_t state);
+
+/**
+ * Cleanup references into requst processing.
+ *
+ * @param stream the stream to cleanup
+ */
+void h2_stream_cleanup(h2_stream *stream);
+
+/**
+ * Notify the stream that amount bytes have been consumed of its input
+ * since the last invocation of this method (delta amount).
+ */
+apr_status_t h2_stream_in_consumed(h2_stream *stream, apr_off_t amount);
+
+/**
+ * Set complete stream headers from given h2_request.
+ *
+ * @param stream stream to write request to
+ * @param r the request with all the meta data
+ * @param eos != 0 iff stream input is closed
+ */
+void h2_stream_set_request(h2_stream *stream, const h2_request *r);
+
+/**
+ * Set complete stream header from given request_rec.
+ *
+ * @param stream stream to write request to
+ * @param r the request with all the meta data
+ * @param eos != 0 iff stream input is closed
+ */
+apr_status_t h2_stream_set_request_rec(h2_stream *stream,
+ request_rec *r, int eos);
+
+/*
+ * Add a HTTP/2 header (including pseudo headers) or trailer
+ * to the given stream, depending on stream state.
+ *
+ * @param stream stream to write the header to
+ * @param name the name of the HTTP/2 header
+ * @param nlen the number of characters in name
+ * @param value the header value
+ * @param vlen the number of characters in value
+ */
+apr_status_t h2_stream_add_header(h2_stream *stream,
+ const char *name, size_t nlen,
+ const char *value, size_t vlen);
+
+/* End the construction of request headers */
+apr_status_t h2_stream_end_headers(h2_stream *stream, int eos, size_t raw_bytes);
+
+
+apr_status_t h2_stream_send_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
+apr_status_t h2_stream_recv_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
+
+/*
+ * Process a frame of received DATA.
+ *
+ * @param stream stream to write the data to
+ * @param flags the frame flags
+ * @param data the beginning of the bytes to write
+ * @param len the number of bytes to write
+ */
+apr_status_t h2_stream_recv_DATA(h2_stream *stream, uint8_t flags,
+ const uint8_t *data, size_t len);
+
+/**
+ * Reset the stream. Stream write/reads will return errors afterwards.
+ *
+ * @param stream the stream to reset
+ * @param error_code the HTTP/2 error code
+ */
+void h2_stream_rst(h2_stream *stream, int error_code);
+
+/**
+ * Stream input signals change. Take necessary actions.
+ * @param stream the stream to read output for
+ */
+void h2_stream_on_input_change(h2_stream *stream);
+
+/**
+ * Stream output signals change. Take necessary actions.
+ * @param stream the stream to read output for
+ */
+void h2_stream_on_output_change(h2_stream *stream);
+
+/**
+ * Read a maximum number of bytes into the bucket brigade.
+ *
+ * @param stream the stream to read from
+ * @param bb the brigade to append output to
+ * @param plen (in-/out) max. number of bytes to append and on return actual
+ * number of bytes appended to brigade
+ * @param peos (out) != 0 iff end of stream has been reached while reading
+ * @return APR_SUCCESS if out information was computed successfully.
+ * APR_EAGAIN if not data is available and end of stream has not been
+ * reached yet.
+ */
+apr_status_t h2_stream_read_to(h2_stream *stream, apr_bucket_brigade *bb,
+ apr_off_t *plen, int *peos);
+
+/**
+ * Get optional trailers for this stream, may be NULL. Meaningful
+ * results can only be expected when the end of the response body has
+ * been reached.
+ *
+ * @param stream to ask for trailers
+ * @return trailers for NULL
+ */
+apr_table_t *h2_stream_get_trailers(h2_stream *stream);
+
+/**
+ * Submit any server push promises on this stream and schedule
+ * the streams for these.
+ *
+ * @param stream the stream for which to submit
+ */
+#if AP_HAS_RESPONSE_BUCKETS
+apr_status_t h2_stream_submit_pushes(h2_stream *stream,
+ ap_bucket_response *response);
+#else
+apr_status_t h2_stream_submit_pushes(h2_stream *stream,
+ struct h2_headers *response);
+#endif
+
+/**
+ * Get priority information set for this stream.
+ */
+#if AP_HAS_RESPONSE_BUCKETS
+const struct h2_priority *h2_stream_get_priority(h2_stream *stream,
+ ap_bucket_response *response);
+#else
+const struct h2_priority *h2_stream_get_priority(h2_stream *stream,
+ struct h2_headers *response);
+#endif
+
+/**
+ * Return a textual representation of the stream state as in RFC 7540
+ * nomenclator, all caps, underscores.
+ */
+const char *h2_stream_state_str(const h2_stream *stream);
+
+/**
+ * Determine if stream is ready for submitting a response or a RST
+ * @param stream the stream to check
+ */
+int h2_stream_is_ready(h2_stream *stream);
+
+#define H2_STRM_MSG(s, msg) \
+ "h2_stream(%d-%lu-%d,%s): "msg, s->session->child_num, \
+ (unsigned long)s->session->id, s->id, h2_stream_state_str(s)
+
+#define H2_STRM_LOG(aplogno, s, msg) aplogno H2_STRM_MSG(s, msg)
+
+#endif /* defined(__mod_h2__h2_stream__) */