/src/h2o/lib/handler/configurator/proxy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2014 DeNA Co., Ltd. |
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 <inttypes.h> |
23 | | #include <errno.h> |
24 | | #include <stdio.h> |
25 | | #include <openssl/crypto.h> |
26 | | #include <openssl/err.h> |
27 | | #include <openssl/ssl.h> |
28 | | #include "h2o.h" |
29 | | #include "h2o/configurator.h" |
30 | | #include "h2o/balancer.h" |
31 | | #include "h2o/socket.h" |
32 | | |
33 | | struct proxy_config_vars_t { |
34 | | h2o_proxy_config_vars_t conf; |
35 | | SSL_CTX *ssl_ctx; |
36 | | }; |
37 | | |
38 | | struct proxy_configurator_t { |
39 | | h2o_configurator_t super; |
40 | | unsigned connect_timeout_set : 1; |
41 | | unsigned first_byte_timeout_set : 1; |
42 | | struct proxy_config_vars_t *vars; |
43 | | struct proxy_config_vars_t _vars_stack[H2O_CONFIGURATOR_NUM_LEVELS + 1]; |
44 | | }; |
45 | | |
46 | | static void warn_deprecation(h2o_configurator_command_t *cmd, yoml_t *node, const char *new_cmd, const char *extra) |
47 | 0 | { |
48 | 0 | if (strcasecmp(cmd->name, new_cmd) != 0) |
49 | 0 | h2o_configurator_errprintf(cmd, node, "the command is deprecated; use %s%s", new_cmd, extra); |
50 | 0 | } |
51 | | |
52 | | static int on_config_timeout_io(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
53 | 0 | { |
54 | 0 | int ret; |
55 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
56 | 0 | ret = h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.io_timeout); |
57 | 0 | if (ret < 0) |
58 | 0 | return ret; |
59 | 0 | if (!self->connect_timeout_set) |
60 | 0 | self->vars->conf.connect_timeout = self->vars->conf.io_timeout; |
61 | 0 | if (!self->first_byte_timeout_set) |
62 | 0 | self->vars->conf.first_byte_timeout = self->vars->conf.io_timeout; |
63 | 0 | return ret; |
64 | 0 | } |
65 | | |
66 | | static int on_config_timeout_connect(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
67 | 0 | { |
68 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
69 | 0 | self->connect_timeout_set = 1; |
70 | 0 | return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.connect_timeout); |
71 | 0 | } |
72 | | |
73 | | static int on_config_timeout_first_byte(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
74 | 0 | { |
75 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
76 | 0 | self->first_byte_timeout_set = 1; |
77 | 0 | return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.first_byte_timeout); |
78 | 0 | } |
79 | | |
80 | | static int on_config_timeout_keepalive(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
81 | 0 | { |
82 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
83 | 0 | return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.keepalive_timeout); |
84 | 0 | } |
85 | | |
86 | | static int on_config_happy_eyeballs_name_resolution_delay(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, |
87 | | yoml_t *node) |
88 | 0 | { |
89 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
90 | 0 | return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.happy_eyeballs.name_resolution_delay); |
91 | 0 | } |
92 | | |
93 | | static int on_config_happy_eyeballs_connection_attempt_delay(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, |
94 | | yoml_t *node) |
95 | 0 | { |
96 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
97 | 0 | return h2o_configurator_scanf(cmd, node, "%" SCNu64, &self->vars->conf.happy_eyeballs.connection_attempt_delay); |
98 | 0 | } |
99 | | |
100 | | static int on_config_preserve_host(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
101 | 0 | { |
102 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
103 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
104 | 0 | if (ret == -1) |
105 | 0 | return -1; |
106 | 0 | self->vars->conf.preserve_host = (int)ret; |
107 | 0 | return 0; |
108 | 0 | } |
109 | | |
110 | | static int on_config_proxy_protocol(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
111 | 0 | { |
112 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
113 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
114 | 0 | if (ret == -1) |
115 | 0 | return -1; |
116 | 0 | self->vars->conf.use_proxy_protocol = (int)ret; |
117 | 0 | return 0; |
118 | 0 | } |
119 | | |
120 | | static int on_config_connect_proxy_status(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
121 | 0 | { |
122 | 0 | warn_deprecation(cmd, node, "proxy.connect.emit-proxy-status", ""); |
123 | |
|
124 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
125 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
126 | 0 | if (ret == -1) |
127 | 0 | return -1; |
128 | 0 | self->vars->conf.connect_proxy_status_enabled = (int)ret; |
129 | 0 | return 0; |
130 | 0 | } |
131 | | |
132 | | static int on_config_connect_proxy_masque_draft_03(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
133 | 0 | { |
134 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
135 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
136 | 0 | if (ret == -1) |
137 | 0 | return -1; |
138 | 0 | self->vars->conf.support_masque_draft_03 = (int)ret; |
139 | 0 | return 0; |
140 | 0 | } |
141 | | |
142 | | static int on_config_proxy_status_identity(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
143 | 0 | { |
144 | 0 | warn_deprecation(cmd, node, "proxy.proxy-status.identity", ""); |
145 | | |
146 | | /* https://tools.ietf.org/html/rfc8941#section-3.3.4 */ |
147 | 0 | static const char *tfirst = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*"; |
148 | 0 | static const char *tchars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&'*+-.^_`|~:/"; |
149 | |
|
150 | 0 | const char *s = node->data.scalar; |
151 | 0 | size_t slen = strlen(s); |
152 | 0 | for (size_t i = 0; i < slen; ++i) { |
153 | 0 | unsigned char b = s[i]; |
154 | 0 | if (b < 0x20 || b > 0x7E) { |
155 | 0 | h2o_configurator_errprintf(cmd, node, "the identity must only consist of printable ASCII characters"); |
156 | 0 | return -1; |
157 | 0 | } |
158 | 0 | } |
159 | 0 | if (s[0] != '\0' && strchr(tfirst, s[0]) != NULL && strspn(s, tchars) == slen) { |
160 | | /* sf-token */ |
161 | 0 | ctx->globalconf->proxy_status_identity = h2o_strdup(NULL, s, slen); |
162 | 0 | } else { |
163 | | /* sf-string */ |
164 | 0 | ctx->globalconf->proxy_status_identity = h2o_encode_sf_string(NULL, s, slen); |
165 | 0 | } |
166 | |
|
167 | 0 | return 0; |
168 | 0 | } |
169 | | |
170 | | static int on_config_tunnel(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
171 | 0 | { |
172 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
173 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
174 | 0 | if (ret == -1) |
175 | 0 | return -1; |
176 | 0 | self->vars->conf.tunnel_enabled = (int)ret; |
177 | 0 | return 0; |
178 | 0 | } |
179 | | |
180 | | static SSL_CTX *create_ssl_ctx(void) |
181 | 0 | { |
182 | 0 | long options; |
183 | 0 | SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method()); |
184 | 0 | options = SSL_CTX_get_options(ctx) | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; |
185 | 0 | #ifdef SSL_OP_NO_RENEGOTIATION |
186 | | /* introduced in openssl 1.1.0h */ |
187 | 0 | options |= SSL_OP_NO_RENEGOTIATION; |
188 | 0 | #endif |
189 | 0 | SSL_CTX_set_options(ctx, options); |
190 | 0 | SSL_CTX_set_session_id_context(ctx, H2O_SESSID_CTX, H2O_SESSID_CTX_LEN); |
191 | 0 | SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE); |
192 | 0 | SSL_CTX_sess_set_new_cb(ctx, h2o_socket_ssl_new_session_cb); |
193 | 0 | return ctx; |
194 | 0 | } |
195 | | |
196 | | static h2o_cache_t *create_ssl_session_cache(size_t capacity, uint64_t duration) |
197 | 0 | { |
198 | 0 | return h2o_cache_create(H2O_CACHE_FLAG_MULTITHREADED, capacity, duration, h2o_socket_ssl_destroy_session_cache_entry); |
199 | 0 | } |
200 | | |
201 | | static void update_ssl_ctx(SSL_CTX **ctx, X509_STORE *cert_store, int verify_mode, h2o_cache_t **session_cache) |
202 | 0 | { |
203 | 0 | assert(*ctx != NULL); |
204 | | |
205 | | /* inherit the properties that weren't specified */ |
206 | 0 | if (cert_store == NULL) |
207 | 0 | cert_store = SSL_CTX_get_cert_store(*ctx); |
208 | 0 | X509_STORE_up_ref(cert_store); |
209 | 0 | if (verify_mode == -1) |
210 | 0 | verify_mode = SSL_CTX_get_verify_mode(*ctx); |
211 | 0 | h2o_cache_t *new_session_cache; |
212 | 0 | if (session_cache == NULL) { |
213 | 0 | h2o_cache_t *current = h2o_socket_ssl_get_session_cache(*ctx); |
214 | 0 | new_session_cache = |
215 | 0 | current == NULL ? NULL : create_ssl_session_cache(h2o_cache_get_capacity(current), h2o_cache_get_duration(current)); |
216 | 0 | } else { |
217 | 0 | new_session_cache = *session_cache; |
218 | 0 | } |
219 | | |
220 | | /* free the existing context */ |
221 | 0 | if (*ctx != NULL) |
222 | 0 | SSL_CTX_free(*ctx); |
223 | | |
224 | | /* create new ctx */ |
225 | 0 | *ctx = create_ssl_ctx(); |
226 | 0 | SSL_CTX_set_session_id_context(*ctx, H2O_SESSID_CTX, H2O_SESSID_CTX_LEN); |
227 | 0 | SSL_CTX_set_cert_store(*ctx, cert_store); |
228 | 0 | SSL_CTX_set_verify(*ctx, verify_mode, NULL); |
229 | 0 | if (new_session_cache != NULL) |
230 | 0 | h2o_socket_ssl_set_session_cache(*ctx, new_session_cache); |
231 | 0 | } |
232 | | |
233 | | static int on_config_ssl_verify_peer(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
234 | 0 | { |
235 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
236 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
237 | 0 | if (ret == -1) |
238 | 0 | return -1; |
239 | | |
240 | 0 | update_ssl_ctx(&self->vars->ssl_ctx, NULL, ret != 0 ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, |
241 | 0 | NULL); |
242 | |
|
243 | 0 | return 0; |
244 | 0 | } |
245 | | |
246 | | static int on_config_ssl_cafile(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
247 | 0 | { |
248 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
249 | 0 | X509_STORE *store = X509_STORE_new(); |
250 | 0 | int ret = -1; |
251 | |
|
252 | 0 | if (X509_STORE_load_locations(store, node->data.scalar, NULL) == 1) { |
253 | 0 | update_ssl_ctx(&self->vars->ssl_ctx, store, -1, NULL); |
254 | 0 | ret = 0; |
255 | 0 | } else { |
256 | 0 | h2o_configurator_errprintf(cmd, node, "failed to load certificates file:%s", node->data.scalar); |
257 | 0 | ERR_print_errors_fp(stderr); |
258 | 0 | } |
259 | |
|
260 | 0 | X509_STORE_free(store); |
261 | 0 | return ret; |
262 | 0 | } |
263 | | |
264 | | static int on_config_ssl_session_cache(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
265 | 0 | { |
266 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
267 | 0 | size_t capacity = 0; |
268 | 0 | uint64_t duration = 0; |
269 | 0 | h2o_cache_t *current_cache = h2o_socket_ssl_get_session_cache(self->vars->ssl_ctx); |
270 | |
|
271 | 0 | switch (node->type) { |
272 | 0 | case YOML_TYPE_SCALAR: |
273 | 0 | if (strcasecmp(node->data.scalar, "OFF") == 0) { |
274 | 0 | if (current_cache != NULL) { |
275 | | /* set the cache NULL */ |
276 | 0 | h2o_cache_t *empty_cache = NULL; |
277 | 0 | update_ssl_ctx(&self->vars->ssl_ctx, NULL, -1, &empty_cache); |
278 | 0 | } |
279 | 0 | return 0; |
280 | 0 | } else if (strcasecmp(node->data.scalar, "ON") == 0) { |
281 | | /* use default values */ |
282 | 0 | capacity = H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_CAPACITY; |
283 | 0 | duration = H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_DURATION; |
284 | 0 | } else { |
285 | 0 | h2o_configurator_errprintf(cmd, node, "scalar argument must be either of: `OFF`, `ON`"); |
286 | 0 | return -1; |
287 | 0 | } |
288 | 0 | break; |
289 | 0 | case YOML_TYPE_MAPPING: { |
290 | 0 | yoml_t **capacity_node, **lifetime_node; |
291 | 0 | if (h2o_configurator_parse_mapping(cmd, node, "capacity:*,lifetime:*", NULL, &capacity_node, &lifetime_node) != 0) |
292 | 0 | return -1; |
293 | 0 | if (h2o_configurator_scanf(cmd, *capacity_node, "%zu", &capacity) != 0) |
294 | 0 | return -1; |
295 | 0 | if (capacity == 0) { |
296 | 0 | h2o_configurator_errprintf(cmd, *capacity_node, "capacity must be greater than zero"); |
297 | 0 | return -1; |
298 | 0 | } |
299 | 0 | unsigned lifetime = 0; |
300 | 0 | if (h2o_configurator_scanf(cmd, *lifetime_node, "%u", &lifetime) != 0) |
301 | 0 | return -1; |
302 | 0 | if (lifetime == 0) { |
303 | 0 | h2o_configurator_errprintf(cmd, *lifetime_node, "lifetime must be greater than zero"); |
304 | 0 | return -1; |
305 | 0 | } |
306 | 0 | duration = (uint64_t)lifetime * 1000; |
307 | 0 | } break; |
308 | 0 | default: |
309 | 0 | h2o_configurator_errprintf(cmd, node, "node must be a scalar or a mapping"); |
310 | 0 | return -1; |
311 | 0 | } |
312 | | |
313 | 0 | if (current_cache != NULL) { |
314 | 0 | size_t current_capacity = h2o_cache_get_capacity(current_cache); |
315 | 0 | uint64_t current_duration = h2o_cache_get_duration(current_cache); |
316 | 0 | if (capacity == current_capacity && duration == current_duration) { |
317 | | /* parameters aren't changed, so reuse it */ |
318 | 0 | return 0; |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | 0 | h2o_cache_t *new_cache = create_ssl_session_cache(capacity, duration); |
323 | 0 | update_ssl_ctx(&self->vars->ssl_ctx, NULL, -1, &new_cache); |
324 | 0 | return 0; |
325 | 0 | } |
326 | | |
327 | | static h2o_socketpool_target_t *parse_backend(h2o_configurator_command_t *cmd, yoml_t *backend) |
328 | 0 | { |
329 | 0 | h2o_mem_pool_t pool; |
330 | 0 | yoml_t **url_node; |
331 | 0 | h2o_socketpool_target_t *result = NULL; |
332 | 0 | h2o_socketpool_target_conf_t lb_per_target_conf = {0}; /* default weight of each target */ |
333 | |
|
334 | 0 | h2o_mem_init_pool(&pool); |
335 | |
|
336 | 0 | switch (backend->type) { |
337 | 0 | case YOML_TYPE_SCALAR: |
338 | 0 | url_node = &backend; |
339 | 0 | break; |
340 | 0 | case YOML_TYPE_MAPPING: { |
341 | 0 | yoml_t **weight_node; |
342 | 0 | if (h2o_configurator_parse_mapping(cmd, backend, "url:s", "weight:*", &url_node, &weight_node) != 0) |
343 | 0 | goto Exit; |
344 | 0 | if (weight_node != NULL) { |
345 | 0 | unsigned weight; |
346 | 0 | if (h2o_configurator_scanf(cmd, *weight_node, "%u", &weight) != 0) |
347 | 0 | goto Exit; |
348 | 0 | if (!(1 <= weight && weight <= H2O_SOCKETPOOL_TARGET_MAX_WEIGHT)) { |
349 | 0 | h2o_configurator_errprintf(cmd, *weight_node, "weight must be an integer in range 1 - 256"); |
350 | 0 | goto Exit; |
351 | 0 | } |
352 | 0 | lb_per_target_conf.weight_m1 = weight - 1; |
353 | 0 | } |
354 | 0 | } break; |
355 | 0 | default: |
356 | 0 | h2o_configurator_errprintf(cmd, backend, |
357 | 0 | "items of arguments passed to proxy.reverse.url must be either a scalar or a mapping"); |
358 | 0 | goto Exit; |
359 | 0 | } |
360 | | |
361 | 0 | h2o_url_t url; |
362 | 0 | if (h2o_url_parse(&pool, (*url_node)->data.scalar, SIZE_MAX, &url) != 0) { |
363 | 0 | h2o_configurator_errprintf(cmd, *url_node, "failed to parse URL: %s\n", (*url_node)->data.scalar); |
364 | 0 | goto Exit; |
365 | 0 | } |
366 | | |
367 | 0 | result = h2o_socketpool_create_target(&url, &lb_per_target_conf); |
368 | |
|
369 | 0 | Exit: |
370 | 0 | h2o_mem_clear_pool(&pool); |
371 | 0 | return result; |
372 | 0 | } |
373 | | |
374 | | static int on_config_reverse_url(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
375 | 0 | { |
376 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
377 | |
|
378 | 0 | yoml_t **backends, **balancer_conf = NULL; |
379 | 0 | size_t i, num_backends = 0; |
380 | 0 | h2o_balancer_t *balancer = NULL; |
381 | | |
382 | | /* collect the nodes */ |
383 | 0 | switch (node->type) { |
384 | 0 | case YOML_TYPE_SCALAR: |
385 | 0 | backends = &node; |
386 | 0 | num_backends = 1; |
387 | 0 | break; |
388 | 0 | case YOML_TYPE_SEQUENCE: |
389 | 0 | backends = node->data.sequence.elements; |
390 | 0 | num_backends = node->data.sequence.size; |
391 | 0 | break; |
392 | 0 | case YOML_TYPE_MAPPING: |
393 | 0 | if (h2o_configurator_parse_mapping(cmd, node, "backends:*", "balancer:s", &backends, &balancer_conf) != 0) |
394 | 0 | return -1; |
395 | 0 | switch ((*backends)->type) { |
396 | 0 | case YOML_TYPE_SCALAR: |
397 | 0 | num_backends = 1; |
398 | 0 | break; |
399 | 0 | case YOML_TYPE_SEQUENCE: |
400 | 0 | num_backends = (*backends)->data.sequence.size; |
401 | 0 | backends = (*backends)->data.sequence.elements; |
402 | 0 | break; |
403 | 0 | default: |
404 | 0 | h2o_configurator_errprintf(cmd, *backends, "value for the `backends` property must be either a scalar or a sequence"); |
405 | 0 | return -1; |
406 | 0 | } |
407 | 0 | break; |
408 | 0 | default: |
409 | 0 | h2o_fatal("unexpected node type"); |
410 | 0 | return -1; |
411 | 0 | } |
412 | 0 | if (num_backends == 0) { |
413 | 0 | h2o_configurator_errprintf(cmd, node, "at least one backend url must be set"); |
414 | 0 | return -1; |
415 | 0 | } |
416 | | |
417 | | /* determine the balancer */ |
418 | 0 | if (balancer_conf != NULL) { |
419 | 0 | if (strcmp((*balancer_conf)->data.scalar, "round-robin") == 0) { |
420 | 0 | balancer = h2o_balancer_create_rr(); |
421 | 0 | } else if (strcmp((*balancer_conf)->data.scalar, "least-conn") == 0) { |
422 | 0 | balancer = h2o_balancer_create_lc(); |
423 | 0 | } else { |
424 | 0 | h2o_configurator_errprintf( |
425 | 0 | cmd, node, "specified balancer is not supported. Currently supported ones are: round-robin, least-conn"); |
426 | 0 | return -1; |
427 | 0 | } |
428 | 0 | } |
429 | | |
430 | | /* parse the backends */ |
431 | 0 | h2o_socketpool_target_t **targets = alloca(sizeof(*targets) * num_backends); |
432 | 0 | for (i = 0; i != num_backends; ++i) |
433 | 0 | if ((targets[i] = parse_backend(cmd, backends[i])) == NULL) |
434 | 0 | return -1; |
435 | | |
436 | | /* check consistency */ |
437 | 0 | if (self->vars->conf.keepalive_timeout != 0 && self->vars->conf.use_proxy_protocol) { |
438 | 0 | h2o_configurator_errprintf(cmd, node, |
439 | 0 | "please either set `proxy.use-proxy-protocol` to `OFF` or disable keep-alive by " |
440 | 0 | "setting `proxy.timeout.keepalive` to zero; the features are mutually exclusive"); |
441 | 0 | return -1; |
442 | 0 | } |
443 | 0 | if (self->vars->conf.protocol_ratio.http2 + self->vars->conf.protocol_ratio.http3 > 100) { |
444 | 0 | h2o_configurator_errprintf(cmd, node, "sum of http2.ratio and http3.ratio cannot be greater than 100"); |
445 | 0 | return -1; |
446 | 0 | } |
447 | 0 | if (self->vars->conf.http2.force_cleartext && self->vars->conf.protocol_ratio.http2 != 100) { |
448 | 0 | h2o_configurator_errprintf( |
449 | 0 | cmd, node, "when `proxy.http2.force-cleartext` is `ON`, `proxy.http2.ratio` must be set to `100` (percent)"); |
450 | 0 | return -1; |
451 | 0 | } |
452 | | |
453 | 0 | if (self->vars->conf.headers_cmds != NULL) |
454 | 0 | h2o_mem_addref_shared(self->vars->conf.headers_cmds); |
455 | |
|
456 | 0 | h2o_socketpool_t *sockpool = h2o_mem_alloc(sizeof(*sockpool)); |
457 | 0 | memset(sockpool, 0, sizeof(*sockpool)); |
458 | | /* init socket pool */ |
459 | 0 | h2o_socketpool_init_specific(sockpool, SIZE_MAX /* FIXME */, targets, num_backends, balancer); |
460 | 0 | h2o_socketpool_set_timeout(sockpool, self->vars->conf.keepalive_timeout); |
461 | 0 | h2o_socketpool_set_ssl_ctx(sockpool, self->vars->ssl_ctx); |
462 | 0 | h2o_proxy_register_reverse_proxy(ctx->pathconf, &self->vars->conf, sockpool); |
463 | 0 | return 0; |
464 | 0 | } |
465 | | |
466 | | static int config_connect_core(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node, |
467 | | void (*registrar)(h2o_pathconf_t *, h2o_proxy_config_vars_t *, h2o_connect_acl_entry_t *, size_t)) |
468 | 0 | { |
469 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
470 | | |
471 | | /* Convert list of ACLs to internal representation; input is a sequence of: [+-]address(?::port|) */ |
472 | 0 | h2o_connect_acl_entry_t acl_entries[node->data.sequence.size]; |
473 | 0 | for (size_t i = 0; i < node->data.sequence.size; ++i) { |
474 | 0 | if (node->data.sequence.elements[i]->type != YOML_TYPE_SCALAR) { |
475 | 0 | h2o_configurator_errprintf(cmd, node->data.sequence.elements[i], "ACL entry must be a scalar"); |
476 | 0 | return -1; |
477 | 0 | } |
478 | 0 | const char *err = h2o_connect_parse_acl(acl_entries + i, node->data.sequence.elements[i]->data.scalar); |
479 | 0 | if (err != NULL) { |
480 | 0 | h2o_configurator_errprintf(cmd, node->data.sequence.elements[i], "%s", err); |
481 | 0 | return -1; |
482 | 0 | } |
483 | 0 | } |
484 | | |
485 | 0 | registrar(ctx->pathconf, &self->vars->conf, acl_entries, node->data.sequence.size); |
486 | 0 | return 0; |
487 | 0 | } |
488 | | |
489 | | static int on_config_classic_connect(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
490 | 0 | { |
491 | 0 | return config_connect_core(cmd, ctx, node, h2o_connect_register); |
492 | 0 | } |
493 | | |
494 | | static int on_config_connect_udp(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
495 | 0 | { |
496 | 0 | return config_connect_core(cmd, ctx, node, h2o_connect_udp_register); |
497 | 0 | } |
498 | | |
499 | | static int on_config_emit_x_forwarded_headers(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
500 | 0 | { |
501 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
502 | 0 | if (ret == -1) |
503 | 0 | return -1; |
504 | 0 | ctx->globalconf->proxy.emit_x_forwarded_headers = (int)ret; |
505 | 0 | return 0; |
506 | 0 | } |
507 | | |
508 | | static int on_config_emit_via_header(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
509 | 0 | { |
510 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
511 | 0 | if (ret == -1) |
512 | 0 | return -1; |
513 | 0 | ctx->globalconf->proxy.emit_via_header = (int)ret; |
514 | 0 | return 0; |
515 | 0 | } |
516 | | |
517 | | static int on_config_emit_missing_date_header(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
518 | 0 | { |
519 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
520 | 0 | if (ret == -1) |
521 | 0 | return -1; |
522 | 0 | ctx->globalconf->proxy.emit_missing_date_header = (int)ret; |
523 | 0 | return 0; |
524 | 0 | } |
525 | | |
526 | | static int on_config_zerocopy(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
527 | 0 | { |
528 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON,ALWAYS"); |
529 | 0 | switch (ret) { |
530 | 0 | case 0: |
531 | 0 | ctx->globalconf->proxy.zerocopy = H2O_PROXY_ZEROCOPY_DISABLED; |
532 | 0 | break; |
533 | 0 | case 1: |
534 | 0 | ctx->globalconf->proxy.zerocopy = H2O_PROXY_ZEROCOPY_ENABLED; |
535 | 0 | break; |
536 | 0 | case 2: |
537 | 0 | ctx->globalconf->proxy.zerocopy = H2O_PROXY_ZEROCOPY_ALWAYS; |
538 | 0 | break; |
539 | 0 | default: |
540 | 0 | return -1; |
541 | 0 | } |
542 | 0 | return 0; |
543 | 0 | } |
544 | | |
545 | | static int on_config_preserve_x_forwarded_proto(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
546 | 0 | { |
547 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
548 | 0 | if (ret == -1) |
549 | 0 | return -1; |
550 | 0 | ctx->globalconf->proxy.preserve_x_forwarded_proto = (int)ret; |
551 | 0 | return 0; |
552 | 0 | } |
553 | | |
554 | | static int on_config_max_buffer_size(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
555 | 0 | { |
556 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
557 | 0 | if (h2o_configurator_scanf(cmd, node, "%zu", &self->vars->conf.max_buffer_size) != 0) |
558 | 0 | return -1; |
559 | 0 | if (self->vars->conf.max_buffer_size == 0) { |
560 | 0 | h2o_configurator_errprintf(cmd, node, "proxy.buffer_size must be a positive value"); |
561 | 0 | return -1; |
562 | 0 | } |
563 | 0 | return 0; |
564 | 0 | } |
565 | | |
566 | | static int on_config_http2_max_concurrent_streams(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
567 | 0 | { |
568 | 0 | warn_deprecation(cmd, node, "proxy.http2.max-concurrent-streams", " (notice `-` and `_`)"); |
569 | |
|
570 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
571 | 0 | return h2o_configurator_scanf(cmd, node, "%u", &self->vars->conf.http2.max_concurrent_streams); |
572 | 0 | } |
573 | | |
574 | | static int on_config_http2_force_cleartext(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
575 | 0 | { |
576 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
577 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
578 | 0 | if (ret < 0) |
579 | 0 | return -1; |
580 | 0 | self->vars->conf.http2.force_cleartext = (unsigned)ret; |
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | | static int on_config_http2_ratio(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
585 | 0 | { |
586 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
587 | 0 | int ret = h2o_configurator_scanf(cmd, node, "%" SCNd8, &self->vars->conf.protocol_ratio.http2); |
588 | 0 | if (ret < 0) |
589 | 0 | return ret; |
590 | 0 | if (self->vars->conf.protocol_ratio.http2 < 0 || 100 < self->vars->conf.protocol_ratio.http2) { |
591 | 0 | h2o_configurator_errprintf(cmd, node, "proxy.http2.ratio must be between 0 and 100"); |
592 | 0 | return -1; |
593 | 0 | } |
594 | 0 | return 0; |
595 | 0 | } |
596 | | |
597 | | static int on_config_http3_ratio(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
598 | 0 | { |
599 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
600 | 0 | int ret = h2o_configurator_scanf(cmd, node, "%" SCNd8, &self->vars->conf.protocol_ratio.http3); |
601 | 0 | if (ret < 0) |
602 | 0 | return ret; |
603 | 0 | if (self->vars->conf.protocol_ratio.http3 < 0 || 100 < self->vars->conf.protocol_ratio.http3) { |
604 | 0 | h2o_configurator_errprintf(cmd, node, "proxy.http3.ratio must be between 0 and 100"); |
605 | 0 | return -1; |
606 | 0 | } |
607 | 0 | return 0; |
608 | 0 | } |
609 | | |
610 | | static int on_config_expect(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
611 | 0 | { |
612 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
613 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON,FORWARD"); |
614 | 0 | switch (ret) { |
615 | 0 | case 0: |
616 | 0 | self->vars->conf.expect_mode = H2O_PROXY_EXPECT_OFF; |
617 | 0 | break; |
618 | 0 | case 1: |
619 | 0 | self->vars->conf.expect_mode = H2O_PROXY_EXPECT_ON; |
620 | 0 | break; |
621 | 0 | case 2: |
622 | 0 | self->vars->conf.expect_mode = H2O_PROXY_EXPECT_FORWARD; |
623 | 0 | break; |
624 | 0 | default: |
625 | 0 | return -1; |
626 | 0 | } |
627 | | |
628 | 0 | return 0; |
629 | 0 | } |
630 | | |
631 | | static int on_config_forward_close_connection(h2o_configurator_command_t *cmd, h2o_configurator_context_t *ctx, yoml_t *node) |
632 | 0 | { |
633 | 0 | struct proxy_configurator_t *self = (void *)cmd->configurator; |
634 | 0 | ssize_t ret = h2o_configurator_get_one_of(cmd, node, "OFF,ON"); |
635 | 0 | if (ret == -1) |
636 | 0 | return -1; |
637 | 0 | self->vars->conf.forward_close_connection = (int)ret; |
638 | 0 | return 0; |
639 | 0 | } |
640 | | |
641 | | static int on_config_enter(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) |
642 | 0 | { |
643 | 0 | struct proxy_configurator_t *self = (void *)_self; |
644 | |
|
645 | 0 | memcpy(self->vars + 1, self->vars, sizeof(*self->vars)); |
646 | 0 | if (self->vars[1].conf.headers_cmds != NULL) |
647 | 0 | h2o_mem_addref_shared(self->vars[1].conf.headers_cmds); |
648 | 0 | ++self->vars; |
649 | 0 | self->connect_timeout_set = 0; |
650 | 0 | self->first_byte_timeout_set = 0; |
651 | |
|
652 | 0 | if (ctx->pathconf == NULL && ctx->hostconf == NULL) { |
653 | | /* is global conf, setup the default SSL context */ |
654 | 0 | self->vars->ssl_ctx = create_ssl_ctx(); |
655 | 0 | char *ca_bundle = h2o_configurator_get_cmd_path("share/h2o/ca-bundle.crt"); |
656 | 0 | if (SSL_CTX_load_verify_locations(self->vars->ssl_ctx, ca_bundle, NULL) != 1) |
657 | 0 | h2o_error_printf("Warning: failed to load the default certificates file at %s. Proxying to HTTPS servers may fail.\n", |
658 | 0 | ca_bundle); |
659 | 0 | free(ca_bundle); |
660 | 0 | SSL_CTX_set_verify(self->vars->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); |
661 | 0 | h2o_cache_t *ssl_session_cache = |
662 | 0 | create_ssl_session_cache(H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_CAPACITY, H2O_DEFAULT_PROXY_SSL_SESSION_CACHE_DURATION); |
663 | 0 | h2o_socket_ssl_set_session_cache(self->vars->ssl_ctx, ssl_session_cache); |
664 | 0 | } else { |
665 | 0 | SSL_CTX_up_ref(self->vars->ssl_ctx); |
666 | 0 | } |
667 | |
|
668 | 0 | return 0; |
669 | 0 | } |
670 | | |
671 | | static int on_config_exit(h2o_configurator_t *_self, h2o_configurator_context_t *ctx, yoml_t *node) |
672 | 0 | { |
673 | 0 | struct proxy_configurator_t *self = (void *)_self; |
674 | |
|
675 | 0 | if (ctx->pathconf == NULL && ctx->hostconf == NULL) { |
676 | | /* is global conf */ |
677 | 0 | ctx->globalconf->proxy.io_timeout = self->vars->conf.io_timeout; |
678 | 0 | ctx->globalconf->proxy.connect_timeout = self->vars->conf.connect_timeout; |
679 | 0 | ctx->globalconf->proxy.first_byte_timeout = self->vars->conf.first_byte_timeout; |
680 | 0 | ctx->globalconf->proxy.keepalive_timeout = self->vars->conf.keepalive_timeout; |
681 | 0 | ctx->globalconf->proxy.max_buffer_size = self->vars->conf.max_buffer_size; |
682 | 0 | ctx->globalconf->proxy.http2.max_concurrent_streams = self->vars->conf.http2.max_concurrent_streams; |
683 | 0 | ctx->globalconf->proxy.protocol_ratio.http2 = self->vars->conf.protocol_ratio.http2; |
684 | 0 | ctx->globalconf->proxy.protocol_ratio.http3 = self->vars->conf.protocol_ratio.http3; |
685 | 0 | h2o_socketpool_set_ssl_ctx(&ctx->globalconf->proxy.global_socketpool, self->vars->ssl_ctx); |
686 | 0 | h2o_socketpool_set_timeout(&ctx->globalconf->proxy.global_socketpool, self->vars->conf.keepalive_timeout); |
687 | 0 | } |
688 | 0 | SSL_CTX_free(self->vars->ssl_ctx); |
689 | |
|
690 | 0 | if (self->vars->conf.headers_cmds != NULL) |
691 | 0 | h2o_mem_release_shared(self->vars->conf.headers_cmds); |
692 | |
|
693 | 0 | --self->vars; |
694 | 0 | return 0; |
695 | 0 | } |
696 | | |
697 | | static h2o_headers_command_t **get_headers_commands(h2o_configurator_t *_self) |
698 | 0 | { |
699 | 0 | struct proxy_configurator_t *self = (void *)_self; |
700 | 0 | return &self->vars->conf.headers_cmds; |
701 | 0 | } |
702 | | |
703 | | void h2o_proxy_register_configurator(h2o_globalconf_t *conf) |
704 | 0 | { |
705 | 0 | struct proxy_configurator_t *c = (void *)h2o_configurator_create(conf, sizeof(*c)); |
706 | | |
707 | | /* set default vars */ |
708 | 0 | c->vars = c->_vars_stack; |
709 | 0 | c->vars->conf = (h2o_proxy_config_vars_t){ |
710 | 0 | .io_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT, |
711 | 0 | .connect_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT, |
712 | 0 | .first_byte_timeout = H2O_DEFAULT_PROXY_IO_TIMEOUT, |
713 | 0 | .happy_eyeballs = |
714 | 0 | { |
715 | 0 | .name_resolution_delay = H2O_DEFAULT_HAPPY_EYEBALLS_NAME_RESOLUTION_DELAY, |
716 | 0 | .connection_attempt_delay = H2O_DEFAULT_HAPPY_EYEBALLS_CONNECTION_ATTEMPT_DELAY, |
717 | 0 | }, |
718 | 0 | .tunnel_enabled = 0, /* experimental support for tunneling (e.g., CONNECT, websocket) is disabled by default */ |
719 | 0 | .max_buffer_size = SIZE_MAX, |
720 | 0 | .http2.max_concurrent_streams = H2O_DEFAULT_PROXY_HTTP2_MAX_CONCURRENT_STREAMS, |
721 | 0 | .protocol_ratio.http2 = -1, |
722 | 0 | .keepalive_timeout = h2o_socketpool_get_timeout(&conf->proxy.global_socketpool), |
723 | 0 | }; |
724 | | |
725 | | /* setup handlers */ |
726 | 0 | c->super.enter = on_config_enter; |
727 | 0 | c->super.exit = on_config_exit; |
728 | 0 | h2o_configurator_define_command(&c->super, "proxy.reverse.url", |
729 | 0 | H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR | |
730 | 0 | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE | H2O_CONFIGURATOR_FLAG_EXPECT_MAPPING | |
731 | 0 | H2O_CONFIGURATOR_FLAG_DEFERRED, |
732 | 0 | on_config_reverse_url); |
733 | 0 | h2o_configurator_define_command(&c->super, "proxy.connect", |
734 | 0 | H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE | |
735 | 0 | H2O_CONFIGURATOR_FLAG_DEFERRED, |
736 | 0 | on_config_classic_connect); |
737 | 0 | h2o_configurator_define_command( |
738 | 0 | &c->super, "proxy.connect-udp", |
739 | 0 | H2O_CONFIGURATOR_FLAG_PATH | H2O_CONFIGURATOR_FLAG_EXPECT_SEQUENCE | H2O_CONFIGURATOR_FLAG_DEFERRED, on_config_connect_udp); |
740 | 0 | h2o_configurator_define_command(&c->super, "proxy.connect.emit-proxy-status", |
741 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
742 | 0 | on_config_connect_proxy_status); |
743 | 0 | h2o_configurator_define_command(&c->super, "proxy.connect.proxy-status", |
744 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
745 | 0 | on_config_connect_proxy_status); |
746 | 0 | h2o_configurator_define_command(&c->super, "proxy.connect.masque-draft-03", |
747 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
748 | 0 | on_config_connect_proxy_masque_draft_03); |
749 | 0 | h2o_configurator_define_command(&c->super, "proxy.proxy-status.identity", |
750 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
751 | 0 | on_config_proxy_status_identity); |
752 | 0 | h2o_configurator_define_command(&c->super, "proxy-status.identity", |
753 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
754 | 0 | on_config_proxy_status_identity); |
755 | 0 | h2o_configurator_define_command(&c->super, "proxy.preserve-host", |
756 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
757 | 0 | on_config_preserve_host); |
758 | 0 | h2o_configurator_define_command(&c->super, "proxy.proxy-protocol", |
759 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
760 | 0 | on_config_proxy_protocol); |
761 | 0 | h2o_configurator_define_command(&c->super, "proxy.timeout.io", |
762 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_timeout_io); |
763 | 0 | h2o_configurator_define_command(&c->super, "proxy.timeout.connect", |
764 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
765 | 0 | on_config_timeout_connect); |
766 | 0 | h2o_configurator_define_command(&c->super, "proxy.timeout.first_byte", |
767 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
768 | 0 | on_config_timeout_first_byte); |
769 | 0 | h2o_configurator_define_command(&c->super, "proxy.timeout.keepalive", |
770 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
771 | 0 | on_config_timeout_keepalive); |
772 | 0 | h2o_configurator_define_command(&c->super, "proxy.happy-eyeballs.name-resolution-delay", |
773 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
774 | 0 | on_config_happy_eyeballs_name_resolution_delay); |
775 | 0 | h2o_configurator_define_command(&c->super, "proxy.happy-eyeballs.connection-attempt-delay", |
776 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
777 | 0 | on_config_happy_eyeballs_connection_attempt_delay); |
778 | 0 | h2o_configurator_define_command(&c->super, "proxy.tunnel", |
779 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_tunnel); |
780 | 0 | h2o_configurator_define_command(&c->super, "proxy.ssl.verify-peer", |
781 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
782 | 0 | on_config_ssl_verify_peer); |
783 | 0 | h2o_configurator_define_command(&c->super, "proxy.ssl.cafile", |
784 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_ssl_cafile); |
785 | 0 | h2o_configurator_define_command(&c->super, "proxy.ssl.session-cache", H2O_CONFIGURATOR_FLAG_ALL_LEVELS, |
786 | 0 | on_config_ssl_session_cache); |
787 | 0 | h2o_configurator_define_command(&c->super, "proxy.preserve-x-forwarded-proto", |
788 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
789 | 0 | on_config_preserve_x_forwarded_proto); |
790 | 0 | h2o_configurator_define_command(&c->super, "proxy.emit-x-forwarded-headers", |
791 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
792 | 0 | on_config_emit_x_forwarded_headers); |
793 | 0 | h2o_configurator_define_command(&c->super, "proxy.emit-via-header", |
794 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_emit_via_header); |
795 | 0 | h2o_configurator_define_command(&c->super, "proxy.emit-missing-date-header", |
796 | 0 | H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
797 | 0 | on_config_emit_missing_date_header); |
798 | 0 | h2o_configurator_define_command(&c->super, "proxy.zerocopy", H2O_CONFIGURATOR_FLAG_GLOBAL | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
799 | 0 | on_config_zerocopy); |
800 | 0 | h2o_configurator_define_headers_commands(conf, &c->super, "proxy.header", get_headers_commands); |
801 | 0 | h2o_configurator_define_command(&c->super, "proxy.max-buffer-size", |
802 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
803 | 0 | on_config_max_buffer_size); |
804 | 0 | h2o_configurator_define_command(&c->super, "proxy.http2.max-concurrent-streams", |
805 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
806 | 0 | on_config_http2_max_concurrent_streams); |
807 | 0 | h2o_configurator_define_command(&c->super, "proxy.http2.max-concurrent_streams", |
808 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
809 | 0 | on_config_http2_max_concurrent_streams); |
810 | 0 | h2o_configurator_define_command(&c->super, "proxy.http2.force-cleartext", |
811 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
812 | 0 | on_config_http2_force_cleartext); |
813 | 0 | h2o_configurator_define_command(&c->super, "proxy.http2.ratio", |
814 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_http2_ratio); |
815 | 0 | h2o_configurator_define_command(&c->super, "proxy.http3.ratio", |
816 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_http3_ratio); |
817 | 0 | h2o_configurator_define_command(&c->super, "proxy.expect", |
818 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, on_config_expect); |
819 | 0 | h2o_configurator_define_command(&c->super, "proxy.forward.close-connection", |
820 | 0 | H2O_CONFIGURATOR_FLAG_ALL_LEVELS | H2O_CONFIGURATOR_FLAG_EXPECT_SCALAR, |
821 | 0 | on_config_forward_close_connection); |
822 | 0 | } |