Apache HTTPD
h2_c2_filter.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 <assert.h>
18#include <stdio.h>
19
20#include <apr_date.h>
21#include <apr_lib.h>
22#include <apr_strings.h>
23
24#include <httpd.h>
25#include <http_core.h>
26#include <http_log.h>
27#include <http_connection.h>
28#include <http_protocol.h>
29#include <http_request.h>
30#include <util_time.h>
31
32#include "h2_private.h"
33#include "h2.h"
34#include "h2_config.h"
35#include "h2_conn_ctx.h"
36#include "h2_headers.h"
37#include "h2_c1.h"
38#include "h2_c2_filter.h"
39#include "h2_c2.h"
40#include "h2_mplx.h"
41#include "h2_request.h"
42#include "h2_ws.h"
43#include "h2_util.h"
44
45
46#if AP_HAS_RESPONSE_BUCKETS
47
49{
53 const char *err;
54
55 if (!f->r) {
56 goto pass;
57 }
58
59 for (b = APR_BRIGADE_FIRST(bb);
62 {
64 resp = b->data;
65 if (resp->status >= 400 && f->r->prev) {
66 /* Error responses are commonly handled via internal
67 * redirects to error documents. That creates a new
68 * request_rec with 'prev' set to the original.
69 * Each of these has its onw 'notes'.
70 * We'd like to copy interesting ones into the current 'r->notes'
71 * as we reset HTTP/2 stream with H2 specific error codes then.
72 */
73 for (r_prev = f->r; r_prev != NULL; r_prev = r_prev->prev) {
74 if ((err = apr_table_get(r_prev->notes, "ssl-renegotiate-forbidden"))) {
75 if (r_prev != f->r) {
76 apr_table_setn(resp->notes, "ssl-renegotiate-forbidden", err);
77 }
78 break;
79 }
80 }
81 }
82 else if (h2_config_rgeti(f->r, H2_CONF_PUSH) == 0
83 && h2_config_sgeti(f->r->server, H2_CONF_PUSH) != 0) {
84 /* location configuration turns off H2 PUSH handling */
86 "h2_c2_filter_notes_out, turning PUSH off");
88 }
89 }
90 }
91pass:
92 return ap_pass_brigade(f->next, bb);
93}
94
100{
102 apr_bucket *b;
103
104 /* just get out of the way for things we don't want to handle. */
106 return ap_get_brigade(f->next, bb, mode, block, readbytes);
107 }
108
109 /* This filter is a one-time wonder */
111
112 if (f->c->master && (conn_ctx = h2_conn_ctx_get(f->c)) &&
113 conn_ctx->stream_id) {
114 const h2_request *req = conn_ctx->request;
115
116 if (req->http_status == H2_HTTP_STATUS_UNSET &&
117 req->protocol && !strcmp("websocket", req->protocol)) {
118 req = h2_ws_rewrite_request(req, f->c, conn_ctx->beam_in == NULL);
119 if (!req)
120 return APR_EGENERAL;
121 }
122
124 "h2_c2_filter_request_in(%s): adding request bucket",
125 conn_ctx->id);
126 b = h2_request_create_bucket(req, f->r);
128
129 if (req->http_status != H2_HTTP_STATUS_UNSET) {
130 /* error was encountered preparing this request */
132 "h2_c2_filter_request_in(%s): adding error bucket %d",
133 conn_ctx->id, req->http_status);
135 f->c->bucket_alloc);
137 return APR_SUCCESS;
138 }
139
140 if (!conn_ctx->beam_in) {
141 b = apr_bucket_eos_create(f->c->bucket_alloc);
143 }
144
145 return APR_SUCCESS;
146 }
147
148 return ap_get_brigade(f->next, bb, mode, block, readbytes);
149}
150
151#else /* AP_HAS_RESPONSE_BUCKETS */
152
153#define H2_FILTER_LOG(name, c, level, rv, msg, bb) \
154 do { \
155 if (APLOG_C_IS_LEVEL((c),(level))) { \
156 char buffer[4 * 1024]; \
157 apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \
158 len = h2_util_bb_print(buffer, bmax, "", "", (bb)); \
159 ap_log_cerror(APLOG_MARK, (level), rv, (c), \
160 "FILTER[%s]: %s %s", \
161 (name), (msg), len? buffer : ""); \
162 } \
163 } while (0)
164
165
166/* This routine is called by apr_table_do and merges all instances of
167 * the passed field values into a single array that will be further
168 * processed by some later routine. Originally intended to help split
169 * and recombine multiple Vary fields, though it is generic to any field
170 * consisting of comma/space-separated tokens.
171 */
172static int uniq_field_values(void *d, const char *key, const char *val)
173{
175 char *start;
176 char *e;
177 char **strpp;
178 int i;
179
180 (void)key;
182
184
185 do {
186 /* Find a non-empty fieldname */
187
188 while (*e == ',' || apr_isspace(*e)) {
189 ++e;
190 }
191 if (*e == '\0') {
192 break;
193 }
194 start = e;
195 while (*e != '\0' && *e != ',' && !apr_isspace(*e)) {
196 ++e;
197 }
198 if (*e != '\0') {
199 *e++ = '\0';
200 }
201
202 /* Now add it to values if it isn't already represented.
203 * Could be replaced by a ap_array_strcasecmp() if we had one.
204 */
205 for (i = 0, strpp = (char **) values->elts; i < values->nelts;
206 ++i, ++strpp) {
207 if (*strpp && apr_strnatcasecmp(*strpp, start) == 0) {
208 break;
209 }
210 }
211 if (i == values->nelts) { /* if not found */
212 *(char **)apr_array_push(values) = start;
213 }
214 } while (*e != '\0');
215
216 return 1;
217}
218
219/*
220 * Since some clients choke violently on multiple Vary fields, or
221 * Vary fields with duplicate tokens, combine any multiples and remove
222 * any duplicates.
223 */
224static void fix_vary(request_rec *r)
225{
227
228 varies = apr_array_make(r->pool, 5, sizeof(char *));
229
230 /* Extract all Vary fields from the headers_out, separate each into
231 * its comma-separated fieldname values, and then add them to varies
232 * if not already present in the array.
233 */
235
236 /* If we found any, replace old Vary fields with unique-ified value */
237
238 if (varies->nelts > 0) {
241 }
242}
243
245{
246 const char *clheader;
247 const char *ctype;
248
249 /*
250 * Now that we are ready to send a response, we need to combine the two
251 * header field tables into a single table. If we don't do this, our
252 * later attempts to set or unset a given fieldname might be bypassed.
253 */
256 r->headers_out);
258 }
259
260 /*
261 * Remove the 'Vary' header field if the client can't handle it.
262 * Since this will have nasty effects on HTTP/1.1 caches, force
263 * the response into HTTP/1.0 mode.
264 */
265 if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) {
266 apr_table_unset(r->headers_out, "Vary");
267 r->proto_num = HTTP_VERSION(1,0);
268 apr_table_setn(r->subprocess_env, "force-response-1.0", "1");
269 }
270 else {
271 fix_vary(r);
272 }
273
274 /*
275 * Now remove any ETag response header field if earlier processing
276 * says so (such as a 'FileETag None' directive).
277 */
278 if (apr_table_get(r->notes, "no-etag") != NULL) {
279 apr_table_unset(r->headers_out, "ETag");
280 }
281
282 /* determine the protocol and whether we should use keepalives. */
284
286 apr_table_unset(r->headers_out, "Transfer-Encoding");
287 apr_table_unset(r->headers_out, "Content-Length");
290 r->clength = r->chunked = 0;
291 }
292 else if (r->chunked) {
293 apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
294 apr_table_unset(r->headers_out, "Content-Length");
295 }
296
298 if (ctype) {
299 apr_table_setn(r->headers_out, "Content-Type", ctype);
300 }
301
302 if (r->content_encoding) {
303 apr_table_setn(r->headers_out, "Content-Encoding",
305 }
306
308 int i;
309 char *token;
310 char **languages = (char **)(r->content_languages->elts);
311 const char *field = apr_table_get(r->headers_out, "Content-Language");
312
313 while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) {
314 for (i = 0; i < r->content_languages->nelts; ++i) {
315 if (!apr_strnatcasecmp(token, languages[i]))
316 break;
317 }
318 if (i == r->content_languages->nelts) {
319 *((char **) apr_array_push(r->content_languages)) = token;
320 }
321 }
322
324 apr_table_setn(r->headers_out, "Content-Language", field);
325 }
326
327 /*
328 * Control cachability for non-cachable responses if not already set by
329 * some other part of the server configuration.
330 */
331 if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
332 char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
334 apr_table_add(r->headers_out, "Expires", date);
335 }
336
337 /* This is a hack, but I can't find anyway around it. The idea is that
338 * we don't want to send out 0 Content-Lengths if it is a head request.
339 * This happens when modules try to outsmart the server, and return
340 * if they see a HEAD request. Apache 1.3 handlers were supposed to
341 * just return in that situation, and the core handled the HEAD. In
342 * 2.0, if a handler returns, then the core sends an EOS bucket down
343 * the filter stack, and the content-length filter computes a C-L of
344 * zero and that gets put in the headers, and we end up sending a
345 * zero C-L to the client. We can't just remove the C-L filter,
346 * because well behaved 2.0 handlers will send their data down the stack,
347 * and we will compute a real C-L for the head request. RBB
348 */
349 if (r->header_only
350 && (clheader = apr_table_get(r->headers_out, "Content-Length"))
351 && !strcmp(clheader, "0")) {
352 apr_table_unset(r->headers_out, "Content-Length");
353 }
354
355 /*
356 * keep the set-by-proxy server and date headers, otherwise
357 * generate a new server header / date header
358 */
359 if (r->proxyreq == PROXYREQ_NONE
360 || !apr_table_get(r->headers_out, "Date")) {
361 char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
363 apr_table_setn(r->headers_out, "Date", date );
364 }
365 if (r->proxyreq == PROXYREQ_NONE
366 || !apr_table_get(r->headers_out, "Server")) {
367 const char *us = ap_get_server_banner();
368 if (us && *us) {
369 apr_table_setn(r->headers_out, "Server", us);
370 }
371 }
372
374}
375
381
393
395 const char *hline;
396 if (line[0] == ' ' || line[0] == '\t') {
397 char **plast;
398 /* continuation line from the header before this */
399 while (line[0] == ' ' || line[0] == '\t') {
400 ++line;
401 }
402
403 plast = apr_array_pop(parser->hlines);
404 if (plast == NULL) {
405 /* not well formed */
406 return APR_EINVAL;
407 }
408 hline = apr_psprintf(parser->pool, "%s %s", *plast, line);
409 }
410 else {
411 /* new header line */
412 hline = apr_pstrdup(parser->pool, line);
413 }
414 APR_ARRAY_PUSH(parser->hlines, const char*) = hline;
415 return APR_SUCCESS;
416}
417
419 char *line, apr_size_t len)
420{
422
423 if (!parser->tmp) {
424 parser->tmp = apr_brigade_create(parser->pool, parser->c->bucket_alloc);
425 }
427 len);
428 if (status == APR_SUCCESS) {
429 --len;
430 status = apr_brigade_flatten(parser->tmp, line, &len);
431 if (status == APR_SUCCESS) {
432 /* we assume a non-0 containing line and remove trailing crlf. */
433 line[len] = '\0';
434 /*
435 * XXX: What to do if there is an LF but no CRLF?
436 * Should we error out?
437 */
438 if (len >= 2 && !strcmp(H2_CRLF, line + len - 2)) {
439 len -= 2;
440 line[len] = '\0';
443 "h2_c2(%s): read response line: %s",
444 parser->id, line);
445 }
446 else {
448
449 /*
450 * If the brigade parser->tmp becomes longer than our buffer
451 * for flattening we never have a chance to get a complete
452 * line. This can happen if we are called multiple times after
453 * previous calls did not find a H2_CRLF and we returned
454 * APR_EAGAIN. In this case parser->tmp (correctly) grows
455 * with each call to apr_brigade_split_line.
456 *
457 * XXX: Currently a stack based buffer of HUGE_STRING_LEN is
458 * used. This means we cannot cope with lines larger than
459 * HUGE_STRING_LEN which might be an issue.
460 */
462 if ((status != APR_SUCCESS) || (brigade_length > (apr_off_t)len)) {
464 "h2_c2(%s): read response, line too long",
465 parser->id);
466 return APR_ENOSPC;
467 }
468 /* this does not look like a complete line yet */
470 "h2_c2(%s): read response, incomplete line: %s",
471 parser->id, line);
472 if (!parser->saveto) {
473 parser->saveto = apr_brigade_create(parser->pool,
474 parser->c->bucket_alloc);
475 }
476 /*
477 * Be on the save side and save the parser->tmp brigade
478 * as it could contain transient buckets which could be
479 * invalid next time we are here.
480 *
481 * NULL for the filter parameter is ok since we
482 * provide our own brigade as second parameter
483 * and ap_save_brigade does not need to create one.
484 */
485 ap_save_brigade(NULL, &(parser->saveto), &(parser->tmp),
486 parser->tmp->p);
487 APR_BRIGADE_CONCAT(parser->tmp, parser->saveto);
488 return APR_EAGAIN;
489 }
490 }
491 }
493 return status;
494}
495
497{
498 apr_array_header_t *hlines = parser->hlines;
499 if (hlines) {
500 apr_table_t *headers = apr_table_make(parser->pool, hlines->nelts);
501 int i;
502
503 for (i = 0; i < hlines->nelts; ++i) {
504 char *hline = ((char **)hlines->elts)[i];
505 char *sep = ap_strchr(hline, ':');
506 if (!sep) {
508 APLOGNO(02955) "h2_c2(%s): invalid header[%d] '%s'",
509 parser->id, i, (char*)hline);
510 /* not valid format, abort */
511 return NULL;
512 }
513 (*sep++) = '\0';
514 while (*sep == ' ' || *sep == '\t') {
515 ++sep;
516 }
517
519 apr_table_merge(headers, hline, sep);
520 }
521 }
522 return headers;
523 }
524 else {
525 return apr_table_make(parser->pool, 0);
526 }
527}
528
531{
532 apr_bucket *b;
534 h2_headers *response = h2_headers_create(parser->http_status,
536 parser->c->notes,
537 0, parser->pool);
539 b = h2_bucket_headers_create(parser->c->bucket_alloc, response);
541 b = apr_bucket_flush_create(parser->c->bucket_alloc);
543 status = ap_pass_brigade(f->next, parser->tmp);
545
546 /* reset parser for possible next response */
547 parser->state = H2_RP_STATUS_LINE;
548 apr_array_clear(parser->hlines);
549
550 if (response->status >= 200) {
551 conn_ctx->has_final_response = 1;
552 }
554 APLOGNO(03197) "h2_c2(%s): passed response %d",
555 parser->id, response->status);
556 return status;
557}
558
560{
561 int sindex = (apr_date_checkmask(line, "HTTP/#.# ###*")? 9 :
562 (apr_date_checkmask(line, "HTTP/# ###*")? 7 : 0));
563 if (sindex > 0) {
564 int k = sindex + 3;
565 char keepchar = line[k];
566 line[k] = '\0';
567 parser->http_status = atoi(&line[sindex]);
568 line[k] = keepchar;
569 parser->state = H2_RP_HEADER_LINE;
570
571 return APR_SUCCESS;
572 }
573 /* Seems like there is garbage on the connection. May be a leftover
574 * from a previous proxy request.
575 * This should only happen if the H2_RESPONSE filter is not yet in
576 * place (post_read_request has not been reached and the handler wants
577 * to write something. Probably just the interim response we are
578 * waiting for. But if there is other data hanging around before
579 * that, this needs to fail. */
581 "h2_c2(%s): unable to parse status line: %s",
582 parser->id, line);
583 return APR_EINVAL;
584}
585
589{
590 char line[HUGE_STRING_LEN];
592
593 while (!APR_BRIGADE_EMPTY(bb) && status == APR_SUCCESS) {
594 switch (parser->state) {
597 status = get_line(parser, bb, line, sizeof(line));
598 if (status == APR_EAGAIN) {
599 /* need more data */
600 return APR_SUCCESS;
601 }
602 else if (status != APR_SUCCESS) {
603 return status;
604 }
605 if (parser->state == H2_RP_STATUS_LINE) {
606 /* instead of parsing, just take it directly */
607 status = parse_status(parser, line);
608 }
609 else if (line[0] == '\0') {
610 /* end of headers, pass response onward */
612 "h2_c2(%s): end of response", parser->id);
613 return pass_response(conn_ctx, f, parser);
614 }
615 else {
617 "h2_c2(%s): response header %s", parser->id, line);
618 status = parse_header(parser, line);
619 }
620 break;
621
622 default:
623 return status;
624 }
625 }
626 return status;
627}
628
630{
633 apr_status_t rv;
634
636 H2_FILTER_LOG("c2_catch_h1_out", f->c, APLOG_TRACE2, 0, "check", bb);
637
638 if (!f->c->aborted && !conn_ctx->has_final_response) {
639 if (!parser) {
640 parser = apr_pcalloc(f->c->pool, sizeof(*parser));
641 parser->id = apr_psprintf(f->c->pool, "%s-%d", conn_ctx->id, conn_ctx->stream_id);
642 parser->pool = f->c->pool;
643 parser->c = f->c;
644 parser->state = H2_RP_STATUS_LINE;
645 parser->hlines = apr_array_make(parser->pool, 10, sizeof(char *));
646 f->ctx = parser;
647 }
648
649 if (!APR_BRIGADE_EMPTY(bb)) {
651 if (AP_BUCKET_IS_EOR(b)) {
652 /* TODO: Yikes, this happens when errors are encountered on input
653 * before anything from the repsonse has been processed. The
654 * ap_die_r() call will do nothing in certain conditions.
655 */
658 request_rec *r = h2_create_request_rec(conn_ctx->request, f->c, 1);
659 if (r) {
661 b = ap_bucket_eor_create(f->c->bucket_alloc, r);
663 }
664 }
665 }
666 /* There are cases where we need to parse a serialized http/1.1 response.
667 * One example is a 100-continue answer via a mod_proxy setup. */
668 while (bb && !f->c->aborted && !conn_ctx->has_final_response) {
669 rv = parse_response(parser, conn_ctx, f, bb);
671 "h2_c2(%s): parsed response", parser->id);
672 if (APR_BRIGADE_EMPTY(bb) || APR_SUCCESS != rv) {
673 return rv;
674 }
675 }
676 }
677
678 return ap_pass_brigade(f->next, bb);
679}
680
682{
684 request_rec *r = f->r;
685 apr_bucket *b, *bresp, *body_bucket = NULL, *next;
687 h2_headers *response = NULL;
688 int headers_passing = 0;
689
690 H2_FILTER_LOG("c2_response_out", f->c, APLOG_TRACE1, 0, "called with", bb);
691
692 if (f->c->aborted || !conn_ctx || conn_ctx->has_final_response) {
693 return ap_pass_brigade(f->next, bb);
694 }
695
696 if (!conn_ctx->has_final_response) {
697 /* check, if we need to send the response now. Until we actually
698 * see a DATA bucket or some EOS/EOR, we do not do so. */
699 for (b = APR_BRIGADE_FIRST(bb);
700 b != APR_BRIGADE_SENTINEL(bb);
702 {
703 if (AP_BUCKET_IS_ERROR(b) && !eb) {
704 eb = b->data;
705 }
706 else if (AP_BUCKET_IS_EOC(b)) {
707 /* If we see an EOC bucket it is a signal that we should get out
708 * of the way doing nothing.
709 */
712 "h2_c2(%s): eoc bucket passed", conn_ctx->id);
713 return ap_pass_brigade(f->next, bb);
714 }
715 else if (H2_BUCKET_IS_HEADERS(b)) {
716 headers_passing = 1;
717 }
718 else if (!APR_BUCKET_IS_FLUSH(b)) {
719 body_bucket = b;
720 break;
721 }
722 }
723
724 if (eb) {
725 int st = eb->status;
727 "h2_c2(%s): err bucket status=%d",
728 conn_ctx->id, st);
729 /* throw everything away and replace it with the error response
730 * generated by ap_die() */
732 ap_die(st, r);
733 return AP_FILTER_ERROR;
734 }
735
737 /* time to insert the response bucket before the body or if
738 * no h2_headers is passed, e.g. the response is empty */
739 response = create_response(r);
740 if (response == NULL) {
742 "h2_c2(%s): unable to create response", conn_ctx->id);
743 return APR_ENOMEM;
744 }
745
746 bresp = h2_bucket_headers_create(f->c->bucket_alloc, response);
747 if (body_bucket) {
749 }
750 else {
752 }
753 conn_ctx->has_final_response = 1;
754 r->sent_bodyct = 1;
755 ap_remove_output_filter_byhandle(f->r->output_filters, "H2_C2_NET_CATCH_H1");
756 }
757 }
758
761 "h2_c2(%s): headers only, cleanup output brigade", conn_ctx->id);
763 while (b != APR_BRIGADE_SENTINEL(bb)) {
764 next = APR_BUCKET_NEXT(b);
766 break;
767 }
768 if (!H2_BUCKET_IS_HEADERS(b)) {
771 }
772 b = next;
773 }
774 }
775 if (conn_ctx->has_final_response) {
776 /* lets get out of the way, our task is done */
778 }
779 return ap_pass_brigade(f->next, bb);
780}
781
782
790
791
794 apr_bucket *tail)
795{
796 /* Surround the buckets [first, tail[ with new buckets carrying the
797 * HTTP/1.1 chunked encoding format. If tail is NULL, the chunk extends
798 * to the end of the brigade. */
799 char buffer[128];
800 apr_bucket *b;
802
807 b = apr_bucket_immortal_create("\r\n", 2, bb->bucket_alloc);
808 if (tail) {
810 }
811 else {
813 }
814 fctx->chunked_total += chunk_len;
816 "h2_c2(%s): added chunk %ld, total %ld",
817 fctx->id, (long)chunk_len, (long)fctx->chunked_total);
818}
819
820static int ser_header(void *ctx, const char *name, const char *value)
821{
823 apr_brigade_printf(bb, NULL, NULL, "%s: %s\r\n", name, value);
824 return 1;
825}
826
829 h2_chunk_filter_t *fctx = f->ctx;
830 request_rec *r = f->r;
832
833 if (!fctx->bbchunk) {
834 fctx->bbchunk = apr_brigade_create(r->pool, f->c->bucket_alloc);
835 }
836
837 if (APR_BRIGADE_EMPTY(fctx->bbchunk)) {
838 apr_bucket *b, *next, *first_data = NULL;
840 apr_off_t bblen = 0;
841
842 /* get more data from the lower layer filters. Always do this
843 * in larger pieces, since we handle the read modes ourself. */
844 status = ap_get_brigade(f->next, fctx->bbchunk,
845 AP_MODE_READBYTES, block, conn_ctx->mplx->stream_max_mem);
846 if (status != APR_SUCCESS) {
847 return status;
848 }
849
850 for (b = APR_BRIGADE_FIRST(fctx->bbchunk);
852 b = next) {
853 next = APR_BUCKET_NEXT(b);
855 if (first_data) {
856 make_chunk(f->c, fctx, fctx->bbchunk, first_data, bblen, b);
858 }
859
860 if (H2_BUCKET_IS_HEADERS(b)) {
862
863 ap_assert(headers);
865 "h2_c2(%s-%d): receiving trailers",
866 conn_ctx->id, conn_ctx->stream_id);
867 tmp = apr_brigade_split_ex(fctx->bbchunk, b, NULL);
868 if (!apr_is_empty_table(headers->headers)) {
869 status = apr_brigade_puts(fctx->bbchunk, NULL, NULL, "0\r\n");
870 apr_table_do(ser_header, fctx->bbchunk, headers->headers, NULL);
871 status = apr_brigade_puts(fctx->bbchunk, NULL, NULL, "\r\n");
872 }
873 else {
874 status = apr_brigade_puts(fctx->bbchunk, NULL, NULL, "0\r\n\r\n");
875 }
876 r->trailers_in = apr_table_clone(r->pool, headers->headers);
879 APR_BRIGADE_CONCAT(fctx->bbchunk, tmp);
881 fctx->eos_chunk_added = 1;
882 }
883 else if (APR_BUCKET_IS_EOS(b)) {
885 "h2_c2(%s-%d): receiving eos",
886 conn_ctx->id, conn_ctx->stream_id);
887 if (!fctx->eos_chunk_added) {
888 tmp = apr_brigade_split_ex(fctx->bbchunk, b, NULL);
889 status = apr_brigade_puts(fctx->bbchunk, NULL, NULL, "0\r\n\r\n");
890 APR_BRIGADE_CONCAT(fctx->bbchunk, tmp);
892 }
893 fctx->eos_chunk_added = 0;
894 }
895 }
896 else if (b->length == 0) {
899 }
900 else {
901 if (!first_data) {
902 first_data = b;
903 bblen = 0;
904 }
905 bblen += b->length;
906 }
907 }
908
909 if (first_data) {
910 make_chunk(f->c, fctx, fctx->bbchunk, first_data, bblen, NULL);
911 }
912 }
913 return status;
914}
915
921{
923 h2_chunk_filter_t *fctx = f->ctx;
924 request_rec *r = f->r;
926 apr_bucket *b, *next;
927 core_server_config *conf =
929 &core_module);
931
932 if (!fctx) {
933 fctx = apr_pcalloc(r->pool, sizeof(*fctx));
934 fctx->id = apr_psprintf(r->pool, "%s-%d", conn_ctx->id, conn_ctx->stream_id);
935 f->ctx = fctx;
936 }
937
939 "h2_c2(%s-%d): request input, mode=%d, block=%d, "
940 "readbytes=%ld, exp=%d",
941 conn_ctx->id, conn_ctx->stream_id, mode, block,
942 (long)readbytes, r->expecting_100);
943 if (!conn_ctx->input_chunked) {
944 status = ap_get_brigade(f->next, bb, mode, block, readbytes);
945 /* pipe data through, just take care of trailers */
946 for (b = APR_BRIGADE_FIRST(bb);
947 b != APR_BRIGADE_SENTINEL(bb); b = next) {
948 next = APR_BUCKET_NEXT(b);
949 if (H2_BUCKET_IS_HEADERS(b)) {
951 ap_assert(headers);
953 "h2_c2(%s-%d): receiving trailers",
954 conn_ctx->id, conn_ctx->stream_id);
955 r->trailers_in = headers->headers;
956 if (conf && conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE) {
958 r->trailers_in);
959 }
963
964 if (headers->raw_bytes && h2_c_logio_add_bytes_in) {
965 h2_c_logio_add_bytes_in(f->c, headers->raw_bytes);
966 }
967 break;
968 }
969 }
970 return status;
971 }
972
973 /* Things are more complicated. The standard HTTP input filter, which
974 * does a lot what we do not want to duplicate, also cares about chunked
975 * transfer encoding and trailers.
976 * We need to simulate chunked encoding for it to be happy.
977 */
979 return status;
980 }
981
982 if (mode == AP_MODE_EXHAUSTIVE) {
983 /* return all we have */
984 APR_BRIGADE_CONCAT(bb, fctx->bbchunk);
985 }
986 else if (mode == AP_MODE_READBYTES) {
988 }
989 else if (mode == AP_MODE_SPECULATIVE) {
991 }
992 else if (mode == AP_MODE_GETLINE) {
993 /* we are reading a single LF line, e.g. the HTTP headers.
994 * this has the nasty side effect to split the bucket, even
995 * though it ends with CRLF and creates a 0 length bucket */
997 if (APLOGctrace1(f->c)) {
998 char buffer[1024];
999 apr_size_t len = sizeof(buffer)-1;
1001 buffer[len] = 0;
1003 "h2_c2(%s-%d): getline: %s",
1004 conn_ctx->id, conn_ctx->stream_id, buffer);
1005 }
1006 }
1007 else {
1008 /* Hmm, well. There is mode AP_MODE_EATCRLF, but we chose not
1009 * to support it. Seems to work. */
1011 APLOGNO(02942)
1012 "h2_c2, unsupported READ mode %d", mode);
1014 }
1015
1016 h2_util_bb_log(f->c, conn_ctx->stream_id, APLOG_TRACE2, "returning input", bb);
1017 return status;
1018}
1019
1021{
1023 request_rec *r = f->r;
1024 apr_bucket *b, *e;
1025
1026 if (conn_ctx && r) {
1027 /* Detect the EOS/EOR bucket and forward any trailers that may have
1028 * been set to our h2_headers.
1029 */
1030 for (b = APR_BRIGADE_FIRST(bb);
1031 b != APR_BRIGADE_SENTINEL(bb);
1032 b = APR_BUCKET_NEXT(b))
1033 {
1036 h2_headers *headers;
1037 apr_table_t *trailers;
1038
1040 "h2_c2(%s-%d): sending trailers",
1041 conn_ctx->id, conn_ctx->stream_id);
1042 trailers = apr_table_clone(r->pool, r->trailers_out);
1043 headers = h2_headers_rcreate(r, HTTP_OK, trailers, r->pool);
1044 e = h2_bucket_headers_create(bb->bucket_alloc, headers);
1048 break;
1049 }
1050 }
1051 }
1052
1053 return ap_pass_brigade(f->next, bb);
1054}
1055
1056#endif /* else #if AP_HAS_RESPONSE_BUCKETS */
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL date routines.
APR general purpose library routines.
apr_size_t const unsigned char unsigned int unsigned int d
Definition apr_siphash.h:72
APR Strings library.
#define ap_get_module_config(v, m)
request_rec * r
#define AP_BUCKET_IS_EOC(e)
#define HUGE_STRING_LEN
Definition httpd.h:303
#define AP_FILTER_ERROR
Definition httpd.h:473
#define HTTP_VERSION(major, minor)
Definition httpd.h:269
const char * ap_get_server_banner(void)
Definition core.c:3593
void ap_remove_input_filter(ap_filter_t *f)
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
apr_status_t ap_remove_output_filter_byhandle(ap_filter_t *next, const char *handle)
apr_status_t ap_save_brigade(ap_filter_t *f, apr_bucket_brigade **save_to, apr_bucket_brigade **b, apr_pool_t *p)
apr_status_t ap_get_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
void ap_remove_output_filter(ap_filter_t *f)
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOGctrace1(c)
Definition http_log.h:257
#define APLOG_DEBUG
Definition http_log.h:71
int ap_map_http_request_error(apr_status_t rv, int status)
int ap_set_keepalive(request_rec *r)
const char * ap_make_content_type(request_rec *r, const char *type)
Definition protocol.c:110
#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)
apr_bucket * ap_bucket_eor_create(apr_bucket_alloc_t *list, request_rec *r)
Definition eor_bucket.c:68
void ap_die(int type, request_rec *r)
apr_status_t ap_recent_rfc822_date(char *date_str, apr_time_t t)
Definition util_time.c:282
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOSPC
Definition apr_errno.h:676
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINVAL
Definition apr_errno.h:711
apr_file_t * f
#define APR_BUCKET_IS_FLUSH(e)
#define APR_BUCKET_REMOVE(e)
#define APR_BUCKET_IS_METADATA(e)
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_file_t apr_off_t start
#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_CONCAT(a, b)
#define APR_BRIGADE_EMPTY(b)
#define APR_BRIGADE_SENTINEL(b)
#define APR_BUCKET_IS_EOS(e)
apr_brigade_flush void * ctx
#define APR_BRIGADE_FIRST(b)
#define APR_BUCKET_INSERT_BEFORE(a, b)
#define apr_bucket_destroy(e)
@ APR_BLOCK_READ
Definition apr_buckets.h:58
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
const char apr_hash_t ** values
apr_xml_parser ** parser
Definition apr_xml.h:228
#define HTTP_OK
Definition httpd.h:490
#define AP_STATUS_IS_HEADER_ONLY(x)
Definition httpd.h:574
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define ap_strchr(s, c)
Definition httpd.h:2351
char * ap_get_list_item(apr_pool_t *p, const char **field)
Definition util.c:1314
#define PROXYREQ_NONE
Definition httpd.h:1133
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define apr_isspace(c)
Definition apr_lib.h:225
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
char * buffer
apr_array_header_t ** result
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_pool_t * b
Definition apr_pools.h:529
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * sep
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
const apr_array_header_t * first
Definition apr_tables.h:207
apr_int32_t apr_int32_t apr_int32_t err
int int status
#define APR_RFC822_DATE_LEN
Definition apr_time.h:186
#define H2_ALEN(a)
Definition h2.h:98
#define H2_PUSH_MODE_NOTE
Definition h2.h:200
#define H2_CRLF
Definition h2.h:83
#define H2_HTTP_STATUS_UNSET
Definition h2.h:190
apr_OFN_ap_logio_add_bytes_in_t * h2_c_logio_add_bytes_in
Definition h2_c1.c:52
#define H2_FILTER_LOG(name, c, level, rv, msg, bb)
static int uniq_field_values(void *d, const char *key, const char *val)
static apr_status_t parse_status(h2_response_parser *parser, char *line)
apr_status_t h2_c2_filter_response_out(ap_filter_t *f, apr_bucket_brigade *bb)
static void fix_vary(request_rec *r)
static h2_headers * create_response(request_rec *r)
static apr_status_t read_and_chunk(ap_filter_t *f, h2_conn_ctx_t *conn_ctx, apr_read_type_e block)
static apr_status_t pass_response(h2_conn_ctx_t *conn_ctx, ap_filter_t *f, h2_response_parser *parser)
static apr_status_t get_line(h2_response_parser *parser, apr_bucket_brigade *bb, char *line, apr_size_t len)
static apr_status_t parse_header(h2_response_parser *parser, char *line)
apr_status_t h2_c2_filter_trailers_out(ap_filter_t *f, apr_bucket_brigade *bb)
apr_status_t h2_c2_filter_request_in(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes)
static int ser_header(void *ctx, const char *name, const char *value)
static apr_table_t * make_table(h2_response_parser *parser)
static apr_status_t parse_response(h2_response_parser *parser, h2_conn_ctx_t *conn_ctx, ap_filter_t *f, apr_bucket_brigade *bb)
h2_rp_state_t
@ H2_RP_HEADER_LINE
@ H2_RP_DONE
@ H2_RP_STATUS_LINE
static void make_chunk(conn_rec *c, h2_chunk_filter_t *fctx, apr_bucket_brigade *bb, apr_bucket *first, apr_off_t chunk_len, apr_bucket *tail)
apr_status_t h2_c2_filter_catch_h1_out(ap_filter_t *f, apr_bucket_brigade *bb)
int h2_config_rgeti(request_rec *r, h2_config_var_t var)
Definition h2_config.c:527
int h2_config_sgeti(server_rec *s, h2_config_var_t var)
Definition h2_config.c:506
@ H2_CONF_PUSH
Definition h2_config.h:38
#define h2_conn_ctx_get(c)
Definition h2_conn_ctx.h:78
h2_headers * h2_bucket_headers_get(apr_bucket *b)
Definition h2_headers.c:85
h2_headers * h2_headers_rcreate(request_rec *r, int status, const apr_table_t *header, apr_pool_t *pool)
Definition h2_headers.c:152
h2_headers * h2_headers_create(int status, const apr_table_t *headers_in, const apr_table_t *notes, apr_off_t raw_bytes, apr_pool_t *pool)
Definition h2_headers.c:119
apr_bucket * h2_bucket_headers_create(apr_bucket_alloc_t *list, h2_headers *r)
Definition h2_headers.c:73
#define H2_BUCKET_IS_HEADERS(e)
Definition h2_headers.h:37
request_rec * h2_create_request_rec(const h2_request *req, conn_rec *c, int no_body)
Definition h2_request.c:370
apr_status_t h2_brigade_copy_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1228
int h2_util_ignore_resp_header(const char *name)
Definition h2_util.c:1660
apr_status_t h2_brigade_concat_length(apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length)
Definition h2_util.c:1193
#define h2_util_bb_log(c, sid, level, tag, bb)
Definition h2_util.h:456
const h2_request * h2_ws_rewrite_request(const h2_request *req, conn_rec *c2, int no_body)
Definition h2_ws.c:348
Apache connection library.
CORE HTTP Daemon.
#define AP_MERGE_TRAILERS_ENABLE
Definition http_core.h:733
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
A bucket referring to an HTTP error.
The representation of a filter chain.
apr_bucket_alloc_t * bucket_alloc
apr_pool_t * pool
apr_pool_t * pool
Definition apr_hash.c:76
apr_pool_t * p
Definition apr_xml.c:58
Structure to store things which are per connection.
Definition httpd.h:1152
const char * id
apr_off_t chunked_total
apr_bucket_brigade * bbchunk
apr_table_t * headers
Definition h2_headers.h:29
apr_off_t raw_bytes
Definition h2_headers.h:31
int http_status
Definition h2.h:179
const char * protocol
Definition h2.h:174
h2_rp_state_t state
apr_bucket_brigade * tmp
apr_pool_t * pool
apr_bucket_brigade * saveto
apr_array_header_t * hlines
A structure that represents the current request.
Definition httpd.h:845
apr_array_header_t * content_languages
Definition httpd.h:999
int status
Definition httpd.h:891
const char * content_type
Definition httpd.h:992
apr_table_t * trailers_in
Definition httpd.h:1104
int header_only
Definition httpd.h:875
apr_table_t * notes
Definition httpd.h:985
unsigned expecting_100
Definition httpd.h:951
apr_pool_t * pool
Definition httpd.h:847
apr_time_t request_time
Definition httpd.h:886
int proxyreq
Definition httpd.h:873
int no_cache
Definition httpd.h:1082
apr_table_t * err_headers_out
Definition httpd.h:981
int proto_num
Definition httpd.h:877
int chunked
Definition httpd.h:942
apr_table_t * headers_in
Definition httpd.h:976
apr_table_t * subprocess_env
Definition httpd.h:983
apr_off_t sent_bodyct
Definition httpd.h:929
server_rec * server
Definition httpd.h:851
apr_off_t clength
Definition httpd.h:940
apr_table_t * trailers_out
Definition httpd.h:1106
const char * content_encoding
Definition httpd.h:997
apr_table_t * headers_out
Definition httpd.h:978
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
ap_input_mode_t
input filtering modes
Definition util_filter.h:41
@ AP_MODE_SPECULATIVE
Definition util_filter.h:53
@ AP_MODE_READBYTES
Definition util_filter.h:43
@ AP_MODE_EXHAUSTIVE
Definition util_filter.h:58
@ AP_MODE_GETLINE
Definition util_filter.h:48
Apache date-time handling functions.