1 /*
2  * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku, Ryosuke Matsumoto
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 #ifndef H20_MRUBY_H
23 #define H20_MRUBY_H
24 
25 #include "h2o.h"
26 #include <mruby.h>
27 #include <mruby/data.h>
28 #include <mruby/proc.h>
29 #include <mruby/compile.h>
30 
31 #define H2O_MRUBY_MODULE_NAME "h2o_mruby"
32 
33 enum {
34     /* [0 .. H2O_MAX_TOKENS-1] are header names */
35     /* [H2O_MAX_TOKENS .. H2O_MAX_TOKENS*2-1] are header names in environment variable style (i.e, "HTTP_FOO_BAR") */
36     H2O_MRUBY_LIT_REQUEST_METHOD = H2O_MAX_TOKENS * 2,
37     H2O_MRUBY_LIT_SCRIPT_NAME,
38     H2O_MRUBY_LIT_PATH_INFO,
39     H2O_MRUBY_LIT_QUERY_STRING,
40     H2O_MRUBY_LIT_SERVER_NAME,
41     H2O_MRUBY_LIT_SERVER_ADDR,
42     H2O_MRUBY_LIT_SERVER_PORT,
43     H2O_MRUBY_LIT_SERVER_PROTOCOL,
44     H2O_MRUBY_LIT_CONTENT_LENGTH,
45     H2O_MRUBY_LIT_REMOTE_ADDR,
46     H2O_MRUBY_LIT_REMOTE_PORT,
47     H2O_MRUBY_LIT_REMOTE_USER,
48     H2O_MRUBY_LIT_RACK_URL_SCHEME,
49     H2O_MRUBY_LIT_RACK_MULTITHREAD,
50     H2O_MRUBY_LIT_RACK_MULTIPROCESS,
51     H2O_MRUBY_LIT_RACK_RUN_ONCE,
52     H2O_MRUBY_LIT_RACK_HIJACK_,
53     H2O_MRUBY_LIT_RACK_INPUT,
54     H2O_MRUBY_LIT_RACK_ERRORS,
55     H2O_MRUBY_LIT_RACK_EARLY_HINTS,
56     H2O_MRUBY_LIT_SERVER_SOFTWARE,
57     H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE,
58     H2O_MRUBY_LIT_H2O_REMAINING_DELEGATIONS,
59     H2O_MRUBY_LIT_H2O_REMAINING_REPROCESSES,
60     H2O_MRUBY_LIT_H2O_GET_RTT,
61     H2O_MRUBY_PROC_EACH_TO_ARRAY,
62     H2O_MRUBY_PROC_APP_TO_FIBER,
63 
64     H2O_MRUBY_H2O_MODULE,
65     H2O_MRUBY_GENERATOR_CLASS,
66     H2O_MRUBY_ERROR_STREAM_CLASS,
67     H2O_MRUBY_APP_REQUEST_CLASS,
68     H2O_MRUBY_APP_INPUT_STREAM_CLASS,
69 
70     /* used by sender.c */
71     H2O_MRUBY_SENDER_PROC_EACH_TO_FIBER,
72 
73     /* used by http_request.c */
74     H2O_MRUBY_HTTP_REQUEST_CLASS,
75     H2O_MRUBY_HTTP_INPUT_STREAM_CLASS,
76     H2O_MRUBY_HTTP_EMPTY_INPUT_STREAM_CLASS,
77 
78     /* used by channel.c */
79     H2O_MRUBY_CHANNEL_CLASS,
80 
81     H2O_MRUBY_NUM_CONSTANTS
82 };
83 
84 typedef struct st_h2o_mruby_config_vars_t {
85     h2o_iovec_t source;
86     char *path;
87     int lineno;
88 } h2o_mruby_config_vars_t;
89 
90 typedef struct st_h2o_mruby_handler_t {
91     h2o_handler_t super;
92     h2o_mruby_config_vars_t config;
93     h2o_pathconf_t *pathconf;
94 } h2o_mruby_handler_t;
95 
96 typedef struct st_h2o_mruby_context_t h2o_mruby_context_t;
97 typedef mrb_value (*h2o_mruby_callback_t)(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args,
98                                           int *run_again);
99 typedef H2O_VECTOR(h2o_mruby_callback_t) h2o_mruby_callbacks_t;
100 
101 typedef struct st_h2o_mruby_shared_context_t {
102     h2o_context_t *ctx;
103     mrb_state *mrb;
104     mrb_value constants;
105     struct st_h2o_mruby_context_t *current_context;
106     struct {
107         mrb_sym sym_call;
108         mrb_sym sym_close;
109         mrb_sym sym_method;
110         mrb_sym sym_headers;
111         mrb_sym sym_body;
112         mrb_sym sym_async;
113     } symbols;
114     h2o_mruby_callbacks_t callbacks;
115 } h2o_mruby_shared_context_t;
116 
117 struct st_h2o_mruby_context_t {
118     h2o_mruby_handler_t *handler;
119     mrb_value proc;
120     h2o_mruby_shared_context_t *shared;
121     mrb_value blocking_reqs;
122     mrb_value resumers;
123 };
124 
125 typedef struct st_h2o_mruby_sender_t h2o_mruby_sender_t;
126 typedef struct st_h2o_mruby_http_request_context_t h2o_mruby_http_request_context_t;
127 typedef struct st_h2o_mruby_channel_context_t h2o_mruby_channel_context_t;
128 typedef struct st_h2o_mruby_generator_t h2o_mruby_generator_t;
129 
130 typedef int (*h2o_mruby_send_response_callback_t)(h2o_mruby_generator_t *generator, mrb_int status, mrb_value resp,
131                                                   int *is_delegate);
132 
133 struct st_h2o_mruby_sender_t {
134     /**
135      * The body object being sent to the native side. Becomes nil on eos.
136      */
137     mrb_value body_obj;
138     /**
139      * Size of the body being sent. SIZE_MAX indicates that the number is undetermined (i.e. no Content-Length).
140      */
141     size_t bytes_left;
142     /**
143      * Initializes the subclass. called immediately after h2o_start_response is called
144      */
145     void (*start)(h2o_mruby_generator_t *generator);
146     /**
147      * called directly by protocol handler
148      */
149     void (*proceed)(h2o_generator_t *generator, h2o_req_t *req);
150     /**
151      * called when the generator is disposed
152      */
153     void (*dispose)(h2o_mruby_generator_t *generator);
154     /**
155      * if `h2o_send` has been closed (by passing any other flag than in-progress
156      */
157     unsigned char final_sent : 1;
158 };
159 
160 typedef struct st_h2o_mruby_error_stream_t {
161     h2o_mruby_context_t *ctx;
162     h2o_mruby_generator_t *generator;
163 } h2o_mruby_error_stream_t;
164 
165 struct st_h2o_mruby_generator_t {
166     h2o_generator_t super;
167     h2o_req_t *req; /* becomes NULL once the underlying connection gets terminated */
168     h2o_mruby_context_t *ctx;
169     mrb_value rack_input;
170     h2o_mruby_sender_t *sender;
171     h2o_mruby_error_stream_t *error_stream;
172     struct {
173         mrb_value generator;
174         mrb_value error_stream;
175     } refs;
176 };
177 
178 #define h2o_mruby_assert(mrb)                                                                                                      \
179     do {                                                                                                                           \
180         if (mrb->exc != NULL)                                                                                                      \
181             h2o_mruby__abort_exc(mrb, "unexpected ruby error", __FILE__, __LINE__);                                                \
182     } while (0)
183 
184 #define h2o_mruby_new_str(mrb, s, l) h2o_mruby__new_str((mrb), (s), (l), 0, __FILE__, __LINE__)
185 #define h2o_mruby_new_str_static(mrb, s, l) h2o_mruby__new_str((mrb), (s), (l), 1, __FILE__, __LINE__)
186 
187 /* source files using this macro should include mruby/throw.h */
188 #define H2O_MRUBY_EXEC_GUARD(block)                                                                                                \
189     do {                                                                                                                           \
190         struct mrb_jmpbuf *prev_jmp = mrb->jmp;                                                                                    \
191         struct mrb_jmpbuf c_jmp;                                                                                                   \
192         MRB_TRY(&c_jmp)                                                                                                            \
193         {                                                                                                                          \
194             mrb->jmp = &c_jmp;                                                                                                     \
195             do {                                                                                                                   \
196                 block                                                                                                              \
197             } while (0);                                                                                                           \
198             mrb->jmp = prev_jmp;                                                                                                   \
199         }                                                                                                                          \
200         MRB_CATCH(&c_jmp)                                                                                                          \
201         {                                                                                                                          \
202             mrb->jmp = prev_jmp;                                                                                                   \
203         }                                                                                                                          \
204         MRB_END_EXC(&c_jmp);                                                                                                       \
205     } while (0)
206 
207 /* handler/mruby.c */
208 void h2o_mruby__abort_exc(mrb_state *mrb, const char *mess, const char *file, int line);
209 mrb_value h2o_mruby__new_str(mrb_state *mrb, const char *s, size_t len, int is_static, const char *file, int line);
210 mrb_value h2o_mruby_to_str(mrb_state *mrb, mrb_value v);
211 mrb_value h2o_mruby_to_int(mrb_state *mrb, mrb_value v);
212 mrb_value h2o_mruby_eval_expr(mrb_state *mrb, const char *expr);
213 mrb_value h2o_mruby_eval_expr_location(mrb_state *mrb, const char *expr, const char *path, const int lineno);
214 void h2o_mruby_define_callback(mrb_state *mrb, const char *name, h2o_mruby_callback_t callback);
215 mrb_value h2o_mruby_create_data_instance(mrb_state *mrb, mrb_value class_obj, void *ptr, const mrb_data_type *type);
216 void h2o_mruby_setup_globals(mrb_state *mrb);
217 struct RProc *h2o_mruby_compile_code(mrb_state *mrb, h2o_mruby_config_vars_t *config, char *errbuf);
218 h2o_mruby_handler_t *h2o_mruby_register(h2o_pathconf_t *pathconf, h2o_mruby_config_vars_t *config);
219 
220 void h2o_mruby_run_fiber(h2o_mruby_context_t *ctx, mrb_value receiver, mrb_value input, int *is_delegate);
221 mrb_value h2o_mruby_each_to_array(h2o_mruby_shared_context_t *shared_ctx, mrb_value src);
222 int h2o_mruby_iterate_rack_headers(h2o_mruby_shared_context_t *shared_ctx, mrb_value headers,
223                                    int (*cb)(h2o_mruby_shared_context_t *, h2o_iovec_t *, h2o_iovec_t, void *), void *cb_data);
224 int h2o_mruby_iterate_header_values(h2o_mruby_shared_context_t *shared_ctx, mrb_value name, mrb_value value,
225                                     int (*cb)(h2o_mruby_shared_context_t *, h2o_iovec_t *, h2o_iovec_t, void *), void *cb_data);
226 int h2o_mruby_iterate_native_headers(h2o_mruby_shared_context_t *shared_ctx, h2o_mem_pool_t *pool, h2o_headers_t *headers,
227                                      int (*cb)(h2o_mruby_shared_context_t *, h2o_mem_pool_t *, h2o_header_t *, void *),
228                                      void *cb_data);
229 int h2o_mruby_set_response_header(h2o_mruby_shared_context_t *shared_ctx, h2o_iovec_t *name, h2o_iovec_t value, void *req);
230 
231 mrb_value h2o_mruby_token_string(h2o_mruby_shared_context_t *shared, const h2o_token_t *token);
232 mrb_value h2o_mruby_token_env_key(h2o_mruby_shared_context_t *shared, const h2o_token_t *token);
233 
234 /* handler/mruby/sender.c */
235 void h2o_mruby_sender_init_context(h2o_mruby_shared_context_t *ctx);
236 /**
237  * create and set new sender object corresponding the body argument. called only from send_response in mruby.c
238  */
239 int h2o_mruby_init_sender(h2o_mruby_generator_t *generator, mrb_value body);
240 /**
241  * create base sender object, called by subclasses (http_request, middleware, etc)
242  */
243 h2o_mruby_sender_t *h2o_mruby_sender_create(h2o_mruby_generator_t *generator, mrb_value body, size_t alignment, size_t sz);
244 /**
245  * a wrapper of h2o_send with counting and checking content-length
246  */
247 void h2o_mruby_sender_do_send(h2o_mruby_generator_t *generator, h2o_sendvec_t *bufs, size_t bufcnt, h2o_send_state_t state);
248 /**
249  * utility function used by sender implementations that needs buffering
250  */
251 void h2o_mruby_sender_do_send_buffer(h2o_mruby_generator_t *generator, h2o_doublebuffer_t *db, h2o_buffer_t **input, int is_final);
252 /**
253  * close body object, called when responding is stopped or finally disposed
254  */
255 void h2o_mruby_sender_close_body(h2o_mruby_generator_t *generator);
256 
257 /* handler/mruby/http_request.c */
258 void h2o_mruby_http_request_init_context(h2o_mruby_shared_context_t *ctx);
259 h2o_mruby_sender_t *h2o_mruby_http_sender_create(h2o_mruby_generator_t *generator, mrb_value body);
260 
261 /* handler/mruby/redis.c */
262 void h2o_mruby_redis_init_context(h2o_mruby_shared_context_t *ctx);
263 
264 /* handler/mruby/sleep.c */
265 void h2o_mruby_sleep_init_context(h2o_mruby_shared_context_t *ctx);
266 
267 /* handler/mruby/middleware.c */
268 void h2o_mruby_middleware_init_context(h2o_mruby_shared_context_t *ctx);
269 h2o_mruby_sender_t *h2o_mruby_middleware_sender_create(h2o_mruby_generator_t *generator, mrb_value body);
270 h2o_mruby_send_response_callback_t h2o_mruby_middleware_get_send_response_callback(h2o_mruby_context_t *ctx, mrb_value resp);
271 
272 /* handler/mruby/channel.c */
273 void h2o_mruby_channel_init_context(h2o_mruby_shared_context_t *ctx);
274 
275 /* handler/configurator/mruby.c */
276 void h2o_mruby_register_configurator(h2o_globalconf_t *conf);
277 
278 h2o_mruby_generator_t *h2o_mruby_get_generator(mrb_state *mrb, mrb_value obj);
279 h2o_mruby_error_stream_t *h2o_mruby_get_error_stream(mrb_state *mrb, mrb_value obj);
280 
281 #endif
282