summaryrefslogtreecommitdiffstats
path: root/modules/http2/h2_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/http2/h2_io.c')
-rw-r--r--modules/http2/h2_io.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/modules/http2/h2_io.c b/modules/http2/h2_io.c
new file mode 100644
index 0000000000..aa0619e230
--- /dev/null
+++ b/modules/http2/h2_io.c
@@ -0,0 +1,164 @@
+/* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
+ *
+ * Licensed 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.
+ */
+
+#include <assert.h>
+
+#include <httpd.h>
+#include <http_core.h>
+#include <http_log.h>
+#include <http_connection.h>
+
+#include "h2_private.h"
+#include "h2_io.h"
+#include "h2_response.h"
+#include "h2_util.h"
+
+h2_io *h2_io_create(int id, apr_pool_t *pool, apr_bucket_alloc_t *bucket_alloc)
+{
+ h2_io *io = apr_pcalloc(pool, sizeof(*io));
+ if (io) {
+ io->id = id;
+ io->bbin = NULL;
+ io->bbout = apr_brigade_create(pool, bucket_alloc);
+ io->response = apr_pcalloc(pool, sizeof(h2_response));
+ }
+ return io;
+}
+
+static void h2_io_cleanup(h2_io *io)
+{
+ if (io->response) {
+ h2_response_cleanup(io->response);
+ }
+}
+
+void h2_io_destroy(h2_io *io)
+{
+ h2_io_cleanup(io);
+}
+
+int h2_io_in_has_eos_for(h2_io *io)
+{
+ return io->eos_in || (io->bbin && h2_util_has_eos(io->bbin, 0));
+}
+
+int h2_io_out_has_data(h2_io *io)
+{
+ return h2_util_bb_has_data_or_eos(io->bbout);
+}
+
+apr_size_t h2_io_out_length(h2_io *io)
+{
+ if (io->bbout) {
+ apr_off_t len = 0;
+ apr_brigade_length(io->bbout, 0, &len);
+ return (len > 0)? len : 0;
+ }
+ return 0;
+}
+
+apr_status_t h2_io_in_read(h2_io *io, apr_bucket_brigade *bb,
+ apr_size_t maxlen)
+{
+ apr_off_t start_len = 0;
+
+ if (!io->bbin || APR_BRIGADE_EMPTY(io->bbin)) {
+ return io->eos_in? APR_EOF : APR_EAGAIN;
+ }
+
+ apr_brigade_length(bb, 1, &start_len);
+ apr_bucket *last = APR_BRIGADE_LAST(bb);
+ apr_status_t status = h2_util_move(bb, io->bbin, maxlen, 0,
+ "h2_io_in_read");
+ if (status == APR_SUCCESS) {
+ apr_bucket *nlast = APR_BRIGADE_LAST(bb);
+ apr_off_t end_len = 0;
+ apr_brigade_length(bb, 1, &end_len);
+ if (last == nlast) {
+ return APR_EAGAIN;
+ }
+ io->input_consumed += (end_len - start_len);
+ }
+ return status;
+}
+
+apr_status_t h2_io_in_write(h2_io *io, apr_bucket_brigade *bb)
+{
+ if (io->eos_in) {
+ return APR_EOF;
+ }
+ io->eos_in = h2_util_has_eos(bb, 0);
+ if (!APR_BRIGADE_EMPTY(bb)) {
+ if (!io->bbin) {
+ io->bbin = apr_brigade_create(io->bbout->p,
+ io->bbout->bucket_alloc);
+ }
+ return h2_util_move(io->bbin, bb, 0, 0, "h2_io_in_write");
+ }
+ return APR_SUCCESS;
+}
+
+apr_status_t h2_io_in_close(h2_io *io)
+{
+ if (io->bbin) {
+ APR_BRIGADE_INSERT_TAIL(io->bbin,
+ apr_bucket_eos_create(io->bbin->bucket_alloc));
+ }
+ io->eos_in = 1;
+ return APR_SUCCESS;
+}
+
+apr_status_t h2_io_out_readx(h2_io *io,
+ h2_io_data_cb *cb, void *ctx,
+ apr_size_t *plen, int *peos)
+{
+ if (cb == NULL) {
+ /* just checking length available */
+ return h2_util_bb_avail(io->bbout, plen, peos);
+ }
+ return h2_util_bb_readx(io->bbout, cb, ctx, plen, peos);
+}
+
+apr_status_t h2_io_out_write(h2_io *io, apr_bucket_brigade *bb,
+ apr_size_t maxlen, int *pfile_handles_allowed)
+{
+ /* Let's move the buckets from the request processing in here, so
+ * that the main thread can read them when it has time/capacity.
+ *
+ * Move at most "maxlen" memory bytes. If buckets remain, it is
+ * the caller's responsibility to take care of this.
+ *
+ * We allow passing of file buckets as long as we do not have too
+ * many open files already buffered. Otherwise we will run out of
+ * file handles.
+ */
+ int start_allowed = *pfile_handles_allowed;
+ apr_status_t status;
+ status = h2_util_move(io->bbout, bb, maxlen, pfile_handles_allowed,
+ "h2_io_out_write");
+ /* track # file buckets moved into our pool */
+ if (start_allowed != *pfile_handles_allowed) {
+ io->files_handles_owned += (start_allowed - *pfile_handles_allowed);
+ }
+ return status;
+}
+
+
+apr_status_t h2_io_out_close(h2_io *io)
+{
+ APR_BRIGADE_INSERT_TAIL(io->bbout,
+ apr_bucket_eos_create(io->bbout->bucket_alloc));
+ return APR_SUCCESS;
+}