]> granicus.if.org Git - apache/blob - modules/http2/h2_from_h1.c
Backport
[apache] / modules / http2 / h2_from_h1.c
1 /* Copyright 2015 greenbytes GmbH (https://www.greenbytes.de)
2  *
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
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  
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.
14  */
15
16 #include <assert.h>
17 #include <stdio.h>
18
19 #include <apr_lib.h>
20 #include <apr_strings.h>
21
22 #include <httpd.h>
23 #include <http_core.h>
24 #include <http_log.h>
25 #include <http_connection.h>
26 #include <http_protocol.h>
27 #include <http_request.h>
28 #include <util_time.h>
29
30 #include "h2_private.h"
31 #include "h2_response.h"
32 #include "h2_from_h1.h"
33 #include "h2_task.h"
34 #include "h2_util.h"
35
36
37 static void set_state(h2_from_h1 *from_h1, h2_from_h1_state_t state);
38
39 h2_from_h1 *h2_from_h1_create(int stream_id, apr_pool_t *pool)
40 {
41     h2_from_h1 *from_h1 = apr_pcalloc(pool, sizeof(h2_from_h1));
42     if (from_h1) {
43         from_h1->stream_id = stream_id;
44         from_h1->pool = pool;
45         from_h1->state = H2_RESP_ST_STATUS_LINE;
46         from_h1->hlines = apr_array_make(pool, 10, sizeof(char *));
47     }
48     return from_h1;
49 }
50
51 static void set_state(h2_from_h1 *from_h1, h2_from_h1_state_t state)
52 {
53     if (from_h1->state != state) {
54         from_h1->state = state;
55     }
56 }
57
58 h2_response *h2_from_h1_get_response(h2_from_h1 *from_h1)
59 {
60     return from_h1->response;
61 }
62
63 static apr_status_t make_h2_headers(h2_from_h1 *from_h1, request_rec *r)
64 {
65     from_h1->response = h2_response_create(from_h1->stream_id, 0,
66                                            from_h1->http_status, 
67                                            from_h1->hlines,
68                                            r->notes,
69                                            from_h1->pool);
70     from_h1->content_length = from_h1->response->content_length;
71     from_h1->chunked = r->chunked;
72     
73     ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, r->connection, APLOGNO(03197)
74                   "h2_from_h1(%d): converted headers, content-length: %d"
75                   ", chunked=%d",
76                   from_h1->stream_id, (int)from_h1->content_length, 
77                   (int)from_h1->chunked);
78     
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 */
82     return APR_SUCCESS;
83 }
84
85 static apr_status_t parse_header(h2_from_h1 *from_h1, ap_filter_t* f, 
86                                  char *line) {
87     (void)f;
88     
89     if (line[0] == ' ' || line[0] == '\t') {
90         char **plast;
91         /* continuation line from the header before this */
92         while (line[0] == ' ' || line[0] == '\t') {
93             ++line;
94         }
95         
96         plast = apr_array_pop(from_h1->hlines);
97         if (plast == NULL) {
98             /* not well formed */
99             return APR_EINVAL;
100         }
101         APR_ARRAY_PUSH(from_h1->hlines, const char*) = apr_psprintf(from_h1->pool, "%s %s", *plast, line);
102     }
103     else {
104         /* new header line */
105         APR_ARRAY_PUSH(from_h1->hlines, const char*) = apr_pstrdup(from_h1->pool, line);
106     }
107     return APR_SUCCESS;
108 }
109
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)
112 {
113     apr_status_t status;
114     if (!from_h1->bb) {
115         from_h1->bb = apr_brigade_create(from_h1->pool, f->c->bucket_alloc);
116     }
117     else {
118         apr_brigade_cleanup(from_h1->bb);                
119     }
120     status = apr_brigade_split_line(from_h1->bb, bb, 
121                                                  APR_BLOCK_READ, 
122                                                  HUGE_STRING_LEN);
123     if (status == APR_SUCCESS) {
124         --len;
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
128              * trailing crlf. */
129             line[len] = '\0';
130             if (len >= 2 && !strcmp(H2_CRLF, line + len - 2)) {
131                 len -= 2;
132                 line[len] = '\0';
133             }
134             
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);
139         }
140     }
141     return status;
142 }
143
144 apr_status_t h2_from_h1_read_response(h2_from_h1 *from_h1, ap_filter_t* f,
145                                       apr_bucket_brigade* bb)
146 {
147     apr_status_t status = APR_SUCCESS;
148     char line[HUGE_STRING_LEN];
149     
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.
158              */
159             status = ap_remove_output_filter_byhandle(f->r->output_filters, 
160                                                       "CHUNK");
161             if (status == APR_SUCCESS) {
162                 ap_remove_output_filter(f);
163             }
164         }
165         
166         return ap_pass_brigade(f->next, bb);
167     }
168     
169     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
170                   "h2_from_h1(%d): read_response", from_h1->stream_id);
171     
172     while (!APR_BRIGADE_EMPTY(bb) && status == APR_SUCCESS) {
173         
174         switch (from_h1->state) {
175                 
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) {
180                     return status;
181                 }
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;
186                 }
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
190                      * chain.
191                      */
192                     status = make_h2_headers(from_h1, f->r);
193                     if (from_h1->bb) {
194                         apr_brigade_destroy(from_h1->bb);
195                         from_h1->bb = NULL;
196                     }
197                     if (!APR_BRIGADE_EMPTY(bb)) {
198                         return ap_pass_brigade(f->next, bb);
199                     }
200                 }
201                 else {
202                     status = parse_header(from_h1, f, line);
203                 }
204                 break;
205                 
206             default:
207                 return ap_pass_brigade(f->next, bb);
208         }
209         
210     }
211     
212     return status;
213 }
214
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.
220  */
221 static int uniq_field_values(void *d, const char *key, const char *val)
222 {
223     apr_array_header_t *values;
224     char *start;
225     char *e;
226     char **strpp;
227     int  i;
228     
229     (void)key;
230     values = (apr_array_header_t *)d;
231     
232     e = apr_pstrdup(values->pool, val);
233     
234     do {
235         /* Find a non-empty fieldname */
236         
237         while (*e == ',' || apr_isspace(*e)) {
238             ++e;
239         }
240         if (*e == '\0') {
241             break;
242         }
243         start = e;
244         while (*e != '\0' && *e != ',' && !apr_isspace(*e)) {
245             ++e;
246         }
247         if (*e != '\0') {
248             *e++ = '\0';
249         }
250         
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.
253          */
254         for (i = 0, strpp = (char **) values->elts; i < values->nelts;
255              ++i, ++strpp) {
256             if (*strpp && apr_strnatcasecmp(*strpp, start) == 0) {
257                 break;
258             }
259         }
260         if (i == values->nelts) {  /* if not found */
261             *(char **)apr_array_push(values) = start;
262         }
263     } while (*e != '\0');
264     
265     return 1;
266 }
267
268 /*
269  * Since some clients choke violently on multiple Vary fields, or
270  * Vary fields with duplicate tokens, combine any multiples and remove
271  * any duplicates.
272  */
273 static void fix_vary(request_rec *r)
274 {
275     apr_array_header_t *varies;
276     
277     varies = apr_array_make(r->pool, 5, sizeof(char *));
278     
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.
282      */
283     apr_table_do((int (*)(void *, const char *, const char *))uniq_field_values,
284                  (void *) varies, r->headers_out, "Vary", NULL);
285     
286     /* If we found any, replace old Vary fields with unique-ified value */
287     
288     if (varies->nelts > 0) {
289         apr_table_setn(r->headers_out, "Vary",
290                        apr_array_pstrcat(r->pool, varies, ','));
291     }
292 }
293
294 void h2_from_h1_set_basic_http_header(apr_table_t *headers, request_rec *r,
295                                       apr_pool_t *pool)
296 {
297     char *date = NULL;
298     const char *proxy_date = NULL;
299     const char *server = NULL;
300     const char *us = ap_get_server_banner();
301     
302     /*
303      * keep the set-by-proxy server and date headers, otherwise
304      * generate a new server header / date header
305      */
306     if (r && r->proxyreq != PROXYREQ_NONE) {
307         proxy_date = apr_table_get(r->headers_out, "Date");
308         if (!proxy_date) {
309             /*
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.
313              */
314             date = apr_palloc(pool, APR_RFC822_DATE_LEN);
315             ap_recent_rfc822_date(date, r->request_time);
316         }
317         server = apr_table_get(r->headers_out, "Server");
318     }
319     else {
320         date = apr_palloc(pool, APR_RFC822_DATE_LEN);
321         ap_recent_rfc822_date(date, r? r->request_time : apr_time_now());
322     }
323     
324     apr_table_setn(headers, "Date", proxy_date ? proxy_date : date );
325     if (r) {
326         apr_table_unset(r->headers_out, "Date");
327     }
328     
329     if (!server && *us) {
330         server = us;
331     }
332     if (server) {
333         apr_table_setn(headers, "Server", server);
334         if (r) {
335             apr_table_unset(r->headers_out, "Server");
336         }
337     }
338 }
339
340 static int copy_header(void *ctx, const char *name, const char *value)
341 {
342     apr_table_t *headers = ctx;
343     
344     apr_table_addn(headers, name, value);
345     return 1;
346 }
347
348 static h2_response *create_response(h2_from_h1 *from_h1, request_rec *r)
349 {
350     const char *clheader;
351     const char *ctype;
352     apr_table_t *headers;
353     /*
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.
357      */
358     if (!apr_is_empty_table(r->err_headers_out)) {
359         r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
360                                            r->headers_out);
361         apr_table_clear(r->err_headers_out);
362     }
363     
364     /*
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.
368      */
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");
373     }
374     else {
375         fix_vary(r);
376     }
377     
378     /*
379      * Now remove any ETag response header field if earlier processing
380      * says so (such as a 'FileETag None' directive).
381      */
382     if (apr_table_get(r->notes, "no-etag") != NULL) {
383         apr_table_unset(r->headers_out, "ETag");
384     }
385     
386     /* determine the protocol and whether we should use keepalives. */
387     ap_set_keepalive(r);
388     
389     if (r->chunked) {
390         apr_table_unset(r->headers_out, "Content-Length");
391     }
392     
393     ctype = ap_make_content_type(r, r->content_type);
394     if (ctype) {
395         apr_table_setn(r->headers_out, "Content-Type", ctype);
396     }
397     
398     if (r->content_encoding) {
399         apr_table_setn(r->headers_out, "Content-Encoding",
400                        r->content_encoding);
401     }
402     
403     if (!apr_is_empty_array(r->content_languages)) {
404         unsigned int i;
405         char *token;
406         char **languages = (char **)(r->content_languages->elts);
407         const char *field = apr_table_get(r->headers_out, "Content-Language");
408         
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]))
412                     break;
413             }
414             if (i == r->content_languages->nelts) {
415                 *((char **) apr_array_push(r->content_languages)) = token;
416             }
417         }
418         
419         field = apr_array_pstrcat(r->pool, r->content_languages, ',');
420         apr_table_setn(r->headers_out, "Content-Language", field);
421     }
422     
423     /*
424      * Control cachability for non-cachable responses if not already set by
425      * some other part of the server configuration.
426      */
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);
431     }
432     
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
444      */
445     if (r->header_only
446         && (clheader = apr_table_get(r->headers_out, "Content-Length"))
447         && !strcmp(clheader, "0")) {
448         apr_table_unset(r->headers_out, "Content-Length");
449     }
450     
451     headers = apr_table_make(r->pool, 10);
452     
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,
457                      "ETag",
458                      "Content-Location",
459                      "Expires",
460                      "Cache-Control",
461                      "Vary",
462                      "Warning",
463                      "WWW-Authenticate",
464                      "Proxy-Authenticate",
465                      "Set-Cookie",
466                      "Set-Cookie2",
467                      NULL);
468     }
469     else {
470         apr_table_do((int (*)(void *, const char *, const char *)) copy_header,
471                      (void *) headers, r->headers_out, NULL);
472     }
473     
474     return h2_response_rcreate(from_h1->stream_id, r, headers, r->pool);
475 }
476
477 apr_status_t h2_response_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
478 {
479     h2_task *task = f->ctx;
480     h2_from_h1 *from_h1 = task->output.from_h1;
481     request_rec *r = f->r;
482     apr_bucket *b;
483     ap_bucket_error *eb = NULL;
484
485     AP_DEBUG_ASSERT(from_h1 != NULL);
486     
487     ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, f->c,
488                   "h2_from_h1(%d): output_filter called", from_h1->stream_id);
489     
490     if (r->header_only && from_h1->response) {
491         /* throw away any data after we have compiled the response */
492         apr_brigade_cleanup(bb);
493         return OK;
494     }
495     
496     for (b = APR_BRIGADE_FIRST(bb);
497          b != APR_BRIGADE_SENTINEL(bb);
498          b = APR_BUCKET_NEXT(b))
499     {
500         if (AP_BUCKET_IS_ERROR(b) && !eb) {
501             eb = b->data;
502             continue;
503         }
504         /*
505          * If we see an EOC bucket it is a signal that we should get out
506          * of the way doing nothing.
507          */
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", 
512                           from_h1->stream_id);
513             return ap_pass_brigade(f->next, bb);
514         }
515     }
516     
517     if (eb) {
518         int st = eb->status;
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);
523         ap_die(st, r);
524         return AP_FILTER_ERROR;
525     }
526     
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", 
531                       from_h1->stream_id);
532         return APR_ENOMEM;
533     }
534     
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", 
538                       from_h1->stream_id);
539         apr_brigade_cleanup(bb);
540         return OK;
541     }
542     
543     r->sent_bodyct = 1;         /* Whatever follows is real body stuff... */
544     
545     ap_remove_output_filter(f);
546     if (APLOGctrace1(f->c)) {
547         apr_off_t len = 0;
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);
552     }
553     return ap_pass_brigade(f->next, bb);
554 }
555
556 apr_status_t h2_response_trailers_filter(ap_filter_t *f, apr_bucket_brigade *bb)
557 {
558     h2_task *task = f->ctx;
559     h2_from_h1 *from_h1 = task->output.from_h1;
560     request_rec *r = f->r;
561     apr_bucket *b;
562  
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.
566          */
567         for (b = APR_BRIGADE_FIRST(bb);
568              b != APR_BRIGADE_SENTINEL(bb);
569              b = APR_BUCKET_NEXT(b))
570         {
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",
577                                   from_h1->stream_id);
578                     h2_response_set_trailers(from_h1->response,
579                                              apr_table_clone(from_h1->pool, 
580                                                              r->trailers_out));
581                 }
582                 break;
583             }
584         }     
585     }
586      
587     return ap_pass_brigade(f->next, bb);
588 }
589