1 /*
2  * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Satoh Hiroh
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 <assert.h>
23 #include <inttypes.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include "h2o.h"
30 #include "h2o/http1.h"
31 #include "h2o/http2.h"
32 #include "h2o/hiredis_.h"
33 
34 struct st_h2o_accept_data_t {
35     h2o_accept_ctx_t *ctx;
36     h2o_socket_t *sock;
37     h2o_timer_t timeout;
38     struct timeval connected_at;
39 };
40 
41 struct st_h2o_memcached_resumption_accept_data_t {
42     struct st_h2o_accept_data_t super;
43     h2o_memcached_req_t *get_req;
44 };
45 
46 struct st_h2o_redis_resumption_accept_data_t {
47     struct st_h2o_accept_data_t super;
48     h2o_redis_command_t *get_command;
49 };
50 
51 static void on_accept_timeout(h2o_timer_t *entry);
52 static void on_redis_accept_timeout(h2o_timer_t *entry);
53 static void on_memcached_accept_timeout(h2o_timer_t *entry);
54 
55 static struct {
56     struct {
57         h2o_memcached_context_t *ctx;
58     } memcached;
59     struct {
60         h2o_iovec_t host;
61         uint16_t port;
62         h2o_iovec_t prefix;
63     } redis;
64     unsigned expiration;
65 } async_resumption_context;
66 
create_accept_data(h2o_accept_ctx_t * ctx,h2o_socket_t * sock,struct timeval connected_at,h2o_timer_cb timeout_cb,size_t sz)67 static struct st_h2o_accept_data_t *create_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at,
68                                                        h2o_timer_cb timeout_cb, size_t sz)
69 {
70     struct st_h2o_accept_data_t *data = h2o_mem_alloc(sz);
71     data->ctx = ctx;
72     data->sock = sock;
73     h2o_timer_init(&data->timeout, timeout_cb);
74     h2o_timer_link(ctx->ctx->loop, ctx->ctx->globalconf->handshake_timeout, &data->timeout);
75     data->connected_at = connected_at;
76     return data;
77 }
78 
create_default_accept_data(h2o_accept_ctx_t * ctx,h2o_socket_t * sock,struct timeval connected_at)79 static struct st_h2o_accept_data_t *create_default_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock,
80                                                                struct timeval connected_at)
81 {
82     struct st_h2o_accept_data_t *data =
83         create_accept_data(ctx, sock, connected_at, on_accept_timeout, sizeof(struct st_h2o_accept_data_t));
84     return data;
85 }
86 
create_redis_accept_data(h2o_accept_ctx_t * ctx,h2o_socket_t * sock,struct timeval connected_at)87 static struct st_h2o_accept_data_t *create_redis_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at)
88 {
89     struct st_h2o_redis_resumption_accept_data_t *data = (struct st_h2o_redis_resumption_accept_data_t *)create_accept_data(
90         ctx, sock, connected_at, on_redis_accept_timeout, sizeof(struct st_h2o_redis_resumption_accept_data_t));
91     data->get_command = NULL;
92     return &data->super;
93 }
94 
create_memcached_accept_data(h2o_accept_ctx_t * ctx,h2o_socket_t * sock,struct timeval connected_at)95 static struct st_h2o_accept_data_t *create_memcached_accept_data(h2o_accept_ctx_t *ctx, h2o_socket_t *sock,
96                                                                  struct timeval connected_at)
97 {
98     struct st_h2o_memcached_resumption_accept_data_t *data = (struct st_h2o_memcached_resumption_accept_data_t *)create_accept_data(
99         ctx, sock, connected_at, on_memcached_accept_timeout, sizeof(struct st_h2o_memcached_resumption_accept_data_t));
100     data->get_req = NULL;
101     return &data->super;
102 }
103 
destroy_accept_data(struct st_h2o_accept_data_t * data)104 static void destroy_accept_data(struct st_h2o_accept_data_t *data)
105 {
106     h2o_timer_unlink(&data->timeout);
107     free(data);
108 }
109 
destroy_default_accept_data(struct st_h2o_accept_data_t * _accept_data)110 static void destroy_default_accept_data(struct st_h2o_accept_data_t *_accept_data)
111 {
112     destroy_accept_data(_accept_data);
113 }
114 
destroy_redis_accept_data(struct st_h2o_accept_data_t * _accept_data)115 static void destroy_redis_accept_data(struct st_h2o_accept_data_t *_accept_data)
116 {
117     struct st_h2o_redis_resumption_accept_data_t *accept_data = (struct st_h2o_redis_resumption_accept_data_t *)_accept_data;
118     assert(accept_data->get_command == NULL);
119     destroy_accept_data(&accept_data->super);
120 }
121 
destroy_memcached_accept_data(struct st_h2o_accept_data_t * _accept_data)122 static void destroy_memcached_accept_data(struct st_h2o_accept_data_t *_accept_data)
123 {
124     struct st_h2o_memcached_resumption_accept_data_t *accept_data =
125         (struct st_h2o_memcached_resumption_accept_data_t *)_accept_data;
126     assert(accept_data->get_req == NULL);
127     destroy_accept_data(&accept_data->super);
128 }
129 
130 static struct {
131     struct st_h2o_accept_data_t *(*create)(h2o_accept_ctx_t *ctx, h2o_socket_t *sock, struct timeval connected_at);
132     void (*destroy)(struct st_h2o_accept_data_t *accept_data);
133 } accept_data_callbacks = {
134     create_default_accept_data,
135     destroy_default_accept_data,
136 };
137 
memcached_resumption_on_get(h2o_iovec_t session_data,void * _accept_data)138 static void memcached_resumption_on_get(h2o_iovec_t session_data, void *_accept_data)
139 {
140     struct st_h2o_memcached_resumption_accept_data_t *accept_data = _accept_data;
141     accept_data->get_req = NULL;
142     h2o_socket_ssl_resume_server_handshake(accept_data->super.sock, session_data);
143 }
144 
memcached_resumption_get(h2o_socket_t * sock,h2o_iovec_t session_id)145 static void memcached_resumption_get(h2o_socket_t *sock, h2o_iovec_t session_id)
146 {
147     struct st_h2o_memcached_resumption_accept_data_t *data = sock->data;
148 
149     data->get_req = h2o_memcached_get(async_resumption_context.memcached.ctx, data->super.ctx->libmemcached_receiver, session_id,
150                                       memcached_resumption_on_get, data, H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE);
151 }
152 
memcached_resumption_new(h2o_socket_t * sock,h2o_iovec_t session_id,h2o_iovec_t session_data)153 static void memcached_resumption_new(h2o_socket_t *sock, h2o_iovec_t session_id, h2o_iovec_t session_data)
154 {
155     h2o_memcached_set(async_resumption_context.memcached.ctx, session_id, session_data,
156                       (uint32_t)time(NULL) + async_resumption_context.expiration,
157                       H2O_MEMCACHED_ENCODE_KEY | H2O_MEMCACHED_ENCODE_VALUE);
158 }
159 
h2o_accept_setup_memcached_ssl_resumption(h2o_memcached_context_t * memc,unsigned expiration)160 void h2o_accept_setup_memcached_ssl_resumption(h2o_memcached_context_t *memc, unsigned expiration)
161 {
162     async_resumption_context.memcached.ctx = memc;
163     async_resumption_context.expiration = expiration;
164     h2o_socket_ssl_async_resumption_init(memcached_resumption_get, memcached_resumption_new);
165     accept_data_callbacks.create = create_memcached_accept_data;
166     accept_data_callbacks.destroy = destroy_memcached_accept_data;
167 }
168 
on_redis_connect(void)169 static void on_redis_connect(void)
170 {
171     h2o_error_printf("connected to redis at %s:%" PRIu16 "\n", async_resumption_context.redis.host.base,
172                      async_resumption_context.redis.port);
173 }
174 
on_redis_close(const char * errstr)175 static void on_redis_close(const char *errstr)
176 {
177     if (errstr == NULL) {
178         h2o_error_printf("disconnected from redis at %s:%" PRIu16 "\n", async_resumption_context.redis.host.base,
179                          async_resumption_context.redis.port);
180     } else {
181         h2o_error_printf("redis connection failure: %s\n", errstr);
182     }
183 }
184 
dispose_redis_connection(void * client)185 static void dispose_redis_connection(void *client)
186 {
187     h2o_redis_free((h2o_redis_client_t *)client);
188 }
189 
get_redis_client(h2o_context_t * ctx)190 static h2o_redis_client_t *get_redis_client(h2o_context_t *ctx)
191 {
192     static size_t key = SIZE_MAX;
193     h2o_redis_client_t **client = (h2o_redis_client_t **)h2o_context_get_storage(ctx, &key, dispose_redis_connection);
194     if (*client == NULL) {
195         *client = h2o_redis_create_client(ctx->loop, sizeof(h2o_redis_client_t));
196         (*client)->on_connect = on_redis_connect;
197         (*client)->on_close = on_redis_close;
198     }
199     return *client;
200 }
201 
202 #define BASE64_LENGTH(len) (((len) + 2) / 3 * 4 + 1)
203 
build_redis_key(h2o_iovec_t session_id,h2o_iovec_t prefix)204 static h2o_iovec_t build_redis_key(h2o_iovec_t session_id, h2o_iovec_t prefix)
205 {
206     h2o_iovec_t key;
207     key.base = h2o_mem_alloc(prefix.len + BASE64_LENGTH(session_id.len));
208     if (prefix.len != 0) {
209         memcpy(key.base, prefix.base, prefix.len);
210     }
211     key.len = prefix.len;
212     key.len += h2o_base64_encode(key.base + key.len, session_id.base, session_id.len, 1);
213     return key;
214 }
215 
build_redis_value(h2o_iovec_t session_data)216 static h2o_iovec_t build_redis_value(h2o_iovec_t session_data)
217 {
218     h2o_iovec_t value;
219     value.base = h2o_mem_alloc(BASE64_LENGTH(session_data.len));
220     value.len = h2o_base64_encode(value.base, session_data.base, session_data.len, 1);
221     return value;
222 }
223 
224 #undef BASE64_LENGTH
225 
redis_resumption_on_get(redisReply * reply,void * _accept_data,const char * errstr)226 static void redis_resumption_on_get(redisReply *reply, void *_accept_data, const char *errstr)
227 {
228     struct st_h2o_redis_resumption_accept_data_t *accept_data = _accept_data;
229     accept_data->get_command = NULL;
230 
231     h2o_iovec_t session_data;
232     if (reply != NULL && reply->type == REDIS_REPLY_STRING) {
233         session_data = h2o_decode_base64url(NULL, reply->str, reply->len);
234     } else {
235         session_data = h2o_iovec_init(NULL, 0);
236     }
237 
238     h2o_socket_ssl_resume_server_handshake(accept_data->super.sock, session_data);
239 
240     if (session_data.base != NULL)
241         free(session_data.base);
242 }
243 
on_redis_resumption_get_failed(h2o_timer_t * timeout_entry)244 static void on_redis_resumption_get_failed(h2o_timer_t *timeout_entry)
245 {
246     struct st_h2o_redis_resumption_accept_data_t *accept_data =
247         H2O_STRUCT_FROM_MEMBER(struct st_h2o_redis_resumption_accept_data_t, super.timeout, timeout_entry);
248     accept_data->get_command = NULL;
249     h2o_socket_ssl_resume_server_handshake(accept_data->super.sock, h2o_iovec_init(NULL, 0));
250     h2o_timer_unlink(timeout_entry);
251 }
252 
redis_resumption_get(h2o_socket_t * sock,h2o_iovec_t session_id)253 static void redis_resumption_get(h2o_socket_t *sock, h2o_iovec_t session_id)
254 {
255     struct st_h2o_redis_resumption_accept_data_t *accept_data = sock->data;
256     h2o_redis_client_t *client = get_redis_client(accept_data->super.ctx->ctx);
257 
258     if (client->state == H2O_REDIS_CONNECTION_STATE_CONNECTED) {
259         h2o_iovec_t key = build_redis_key(session_id, async_resumption_context.redis.prefix);
260         accept_data->get_command = h2o_redis_command(client, redis_resumption_on_get, accept_data, "GET %s", key.base);
261         free(key.base);
262     } else {
263         if (client->state == H2O_REDIS_CONNECTION_STATE_CLOSED) {
264             // try to connect
265             h2o_redis_connect(client, async_resumption_context.redis.host.base, async_resumption_context.redis.port);
266         }
267         // abort resumption
268         h2o_timer_unlink(&accept_data->super.timeout);
269         accept_data->super.timeout.cb = on_redis_resumption_get_failed;
270         h2o_timer_link(accept_data->super.ctx->ctx->loop, 0, &accept_data->super.timeout);
271     }
272 }
273 
redis_resumption_new(h2o_socket_t * sock,h2o_iovec_t session_id,h2o_iovec_t session_data)274 static void redis_resumption_new(h2o_socket_t *sock, h2o_iovec_t session_id, h2o_iovec_t session_data)
275 {
276     struct st_h2o_redis_resumption_accept_data_t *accept_data = sock->data;
277     h2o_redis_client_t *client = get_redis_client(accept_data->super.ctx->ctx);
278 
279     if (client->state == H2O_REDIS_CONNECTION_STATE_CLOSED) {
280         // try to connect
281         h2o_redis_connect(client, async_resumption_context.redis.host.base, async_resumption_context.redis.port);
282     }
283 
284     h2o_iovec_t key = build_redis_key(session_id, async_resumption_context.redis.prefix);
285     h2o_iovec_t value = build_redis_value(session_data);
286     h2o_redis_command(client, NULL, NULL, "SETEX %s %d %s", key.base, async_resumption_context.expiration * 10, value.base);
287     free(key.base);
288     free(value.base);
289 }
290 
h2o_accept_setup_redis_ssl_resumption(const char * host,uint16_t port,unsigned expiration,const char * prefix)291 void h2o_accept_setup_redis_ssl_resumption(const char *host, uint16_t port, unsigned expiration, const char *prefix)
292 {
293     async_resumption_context.redis.host = h2o_strdup(NULL, host, SIZE_MAX);
294     async_resumption_context.redis.port = port;
295     async_resumption_context.redis.prefix = h2o_strdup(NULL, prefix, SIZE_MAX);
296     async_resumption_context.expiration = expiration;
297 
298     h2o_socket_ssl_async_resumption_init(redis_resumption_get, redis_resumption_new);
299 
300     accept_data_callbacks.create = create_redis_accept_data;
301     accept_data_callbacks.destroy = destroy_redis_accept_data;
302 }
303 
accept_timeout(struct st_h2o_accept_data_t * data)304 static void accept_timeout(struct st_h2o_accept_data_t *data)
305 {
306     /* TODO log */
307     h2o_socket_t *sock = data->sock;
308     accept_data_callbacks.destroy(data);
309     h2o_socket_close(sock);
310 }
311 
on_accept_timeout(h2o_timer_t * entry)312 static void on_accept_timeout(h2o_timer_t *entry)
313 {
314     struct st_h2o_accept_data_t *data = H2O_STRUCT_FROM_MEMBER(struct st_h2o_accept_data_t, timeout, entry);
315     accept_timeout(data);
316 }
317 
on_redis_accept_timeout(h2o_timer_t * entry)318 static void on_redis_accept_timeout(h2o_timer_t *entry)
319 {
320     struct st_h2o_redis_resumption_accept_data_t *data =
321         H2O_STRUCT_FROM_MEMBER(struct st_h2o_redis_resumption_accept_data_t, super.timeout, entry);
322     if (data->get_command != NULL) {
323         data->get_command->cb = NULL;
324         data->get_command = NULL;
325     }
326     accept_timeout(&data->super);
327 }
328 
on_memcached_accept_timeout(h2o_timer_t * entry)329 static void on_memcached_accept_timeout(h2o_timer_t *entry)
330 {
331     struct st_h2o_memcached_resumption_accept_data_t *data =
332         H2O_STRUCT_FROM_MEMBER(struct st_h2o_memcached_resumption_accept_data_t, super.timeout, entry);
333     if (data->get_req != NULL) {
334         h2o_memcached_cancel_get(async_resumption_context.memcached.ctx, data->get_req);
335         data->get_req = NULL;
336     }
337     accept_timeout(&data->super);
338 }
339 
on_ssl_handshake_complete(h2o_socket_t * sock,const char * err)340 static void on_ssl_handshake_complete(h2o_socket_t *sock, const char *err)
341 {
342     struct st_h2o_accept_data_t *data = sock->data;
343     sock->data = NULL;
344 
345     if (err != NULL) {
346         ++data->ctx->ctx->ssl.errors;
347         h2o_socket_close(sock);
348         goto Exit;
349     }
350 
351     /* stats for handshake */
352     struct timeval handshake_completed_at = h2o_gettimeofday(data->ctx->ctx->loop);
353     int64_t handshake_time = h2o_timeval_subtract(&data->connected_at, &handshake_completed_at);
354     if (h2o_socket_get_ssl_session_reused(sock)) {
355         ++data->ctx->ctx->ssl.handshake_resume;
356         data->ctx->ctx->ssl.handshake_accum_time_resume += handshake_time;
357     } else {
358         ++data->ctx->ctx->ssl.handshake_full;
359         data->ctx->ctx->ssl.handshake_accum_time_full += handshake_time;
360     }
361 
362     h2o_iovec_t proto = h2o_socket_ssl_get_selected_protocol(sock);
363     const h2o_iovec_t *ident;
364     for (ident = h2o_http2_alpn_protocols; ident->len != 0; ++ident) {
365         if (proto.len == ident->len && memcmp(proto.base, ident->base, proto.len) == 0) {
366             /* connect as http2 */
367             ++data->ctx->ctx->ssl.alpn_h2;
368             h2o_http2_accept(data->ctx, sock, data->connected_at);
369             goto Exit;
370         }
371     }
372     /* connect as http1 */
373     if (proto.len != 0)
374         ++data->ctx->ctx->ssl.alpn_h1;
375     h2o_http1_accept(data->ctx, sock, data->connected_at);
376 
377 Exit:
378     accept_data_callbacks.destroy(data);
379 }
380 
parse_proxy_line(char * src,size_t len,struct sockaddr * sa,socklen_t * salen)381 static ssize_t parse_proxy_line(char *src, size_t len, struct sockaddr *sa, socklen_t *salen)
382 {
383 #define CHECK_EOF()                                                                                                                \
384     if (p == end)                                                                                                                  \
385     return -2
386 #define EXPECT_CHAR(ch)                                                                                                            \
387     do {                                                                                                                           \
388         CHECK_EOF();                                                                                                               \
389         if (*p++ != ch)                                                                                                            \
390             return -1;                                                                                                             \
391     } while (0)
392 #define SKIP_TO_WS()                                                                                                               \
393     do {                                                                                                                           \
394         do {                                                                                                                       \
395             CHECK_EOF();                                                                                                           \
396         } while (*p++ != ' ');                                                                                                     \
397         --p;                                                                                                                       \
398     } while (0)
399 
400     char *p = src, *end = p + len;
401     void *addr;
402     in_port_t *port;
403 
404     /* "PROXY "*/
405     EXPECT_CHAR('P');
406     EXPECT_CHAR('R');
407     EXPECT_CHAR('O');
408     EXPECT_CHAR('X');
409     EXPECT_CHAR('Y');
410     EXPECT_CHAR(' ');
411 
412     /* "TCP[46] " */
413     CHECK_EOF();
414     if (*p++ != 'T') {
415         *salen = 0; /* indicate that no data has been obtained */
416         goto SkipToEOL;
417     }
418     EXPECT_CHAR('C');
419     EXPECT_CHAR('P');
420     CHECK_EOF();
421     switch (*p++) {
422     case '4':
423         *salen = sizeof(struct sockaddr_in);
424         memset(sa, 0, sizeof(struct sockaddr_in));
425         sa->sa_family = AF_INET;
426         addr = &((struct sockaddr_in *)sa)->sin_addr;
427         port = &((struct sockaddr_in *)sa)->sin_port;
428         break;
429     case '6':
430         *salen = sizeof(struct sockaddr_in6);
431         memset(sa, 0, sizeof(struct sockaddr_in6));
432         sa->sa_family = AF_INET6;
433         addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
434         port = &((struct sockaddr_in6 *)sa)->sin6_port;
435         break;
436     default:
437         return -1;
438     }
439     EXPECT_CHAR(' ');
440 
441     /* parse peer address */
442     char *addr_start = p;
443     SKIP_TO_WS();
444     *p = '\0';
445     if (inet_pton(sa->sa_family, addr_start, addr) != 1)
446         return -1;
447     *p++ = ' ';
448 
449     /* skip local address */
450     SKIP_TO_WS();
451     ++p;
452 
453     /* parse peer port */
454     char *port_start = p;
455     SKIP_TO_WS();
456     *p = '\0';
457     unsigned short usval;
458     if (sscanf(port_start, "%hu", &usval) != 1)
459         return -1;
460     *port = htons(usval);
461     *p++ = ' ';
462 
463 SkipToEOL:
464     do {
465         CHECK_EOF();
466     } while (*p++ != '\r');
467     CHECK_EOF();
468     if (*p++ != '\n')
469         return -2;
470     return p - src;
471 
472 #undef CHECK_EOF
473 #undef EXPECT_CHAR
474 #undef SKIP_TO_WS
475 }
476 
on_read_proxy_line(h2o_socket_t * sock,const char * err)477 static void on_read_proxy_line(h2o_socket_t *sock, const char *err)
478 {
479     struct st_h2o_accept_data_t *data = sock->data;
480 
481     if (err != NULL) {
482         accept_data_callbacks.destroy(data);
483         h2o_socket_close(sock);
484         return;
485     }
486 
487     struct sockaddr_storage addr;
488     socklen_t addrlen;
489     ssize_t r = parse_proxy_line(sock->input->bytes, sock->input->size, (void *)&addr, &addrlen);
490     switch (r) {
491     case -1: /* error, just pass the input to the next handler */
492         break;
493     case -2: /* incomplete */
494         return;
495     default:
496         h2o_buffer_consume(&sock->input, r);
497         if (addrlen != 0)
498             h2o_socket_setpeername(sock, (void *)&addr, addrlen);
499         break;
500     }
501 
502     if (data->ctx->ssl_ctx != NULL) {
503         h2o_socket_ssl_handshake(sock, data->ctx->ssl_ctx, NULL, h2o_iovec_init(NULL, 0), on_ssl_handshake_complete);
504     } else {
505         struct st_h2o_accept_data_t *data = sock->data;
506         sock->data = NULL;
507         h2o_http1_accept(data->ctx, sock, data->connected_at);
508         accept_data_callbacks.destroy(data);
509     }
510 }
511 
h2o_accept(h2o_accept_ctx_t * ctx,h2o_socket_t * sock)512 void h2o_accept(h2o_accept_ctx_t *ctx, h2o_socket_t *sock)
513 {
514     struct timeval connected_at = h2o_gettimeofday(ctx->ctx->loop);
515 
516     if (ctx->expect_proxy_line || ctx->ssl_ctx != NULL) {
517         sock->data = accept_data_callbacks.create(ctx, sock, connected_at);
518         if (ctx->expect_proxy_line) {
519             h2o_socket_read_start(sock, on_read_proxy_line);
520         } else {
521             h2o_socket_ssl_handshake(sock, ctx->ssl_ctx, NULL, h2o_iovec_init(NULL, 0), on_ssl_handshake_complete);
522         }
523     } else {
524         h2o_http1_accept(ctx, sock, connected_at);
525     }
526 }
527 
h2o_stringify_protocol_version(char * dst,int version)528 size_t h2o_stringify_protocol_version(char *dst, int version)
529 {
530     char *p = dst;
531 
532     if (version < 0x200) {
533         assert(version <= 0x109);
534 #define PREFIX "HTTP/1."
535         memcpy(p, PREFIX, sizeof(PREFIX) - 1);
536         p += sizeof(PREFIX) - 1;
537 #undef PREFIX
538         *p++ = '0' + (version & 0xff);
539     } else {
540 #define PREFIX "HTTP/"
541         memcpy(p, PREFIX, sizeof(PREFIX) - 1);
542         p += sizeof(PREFIX) - 1;
543 #undef PREFIX
544         *p++ = (version >> 8) + '0';
545     }
546 
547     *p = '\0';
548     return p - dst;
549 }
550 
h2o_stringify_proxy_header(h2o_conn_t * conn,char * buf)551 size_t h2o_stringify_proxy_header(h2o_conn_t *conn, char *buf)
552 {
553     struct sockaddr_storage ss;
554     socklen_t sslen;
555     size_t strlen;
556     uint16_t peerport;
557     char *dst = buf;
558 
559     if ((sslen = conn->callbacks->get_peername(conn, (void *)&ss)) == 0)
560         goto Unknown;
561     switch (ss.ss_family) {
562     case AF_INET:
563         memcpy(dst, "PROXY TCP4 ", 11);
564         dst += 11;
565         break;
566     case AF_INET6:
567         memcpy(dst, "PROXY TCP6 ", 11);
568         dst += 11;
569         break;
570     default:
571         goto Unknown;
572     }
573     if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX)
574         goto Unknown;
575     dst += strlen;
576     *dst++ = ' ';
577 
578     peerport = h2o_socket_getport((void *)&ss);
579 
580     if ((sslen = conn->callbacks->get_sockname(conn, (void *)&ss)) == 0)
581         goto Unknown;
582     if ((strlen = h2o_socket_getnumerichost((void *)&ss, sslen, dst)) == SIZE_MAX)
583         goto Unknown;
584     dst += strlen;
585     *dst++ = ' ';
586 
587     dst += sprintf(dst, "%" PRIu16 " %" PRIu16 "\r\n", peerport, (uint16_t)h2o_socket_getport((void *)&ss));
588 
589     return dst - buf;
590 
591 Unknown:
592     memcpy(buf, "PROXY UNKNOWN\r\n", 15);
593     return 15;
594 }
595 
to_push_path(h2o_mem_pool_t * pool,h2o_iovec_t url,h2o_iovec_t base_path,const h2o_url_scheme_t * input_scheme,h2o_iovec_t input_authority,const h2o_url_scheme_t * base_scheme,h2o_iovec_t * base_authority,int allow_cross_origin_push)596 static h2o_iovec_t to_push_path(h2o_mem_pool_t *pool, h2o_iovec_t url, h2o_iovec_t base_path, const h2o_url_scheme_t *input_scheme,
597                                 h2o_iovec_t input_authority, const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority,
598                                 int allow_cross_origin_push)
599 {
600     h2o_url_t parsed, resolved;
601 
602     /* check the authority, and extract absolute path */
603     if (h2o_url_parse_relative(url.base, url.len, &parsed) != 0)
604         goto Invalid;
605 
606     /* fast-path for abspath form */
607     if (base_scheme == NULL && parsed.scheme == NULL && parsed.authority.base == NULL && url.len != 0 && url.base[0] == '/') {
608         return h2o_strdup(pool, url.base, url.len);
609     }
610 
611     /* check scheme and authority if given URL contains either of the two, or if base is specified */
612     h2o_url_t base = {input_scheme, input_authority, {NULL}, base_path, 65535};
613     if (base_scheme != NULL) {
614         base.scheme = base_scheme;
615         base.authority = *base_authority;
616     }
617     h2o_url_resolve(pool, &base, &parsed, &resolved);
618     if (input_scheme != resolved.scheme)
619         goto Invalid;
620     if (!allow_cross_origin_push &&
621         !h2o_lcstris(input_authority.base, input_authority.len, resolved.authority.base, resolved.authority.len))
622         goto Invalid;
623 
624     return resolved.path;
625 
626 Invalid:
627     return h2o_iovec_init(NULL, 0);
628 }
629 
h2o_extract_push_path_from_link_header(h2o_mem_pool_t * pool,const char * value,size_t value_len,h2o_iovec_t base_path,const h2o_url_scheme_t * input_scheme,h2o_iovec_t input_authority,const h2o_url_scheme_t * base_scheme,h2o_iovec_t * base_authority,void (* cb)(void * ctx,const char * path,size_t path_len,int is_critical),void * cb_ctx,h2o_iovec_t * filtered_value,int allow_cross_origin_push)630 void h2o_extract_push_path_from_link_header(h2o_mem_pool_t *pool, const char *value, size_t value_len, h2o_iovec_t base_path,
631                                             const h2o_url_scheme_t *input_scheme, h2o_iovec_t input_authority,
632                                             const h2o_url_scheme_t *base_scheme, h2o_iovec_t *base_authority,
633                                             void (*cb)(void *ctx, const char *path, size_t path_len, int is_critical), void *cb_ctx,
634                                             h2o_iovec_t *filtered_value, int allow_cross_origin_push)
635 {
636     h2o_iovec_t iter = h2o_iovec_init(value, value_len), token_value;
637     const char *token;
638     size_t token_len;
639     *filtered_value = h2o_iovec_init(NULL, 0);
640 
641 #define PUSH_FILTERED_VALUE(s, e)                                                                                                  \
642     do {                                                                                                                           \
643         if (filtered_value->len != 0) {                                                                                            \
644             memcpy(filtered_value->base + filtered_value->len, ", ", 2);                                                           \
645             filtered_value->len += 2;                                                                                              \
646         }                                                                                                                          \
647         memcpy(filtered_value->base + filtered_value->len, (s), (e) - (s));                                                        \
648         filtered_value->len += (e) - (s);                                                                                          \
649     } while (0)
650 
651     /* extract URL values from Link: </pushed.css>; rel=preload */
652     do {
653         if ((token = h2o_next_token(&iter, ';', ',', &token_len, NULL)) == NULL)
654             break;
655         /* first element should be <URL> */
656         if (!(token_len >= 2 && token[0] == '<' && token[token_len - 1] == '>'))
657             break;
658         h2o_iovec_t url_with_brackets = h2o_iovec_init(token, token_len);
659         /* find rel=preload */
660         int preload = 0, nopush = 0, push_only = 0, critical = 0;
661         while ((token = h2o_next_token(&iter, ';', ',', &token_len, &token_value)) != NULL &&
662                !h2o_memis(token, token_len, H2O_STRLIT(","))) {
663             if (h2o_lcstris(token, token_len, H2O_STRLIT("rel")) &&
664                 h2o_lcstris(token_value.base, token_value.len, H2O_STRLIT("preload"))) {
665                 preload = 1;
666             } else if (h2o_lcstris(token, token_len, H2O_STRLIT("nopush"))) {
667                 nopush = 1;
668             } else if (h2o_lcstris(token, token_len, H2O_STRLIT("x-http2-push-only"))) {
669                 push_only = 1;
670             } else if (h2o_lcstris(token, token_len, H2O_STRLIT("critical"))) {
671                 critical = 1;
672             }
673         }
674         /* push the path */
675         if (!nopush && preload) {
676             h2o_iovec_t path = to_push_path(pool, h2o_iovec_init(url_with_brackets.base + 1, url_with_brackets.len - 2), base_path,
677                                             input_scheme, input_authority, base_scheme, base_authority, allow_cross_origin_push);
678             if (path.len != 0)
679                 (*cb)(cb_ctx, path.base, path.len, critical);
680         }
681         /* store the elements that needs to be preserved to filtered_value */
682         if (push_only) {
683             if (filtered_value->base == NULL) {
684                 /* the max. size of filtered_value would be x2 in the worst case, when "," is converted to ", " */
685                 filtered_value->base = h2o_mem_alloc_pool(pool, char, value_len * 2);
686                 const char *prev_comma = h2o_memrchr(value, ',', url_with_brackets.base - value);
687                 if (prev_comma != NULL)
688                     PUSH_FILTERED_VALUE(value, prev_comma);
689             }
690         } else if (filtered_value->base != NULL) {
691             PUSH_FILTERED_VALUE(url_with_brackets.base, token != NULL ? token : value + value_len);
692         }
693     } while (token != NULL);
694 
695     if (filtered_value->base != NULL) {
696         if (token != NULL)
697             PUSH_FILTERED_VALUE(token, value + value_len);
698     } else {
699         *filtered_value = h2o_iovec_init(value, value_len);
700     }
701 
702 #undef PUSH_FILTERED_VALUE
703 }
704 
h2o_get_compressible_types(const h2o_headers_t * headers)705 int h2o_get_compressible_types(const h2o_headers_t *headers)
706 {
707     size_t header_index;
708     int compressible_types = 0;
709 
710     for (header_index = 0; header_index != headers->size; ++header_index) {
711         const h2o_header_t *header = headers->entries + header_index;
712         if (H2O_UNLIKELY(header->name == &H2O_TOKEN_ACCEPT_ENCODING->buf)) {
713             h2o_iovec_t iter = h2o_iovec_init(header->value.base, header->value.len);
714             const char *token = NULL;
715             size_t token_len = 0;
716             while ((token = h2o_next_token(&iter, ',', ',', &token_len, NULL)) != NULL) {
717                 if (h2o_lcstris(token, token_len, H2O_STRLIT("gzip")))
718                     compressible_types |= H2O_COMPRESSIBLE_GZIP;
719                 else if (h2o_lcstris(token, token_len, H2O_STRLIT("br")))
720                     compressible_types |= H2O_COMPRESSIBLE_BROTLI;
721             }
722         }
723     }
724 
725     return compressible_types;
726 }
727 
h2o_build_destination(h2o_req_t * req,const char * prefix,size_t prefix_len,int use_path_normalized)728 h2o_iovec_t h2o_build_destination(h2o_req_t *req, const char *prefix, size_t prefix_len, int use_path_normalized)
729 {
730     h2o_iovec_t parts[4];
731     size_t num_parts = 0;
732     int conf_ends_with_slash = req->pathconf->path.base[req->pathconf->path.len - 1] == '/', prefix_ends_with_slash;
733 
734     /* destination starts with given prefix, if any */
735     if (prefix_len != 0) {
736         parts[num_parts++] = h2o_iovec_init(prefix, prefix_len);
737         prefix_ends_with_slash = prefix[prefix_len - 1] == '/';
738     } else {
739         prefix_ends_with_slash = 0;
740     }
741 
742     /* make adjustments depending on the trailing slashes */
743     if (conf_ends_with_slash != prefix_ends_with_slash) {
744         if (conf_ends_with_slash) {
745             parts[num_parts++] = h2o_iovec_init(H2O_STRLIT("/"));
746         } else {
747             if (req->path_normalized.len != req->pathconf->path.len)
748                 parts[num_parts - 1].len -= 1;
749         }
750     }
751 
752     /* append suffix path and query */
753 
754     if (use_path_normalized) {
755         parts[num_parts++] = h2o_uri_escape(&req->pool, req->path_normalized.base + req->pathconf->path.len,
756                                             req->path_normalized.len - req->pathconf->path.len, "/@:");
757         if (req->query_at != SIZE_MAX) {
758             parts[num_parts++] = h2o_iovec_init(req->path.base + req->query_at, req->path.len - req->query_at);
759         }
760     } else {
761         if (req->path.len > 1) {
762             /*
763              * When proxying, we want to modify the input URL as little
764              * as possible. We use norm_indexes to find the start of
765              * the path we want to forward.
766              */
767             size_t next_unnormalized;
768             if (req->norm_indexes && req->pathconf->path.len > 1) {
769                 next_unnormalized = req->norm_indexes[req->pathconf->path.len - 1];
770             } else {
771                 next_unnormalized = req->pathconf->path.len;
772             }
773 
774             /*
775              * Special case: the input path didn't have any '/' including the first,
776              * so the first character is actually found at '0'
777              */
778             if (req->path.base[0] != '/' && next_unnormalized == 1) {
779                 next_unnormalized = 0;
780             }
781             parts[num_parts++] = (h2o_iovec_t){req->path.base + next_unnormalized, req->path.len - next_unnormalized};
782         }
783     }
784 
785     return h2o_concat_list(&req->pool, parts, num_parts);
786 }
787 
788 #define SERVER_TIMING_DURATION_LONGEST_STR "dur=" H2O_INT32_LONGEST_STR ".000"
789 
stringify_duration(char * buf,int64_t usec)790 size_t stringify_duration(char *buf, int64_t usec)
791 {
792     int32_t msec = (int32_t)(usec / 1000);
793     usec -= ((int64_t)msec * 1000);
794     char *pos = buf;
795     pos += sprintf(pos, "dur=%" PRId32, msec);
796     if (usec != 0) {
797         *pos++ = '.';
798         int denom;
799         for (denom = 100; denom != 0; denom /= 10) {
800             int d = (int)usec / denom;
801             *pos++ = '0' + d;
802             usec -= d * denom;
803             if (usec == 0)
804                 break;
805         }
806     }
807     return pos - buf;
808 }
809 
810 #define DELIMITER ", "
811 #define ELEMENT_LONGEST_STR(name) name "; " SERVER_TIMING_DURATION_LONGEST_STR
812 
emit_server_timing_element(h2o_req_t * req,h2o_iovec_t * dst,const char * name,int (* compute_func)(h2o_req_t *,int64_t *),size_t max_len)813 static void emit_server_timing_element(h2o_req_t *req, h2o_iovec_t *dst, const char *name,
814                                        int (*compute_func)(h2o_req_t *, int64_t *), size_t max_len)
815 {
816     int64_t usec;
817     if (compute_func(req, &usec) == 0)
818         return;
819     if (dst->len == 0) {
820         if (max_len != SIZE_MAX)
821             dst->base = h2o_mem_alloc_pool(&req->pool, *dst->base, max_len);
822     } else {
823         dst->base[dst->len++] = ',';
824         dst->base[dst->len++] = ' ';
825     }
826     size_t name_len = strlen(name);
827     memcpy(dst->base + dst->len, name, name_len);
828     dst->len += name_len;
829     dst->base[dst->len++] = ';';
830     dst->base[dst->len++] = ' ';
831     dst->len += stringify_duration(dst->base + dst->len, usec);
832 }
833 
h2o_add_server_timing_header(h2o_req_t * req,int uses_trailer)834 void h2o_add_server_timing_header(h2o_req_t *req, int uses_trailer)
835 {
836     /* caller needs to make sure that trailers can be used */
837     if (0x101 <= req->version && req->version < 0x200)
838         assert(req->content_length == SIZE_MAX);
839 
840     /* emit timings */
841     h2o_iovec_t dst = {NULL};
842 
843 #define LONGEST_STR                                                                                                                \
844     ELEMENT_LONGEST_STR("connect")                                                                                                 \
845     DELIMITER ELEMENT_LONGEST_STR("request-header") DELIMITER ELEMENT_LONGEST_STR("request-body")                                  \
846         DELIMITER ELEMENT_LONGEST_STR("request-total") DELIMITER ELEMENT_LONGEST_STR("process")                                    \
847             DELIMITER ELEMENT_LONGEST_STR("proxy.idle") DELIMITER ELEMENT_LONGEST_STR("proxy.connect")                             \
848                 DELIMITER ELEMENT_LONGEST_STR("proxy.request") DELIMITER ELEMENT_LONGEST_STR("proxy.process")
849     size_t max_len = sizeof(LONGEST_STR) - 1;
850 
851     if ((req->send_server_timing & H2O_SEND_SERVER_TIMING_BASIC) != 0) {
852         emit_server_timing_element(req, &dst, "connect", h2o_time_compute_connect_time, max_len);
853         emit_server_timing_element(req, &dst, "request-header", h2o_time_compute_header_time, max_len);
854         emit_server_timing_element(req, &dst, "request-body", h2o_time_compute_body_time, max_len);
855         emit_server_timing_element(req, &dst, "request-total", h2o_time_compute_request_total_time, max_len);
856         emit_server_timing_element(req, &dst, "process", h2o_time_compute_process_time, max_len);
857     }
858     if ((req->send_server_timing & H2O_SEND_SERVER_TIMING_PROXY) != 0) {
859         emit_server_timing_element(req, &dst, "proxy.idle", h2o_time_compute_proxy_idle_time, max_len);
860         emit_server_timing_element(req, &dst, "proxy.connect", h2o_time_compute_proxy_connect_time, max_len);
861         emit_server_timing_element(req, &dst, "proxy.request", h2o_time_compute_proxy_request_time, max_len);
862         emit_server_timing_element(req, &dst, "proxy.process", h2o_time_compute_proxy_process_time, max_len);
863     }
864 
865 #undef LONGEST_STR
866 
867     if (uses_trailer)
868         h2o_add_header_by_str(&req->pool, &req->res.headers, H2O_STRLIT("trailer"), 0, NULL, H2O_STRLIT("server-timing"));
869     if (dst.len != 0)
870         h2o_add_header_by_str(&req->pool, &req->res.headers, H2O_STRLIT("server-timing"), 0, NULL, dst.base, dst.len);
871 }
872 
h2o_build_server_timing_trailer(h2o_req_t * req,const char * prefix,size_t prefix_len,const char * suffix,size_t suffix_len)873 h2o_iovec_t h2o_build_server_timing_trailer(h2o_req_t *req, const char *prefix, size_t prefix_len, const char *suffix,
874                                             size_t suffix_len)
875 {
876     h2o_iovec_t value;
877 
878 #define LONGEST_STR                                                                                                                \
879     ELEMENT_LONGEST_STR("response")                                                                                                \
880     DELIMITER ELEMENT_LONGEST_STR("total") DELIMITER ELEMENT_LONGEST_STR("proxy.response")                                         \
881         DELIMITER ELEMENT_LONGEST_STR("proxy.total")
882 
883     value.base = h2o_mem_alloc_pool(&req->pool, *value.base, prefix_len + suffix_len + sizeof(LONGEST_STR) - 1);
884     value.len = 0;
885 
886     if (prefix_len != 0) {
887         memcpy(value.base + value.len, prefix, prefix_len);
888         value.len += prefix_len;
889     }
890 
891     h2o_iovec_t dst = h2o_iovec_init(value.base + value.len, 0);
892 
893     if ((req->send_server_timing & H2O_SEND_SERVER_TIMING_BASIC) != 0) {
894         emit_server_timing_element(req, &dst, "response", h2o_time_compute_response_time, SIZE_MAX);
895         emit_server_timing_element(req, &dst, "total", h2o_time_compute_total_time, SIZE_MAX);
896     }
897     if ((req->send_server_timing & H2O_SEND_SERVER_TIMING_PROXY) != 0) {
898         emit_server_timing_element(req, &dst, "proxy.response", h2o_time_compute_proxy_response_time, SIZE_MAX);
899         emit_server_timing_element(req, &dst, "proxy.total", h2o_time_compute_proxy_total_time, SIZE_MAX);
900     }
901 
902     if (dst.len == 0)
903         return h2o_iovec_init(NULL, 0);
904     value.len += dst.len;
905 
906     if (suffix_len != 0) {
907         memcpy(value.base + value.len, suffix, suffix_len);
908         value.len += suffix_len;
909     }
910 
911     return value;
912 
913 #undef LONGEST_STR
914 }
915 
916 #undef ELEMENT_LONGEST_STR
917 #undef DELIMITER
918 
919 /* h2-14 and h2-16 are kept for backwards compatibility, as they are often used */
920 #define ALPN_ENTRY(s)                                                                                                              \
921     {                                                                                                                              \
922         H2O_STRLIT(s)                                                                                                              \
923     }
924 #define ALPN_PROTOCOLS_CORE ALPN_ENTRY("h2"), ALPN_ENTRY("h2-16"), ALPN_ENTRY("h2-14")
925 #define NPN_PROTOCOLS_CORE                                                                                                         \
926     "\x02"                                                                                                                         \
927     "h2"                                                                                                                           \
928     "\x05"                                                                                                                         \
929     "h2-16"                                                                                                                        \
930     "\x05"                                                                                                                         \
931     "h2-14"
932 
933 const h2o_iovec_t h2o_http2_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, {NULL}};
934 const h2o_iovec_t h2o_alpn_protocols[] = {ALPN_PROTOCOLS_CORE, ALPN_ENTRY("http/1.1"), {NULL}};
935 
936 const char h2o_http2_npn_protocols[] = NPN_PROTOCOLS_CORE;
937 const char h2o_npn_protocols[] = NPN_PROTOCOLS_CORE "\x08"
938                                                     "http/1.1";
939 
940 uint64_t h2o_connection_id = 0;
941 
h2o_cleanup_thread(void)942 void h2o_cleanup_thread(void)
943 {
944     h2o_mem_clear_recycle(&h2o_mem_pool_allocator, 1);
945     h2o_buffer_clear_recycle(1);
946 }
947