1 /*
2  * Copyright (c) 2014,2015 DeNA Co., Ltd., Kazuho Oku, Masahiro Nagano
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20  * IN THE SOFTWARE.
21  */
22 #include <netdb.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/socket.h>
26 #include "picohttpparser.h"
27 #include "h2o.h"
28 #include "h2o/http1.h"
29 #include "h2o/httpclient.h"
30 
31 struct rp_generator_t {
32     h2o_generator_t super;
33     h2o_req_t *src_req;
34     h2o_httpclient_t *client;
35     struct {
36         h2o_iovec_t bufs[2]; /* first buf is the request line and headers, the second is the POST content */
37         int is_head;
38     } up_req;
39     h2o_buffer_t *last_content_before_send;
40     h2o_doublebuffer_t sending;
41     h2o_timer_t send_headers_timeout;
42     unsigned had_body_error : 1; /* set if an error happened while fetching the body so that we can propagate the error */
43     unsigned req_done : 1;
44     unsigned res_done : 1;
45 };
46 
get_client_ctx(h2o_req_t * req)47 static h2o_httpclient_ctx_t *get_client_ctx(h2o_req_t *req)
48 {
49     h2o_req_overrides_t *overrides = req->overrides;
50     if (overrides != NULL && overrides->client_ctx != NULL)
51         return overrides->client_ctx;
52     return &req->conn->ctx->proxy.client_ctx;
53 }
54 
rewrite_location(h2o_mem_pool_t * pool,const char * location,size_t location_len,h2o_url_t * match,const h2o_url_scheme_t * req_scheme,h2o_iovec_t req_authority,h2o_iovec_t req_basepath)55 static h2o_iovec_t rewrite_location(h2o_mem_pool_t *pool, const char *location, size_t location_len, h2o_url_t *match,
56                                     const h2o_url_scheme_t *req_scheme, h2o_iovec_t req_authority, h2o_iovec_t req_basepath)
57 {
58     h2o_url_t loc_parsed;
59 
60     if (h2o_url_parse(location, location_len, &loc_parsed) != 0)
61         goto NoRewrite;
62     if (loc_parsed.scheme != &H2O_URL_SCHEME_HTTP)
63         goto NoRewrite;
64     if (!h2o_url_hosts_are_equal(&loc_parsed, match))
65         goto NoRewrite;
66     if (h2o_url_get_port(&loc_parsed) != h2o_url_get_port(match))
67         goto NoRewrite;
68     if (loc_parsed.path.len < match->path.len)
69         goto NoRewrite;
70     if (memcmp(loc_parsed.path.base, match->path.base, match->path.len) != 0)
71         goto NoRewrite;
72 
73     return h2o_concat(pool, req_scheme->name, h2o_iovec_init(H2O_STRLIT("://")), req_authority, req_basepath,
74                       h2o_iovec_init(loc_parsed.path.base + match->path.len, loc_parsed.path.len - match->path.len));
75 
76 NoRewrite:
77     return (h2o_iovec_t){NULL};
78 }
79 
build_request_merge_headers(h2o_mem_pool_t * pool,h2o_iovec_t merged,h2o_iovec_t added,int seperator)80 static h2o_iovec_t build_request_merge_headers(h2o_mem_pool_t *pool, h2o_iovec_t merged, h2o_iovec_t added, int seperator)
81 {
82     if (added.len == 0)
83         return merged;
84     if (merged.len == 0)
85         return added;
86 
87     size_t newlen = merged.len + 2 + added.len;
88     char *buf = h2o_mem_alloc_pool(pool, *buf, newlen);
89     memcpy(buf, merged.base, merged.len);
90     buf[merged.len] = seperator;
91     buf[merged.len + 1] = ' ';
92     memcpy(buf + merged.len + 2, added.base, added.len);
93     merged.base = buf;
94     merged.len = newlen;
95     return merged;
96 }
97 
98 /*
99  * A request without neither Content-Length or Transfer-Encoding header implies a zero-length request body (see 6th rule of RFC 7230
100  * 3.3.3).
101  * OTOH, section 3.3.3 states:
102  *
103  *   A user agent SHOULD send a Content-Length in a request message when
104  *   no Transfer-Encoding is sent and the request method defines a meaning
105  *   for an enclosed payload body.  For example, a Content-Length header
106  *   field is normally sent in a POST request even when the value is 0
107  *   (indicating an empty payload body).  A user agent SHOULD NOT send a
108  *   Content-Length header field when the request message does not contain
109  *   a payload body and the method semantics do not anticipate such a
110  *   body.
111  *
112  * PUT and POST define a meaning for the payload body, let's emit a
113  * Content-Length header if it doesn't exist already, since the server
114  * might send a '411 Length Required' response.
115  *
116  * see also: ML thread starting at https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0580.html
117  */
req_requires_content_length(h2o_req_t * req)118 static int req_requires_content_length(h2o_req_t *req)
119 {
120     int is_put_or_post = (req->method.len >= 1 && req->method.base[0] == 'P' &&
121                           (h2o_memis(req->method.base, req->method.len, H2O_STRLIT("POST")) ||
122                            h2o_memis(req->method.base, req->method.len, H2O_STRLIT("PUT"))));
123 
124     return is_put_or_post && h2o_find_header(&req->res.headers, H2O_TOKEN_TRANSFER_ENCODING, -1) == -1;
125 }
126 
build_content_length(h2o_mem_pool_t * pool,size_t cl)127 static h2o_iovec_t build_content_length(h2o_mem_pool_t *pool, size_t cl)
128 {
129     h2o_iovec_t cl_buf;
130     cl_buf.base = h2o_mem_alloc_pool(pool, char, sizeof(H2O_SIZE_T_LONGEST_STR));
131     cl_buf.len = sprintf(cl_buf.base, "%zu", cl);
132     return cl_buf;
133 }
134 
build_request(h2o_req_t * req,h2o_iovec_t * method,h2o_url_t * url,h2o_headers_t * headers,h2o_httpclient_properties_t * props,int keepalive,const char * upgrade_to,int use_proxy_protocol,int * reprocess_if_too_early,h2o_url_t * origin)135 static void build_request(h2o_req_t *req, h2o_iovec_t *method, h2o_url_t *url, h2o_headers_t *headers,
136                           h2o_httpclient_properties_t *props, int keepalive, const char *upgrade_to, int use_proxy_protocol,
137                           int *reprocess_if_too_early, h2o_url_t *origin)
138 {
139     size_t remote_addr_len = SIZE_MAX;
140     char remote_addr[NI_MAXHOST];
141     struct sockaddr_storage ss;
142     socklen_t sslen;
143     h2o_iovec_t cookie_buf = {NULL}, xff_buf = {NULL}, via_buf = {NULL};
144     int preserve_x_forwarded_proto = req->conn->ctx->globalconf->proxy.preserve_x_forwarded_proto;
145     int emit_x_forwarded_headers = req->conn->ctx->globalconf->proxy.emit_x_forwarded_headers;
146     int emit_via_header = req->conn->ctx->globalconf->proxy.emit_via_header;
147 
148     /* for x-f-f */
149     if ((sslen = req->conn->callbacks->get_peername(req->conn, (void *)&ss)) != 0)
150         remote_addr_len = h2o_socket_getnumerichost((void *)&ss, sslen, remote_addr);
151 
152     if (props->proxy_protocol != NULL && use_proxy_protocol) {
153         props->proxy_protocol->base = h2o_mem_alloc_pool(&req->pool, char, H2O_PROXY_HEADER_MAX_LENGTH);
154         props->proxy_protocol->len = h2o_stringify_proxy_header(req->conn, props->proxy_protocol->base);
155     }
156 
157     /* method */
158     *method = h2o_strdup(&req->pool, req->method.base, req->method.len);
159 
160     /* url */
161     h2o_url_init(url, origin->scheme, req->authority, h2o_strdup(&req->pool, req->path.base, req->path.len));
162 
163     if (props->connection_header != NULL) {
164         if (upgrade_to != NULL && upgrade_to != h2o_httpclient_upgrade_to_connect) {
165             *props->connection_header = h2o_iovec_init(H2O_STRLIT("upgrade"));
166             h2o_add_header(&req->pool, headers, H2O_TOKEN_UPGRADE, NULL, upgrade_to, strlen(upgrade_to));
167         } else if (keepalive) {
168             *props->connection_header = h2o_iovec_init(H2O_STRLIT("keep-alive"));
169         } else {
170             *props->connection_header = h2o_iovec_init(H2O_STRLIT("close"));
171         }
172     }
173 
174     /* setup CL or TE, if necessary; chunked encoding is used when the request body is stream and content-length is unknown */
175     if (!req->is_tunnel_req) {
176         if (req->proceed_req == NULL) {
177             if (req->entity.base != NULL || req_requires_content_length(req)) {
178                 h2o_iovec_t cl_buf = build_content_length(&req->pool, req->entity.len);
179                 h2o_add_header(&req->pool, headers, H2O_TOKEN_CONTENT_LENGTH, NULL, cl_buf.base, cl_buf.len);
180             }
181         } else {
182             if (req->content_length != SIZE_MAX) {
183                 h2o_iovec_t cl_buf = build_content_length(&req->pool, req->content_length);
184                 h2o_add_header(&req->pool, headers, H2O_TOKEN_CONTENT_LENGTH, NULL, cl_buf.base, cl_buf.len);
185             } else if (props->chunked != NULL) {
186                 *props->chunked = 1;
187                 h2o_add_header(&req->pool, headers, H2O_TOKEN_TRANSFER_ENCODING, NULL, H2O_STRLIT("chunked"));
188             }
189         }
190     }
191 
192     /* headers */
193     {
194         const h2o_header_t *h, *h_end;
195         int found_early_data = 0;
196         for (h = req->headers.entries, h_end = h + req->headers.size; h != h_end; ++h) {
197             if (h2o_iovec_is_token(h->name)) {
198                 const h2o_token_t *token = (void *)h->name;
199                 if (token->flags.proxy_should_drop_for_req)
200                     continue;
201                 if (token == H2O_TOKEN_COOKIE) {
202                     /* merge the cookie headers; see HTTP/2 8.1.2.5 and HTTP/1 (RFC6265 5.4) */
203                     /* FIXME current algorithm is O(n^2) against the number of cookie headers */
204                     cookie_buf = build_request_merge_headers(&req->pool, cookie_buf, h->value, ';');
205                     continue;
206                 } else if (token == H2O_TOKEN_VIA) {
207                     if (!emit_via_header) {
208                         goto AddHeader;
209                     }
210                     via_buf = build_request_merge_headers(&req->pool, via_buf, h->value, ',');
211                     continue;
212                 } else if (token == H2O_TOKEN_X_FORWARDED_FOR) {
213                     if (!emit_x_forwarded_headers) {
214                         goto AddHeader;
215                     }
216                     xff_buf = build_request_merge_headers(&req->pool, xff_buf, h->value, ',');
217                     continue;
218                 } else if (token == H2O_TOKEN_EARLY_DATA) {
219                     found_early_data = 1;
220                     goto AddHeader;
221                 }
222             }
223             if (!preserve_x_forwarded_proto && h2o_lcstris(h->name->base, h->name->len, H2O_STRLIT("x-forwarded-proto")))
224                 continue;
225         AddHeader:
226             if (h2o_iovec_is_token(h->name)) {
227                 const h2o_token_t *token = (void *)h->name;
228                 h2o_add_header(&req->pool, headers, token, h->orig_name, h->value.base, h->value.len);
229             } else {
230                 h2o_add_header_by_str(&req->pool, headers, h->name->base, h->name->len, 0, h->orig_name, h->value.base,
231                                       h->value.len);
232             }
233         }
234         if (found_early_data) {
235             *reprocess_if_too_early = 0;
236         } else if (*reprocess_if_too_early) {
237             h2o_add_header(&req->pool, headers, H2O_TOKEN_EARLY_DATA, NULL, H2O_STRLIT("1"));
238         }
239     }
240 
241     if (cookie_buf.len != 0) {
242         h2o_add_header(&req->pool, headers, H2O_TOKEN_COOKIE, NULL, cookie_buf.base, cookie_buf.len);
243     }
244     if (emit_x_forwarded_headers) {
245         if (!preserve_x_forwarded_proto)
246             h2o_add_header_by_str(&req->pool, headers, H2O_STRLIT("x-forwarded-proto"), 0, NULL, req->input.scheme->name.base,
247                                   req->input.scheme->name.len);
248         if (remote_addr_len != SIZE_MAX)
249             xff_buf = build_request_merge_headers(&req->pool, xff_buf, h2o_strdup(&req->pool, remote_addr, remote_addr_len), ',');
250         if (xff_buf.len != 0)
251             h2o_add_header(&req->pool, headers, H2O_TOKEN_X_FORWARDED_FOR, NULL, xff_buf.base, xff_buf.len);
252     }
253     if (emit_via_header) {
254         h2o_iovec_t added;
255         added.base = h2o_mem_alloc_pool(&req->pool, char, sizeof("1.1 ") - 1 + req->input.authority.len);
256         added.len = 0;
257 
258         if (req->version < 0x200) {
259             added.base[added.len++] = '1';
260             added.base[added.len++] = '.';
261             added.base[added.len++] = '0' + (0x100 <= req->version && req->version <= 0x109 ? req->version - 0x100 : 0);
262         } else {
263             added.base[added.len++] = '0' + req->version / 0x100;
264         }
265         added.base[added.len++] = ' ';
266         memcpy(added.base + added.len, req->input.authority.base, req->input.authority.len);
267         added.len += req->input.authority.len;
268 
269         via_buf = build_request_merge_headers(&req->pool, via_buf, added, ',');
270         h2o_add_header(&req->pool, headers, H2O_TOKEN_VIA, NULL, via_buf.base, via_buf.len);
271     }
272 
273     /* rewrite headers if necessary */
274     if (req->overrides != NULL && req->overrides->headers_cmds != NULL) {
275         h2o_headers_command_t *cmd;
276         for (cmd = req->overrides->headers_cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd)
277             h2o_rewrite_headers(&req->pool, headers, cmd);
278     }
279 }
280 
detach_client(struct rp_generator_t * self)281 static h2o_httpclient_t *detach_client(struct rp_generator_t *self)
282 {
283     h2o_httpclient_t *client = self->client;
284     assert(client != NULL);
285     client->data = NULL;
286     self->client = NULL;
287     return client;
288 }
289 
do_close(struct rp_generator_t * self)290 static void do_close(struct rp_generator_t *self)
291 {
292     /**
293      * This can be called in the following three scenarios:
294      *   1. Downstream timeout before receiving header from upstream
295      *        dispose callback calls this function, but stop callback doesn't
296      *   2. Reprocess
297      *        stop callback calls this, but dispose callback does it later (after reprocessed request gets finished)
298      *   3. Others
299      *        Both of stop and dispose callbacks call this function in order
300      * Thus, to ensure to do closing things, both of dispose and stop callbacks call this function.
301      */
302     if (self->client != NULL) {
303         h2o_httpclient_t *client = detach_client(self);
304         client->cancel(client);
305     }
306     h2o_timer_unlink(&self->send_headers_timeout);
307 }
308 
do_stop(h2o_generator_t * generator,h2o_req_t * req)309 static void do_stop(h2o_generator_t *generator, h2o_req_t *req)
310 {
311     struct rp_generator_t *self = (void *)generator;
312     do_close(self);
313 }
314 
do_send(struct rp_generator_t * self)315 static void do_send(struct rp_generator_t *self)
316 {
317     h2o_iovec_t vecs[1];
318     size_t veccnt;
319     h2o_send_state_t ststate;
320 
321     vecs[0] = h2o_doublebuffer_prepare(&self->sending,
322                                        self->last_content_before_send != NULL ? &self->last_content_before_send : self->client->buf,
323                                        self->src_req->preferred_chunk_size);
324 
325     if (self->last_content_before_send != NULL && vecs[0].len == self->sending.buf->size &&
326         self->last_content_before_send->size == 0) {
327         veccnt = vecs[0].len != 0 ? 1 : 0;
328         ststate = H2O_SEND_STATE_FINAL;
329     } else {
330         if (vecs[0].len == 0)
331             return;
332         veccnt = 1;
333         ststate = H2O_SEND_STATE_IN_PROGRESS;
334     }
335 
336     if (self->had_body_error)
337         ststate = H2O_SEND_STATE_ERROR;
338 
339     h2o_send(self->src_req, vecs, veccnt, ststate);
340 }
341 
do_proceed(h2o_generator_t * generator,h2o_req_t * req)342 static void do_proceed(h2o_generator_t *generator, h2o_req_t *req)
343 {
344     struct rp_generator_t *self = (void *)generator;
345 
346     h2o_doublebuffer_consume(&self->sending);
347     do_send(self);
348     if (self->last_content_before_send == NULL)
349         self->client->update_window(self->client);
350 }
351 
copy_stats(struct rp_generator_t * self)352 static void copy_stats(struct rp_generator_t *self)
353 {
354     self->src_req->proxy_stats.timestamps = self->client->timings;
355     self->src_req->proxy_stats.bytes_written.total = self->client->bytes_written.total;
356     self->src_req->proxy_stats.bytes_written.header = self->client->bytes_written.header;
357     self->src_req->proxy_stats.bytes_written.body = self->client->bytes_written.body;
358     self->src_req->proxy_stats.bytes_read.total = self->client->bytes_read.total;
359     self->src_req->proxy_stats.bytes_read.header = self->client->bytes_read.header;
360     self->src_req->proxy_stats.bytes_read.body = self->client->bytes_read.body;
361 }
362 
on_body(h2o_httpclient_t * client,const char * errstr)363 static int on_body(h2o_httpclient_t *client, const char *errstr)
364 {
365     struct rp_generator_t *self = client->data;
366 
367     h2o_timer_unlink(&self->send_headers_timeout);
368 
369     if (errstr != NULL) {
370         copy_stats(self);
371 
372         /* detach the content */
373         self->last_content_before_send = *self->client->buf;
374         h2o_buffer_init(self->client->buf, &h2o_socket_buffer_prototype);
375         if (errstr == h2o_httpclient_error_is_eos) {
376             self->res_done = 1;
377             if (self->req_done)
378                 detach_client(self);
379         } else {
380             detach_client(self);
381             h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr);
382             self->had_body_error = 1;
383             if (self->src_req->proceed_req != NULL)
384                 self->src_req->proceed_req(self->src_req, errstr);
385         }
386     }
387     if (!self->sending.inflight)
388         do_send(self);
389 
390     return 0;
391 }
392 
compress_hint_to_enum(const char * val,size_t len)393 static char compress_hint_to_enum(const char *val, size_t len)
394 {
395     if (h2o_lcstris(val, len, H2O_STRLIT("on"))) {
396         return H2O_COMPRESS_HINT_ENABLE;
397     }
398     if (h2o_lcstris(val, len, H2O_STRLIT("off"))) {
399         return H2O_COMPRESS_HINT_DISABLE;
400     }
401     if (h2o_lcstris(val, len, H2O_STRLIT("gzip"))) {
402         return H2O_COMPRESS_HINT_ENABLE_GZIP;
403     }
404     if (h2o_lcstris(val, len, H2O_STRLIT("br"))) {
405         return H2O_COMPRESS_HINT_ENABLE_BR;
406     }
407     return H2O_COMPRESS_HINT_AUTO;
408 }
409 
on_send_headers_timeout(h2o_timer_t * entry)410 static void on_send_headers_timeout(h2o_timer_t *entry)
411 {
412     struct rp_generator_t *self = H2O_STRUCT_FROM_MEMBER(struct rp_generator_t, send_headers_timeout, entry);
413     h2o_doublebuffer_prepare_empty(&self->sending);
414     h2o_send(self->src_req, NULL, 0, H2O_SEND_STATE_IN_PROGRESS);
415 }
416 
on_head(h2o_httpclient_t * client,const char * errstr,h2o_httpclient_on_head_t * args)417 static h2o_httpclient_body_cb on_head(h2o_httpclient_t *client, const char *errstr, h2o_httpclient_on_head_t *args)
418 {
419     struct rp_generator_t *self = client->data;
420     h2o_req_t *req = self->src_req;
421     size_t i;
422     int emit_missing_date_header = req->conn->ctx->globalconf->proxy.emit_missing_date_header;
423     int seen_date_header = 0;
424 
425     copy_stats(self);
426 
427     if (errstr != NULL && errstr != h2o_httpclient_error_is_eos) {
428         detach_client(self);
429         h2o_req_log_error(req, "lib/core/proxy.c", "%s", errstr);
430 
431         if (errstr == h2o_httpclient_error_refused_stream) {
432             req->upstream_refused = 1;
433             static h2o_generator_t generator = {NULL, NULL};
434             h2o_start_response(req, &generator);
435             h2o_send(req, NULL, 0, H2O_SEND_STATE_ERROR);
436         } else {
437             h2o_send_error_502(req, "Gateway Error", errstr, 0);
438             if (self->src_req->proceed_req != NULL)
439                 self->src_req->proceed_req(self->src_req, h2o_httpclient_error_refused_stream);
440         }
441 
442         return NULL;
443     }
444 
445     /* copy the response (note: all the headers must be copied; http1client discards the input once we return from this callback) */
446     req->res.status = args->status;
447     req->res.reason = h2o_strdup(&req->pool, args->msg.base, args->msg.len).base;
448     for (i = 0; i != args->num_headers; ++i) {
449         h2o_iovec_t value = args->headers[i].value;
450         if (h2o_iovec_is_token(args->headers[i].name)) {
451             const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, args->headers[i].name);
452             if (token->flags.proxy_should_drop_for_res) {
453                 if (token == H2O_TOKEN_CONNECTION && self->src_req->version < 0x200 &&
454                     req->conn->ctx->globalconf->proxy.forward_close_connection) {
455                     if (h2o_lcstris(args->headers[i].value.base, args->headers[i].value.len, H2O_STRLIT("close")))
456                         self->src_req->http1_is_persistent = 0;
457                 }
458                 continue;
459             }
460             if (token == H2O_TOKEN_CONTENT_LENGTH) {
461                 if (req->res.content_length != SIZE_MAX ||
462                     (req->res.content_length = h2o_strtosize(args->headers[i].value.base, args->headers[i].value.len)) ==
463                         SIZE_MAX) {
464                     detach_client(self);
465                     h2o_req_log_error(req, "lib/core/proxy.c", "%s", "invalid response from upstream (malformed content-length)");
466                     h2o_send_error_502(req, "Gateway Error", "invalid response from upstream", 0);
467                     if (self->src_req->proceed_req != NULL)
468                         self->src_req->proceed_req(self->src_req, h2o_httpclient_error_io);
469                     return NULL;
470                 }
471                 goto Skip;
472             } else if (token == H2O_TOKEN_LOCATION) {
473                 if (req->res_is_delegated && (300 <= args->status && args->status <= 399) && args->status != 304) {
474                     detach_client(self);
475                     h2o_iovec_t method = h2o_get_redirect_method(req->method, args->status);
476                     h2o_send_redirect_internal(req, method, args->headers[i].value.base, args->headers[i].value.len, 1);
477                     return NULL;
478                 }
479                 if (req->overrides != NULL && req->overrides->location_rewrite.match != NULL) {
480                     h2o_iovec_t new_value =
481                         rewrite_location(&req->pool, value.base, value.len, req->overrides->location_rewrite.match,
482                                          req->input.scheme, req->input.authority, req->overrides->location_rewrite.path_prefix);
483                     if (new_value.base != NULL) {
484                         value = new_value;
485                         goto AddHeader;
486                     }
487                 }
488             } else if (token == H2O_TOKEN_LINK) {
489                 value = h2o_push_path_in_link_header(req, value.base, value.len);
490                 if (!value.len)
491                     goto Skip;
492             } else if (token == H2O_TOKEN_SERVER) {
493                 if (!req->conn->ctx->globalconf->proxy.preserve_server_header)
494                     goto Skip;
495             } else if (token == H2O_TOKEN_X_COMPRESS_HINT) {
496                 req->compress_hint = compress_hint_to_enum(value.base, value.len);
497                 goto Skip;
498             } else if (token == H2O_TOKEN_DATE) {
499                 seen_date_header = 1;
500             }
501             if (args->header_requires_dup)
502                 value = h2o_strdup(&req->pool, value.base, value.len);
503         AddHeader:
504             h2o_add_header(&req->pool, &req->res.headers, token, args->headers[i].orig_name, value.base, value.len);
505         Skip:;
506         } else {
507             h2o_iovec_t name = *args->headers[i].name;
508             if (args->header_requires_dup) {
509                 name = h2o_strdup(&req->pool, name.base, name.len);
510                 value = h2o_strdup(&req->pool, value.base, value.len);
511             }
512             h2o_add_header_by_str(&req->pool, &req->res.headers, name.base, name.len, 0, args->headers[i].orig_name, value.base,
513                                   value.len);
514         }
515     }
516 
517     if (!seen_date_header && emit_missing_date_header)
518         h2o_resp_add_date_header(req);
519 
520     if (req->upgrade.base != NULL && req->res.status == 101) {
521         assert(req->is_tunnel_req);
522         h2o_add_header(&req->pool, &req->res.headers, H2O_TOKEN_UPGRADE, NULL, req->upgrade.base, req->upgrade.len);
523     }
524 
525     /* declare the start of the response */
526     h2o_start_response(req, &self->super);
527 
528     if (errstr == h2o_httpclient_error_is_eos) {
529         self->res_done = 1;
530         if (self->req_done)
531             detach_client(self);
532         h2o_send(req, NULL, 0, H2O_SEND_STATE_FINAL);
533         return NULL; /* TODO this returning NULL causes keepalive to be disabled in http1client. is this what we intended? */
534     }
535 
536     /* if httpclient has no received body at this time, immediately send only headers using zero timeout */
537     h2o_timer_link(req->conn->ctx->loop, 0, &self->send_headers_timeout);
538 
539     return on_body;
540 }
541 
on_1xx(h2o_httpclient_t * client,int version,int status,h2o_iovec_t msg,h2o_header_t * headers,size_t num_headers)542 static int on_1xx(h2o_httpclient_t *client, int version, int status, h2o_iovec_t msg, h2o_header_t *headers, size_t num_headers)
543 {
544     struct rp_generator_t *self = client->data;
545     size_t i;
546 
547     for (i = 0; i != num_headers; ++i) {
548         if (headers[i].name == &H2O_TOKEN_LINK->buf)
549             h2o_push_path_in_link_header(self->src_req, headers[i].value.base, headers[i].value.len);
550     }
551 
552     if (status != 101) {
553         self->src_req->res.status = status;
554         self->src_req->res.headers = (h2o_headers_t){headers, num_headers, num_headers};
555         h2o_send_informational(self->src_req);
556     }
557 
558     return 0;
559 }
560 
proceed_request(h2o_httpclient_t * client,const char * errstr)561 static void proceed_request(h2o_httpclient_t *client, const char *errstr)
562 {
563     struct rp_generator_t *self = client->data;
564     if (self == NULL)
565         return;
566     if (errstr != NULL)
567         detach_client(self);
568     if (self->src_req->proceed_req != NULL)
569         self->src_req->proceed_req(self->src_req, errstr);
570 }
571 
write_req(void * ctx,int is_end_stream)572 static int write_req(void *ctx, int is_end_stream)
573 {
574     struct rp_generator_t *self = ctx;
575     h2o_httpclient_t *client = self->client;
576     h2o_iovec_t chunk = self->src_req->entity;
577 
578     assert(chunk.len != 0 || is_end_stream);
579 
580     if (client == NULL) {
581         return -1;
582     }
583 
584     if (is_end_stream) {
585         self->src_req->write_req.cb = NULL;
586         self->req_done = 1;
587         if (self->res_done)
588             detach_client(self);
589     }
590 
591     return client->write_req(client, chunk, is_end_stream);
592 }
593 
on_connect(h2o_httpclient_t * client,const char * errstr,h2o_iovec_t * method,h2o_url_t * url,const h2o_header_t ** headers,size_t * num_headers,h2o_iovec_t * body,h2o_httpclient_proceed_req_cb * proceed_req_cb,h2o_httpclient_properties_t * props,h2o_url_t * origin)594 static h2o_httpclient_head_cb on_connect(h2o_httpclient_t *client, const char *errstr, h2o_iovec_t *method, h2o_url_t *url,
595                                          const h2o_header_t **headers, size_t *num_headers, h2o_iovec_t *body,
596                                          h2o_httpclient_proceed_req_cb *proceed_req_cb, h2o_httpclient_properties_t *props,
597                                          h2o_url_t *origin)
598 {
599     struct rp_generator_t *self = client->data;
600     h2o_req_t *req = self->src_req;
601     int use_proxy_protocol = 0, reprocess_if_too_early = 0;
602 
603     copy_stats(self);
604 
605     if (errstr != NULL) {
606         detach_client(self);
607         h2o_req_log_error(self->src_req, "lib/core/proxy.c", "%s", errstr);
608         h2o_send_error_502(self->src_req, "Gateway Error", errstr, 0);
609         return NULL;
610     }
611 
612     assert(origin != NULL);
613 
614     if (req->overrides != NULL) {
615         use_proxy_protocol = req->overrides->use_proxy_protocol;
616         req->overrides->location_rewrite.match = origin;
617         if (!req->overrides->proxy_preserve_host) {
618             req->scheme = origin->scheme;
619             req->authority = origin->authority;
620         }
621         h2o_iovec_t append = req->path;
622         if (origin->path.base[origin->path.len - 1] == '/' && append.base[0] == '/') {
623             append.base += 1;
624             append.len -= 1;
625         }
626         req->path = h2o_concat(&req->pool, origin->path, append);
627         req->path_normalized =
628             h2o_url_normalize_path(&req->pool, req->path.base, req->path.len, &req->query_at, &req->norm_indexes);
629     }
630 
631     reprocess_if_too_early = h2o_conn_is_early_data(req->conn);
632     h2o_headers_t headers_vec = (h2o_headers_t){NULL};
633     build_request(req, method, url, &headers_vec, props,
634                   !use_proxy_protocol && h2o_socketpool_can_keepalive(client->connpool->socketpool), self->client->upgrade_to,
635                   use_proxy_protocol, &reprocess_if_too_early, origin);
636     *headers = headers_vec.entries;
637     *num_headers = headers_vec.size;
638 
639     if (reprocess_if_too_early)
640         req->reprocess_if_too_early = 1;
641 
642     *body = h2o_iovec_init(NULL, 0);
643     *proceed_req_cb = NULL;
644     self->req_done = 1;
645     if (self->src_req->entity.base != NULL) {
646         *body = self->src_req->entity;
647         if (self->src_req->proceed_req != NULL) {
648             *proceed_req_cb = proceed_request;
649             self->src_req->write_req.cb = write_req;
650             self->src_req->write_req.ctx = self;
651             self->req_done = 0;
652         }
653     }
654     self->client->informational_cb = on_1xx;
655 
656     client->get_conn_properties(client, &req->proxy_stats.conn);
657 
658     return on_head;
659 }
660 
on_generator_dispose(void * _self)661 static void on_generator_dispose(void *_self)
662 {
663     struct rp_generator_t *self = _self;
664     do_close(self);
665 
666     if (self->last_content_before_send != NULL) {
667         h2o_buffer_dispose(&self->last_content_before_send);
668     }
669     h2o_doublebuffer_dispose(&self->sending);
670 }
671 
proxy_send_prepare(h2o_req_t * req)672 static struct rp_generator_t *proxy_send_prepare(h2o_req_t *req)
673 {
674     struct rp_generator_t *self = h2o_mem_alloc_shared(&req->pool, sizeof(*self), on_generator_dispose);
675 
676     self->super.proceed = do_proceed;
677     self->super.stop = do_stop;
678     self->src_req = req;
679     self->client = NULL; /* when connection establish timeouts, self->client remains unset by `h2o_httpclient_connect` */
680     self->had_body_error = 0;
681     self->up_req.is_head = h2o_memis(req->method.base, req->method.len, H2O_STRLIT("HEAD"));
682     self->last_content_before_send = NULL;
683     h2o_doublebuffer_init(&self->sending, &h2o_socket_buffer_prototype);
684     memset(&req->proxy_stats, 0, sizeof(req->proxy_stats));
685     h2o_timer_init(&self->send_headers_timeout, on_send_headers_timeout);
686     self->req_done = 0;
687     self->res_done = 0;
688 
689     return self;
690 }
691 
h2o__proxy_process_request(h2o_req_t * req)692 void h2o__proxy_process_request(h2o_req_t *req)
693 {
694     h2o_req_overrides_t *overrides = req->overrides;
695     h2o_httpclient_ctx_t *client_ctx = get_client_ctx(req);
696     h2o_url_t target_buf, *target = &target_buf;
697 
698     h2o_httpclient_connection_pool_t *connpool = &req->conn->ctx->proxy.connpool;
699     if (overrides != NULL && overrides->connpool != NULL) {
700         connpool = overrides->connpool;
701         if (!overrides->proxy_preserve_host)
702             target = NULL;
703     }
704     if (target == &target_buf)
705         h2o_url_init(&target_buf, req->scheme, req->authority, h2o_iovec_init(H2O_STRLIT("/")));
706 
707     const char *upgrade_to = NULL;
708     if (req->is_tunnel_req) {
709         if (req->upgrade.base != NULL) {
710             /* upgrade requests (e.g. websocket) are either tunnelled or converted to a normal request (by omitting the Upgrade
711              * header field)  depending on the configuration */
712             if (client_ctx->tunnel_enabled)
713                 upgrade_to = h2o_strdup(&req->pool, req->upgrade.base, req->upgrade.len).base;
714         } else {
715             /* CONNECT request; process as a CONNECT upgrade or reject */
716             if (client_ctx->tunnel_enabled) {
717                 upgrade_to = h2o_httpclient_upgrade_to_connect;
718             } else {
719                 h2o_send_error_405(req, "Method Not Allowed", "refusing CONNECT", H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION);
720                 return;
721             }
722         }
723     }
724     struct rp_generator_t *self = proxy_send_prepare(req);
725 
726     /*
727       When the PROXY protocol is being used (i.e. when overrides->use_proxy_protocol is set), the client needs to establish a new
728      connection even when there is a pooled connection to the peer, since the header (as defined in
729      https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) needs to be sent at the beginning of the connection.
730 
731      However, currently h2o_http1client_connect doesn't provide an interface to enforce estabilishing a new connection. In other
732      words, there is a chance that we would use a pool connection here.
733 
734      OTOH, the probability of seeing such issue is rare; it would only happen if the same destination identified by its host:port is
735      accessed in both ways (i.e. in one path with use_proxy_protocol set and in the other path without).
736 
737      So I leave this as it is for the time being.
738      */
739     h2o_httpclient_connect(&self->client, &req->pool, self, client_ctx, connpool, target, upgrade_to, on_connect);
740 }
741