/src/h2o/lib/handler/proxy.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2014,2015 DeNA Co., Ltd., 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 <sys/un.h> |
23 | | #include "h2o.h" |
24 | | #include "h2o/socketpool.h" |
25 | | #include "h2o/balancer.h" |
26 | | |
27 | | struct rp_handler_t { |
28 | | h2o_handler_t super; |
29 | | h2o_socketpool_t *sockpool; |
30 | | h2o_proxy_config_vars_t config; |
31 | | }; |
32 | | |
33 | | struct rp_handler_context_t { |
34 | | h2o_httpclient_connection_pool_t connpool; |
35 | | h2o_httpclient_ctx_t *client_ctx; |
36 | | }; |
37 | | |
38 | | static int on_req(h2o_handler_t *_self, h2o_req_t *req) |
39 | 3.91k | { |
40 | 3.91k | struct rp_handler_t *self = (void *)_self; |
41 | 3.91k | h2o_req_overrides_t *overrides = h2o_mem_alloc_pool(&req->pool, *overrides, 1); |
42 | 3.91k | struct rp_handler_context_t *handler_ctx = h2o_context_get_handler_context(req->conn->ctx, &self->super); |
43 | | |
44 | | /* setup overrides */ |
45 | 3.91k | *overrides = (h2o_req_overrides_t){NULL}; |
46 | 3.91k | overrides->connpool = &handler_ctx->connpool; |
47 | 3.91k | overrides->location_rewrite.path_prefix = req->pathconf->path; |
48 | 3.91k | overrides->use_proxy_protocol = self->config.use_proxy_protocol; |
49 | 3.91k | overrides->client_ctx = handler_ctx->client_ctx; |
50 | 3.91k | overrides->headers_cmds = self->config.headers_cmds; |
51 | 3.91k | overrides->proxy_preserve_host = self->config.preserve_host; |
52 | 3.91k | overrides->proxy_expect_mode = self->config.expect_mode; |
53 | 3.91k | overrides->forward_close_connection = self->config.forward_close_connection; |
54 | | |
55 | | /* request reprocess (note: path may become an empty string, to which one of the target URL within the socketpool will be |
56 | | * right-padded when lib/core/proxy connects to upstream; see #1563) */ |
57 | 3.91k | h2o_iovec_t path = h2o_build_destination(req, NULL, 0, 0); |
58 | 3.91k | h2o_reprocess_request(req, req->method, req->scheme, req->authority, path, overrides, 0); |
59 | | |
60 | 3.91k | return 0; |
61 | 3.91k | } |
62 | | |
63 | | static void on_context_init(h2o_handler_t *_self, h2o_context_t *ctx) |
64 | 3 | { |
65 | 3 | struct rp_handler_t *self = (void *)_self; |
66 | | |
67 | | /* use the loop of first context for handling socketpool timeouts */ |
68 | 3 | h2o_socketpool_register_loop(self->sockpool, ctx->loop); |
69 | | |
70 | 3 | struct rp_handler_context_t *handler_ctx = h2o_mem_alloc(sizeof(*handler_ctx)); |
71 | 3 | memset(handler_ctx, 0, sizeof(*handler_ctx)); |
72 | 3 | h2o_httpclient_connection_pool_init(&handler_ctx->connpool, self->sockpool); |
73 | 3 | h2o_context_set_handler_context(ctx, &self->super, handler_ctx); |
74 | | |
75 | | /* setup a specific client context only if we need to */ |
76 | 3 | if (ctx->globalconf->proxy.io_timeout == self->config.io_timeout && |
77 | 0 | ctx->globalconf->proxy.connect_timeout == self->config.connect_timeout && |
78 | 0 | ctx->globalconf->proxy.first_byte_timeout == self->config.first_byte_timeout && |
79 | 0 | ctx->globalconf->proxy.keepalive_timeout == self->config.keepalive_timeout && |
80 | 0 | ctx->globalconf->proxy.max_buffer_size == self->config.max_buffer_size && |
81 | 0 | ctx->globalconf->proxy.protocol_ratio.http2 == self->config.protocol_ratio.http2 && |
82 | 0 | ctx->globalconf->proxy.protocol_ratio.http3 == self->config.protocol_ratio.http3 && |
83 | 0 | ctx->globalconf->proxy.http3.ecn == self->config.http3.ecn && !self->config.tunnel_enabled) |
84 | 0 | return; |
85 | | |
86 | 3 | h2o_httpclient_ctx_t *client_ctx = h2o_mem_alloc(sizeof(*ctx)); |
87 | 3 | *client_ctx = (h2o_httpclient_ctx_t){ |
88 | 3 | .loop = ctx->loop, |
89 | 3 | .getaddr_receiver = &ctx->receivers.hostinfo_getaddr, |
90 | 3 | .io_timeout = self->config.io_timeout, |
91 | 3 | .connect_timeout = self->config.connect_timeout, |
92 | 3 | .first_byte_timeout = self->config.first_byte_timeout, |
93 | 3 | .keepalive_timeout = self->config.keepalive_timeout, |
94 | 3 | .max_buffer_size = self->config.max_buffer_size, |
95 | 3 | .tunnel_enabled = self->config.tunnel_enabled, |
96 | 3 | .protocol_selector = {.ratio = self->config.protocol_ratio}, |
97 | 3 | .force_cleartext_http2 = self->config.http2.force_cleartext, |
98 | 3 | .http2 = |
99 | 3 | { |
100 | 3 | .latency_optimization = ctx->globalconf->http2.latency_optimization, /* TODO provide config knob, or disable? */ |
101 | 3 | .max_concurrent_streams = self->config.http2.max_concurrent_streams, |
102 | 3 | }, |
103 | 3 | .http3 = self->config.protocol_ratio.http3 != 0 |
104 | 3 | ? h2o_create_proxy_http3_context(ctx, self->sockpool->_ssl_ctx, self->config.http3.ecn, |
105 | 0 | ctx->globalconf->http3.use_gso) |
106 | 3 | : NULL, |
107 | 3 | }; |
108 | | |
109 | 3 | handler_ctx->client_ctx = client_ctx; |
110 | 3 | } |
111 | | |
112 | | static void on_context_dispose(h2o_handler_t *_self, h2o_context_t *ctx) |
113 | 0 | { |
114 | 0 | struct rp_handler_t *self = (void *)_self; |
115 | 0 | struct rp_handler_context_t *handler_ctx = h2o_context_get_handler_context(ctx, &self->super); |
116 | |
|
117 | 0 | if (handler_ctx->client_ctx != NULL) { |
118 | 0 | if (handler_ctx->client_ctx->http3 != NULL) |
119 | 0 | h2o_destroy_proxy_http3_context(handler_ctx->client_ctx->http3); |
120 | 0 | free(handler_ctx->client_ctx); |
121 | 0 | } |
122 | |
|
123 | 0 | h2o_socketpool_unregister_loop(self->sockpool, ctx->loop); |
124 | 0 | } |
125 | | |
126 | | static void on_handler_dispose(h2o_handler_t *_self) |
127 | 0 | { |
128 | 0 | struct rp_handler_t *self = (void *)_self; |
129 | |
|
130 | 0 | h2o_socketpool_dispose(self->sockpool); |
131 | 0 | free(self->sockpool); |
132 | 0 | } |
133 | | |
134 | | void h2o_proxy_register_reverse_proxy(h2o_pathconf_t *pathconf, h2o_proxy_config_vars_t *config, h2o_socketpool_t *sockpool) |
135 | 3 | { |
136 | 3 | assert(config->max_buffer_size != 0); |
137 | | |
138 | 3 | struct rp_handler_t *self = (void *)h2o_create_handler(pathconf, sizeof(*self)); |
139 | | |
140 | 3 | self->super.on_context_init = on_context_init; |
141 | 3 | self->super.on_context_dispose = on_context_dispose; |
142 | 3 | self->super.dispose = on_handler_dispose; |
143 | 3 | self->super.on_req = on_req; |
144 | 3 | self->super.supports_request_streaming = 1; |
145 | 3 | self->super.handles_expect = config->expect_mode == H2O_PROXY_EXPECT_FORWARD; |
146 | 3 | self->config = *config; |
147 | 3 | self->sockpool = sockpool; |
148 | 3 | } |