Apache HTTPD
h2_bucket_beam.c
Go to the documentation of this file.
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#include <apr_lib.h>
18#include <apr_atomic.h>
19#include <apr_strings.h>
20#include <apr_time.h>
21#include <apr_buckets.h>
22#include <apr_thread_mutex.h>
23#include <apr_thread_cond.h>
24
25#include <httpd.h>
26#include <http_protocol.h>
27#include <http_request.h>
28#include <http_log.h>
29
30#include "h2_private.h"
31#include "h2_conn_ctx.h"
32#include "h2_headers.h"
33#include "h2_util.h"
34#include "h2_bucket_beam.h"
35
36
37#define H2_BLIST_INIT(b) APR_RING_INIT(&(b)->list, apr_bucket, link);
38#define H2_BLIST_SENTINEL(b) APR_RING_SENTINEL(&(b)->list, apr_bucket, link)
39#define H2_BLIST_EMPTY(b) APR_RING_EMPTY(&(b)->list, apr_bucket, link)
40#define H2_BLIST_FIRST(b) APR_RING_FIRST(&(b)->list)
41#define H2_BLIST_LAST(b) APR_RING_LAST(&(b)->list)
42#define H2_BLIST_INSERT_HEAD(b, e) do { \
43 apr_bucket *ap__b = (e); \
44 APR_RING_INSERT_HEAD(&(b)->list, ap__b, apr_bucket, link); \
45 } while (0)
46#define H2_BLIST_INSERT_TAIL(b, e) do { \
47 apr_bucket *ap__b = (e); \
48 APR_RING_INSERT_TAIL(&(b)->list, ap__b, apr_bucket, link); \
49 } while (0)
50#define H2_BLIST_CONCAT(a, b) do { \
51 APR_RING_CONCAT(&(a)->list, &(b)->list, apr_bucket, link); \
52 } while (0)
53#define H2_BLIST_PREPEND(a, b) do { \
54 APR_RING_PREPEND(&(a)->list, &(b)->list, apr_bucket, link); \
55 } while (0)
56
57
60
62{
64 int count = 0;
65
67 b = APR_BUCKET_NEXT(b)) {
68 ++count;
69 }
70 return count;
71}
72
73#define H2_BEAM_LOG(beam, c, level, rv, msg, bb) \
74 do { \
75 if (APLOG_C_IS_LEVEL((c),(level))) { \
76 char buffer[4 * 1024]; \
77 apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \
78 len = bb? h2_util_bb_print(buffer, bmax, "", "", bb) : 0; \
79 ap_log_cerror(APLOG_MARK, (level), rv, (c), \
80 "BEAM[%s,%s%sdata=%ld,buckets(send/consumed)=%d/%d]: %s %s", \
81 (beam)->name, \
82 (beam)->aborted? "aborted," : "", \
83 buffer_is_empty(beam)? "empty," : "", \
84 (long)get_buffered_data_len(beam), \
85 h2_blist_count(&(beam)->buckets_to_send), \
86 h2_blist_count(&(beam)->buckets_consumed), \
87 (msg), len? buffer : ""); \
88 } \
89 } while (0)
90
91
93{
94#if APR_HAS_MMAP
95 return APR_BUCKET_IS_MMAP(b);
96#else
97 /* if it is not defined as enabled, it should always be no */
98 return 0;
99#endif
100}
101
103{
105 return 0;
106 }
107 else {
108 /* should all have determinate length */
109 return (apr_off_t)b->length;
110 }
111}
112
113static int report_consumption(h2_bucket_beam *beam, int locked)
114{
115 int rv = 0;
116 apr_off_t len = beam->recv_bytes - beam->recv_bytes_reported;
117 h2_beam_io_callback *cb = beam->cons_io_cb;
118
119 if (len > 0) {
120 if (cb) {
121 void *ctx = beam->cons_ctx;
122
123 if (locked) apr_thread_mutex_unlock(beam->lock);
124 cb(ctx, beam, len);
125 if (locked) apr_thread_mutex_lock(beam->lock);
126 rv = 1;
127 }
128 beam->recv_bytes_reported += len;
129 }
130 return rv;
131}
132
134{
135 apr_size_t len = 0;
136 apr_bucket *b;
137 for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
138 b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
139 b = APR_BUCKET_NEXT(b)) {
140 if (b->length == ((apr_size_t)-1)) {
141 /* do not count */
142 }
143 else if (APR_BUCKET_IS_FILE(b) || bucket_is_mmap(b)) {
144 /* if unread, has no real mem footprint. */
145 }
146 else {
147 len += b->length;
148 }
149 }
150 return len;
151}
152
154{
155 apr_bucket *b;
156 /* delete all sender buckets in purge brigade, needs to be called
157 * from sender thread only */
158 while (!H2_BLIST_EMPTY(&beam->buckets_consumed)) {
159 b = H2_BLIST_FIRST(&beam->buckets_consumed);
160 if(AP_BUCKET_IS_EOR(b)) {
162 H2_BLIST_INSERT_TAIL(&beam->buckets_eor, b);
163 }
164 else {
166 }
167 }
168}
169
171{
172 apr_bucket *b;
173 /* delete all sender buckets in purge brigade, needs to be called
174 * from sender thread only */
175 while (!H2_BLIST_EMPTY(&beam->buckets_eor)) {
176 b = H2_BLIST_FIRST(&beam->buckets_eor);
178 }
179}
180
182{
183 if (beam->max_buf_size > 0) {
185 return (beam->max_buf_size > len? (beam->max_buf_size - len) : 0);
186 }
187 return APR_SIZE_MAX;
188}
189
191{
192 return H2_BLIST_EMPTY(&beam->buckets_to_send);
193}
194
196{
198
199 while (buffer_is_empty(beam) && APR_SUCCESS == rv) {
200 if (beam->aborted) {
201 rv = APR_ECONNABORTED;
202 }
203 else if (beam->closed) {
204 rv = APR_EOF;
205 }
206 else if (APR_BLOCK_READ != block) {
207 rv = APR_EAGAIN;
208 }
209 else if (beam->timeout > 0) {
210 H2_BEAM_LOG(beam, c, APLOG_TRACE2, rv, "wait_not_empty, timeout", NULL);
211 rv = apr_thread_cond_timedwait(beam->change, beam->lock, beam->timeout);
212 }
213 else {
214 H2_BEAM_LOG(beam, c, APLOG_TRACE2, rv, "wait_not_empty, forever", NULL);
215 rv = apr_thread_cond_wait(beam->change, beam->lock);
216 }
217 }
218 return rv;
219}
220
224{
226 apr_size_t left;
227
228 while (0 == (left = calc_space_left(beam)) && APR_SUCCESS == rv) {
229 if (beam->aborted) {
230 rv = APR_ECONNABORTED;
231 }
232 else if (block != APR_BLOCK_READ) {
233 rv = APR_EAGAIN;
234 }
235 else {
236 if (beam->timeout > 0) {
237 H2_BEAM_LOG(beam, c, APLOG_TRACE2, rv, "wait_not_full, timeout", NULL);
238 rv = apr_thread_cond_timedwait(beam->change, beam->lock, beam->timeout);
239 }
240 else {
241 H2_BEAM_LOG(beam, c, APLOG_TRACE2, rv, "wait_not_full, forever", NULL);
242 rv = apr_thread_cond_wait(beam->change, beam->lock);
243 }
244 }
245 }
246 *pspace_left = left;
247 return rv;
248}
249
251{
252 apr_bucket *e;
253
254 while (!H2_BLIST_EMPTY(bl)) {
257 }
258}
259
261{
262 if (!beam->pool) {
263 /* pool being cleared already */
264 return;
265 }
266
267 /* shutdown both receiver and sender? */
269 beam->cons_io_cb = NULL;
270 beam->recv_cb = NULL;
271 beam->eagain_cb = NULL;
272 }
273
274 /* shutdown sender (or both)? */
275 if (how != APR_SHUTDOWN_READ) {
277 h2_blist_cleanup(&beam->buckets_to_send);
278 }
279}
280
282{
286 beam->pool = NULL; /* the pool is clearing now */
287 return APR_SUCCESS;
288}
289
291{
292 if (beam->pool) {
293 H2_BEAM_LOG(beam, c, APLOG_TRACE2, 0, "destroy", NULL);
295 }
296 H2_BEAM_LOG(beam, c, APLOG_TRACE2, 0, "destroyed", NULL);
297 return APR_SUCCESS;
298}
299
301 apr_pool_t *pool, int id, const char *tag,
302 apr_size_t max_buf_size,
304{
307 apr_status_t rv;
308
309 beam = apr_pcalloc(pool, sizeof(*beam));
310 beam->pool = pool;
311 beam->from = from;
312 beam->id = id;
313 beam->name = apr_psprintf(pool, "%s-%d-%s",
314 conn_ctx->id, id, tag);
315
316 H2_BLIST_INIT(&beam->buckets_to_send);
317 H2_BLIST_INIT(&beam->buckets_consumed);
318 H2_BLIST_INIT(&beam->buckets_eor);
319 beam->tx_mem_limits = 1;
320 beam->max_buf_size = max_buf_size;
321 beam->timeout = timeout;
322
324 if (APR_SUCCESS != rv) goto cleanup;
325 rv = apr_thread_cond_create(&beam->change, pool);
326 if (APR_SUCCESS != rv) goto cleanup;
328
329cleanup:
330 H2_BEAM_LOG(beam, from, APLOG_TRACE2, rv, "created", NULL);
331 *pbeam = (APR_SUCCESS == rv)? beam : NULL;
332 return rv;
333}
334
341
343{
345 beam->copy_files = enabled;
347}
348
358
368
375
377{
379 beam->aborted = 1;
380 if (c == beam->from) {
381 /* sender aborts */
382 if (beam->send_cb) {
383 beam->send_cb(beam->send_ctx, beam);
384 }
385 if (beam->was_empty_cb && buffer_is_empty(beam)) {
386 beam->was_empty_cb(beam->was_empty_ctx, beam);
387 }
388 /* no more consumption reporting to sender */
390 beam->cons_ctx = NULL;
391
393 }
394 else {
395 /* receiver aborts */
397 }
400}
401
403{
405 if (!beam->closed) {
406 /* should only be called from sender */
407 ap_assert(c == beam->from);
408 beam->closed = 1;
409 if (beam->send_cb) {
410 beam->send_cb(beam->send_ctx, beam);
411 }
412 if (beam->was_empty_cb && buffer_is_empty(beam)) {
413 beam->was_empty_cb(beam->was_empty_ctx, beam);
414 }
416 }
418}
419
425{
426 apr_bucket *b;
427 const char *data;
430 int can_beam = 0;
431
432 (void)block;
433 if (beam->aborted) {
434 rv = APR_ECONNABORTED;
435 goto cleanup;
436 }
437
438 ap_assert(beam->pool);
439
440 b = APR_BRIGADE_FIRST(bb);
443 apr_bucket_setaside(b, beam->pool);
444 H2_BLIST_INSERT_TAIL(&beam->buckets_to_send, b);
445 goto cleanup;
446 }
447 /* non meta bucket */
448
449 /* in case of indeterminate length, we need to read the bucket,
450 * so that it transforms itself into something stable. */
451 if (b->length == ((apr_size_t)-1)) {
453 if (rv != APR_SUCCESS) goto cleanup;
454 }
455
456 if (APR_BUCKET_IS_FILE(b)) {
457 /* For file buckets the problem is their internal readpool that
458 * is used on the first read to allocate buffer/mmap.
459 * Since setting aside a file bucket will de-register the
460 * file cleanup function from the previous pool, we need to
461 * call that only from the sender thread.
462 *
463 * Currently, we do not handle file bucket with refcount > 1 as
464 * the beam is then not in complete control of the file's lifetime.
465 * Which results in the bug that a file get closed by the receiver
466 * while the sender or the beam still have buckets using it.
467 *
468 * Additionally, we allow callbacks to prevent beaming file
469 * handles across. The use case for this is to limit the number
470 * of open file handles and rather use a less efficient beam
471 * transport. */
472 apr_bucket_file *bf = b->data;
473 can_beam = !beam->copy_files && (bf->refcount.refcount == 1);
474 }
475 else if (bucket_is_mmap(b)) {
476 can_beam = !beam->copy_files;
477 }
478
479 if (b->length == 0) {
481 rv = APR_SUCCESS;
482 goto cleanup;
483 }
484
485 if (!*pspace_left) {
486 rv = APR_EAGAIN;
487 goto cleanup;
488 }
489
490 /* bucket is accepted and added to beam->buckets_to_send */
491 if (APR_BUCKET_IS_HEAP(b)) {
492 /* For heap buckets, a read from a receiver thread is fine. The
493 * data will be there and live until the bucket itself is
494 * destroyed. */
495 rv = apr_bucket_setaside(b, beam->pool);
496 if (rv != APR_SUCCESS) goto cleanup;
497 }
498 else if (can_beam && (APR_BUCKET_IS_FILE(b) || bucket_is_mmap(b))) {
499 rv = apr_bucket_setaside(b, beam->pool);
500 if (rv != APR_SUCCESS) goto cleanup;
501 }
502 else {
503 /* we know of no special shortcut to transfer the bucket to
504 * another pool without copying. So we make it a heap bucket. */
505 apr_bucket *b2;
506
508 if (rv != APR_SUCCESS) goto cleanup;
509 /* this allocates and copies data */
512 b = b2;
514 }
515
517 H2_BLIST_INSERT_TAIL(&beam->buckets_to_send, b);
518 *pwritten += (apr_off_t)b->length;
519 if (b->length > *pspace_left) {
520 *pspace_left = 0;
521 }
522 else {
523 *pspace_left -= b->length;
524 }
525
526cleanup:
527 return rv;
528}
529
534{
537 int was_empty;
538
539 ap_assert(beam->pool);
540
541 /* Called from the sender thread to add buckets to the beam */
543 ap_assert(beam->from == from);
545 H2_BEAM_LOG(beam, from, APLOG_TRACE2, rv, "start send", sender_bb);
547 *pwritten = 0;
549
551 while (!APR_BRIGADE_EMPTY(sender_bb) && APR_SUCCESS == rv) {
553 if (beam->aborted) {
554 goto cleanup;
555 }
556 else if (APR_EAGAIN == rv) {
557 /* bucket was not added, as beam buffer has no space left.
558 * Trigger event callbacks, so receiver can know there is something
559 * to receive before we do a conditional wait. */
561 if (beam->send_cb) {
562 beam->send_cb(beam->send_ctx, beam);
563 }
564 if (was_empty && beam->was_empty_cb) {
565 beam->was_empty_cb(beam->was_empty_ctx, beam);
566 }
567 rv = wait_not_full(beam, from, block, &space_left);
568 if (APR_SUCCESS != rv) {
569 break;
570 }
572 }
573 }
574
575cleanup:
576 if (beam->send_cb && !buffer_is_empty(beam)) {
577 beam->send_cb(beam->send_ctx, beam);
578 }
579 if (was_empty && beam->was_empty_cb && !buffer_is_empty(beam)) {
580 beam->was_empty_cb(beam->was_empty_ctx, beam);
581 }
583
585 if (beam->aborted) {
586 rv = APR_ECONNABORTED;
587 }
588 H2_BEAM_LOG(beam, from, APLOG_TRACE2, rv, "end send", sender_bb);
589 if(rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv) && sender_bb != NULL) {
591 }
593 return rv;
594}
595
597 conn_rec *to,
601{
603 int transferred = 0;
606 int consumed_buckets = 0;
607
609 H2_BEAM_LOG(beam, to, APLOG_TRACE2, 0, "start receive", bb);
610 if (readbytes <= 0) {
612 }
614
616 if (beam->aborted) {
618 rv = APR_ECONNABORTED;
619 goto leave;
620 }
621
622 ap_assert(beam->pool);
623
624 /* transfer from our sender brigade, transforming sender buckets to
625 * receiver ones until we have enough */
626 while (remain >= 0 && !H2_BLIST_EMPTY(&beam->buckets_to_send)) {
627
628 brecv = NULL;
629 bsender = H2_BLIST_FIRST(&beam->buckets_to_send);
630 if (bsender->length > 0 && remain <= 0) {
631 break;
632 }
633
635 /* we need a real copy into the receivers bucket_alloc */
637 /* this closes the beam */
638 beam->closed = 1;
640 }
641 else if (APR_BUCKET_IS_FLUSH(bsender)) {
643 }
644#if AP_HAS_RESPONSE_BUCKETS
645 else if (AP_BUCKET_IS_RESPONSE(bsender)) {
647 }
648 else if (AP_BUCKET_IS_REQUEST(bsender)) {
650 }
651 else if (AP_BUCKET_IS_HEADERS(bsender)) {
653 }
654#else
655 else if (H2_BUCKET_IS_HEADERS(bsender)) {
657 }
658#endif /* AP_HAS_RESPONSE_BUCKETS */
659 else if (AP_BUCKET_IS_ERROR(bsender)) {
661 brecv = ap_bucket_error_create(eb->status, eb->data,
662 bb->p, bb->bucket_alloc);
663 }
664 }
665 else if (bsender->length == 0) {
666 /* nop */
667 }
668#if APR_HAS_MMAP
669 else if (APR_BUCKET_IS_MMAP(bsender)) {
672 rv = apr_mmap_dup(&mmap, bmmap->mmap, bb->p);
673 if (rv != APR_SUCCESS) goto leave;
675 }
676#endif
677 else if (APR_BUCKET_IS_FILE(bsender)) {
678 /* This is setaside into the target brigade pool so that
679 * any read operation messes with that pool and not
680 * the sender one. */
682 apr_file_t *fd = f->fd;
683 int setaside = (f->readpool != bb->p);
684
685 if (setaside) {
686 rv = apr_file_setaside(&fd, fd, bb->p);
687 if (rv != APR_SUCCESS) goto leave;
688 }
689 ng = apr_brigade_insert_file(bb, fd, bsender->start, (apr_off_t)bsender->length,
690 bb->p);
691#if APR_HAS_MMAP
692 /* disable mmap handling as this leads to segfaults when
693 * the underlying file is changed while memory pointer has
694 * been handed out. See also PR 59348 */
696#endif
697 remain -= bsender->length;
698 ++transferred;
699 }
700 else {
701 const char *data;
703 /* we did that when the bucket was added, so this should
704 * give us the same data as before without changing the bucket
705 * or anything (pool) connected to it. */
707 if (rv != APR_SUCCESS) goto leave;
708 rv = apr_brigade_write(bb, NULL, NULL, data, dlen);
709 if (rv != APR_SUCCESS) goto leave;
710
711 remain -= dlen;
712 ++transferred;
713 }
714
715 if (brecv) {
716 /* we have a proxy that we can give the receiver */
718 remain -= brecv->length;
719 ++transferred;
720 }
722 H2_BLIST_INSERT_TAIL(&beam->buckets_consumed, bsender);
723 beam->recv_bytes += bsender->length;
725 }
726
727 if (beam->recv_cb && consumed_buckets > 0) {
728 beam->recv_cb(beam->recv_ctx, beam);
729 }
730
731 if (transferred) {
733 rv = APR_SUCCESS;
734 }
735 else if (beam->aborted) {
736 rv = APR_ECONNABORTED;
737 }
738 else if (beam->closed) {
739 rv = APR_EOF;
740 }
741 else {
742 rv = wait_not_empty(beam, to, block);
743 if (rv != APR_SUCCESS) {
744 goto leave;
745 }
746 goto transfer;
747 }
748
749leave:
750 H2_BEAM_LOG(beam, to, APLOG_TRACE2, rv, "end receive", bb);
751 if (rv == APR_EAGAIN && beam->eagain_cb) {
752 beam->eagain_cb(beam->eagain_ctx, beam);
753 }
755 return rv;
756}
757
760{
762 beam->cons_io_cb = io_cb;
763 beam->cons_ctx = ctx;
765}
766
768 h2_beam_ev_callback *recv_cb, void *ctx)
769{
771 beam->recv_cb = recv_cb;
772 beam->recv_ctx = ctx;
774}
775
777 h2_beam_ev_callback *eagain_cb, void *ctx)
778{
780 beam->eagain_cb = eagain_cb;
781 beam->eagain_ctx = ctx;
783}
784
787{
789 beam->send_cb = send_cb;
790 beam->send_ctx = ctx;
792}
793
795 h2_beam_ev_callback *was_empty_cb, void *ctx)
796{
798 beam->was_empty_cb = was_empty_cb;
799 beam->was_empty_ctx = ctx;
801}
802
803
805{
806 apr_bucket *b;
807 apr_off_t l = 0;
808
809 for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
810 b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
811 b = APR_BUCKET_NEXT(b)) {
812 /* should all have determinate length */
813 l += b->length;
814 }
815 return l;
816}
817
827
829{
830 apr_bucket *b;
831 apr_off_t l = 0;
832
834 for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
835 b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
836 b = APR_BUCKET_NEXT(b)) {
837 l += bucket_mem_used(b);
838 }
840 return l;
841}
842
844{
845 int empty = 1;
846
850 return empty;
851}
852
854{
855 int rv = 0;
856
858 rv = report_consumption(beam, 1);
860 return rv;
861}
862
864{
865 int rv = 0;
866
868 if (beam->closed)
869 rv = 1;
870 else {
871 apr_bucket *b;
872 for (b = H2_BLIST_FIRST(&beam->buckets_to_send);
873 b != H2_BLIST_SENTINEL(&beam->buckets_to_send);
874 b = APR_BUCKET_NEXT(b)) {
875 if (APR_BUCKET_IS_EOS(b)) {
876 rv = 1;
877 break;
878 }
879 }
880 }
882 return rv;
883}
const char apr_size_t len
Definition ap_regex.h:187
APR Atomic Operations.
APR-UTIL Buckets/Bucket Brigades.
APR general purpose library routines.
APR Strings library.
APR Condition Variable Routines.
APR Thread Mutex Routines.
APR Time Library.
#define APLOG_TRACE2
Definition http_log.h:73
#define AP_BUCKET_IS_ERROR(e)
apr_bucket * ap_bucket_error_create(int error, const char *buf, apr_pool_t *p, apr_bucket_alloc_t *list)
#define AP_BUCKET_IS_EOR(e)
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EOF
Definition apr_errno.h:461
#define APR_ECONNABORTED
Definition apr_errno.h:769
unsigned int count
Definition apr_md5.h:152
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
int enabled
apr_file_t * f
#define APR_BUCKET_IS_FILE(e)
#define APR_BUCKET_IS_FLUSH(e)
#define APR_BUCKET_REMOVE(e)
#define APR_BUCKET_IS_HEAP(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
#define APR_BRIGADE_INSERT_HEAD(b, e)
#define APR_BUCKET_NEXT(e)
apr_read_type_e
Definition apr_buckets.h:57
apr_bucket * e
#define APR_BRIGADE_EMPTY(b)
#define apr_bucket_delete(e)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define apr_bucket_setaside(e, p)
#define APR_BRIGADE_FIRST(b)
apr_file_t * fd
#define apr_bucket_read(e, str, len, block)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
void const char apr_status_t(* cleanup)(void *))
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_shutdown_how_e how
const char apr_uint32_t * id
apr_shutdown_how_e
@ APR_SHUTDOWN_WRITE
@ APR_SHUTDOWN_READ
@ APR_SHUTDOWN_READWRITE
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
int to
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
void h2_beam_abort(h2_bucket_beam *beam, conn_rec *c)
static apr_status_t beam_cleanup(void *data)
#define H2_BLIST_FIRST(b)
apr_size_t h2_beam_buffer_size_get(h2_bucket_beam *beam)
void h2_beam_on_received(h2_bucket_beam *beam, h2_beam_ev_callback *recv_cb, void *ctx)
apr_interval_time_t h2_beam_timeout_get(h2_bucket_beam *beam)
void h2_beam_on_eagain(h2_bucket_beam *beam, h2_beam_ev_callback *eagain_cb, void *ctx)
static apr_status_t wait_not_full(h2_bucket_beam *beam, conn_rec *c, apr_read_type_e block, apr_size_t *pspace_left)
apr_status_t h2_beam_destroy(h2_bucket_beam *beam, conn_rec *c)
static apr_status_t append_bucket(h2_bucket_beam *beam, apr_bucket_brigade *bb, apr_read_type_e block, apr_size_t *pspace_left, apr_off_t *pwritten)
void h2_beam_on_was_empty(h2_bucket_beam *beam, h2_beam_ev_callback *was_empty_cb, void *ctx)
#define H2_BLIST_INIT(b)
int h2_beam_empty(h2_bucket_beam *beam)
void h2_beam_timeout_set(h2_bucket_beam *beam, apr_interval_time_t timeout)
static void purge_eor_buckets(h2_bucket_beam *beam)
void h2_beam_close(h2_bucket_beam *beam, conn_rec *c)
static int bucket_is_mmap(apr_bucket *b)
static int h2_blist_count(h2_blist *blist)
apr_status_t h2_beam_create(h2_bucket_beam **pbeam, conn_rec *from, apr_pool_t *pool, int id, const char *tag, apr_size_t max_buf_size, apr_interval_time_t timeout)
#define H2_BEAM_LOG(beam, c, level, rv, msg, bb)
apr_off_t h2_beam_get_mem_used(h2_bucket_beam *beam)
static void beam_shutdown(h2_bucket_beam *beam, apr_shutdown_how_e how)
static void purge_consumed_buckets(h2_bucket_beam *beam)
static int report_consumption(h2_bucket_beam *beam, int locked)
static apr_size_t calc_buffered(h2_bucket_beam *beam)
static int buffer_is_empty(h2_bucket_beam *beam)
#define H2_BLIST_SENTINEL(b)
apr_status_t h2_beam_send(h2_bucket_beam *beam, conn_rec *from, apr_bucket_brigade *sender_bb, apr_read_type_e block, apr_off_t *pwritten)
void h2_beam_on_send(h2_bucket_beam *beam, h2_beam_ev_callback *send_cb, void *ctx)
static apr_off_t get_buffered_data_len(h2_bucket_beam *beam)
static apr_size_t calc_space_left(h2_bucket_beam *beam)
static apr_off_t bucket_mem_used(apr_bucket *b)
int h2_beam_is_complete(h2_bucket_beam *beam)
static apr_status_t wait_not_empty(h2_bucket_beam *beam, conn_rec *c, apr_read_type_e block)
void h2_beam_set_copy_files(h2_bucket_beam *beam, int enabled)
#define H2_BLIST_EMPTY(b)
int h2_beam_report_consumption(h2_bucket_beam *beam)
static void h2_blist_cleanup(h2_blist *bl)
void h2_beam_on_consumed(h2_bucket_beam *beam, h2_beam_io_callback *io_cb, void *ctx)
#define H2_BLIST_INSERT_TAIL(b, e)
apr_off_t h2_beam_get_buffered(h2_bucket_beam *beam)
void h2_beam_buffer_size_set(h2_bucket_beam *beam, apr_size_t buffer_size)
apr_status_t h2_beam_receive(h2_bucket_beam *beam, conn_rec *to, apr_bucket_brigade *bb, apr_read_type_e block, apr_off_t readbytes)
void h2_beam_ev_callback(void *ctx, h2_bucket_beam *beam)
void h2_beam_io_callback(void *ctx, h2_bucket_beam *beam, apr_off_t bytes)
#define h2_conn_ctx_get(c)
Definition h2_conn_ctx.h:78
apr_bucket * h2_bucket_headers_clone(apr_bucket *b, apr_pool_t *pool, apr_bucket_alloc_t *list)
Definition h2_headers.c:111
#define H2_BUCKET_IS_HEADERS(e)
Definition h2_headers.h:37
static ssize_t send_cb(nghttp2_session *ngh2, const uint8_t *data, size_t length, int flags, void *userp)
Definition h2_session.c:185
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
return NULL
Definition mod_so.c:359
A bucket referring to an HTTP error.
const char * data
apr_bucket_alloc_t * bucket_alloc
Structure to store things which are per connection.
Definition httpd.h:1152
long id
Definition httpd.h:1187
IN ULONG IN INT timeout