1 /*
2 * Copyright (c) 2015 DeNA Co., Ltd., Kazuho Oku
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 "h2o.h"
23
24 struct st_headers_filter_t {
25 h2o_filter_t super;
26 h2o_headers_command_t *cmds;
27 };
28
29 struct st_headers_early_hints_handler_t {
30 h2o_handler_t super;
31 h2o_headers_command_t *cmds;
32 };
33
34 struct st_headers_early_hints_sender_t {
35 h2o_req_t *req;
36 h2o_headers_command_t *cmds;
37 h2o_timer_t deferred_timeout_entry;
38 };
39
on_setup_ostream(h2o_filter_t * _self,h2o_req_t * req,h2o_ostream_t ** slot)40 static void on_setup_ostream(h2o_filter_t *_self, h2o_req_t *req, h2o_ostream_t **slot)
41 {
42 struct st_headers_filter_t *self = (void *)_self;
43 h2o_headers_command_t *cmd;
44
45 for (cmd = self->cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) {
46 if (cmd->when != H2O_HEADERS_CMD_WHEN_EARLY)
47 h2o_rewrite_headers(&req->pool, &req->res.headers, cmd);
48 }
49
50 h2o_setup_next_ostream(req, slot);
51 }
52
on_informational(h2o_filter_t * _self,h2o_req_t * req)53 static void on_informational(h2o_filter_t *_self, h2o_req_t *req)
54 {
55 struct st_headers_filter_t *self = (void *)_self;
56 h2o_headers_command_t *cmd;
57
58 if (req->res.status != 103)
59 return;
60
61 for (cmd = self->cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) {
62 if (cmd->when != H2O_HEADERS_CMD_WHEN_FINAL)
63 h2o_rewrite_headers(&req->pool, &req->res.headers, cmd);
64 }
65 }
66
on_sender_deferred_timeout(h2o_timer_t * entry)67 static void on_sender_deferred_timeout(h2o_timer_t *entry)
68 {
69 struct st_headers_early_hints_sender_t *sender =
70 H2O_STRUCT_FROM_MEMBER(struct st_headers_early_hints_sender_t, deferred_timeout_entry, entry);
71
72 if (sender->req->res.status != 0)
73 return;
74
75 sender->req->res.status = 103;
76
77 /* expect on_informational will be called and applies headers commands */
78 h2o_send_informational(sender->req);
79 }
80
on_sender_dispose(void * _sender)81 static void on_sender_dispose(void *_sender)
82 {
83 struct st_headers_early_hints_sender_t *sender = (struct st_headers_early_hints_sender_t *)_sender;
84 if (h2o_timer_is_linked(&sender->deferred_timeout_entry))
85 h2o_timer_unlink(&sender->deferred_timeout_entry);
86 }
87
on_req(h2o_handler_t * _handler,h2o_req_t * req)88 static int on_req(h2o_handler_t *_handler, h2o_req_t *req)
89 {
90 struct st_headers_early_hints_handler_t *handler = (void *)_handler;
91
92 struct st_headers_early_hints_sender_t *sender = h2o_mem_alloc_shared(&req->pool, sizeof(*sender), on_sender_dispose);
93 sender->req = req;
94 sender->cmds = handler->cmds;
95 h2o_timer_init(&sender->deferred_timeout_entry, on_sender_deferred_timeout);
96 h2o_timer_link(req->conn->ctx->loop, 0, &sender->deferred_timeout_entry);
97
98 return -1;
99 }
100
requires_early_hints_handler(struct st_headers_filter_t * self)101 static int requires_early_hints_handler(struct st_headers_filter_t *self)
102 {
103 h2o_headers_command_t *cmd;
104 for (cmd = self->cmds; cmd->cmd != H2O_HEADERS_CMD_NULL; ++cmd) {
105 if (cmd->cmd != H2O_HEADERS_CMD_UNSET && cmd->when != H2O_HEADERS_CMD_WHEN_FINAL)
106 return 1;
107 }
108 return 0;
109 }
110
h2o_headers_register(h2o_pathconf_t * pathconf,h2o_headers_command_t * cmds)111 void h2o_headers_register(h2o_pathconf_t *pathconf, h2o_headers_command_t *cmds)
112 {
113 struct st_headers_filter_t *self = (void *)h2o_create_filter(pathconf, sizeof(*self));
114
115 self->super.on_setup_ostream = on_setup_ostream;
116 self->super.on_informational = on_informational;
117 self->cmds = cmds;
118
119 if (requires_early_hints_handler(self)) {
120 struct st_headers_early_hints_handler_t *handler = (void *)h2o_create_handler(pathconf, sizeof(*handler));
121 handler->cmds = cmds;
122 handler->super.on_req = on_req;
123
124 /* move this handler to first */
125 memmove(pathconf->handlers.entries + 1, pathconf->handlers.entries,
126 sizeof(h2o_handler_t *) * (pathconf->handlers.size - 1));
127 pathconf->handlers.entries[0] = &handler->super;
128 }
129 }
130
h2o_headers_is_prohibited_name(const h2o_token_t * token)131 int h2o_headers_is_prohibited_name(const h2o_token_t *token)
132 {
133 /* prohibit connection-specific headers */
134 if (token == H2O_TOKEN_CONNECTION || token == H2O_TOKEN_CONTENT_LENGTH || token == H2O_TOKEN_TRANSFER_ENCODING)
135 return 1;
136 /* prohibit headers added at protocol layer */
137 if (token == H2O_TOKEN_DATE || token == H2O_TOKEN_SERVER)
138 return 1;
139 /* all others are permitted */
140 return 0;
141 }
142