1 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
20 #include <apr_strings.h>
23 #include <http_core.h>
25 #include <http_connection.h>
26 #include <http_protocol.h>
27 #include <http_request.h>
28 #include <util_time.h>
30 #include "h2_private.h"
31 #include "h2_response.h"
32 #include "h2_from_h1.h"
37 static void set_state(h2_from_h1 *from_h1, h2_from_h1_state_t state);
39 h2_from_h1 *h2_from_h1_create(int stream_id, apr_pool_t *pool)
41 h2_from_h1 *from_h1 = apr_pcalloc(pool, sizeof(h2_from_h1));
43 from_h1->stream_id = stream_id;
45 from_h1->state = H2_RESP_ST_STATUS_LINE;
46 from_h1->hlines = apr_array_make(pool, 10, sizeof(char *));
51 static void set_state(h2_from_h1 *from_h1, h2_from_h1_state_t state)
53 if (from_h1->state != state) {
54 from_h1->state = state;
58 h2_response *h2_from_h1_get_response(h2_from_h1 *from_h1)
60 return from_h1->response;
63 static apr_status_t make_h2_headers(h2_from_h1 *from_h1, request_rec *r)
65 from_h1->response = h2_response_create(from_h1->stream_id, 0,
70 from_h1->content_length = from_h1->response->content_length;
71 from_h1->chunked = r->chunked;
73 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, r->connection, APLOGNO(03197)
74 "h2_from_h1(%d): converted headers, content-length: %d"
76 from_h1->stream_id, (int)from_h1->content_length,
77 (int)from_h1->chunked);
79 set_state(from_h1, ((from_h1->chunked || from_h1->content_length > 0)?
80 H2_RESP_ST_BODY : H2_RESP_ST_DONE));
81 /* We are ready to be sent to the client */
85 static apr_status_t parse_header(h2_from_h1 *from_h1, ap_filter_t* f,
89 if (line[0] == ' ' || line[0] == '\t') {
91 /* continuation line from the header before this */
92 while (line[0] == ' ' || line[0] == '\t') {
96 plast = apr_array_pop(from_h1->hlines);
101 APR_ARRAY_PUSH(from_h1->hlines, const char*) = apr_psprintf(from_h1->pool, "%s %s", *plast, line);
104 /* new header line */
105 APR_ARRAY_PUSH(from_h1->hlines, const char*) = apr_pstrdup(from_h1->pool, line);
110 static apr_status_t get_line(h2_from_h1 *from_h1, apr_bucket_brigade *bb,
111 ap_filter_t* f, char *line, apr_size_t len)
115 from_h1->bb = apr_brigade_create(from_h1->pool, f->c->bucket_alloc);
118 apr_brigade_cleanup(from_h1->bb);
120 status = apr_brigade_split_line(from_h1->bb, bb,
123 if (status == APR_SUCCESS) {
125 status = apr_brigade_flatten(from_h1->bb, line, &len);
126 if (status == APR_SUCCESS) {
127 /* we assume a non-0 containing line and remove
130 if (len >= 2 && !strcmp(H2_CRLF, line + len - 2)) {
135 apr_brigade_cleanup(from_h1->bb);
136 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
137 "h2_from_h1(%d): read line: %s",
138 from_h1->stream_id, line);
144 apr_status_t h2_from_h1_read_response(h2_from_h1 *from_h1, ap_filter_t* f,
145 apr_bucket_brigade* bb)
147 apr_status_t status = APR_SUCCESS;
148 char line[HUGE_STRING_LEN];
150 if ((from_h1->state == H2_RESP_ST_BODY)
151 || (from_h1->state == H2_RESP_ST_DONE)) {
152 if (from_h1->chunked) {
153 /* The httpd core HTTP_HEADER filter has or will install the
154 * "CHUNK" output transcode filter, which appears further down
155 * the filter chain. We do not want it for HTTP/2.
156 * Once we successfully deinstalled it, this filter has no
157 * further function and we remove it.
159 status = ap_remove_output_filter_byhandle(f->r->output_filters,
161 if (status == APR_SUCCESS) {
162 ap_remove_output_filter(f);
166 return ap_pass_brigade(f->next, bb);
169 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
170 "h2_from_h1(%d): read_response", from_h1->stream_id);
172 while (!APR_BRIGADE_EMPTY(bb) && status == APR_SUCCESS) {
174 switch (from_h1->state) {
176 case H2_RESP_ST_STATUS_LINE:
177 case H2_RESP_ST_HEADERS:
178 status = get_line(from_h1, bb, f, line, sizeof(line));
179 if (status != APR_SUCCESS) {
182 if (from_h1->state == H2_RESP_ST_STATUS_LINE) {
183 /* instead of parsing, just take it directly */
184 from_h1->http_status = f->r->status;
185 from_h1->state = H2_RESP_ST_HEADERS;
187 else if (line[0] == '\0') {
188 /* end of headers, create the h2_response and
189 * pass the rest of the brigade down the filter
192 status = make_h2_headers(from_h1, f->r);
194 apr_brigade_destroy(from_h1->bb);
197 if (!APR_BRIGADE_EMPTY(bb)) {
198 return ap_pass_brigade(f->next, bb);
202 status = parse_header(from_h1, f, line);
207 return ap_pass_brigade(f->next, bb);
215 /* This routine is called by apr_table_do and merges all instances of
216 * the passed field values into a single array that will be further
217 * processed by some later routine. Originally intended to help split
218 * and recombine multiple Vary fields, though it is generic to any field
219 * consisting of comma/space-separated tokens.
221 static int uniq_field_values(void *d, const char *key, const char *val)
223 apr_array_header_t *values;
230 values = (apr_array_header_t *)d;
232 e = apr_pstrdup(values->pool, val);
235 /* Find a non-empty fieldname */
237 while (*e == ',' || apr_isspace(*e)) {
244 while (*e != '\0' && *e != ',' && !apr_isspace(*e)) {
251 /* Now add it to values if it isn't already represented.
252 * Could be replaced by a ap_array_strcasecmp() if we had one.
254 for (i = 0, strpp = (char **) values->elts; i < values->nelts;
256 if (*strpp && apr_strnatcasecmp(*strpp, start) == 0) {
260 if (i == values->nelts) { /* if not found */
261 *(char **)apr_array_push(values) = start;
263 } while (*e != '\0');
269 * Since some clients choke violently on multiple Vary fields, or
270 * Vary fields with duplicate tokens, combine any multiples and remove
273 static void fix_vary(request_rec *r)
275 apr_array_header_t *varies;
277 varies = apr_array_make(r->pool, 5, sizeof(char *));
279 /* Extract all Vary fields from the headers_out, separate each into
280 * its comma-separated fieldname values, and then add them to varies
281 * if not already present in the array.
283 apr_table_do((int (*)(void *, const char *, const char *))uniq_field_values,
284 (void *) varies, r->headers_out, "Vary", NULL);
286 /* If we found any, replace old Vary fields with unique-ified value */
288 if (varies->nelts > 0) {
289 apr_table_setn(r->headers_out, "Vary",
290 apr_array_pstrcat(r->pool, varies, ','));
294 void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r,
298 const char *proxy_date = NULL;
299 const char *server = NULL;
300 const char *us = ap_get_server_banner();
303 * keep the set-by-proxy server and date headers, otherwise
304 * generate a new server header / date header
306 if (r && r->proxyreq != PROXYREQ_NONE) {
307 proxy_date = apr_table_get(r->headers_out, "Date");
310 * proxy_date needs to be const. So use date for the creation of
311 * our own Date header and pass it over to proxy_date later to
312 * avoid a compiler warning.
314 date = apr_palloc(pool, APR_RFC822_DATE_LEN);
315 ap_recent_rfc822_date(date, r->request_time);
317 server = apr_table_get(r->headers_out, "Server");
320 date = apr_palloc(pool, APR_RFC822_DATE_LEN);
321 ap_recent_rfc822_date(date, r? r->request_time : apr_time_now());
324 apr_table_setn(headers, "Date", proxy_date ? proxy_date : date );
326 apr_table_unset(r->headers_out, "Date");
329 if (!server && *us) {
333 apr_table_setn(headers, "Server", server);
335 apr_table_unset(r->headers_out, "Server");
340 static int copy_header(void *ctx, const char *name, const char *value)
342 apr_table_t *headers = ctx;
344 apr_table_addn(headers, name, value);
348 static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r)
350 const char *clheader;
352 apr_table_t *headers;
354 * Now that we are ready to send a response, we need to combine the two
355 * header field tables into a single table. If we don't do this, our
356 * later attempts to set or unset a given fieldname might be bypassed.
358 if (!apr_is_empty_table(r->err_headers_out)) {
359 r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
361 apr_table_clear(r->err_headers_out);
365 * Remove the 'Vary' header field if the client can't handle it.
366 * Since this will have nasty effects on HTTP/1.1 caches, force
367 * the response into HTTP/1.0 mode.
369 if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) {
370 apr_table_unset(r->headers_out, "Vary");
371 r->proto_num = HTTP_VERSION(1,0);
372 apr_table_setn(r->subprocess_env, "force-response-1.0", "1");
379 * Now remove any ETag response header field if earlier processing
380 * says so (such as a 'FileETag None' directive).
382 if (apr_table_get(r->notes, "no-etag") != NULL) {
383 apr_table_unset(r->headers_out, "ETag");
386 /* determine the protocol and whether we should use keepalives. */
390 apr_table_unset(r->headers_out, "Content-Length");
393 ctype = ap_make_content_type(r, r->content_type);
395 apr_table_setn(r->headers_out, "Content-Type", ctype);
398 if (r->content_encoding) {
399 apr_table_setn(r->headers_out, "Content-Encoding",
400 r->content_encoding);
403 if (!apr_is_empty_array(r->content_languages)) {
406 char **languages = (char **)(r->content_languages->elts);
407 const char *field = apr_table_get(r->headers_out, "Content-Language");
409 while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) {
410 for (i = 0; i < r->content_languages->nelts; ++i) {
411 if (!apr_strnatcasecmp(token, languages[i]))
414 if (i == r->content_languages->nelts) {
415 *((char **) apr_array_push(r->content_languages)) = token;
419 field = apr_array_pstrcat(r->pool, r->content_languages, ',');
420 apr_table_setn(r->headers_out, "Content-Language", field);
424 * Control cachability for non-cachable responses if not already set by
425 * some other part of the server configuration.
427 if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
428 char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
429 ap_recent_rfc822_date(date, r->request_time);
430 apr_table_addn(r->headers_out, "Expires", date);
433 /* This is a hack, but I can't find anyway around it. The idea is that
434 * we don't want to send out 0 Content-Lengths if it is a head request.
435 * This happens when modules try to outsmart the server, and return
436 * if they see a HEAD request. Apache 1.3 handlers were supposed to
437 * just return in that situation, and the core handled the HEAD. In
438 * 2.0, if a handler returns, then the core sends an EOS bucket down
439 * the filter stack, and the content-length filter computes a C-L of
440 * zero and that gets put in the headers, and we end up sending a
441 * zero C-L to the client. We can't just remove the C-L filter,
442 * because well behaved 2.0 handlers will send their data down the stack,
443 * and we will compute a real C-L for the head request. RBB
446 && (clheader = apr_table_get(r->headers_out, "Content-Length"))
447 && !strcmp(clheader, "0")) {
448 apr_table_unset(r->headers_out, "Content-Length");
451 headers = apr_table_make(r->pool, 10);
453 h2_from_h1_set_basic_http_header(headers, r, r->pool);
454 if (r->status == HTTP_NOT_MODIFIED) {
455 apr_table_do((int (*)(void *, const char *, const char *)) copy_header,
456 (void *) headers, r->headers_out,
464 "Proxy-Authenticate",
470 apr_table_do((int (*)(void *, const char *, const char *)) copy_header,
471 (void *) headers, r->headers_out, NULL);
474 return h2_response_rcreate(from_h1->stream_id, r, headers, r->pool);
477 apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
479 h2_task *task = f->ctx;
480 h2_from_h1 *from_h1 = task->output.from_h1;
481 request_rec *r = f->r;
483 ap_bucket_error *eb = NULL;
485 AP_DEBUG_ASSERT(from_h1 != NULL);
487 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
488 "h2_from_h1(%d): output_filter called", from_h1->stream_id);
490 if (r->header_only && from_h1->response) {
491 /* throw away any data after we have compiled the response */
492 apr_brigade_cleanup(bb);
496 for (b = APR_BRIGADE_FIRST(bb);
497 b != APR_BRIGADE_SENTINEL(bb);
498 b = APR_BUCKET_NEXT(b))
500 if (AP_BUCKET_IS_ERROR(b) && !eb) {
505 * If we see an EOC bucket it is a signal that we should get out
506 * of the way doing nothing.
508 if (AP_BUCKET_IS_EOC(b)) {
509 ap_remove_output_filter(f);
510 ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, f->c,
511 "h2_from_h1(%d): eoc bucket passed",
513 return ap_pass_brigade(f->next, bb);
519 apr_brigade_cleanup(bb);
520 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03047)
521 "h2_from_h1(%d): err bucket status=%d",
522 from_h1->stream_id, st);
524 return AP_FILTER_ERROR;
527 from_h1->response = create_response(from_h1, r);
528 if (from_h1->response == NULL) {
529 ap_log_cerror(APLOG_MARK, APLOG_NOTICE, 0, f->c, APLOGNO(03048)
530 "h2_from_h1(%d): unable to create response",
535 if (r->header_only) {
536 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
537 "h2_from_h1(%d): header_only, cleanup output brigade",
539 apr_brigade_cleanup(bb);
543 r->sent_bodyct = 1; /* Whatever follows is real body stuff... */
545 ap_remove_output_filter(f);
546 if (APLOGctrace1(f->c)) {
548 apr_brigade_length(bb, 0, &len);
549 ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
550 "h2_from_h1(%d): removed header filter, passing brigade "
551 "len=%ld", from_h1->stream_id, (long)len);
553 return ap_pass_brigade(f->next, bb);
556 apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb)
558 h2_task *task = f->ctx;
559 h2_from_h1 *from_h1 = task->output.from_h1;
560 request_rec *r = f->r;
563 if (from_h1 && from_h1->response) {
564 /* Detect the EOR bucket and forward any trailers that may have
565 * been set to our h2_response.
567 for (b = APR_BRIGADE_FIRST(bb);
568 b != APR_BRIGADE_SENTINEL(bb);
569 b = APR_BUCKET_NEXT(b))
571 if (AP_BUCKET_IS_EOR(b)) {
572 /* FIXME: need a better test case than this.
573 apr_table_setn(r->trailers_out, "X", "1"); */
574 if (r->trailers_out && !apr_is_empty_table(r->trailers_out)) {
575 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, APLOGNO(03049)
576 "h2_from_h1(%d): trailers filter, saving trailers",
578 h2_response_set_trailers(from_h1->response,
579 apr_table_clone(from_h1->pool,
587 return ap_pass_brigade(f->next, bb);