|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#ifndef __mod_h2__h2_stream__
|
|
Packit |
90a5c9 |
#define __mod_h2__h2_stream__
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "h2.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* A HTTP/2 stream, e.g. a client request+response in HTTP/1.1 terms.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* A stream always belongs to a h2_session, the one managing the
|
|
Packit |
90a5c9 |
* connection to the client. The h2_session writes to the h2_stream,
|
|
Packit |
90a5c9 |
* adding HEADERS and DATA and finally an EOS. When headers are done,
|
|
Packit |
90a5c9 |
* h2_stream is scheduled for handling, which is expected to produce
|
|
Packit |
90a5c9 |
* a response h2_headers at least.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* The h2_headers may be followed by more h2_headers (interim responses) and
|
|
Packit |
90a5c9 |
* by DATA frames read from the h2_stream until EOS is reached. Trailers
|
|
Packit |
90a5c9 |
* are send when a last h2_headers is received. This always closes the stream
|
|
Packit |
90a5c9 |
* output.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_mplx;
|
|
Packit |
90a5c9 |
struct h2_priority;
|
|
Packit |
90a5c9 |
struct h2_request;
|
|
Packit |
90a5c9 |
struct h2_headers;
|
|
Packit |
90a5c9 |
struct h2_session;
|
|
Packit |
90a5c9 |
struct h2_task;
|
|
Packit |
90a5c9 |
struct h2_bucket_beam;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef struct h2_stream h2_stream;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
typedef void h2_stream_state_cb(void *ctx, h2_stream *stream);
|
|
Packit |
90a5c9 |
typedef void h2_stream_event_cb(void *ctx, h2_stream *stream,
|
|
Packit |
90a5c9 |
h2_stream_event_t ev);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Callback structure for events and stream state transisitions
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct h2_stream_monitor {
|
|
Packit |
90a5c9 |
void *ctx;
|
|
Packit |
90a5c9 |
h2_stream_state_cb *on_state_enter; /* called when a state is entered */
|
|
Packit |
90a5c9 |
h2_stream_state_cb *on_state_invalid; /* called when an invalid state change
|
|
Packit |
90a5c9 |
was detected */
|
|
Packit |
90a5c9 |
h2_stream_event_cb *on_state_event; /* called right before the given event
|
|
Packit |
90a5c9 |
result in a new stream state */
|
|
Packit |
90a5c9 |
h2_stream_event_cb *on_event; /* called for events that do not
|
|
Packit |
90a5c9 |
trigger a state change */
|
|
Packit |
90a5c9 |
} h2_stream_monitor;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_stream {
|
|
Packit |
90a5c9 |
int id; /* http2 stream identifier */
|
|
Packit |
90a5c9 |
int initiated_on; /* initiating stream id (PUSH) or 0 */
|
|
Packit |
90a5c9 |
apr_pool_t *pool; /* the memory pool for this stream */
|
|
Packit |
90a5c9 |
struct h2_session *session; /* the session this stream belongs to */
|
|
Packit |
90a5c9 |
h2_stream_state_t state; /* state of this stream */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_time_t created; /* when stream was created */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const struct h2_request *request; /* the request made in this stream */
|
|
Packit |
90a5c9 |
struct h2_request *rtmp; /* request being assembled */
|
|
Packit |
90a5c9 |
apr_table_t *trailers; /* optional incoming trailers */
|
|
Packit |
90a5c9 |
int request_headers_added; /* number of request headers added */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_bucket_beam *input;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *in_buffer;
|
|
Packit |
90a5c9 |
int in_window_size;
|
|
Packit |
90a5c9 |
apr_time_t in_last_write;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_bucket_beam *output;
|
|
Packit |
90a5c9 |
apr_bucket_brigade *out_buffer;
|
|
Packit |
90a5c9 |
apr_size_t max_mem; /* maximum amount of data buffered */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
int rst_error; /* stream error for RST_STREAM */
|
|
Packit |
90a5c9 |
unsigned int aborted : 1; /* was aborted */
|
|
Packit |
90a5c9 |
unsigned int scheduled : 1; /* stream has been scheduled */
|
|
Packit |
90a5c9 |
unsigned int has_response : 1; /* response headers are known */
|
|
Packit |
90a5c9 |
unsigned int input_eof : 1; /* no more request data coming */
|
|
Packit |
90a5c9 |
unsigned int out_checked : 1; /* output eof was double checked */
|
|
Packit |
90a5c9 |
unsigned int push_policy; /* which push policy to use for this request */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
struct h2_task *task; /* assigned task to fullfill request */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
const h2_priority *pref_priority; /* preferred priority for this stream */
|
|
Packit |
90a5c9 |
apr_off_t out_frames; /* # of frames sent out */
|
|
Packit |
90a5c9 |
apr_off_t out_frame_octets; /* # of RAW frame octets sent out */
|
|
Packit |
90a5c9 |
apr_off_t out_data_frames; /* # of DATA frames sent */
|
|
Packit |
90a5c9 |
apr_off_t out_data_octets; /* # of DATA octets (payload) sent */
|
|
Packit |
90a5c9 |
apr_off_t in_data_frames; /* # of DATA frames received */
|
|
Packit |
90a5c9 |
apr_off_t in_data_octets; /* # of DATA octets (payload) received */
|
|
Packit |
90a5c9 |
apr_off_t in_trailer_octets; /* # of HEADER octets (payload) received in trailers */
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
h2_stream_monitor *monitor; /* optional monitor for stream states */
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define H2_STREAM_RST(s, def) (s->rst_error? s->rst_error : (def))
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Create a stream in H2_SS_IDLE state.
|
|
Packit |
90a5c9 |
* @param id the stream identifier
|
|
Packit |
90a5c9 |
* @param pool the memory pool to use for this stream
|
|
Packit |
90a5c9 |
* @param session the session this stream belongs to
|
|
Packit |
90a5c9 |
* @param monitor an optional monitor to be called for events and
|
|
Packit |
90a5c9 |
* state transisitions
|
|
Packit |
90a5c9 |
* @param initiated_on the id of the stream this one was initiated on (PUSH)
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @return the newly opened stream
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
h2_stream *h2_stream_create(int id, apr_pool_t *pool,
|
|
Packit |
90a5c9 |
struct h2_session *session,
|
|
Packit |
90a5c9 |
h2_stream_monitor *monitor,
|
|
Packit |
90a5c9 |
int initiated_on);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Destroy memory pool if still owned by the stream.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_destroy(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Prepare the stream so that processing may start.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* This is the time to allocated resources not needed before.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to prep
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_prep_processing(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Set a new monitor for this stream, replacing any existing one. Can
|
|
Packit |
90a5c9 |
* be called with NULL to have no monitor installed.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_set_monitor(h2_stream *stream, h2_stream_monitor *monitor);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Dispatch (handle) an event on the given stream.
|
|
Packit |
90a5c9 |
* @param stream the streama the event happened on
|
|
Packit |
90a5c9 |
* @param ev the type of event
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_dispatch(h2_stream *stream, h2_stream_event_t ev);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Cleanup references into requst processing.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to cleanup
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_cleanup(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Notify the stream that amount bytes have been consumed of its input
|
|
Packit |
90a5c9 |
* since the last invocation of this method (delta amount).
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_in_consumed(h2_stream *stream, apr_off_t amount);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Set complete stream headers from given h2_request.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream stream to write request to
|
|
Packit |
90a5c9 |
* @param r the request with all the meta data
|
|
Packit |
90a5c9 |
* @param eos != 0 iff stream input is closed
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_set_request(h2_stream *stream, const h2_request *r);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Set complete stream header from given request_rec.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream stream to write request to
|
|
Packit |
90a5c9 |
* @param r the request with all the meta data
|
|
Packit |
90a5c9 |
* @param eos != 0 iff stream input is closed
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_set_request_rec(h2_stream *stream,
|
|
Packit |
90a5c9 |
request_rec *r, int eos);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Add a HTTP/2 header (including pseudo headers) or trailer
|
|
Packit |
90a5c9 |
* to the given stream, depending on stream state.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream stream to write the header to
|
|
Packit |
90a5c9 |
* @param name the name of the HTTP/2 header
|
|
Packit |
90a5c9 |
* @param nlen the number of characters in name
|
|
Packit |
90a5c9 |
* @param value the header value
|
|
Packit |
90a5c9 |
* @param vlen the number of characters in value
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_add_header(h2_stream *stream,
|
|
Packit |
90a5c9 |
const char *name, size_t nlen,
|
|
Packit |
90a5c9 |
const char *value, size_t vlen);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_send_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_recv_frame(h2_stream *stream, int frame_type, int flags, size_t frame_len);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* Process a frame of received DATA.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream stream to write the data to
|
|
Packit |
90a5c9 |
* @param flags the frame flags
|
|
Packit |
90a5c9 |
* @param data the beginning of the bytes to write
|
|
Packit |
90a5c9 |
* @param len the number of bytes to write
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_recv_DATA(h2_stream *stream, uint8_t flags,
|
|
Packit |
90a5c9 |
const uint8_t *data, size_t len);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_flush_input(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Reset the stream. Stream write/reads will return errors afterwards.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to reset
|
|
Packit |
90a5c9 |
* @param error_code the HTTP/2 error code
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
void h2_stream_rst(h2_stream *stream, int error_code);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Determine if stream was closed already. This is true for
|
|
Packit |
90a5c9 |
* states H2_SS_CLOSED, H2_SS_CLEANUP. But not true
|
|
Packit |
90a5c9 |
* for H2_SS_CLOSED_L and H2_SS_CLOSED_R.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to check on
|
|
Packit |
90a5c9 |
* @return != 0 iff stream has been closed
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
int h2_stream_was_closed(const h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Do a speculative read on the stream output to determine the
|
|
Packit |
90a5c9 |
* amount of data that can be read.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to speculatively read from
|
|
Packit |
90a5c9 |
* @param plen (in-/out) number of bytes requested and on return amount of bytes that
|
|
Packit |
90a5c9 |
* may be read without blocking
|
|
Packit |
90a5c9 |
* @param peos (out) != 0 iff end of stream will be reached when reading plen
|
|
Packit |
90a5c9 |
* bytes (out value).
|
|
Packit |
90a5c9 |
* @param presponse (out) the response of one became available
|
|
Packit |
90a5c9 |
* @return APR_SUCCESS if out information was computed successfully.
|
|
Packit |
90a5c9 |
* APR_EAGAIN if not data is available and end of stream has not been
|
|
Packit |
90a5c9 |
* reached yet.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_out_prepare(h2_stream *stream, apr_off_t *plen,
|
|
Packit |
90a5c9 |
int *peos, h2_headers **presponse);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Read a maximum number of bytes into the bucket brigade.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream to read from
|
|
Packit |
90a5c9 |
* @param bb the brigade to append output to
|
|
Packit |
90a5c9 |
* @param plen (in-/out) max. number of bytes to append and on return actual
|
|
Packit |
90a5c9 |
* number of bytes appended to brigade
|
|
Packit |
90a5c9 |
* @param peos (out) != 0 iff end of stream has been reached while reading
|
|
Packit |
90a5c9 |
* @return APR_SUCCESS if out information was computed successfully.
|
|
Packit |
90a5c9 |
* APR_EAGAIN if not data is available and end of stream has not been
|
|
Packit |
90a5c9 |
* reached yet.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_read_to(h2_stream *stream, apr_bucket_brigade *bb,
|
|
Packit |
90a5c9 |
apr_off_t *plen, int *peos);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Get optional trailers for this stream, may be NULL. Meaningful
|
|
Packit |
90a5c9 |
* results can only be expected when the end of the response body has
|
|
Packit |
90a5c9 |
* been reached.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream to ask for trailers
|
|
Packit |
90a5c9 |
* @return trailers for NULL
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_table_t *h2_stream_get_trailers(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Submit any server push promises on this stream and schedule
|
|
Packit |
90a5c9 |
* the tasks connection with these.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param stream the stream for which to submit
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
apr_status_t h2_stream_submit_pushes(h2_stream *stream, h2_headers *response);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Get priority information set for this stream.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
const struct h2_priority *h2_stream_get_priority(h2_stream *stream,
|
|
Packit |
90a5c9 |
h2_headers *response);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Return a textual representation of the stream state as in RFC 7540
|
|
Packit |
90a5c9 |
* nomenclator, all caps, underscores.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
const char *h2_stream_state_str(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Determine if stream is ready for submitting a response or a RST
|
|
Packit |
90a5c9 |
* @param stream the stream to check
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
int h2_stream_is_ready(h2_stream *stream);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define H2_STRM_MSG(s, msg) \
|
|
Packit |
90a5c9 |
"h2_stream(%ld-%d,%s): "msg, s->session->id, s->id, h2_stream_state_str(s)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define H2_STRM_LOG(aplogno, s, msg) aplogno H2_STRM_MSG(s, msg)
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#endif /* defined(__mod_h2__h2_stream__) */
|