int decode_ssl_input(h2o_socket_t *sock) { assert(sock->ssl != NULL); assert(sock->ssl->handshake.cb == NULL); while (sock->ssl->input.encrypted->size != 0 || SSL_pending(sock->ssl->ssl)) { int rlen; h2o_iovec_t buf = h2o_buffer_reserve(&sock->input, 4096); if (buf.base == NULL) return errno; { /* call SSL_read (while detecting SSL renegotiation and reporting it as error) */ int did_write_in_read = 0; sock->ssl->did_write_in_read = &did_write_in_read; rlen = SSL_read(sock->ssl->ssl, buf.base, (int)buf.len); sock->ssl->did_write_in_read = NULL; if (did_write_in_read) return EIO; } if (rlen == -1) { if (SSL_get_error(sock->ssl->ssl, rlen) != SSL_ERROR_WANT_READ) { return EIO; } break; } else if (rlen == 0) { break; } else { sock->input->size += rlen; } } return 0; }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; pid_t pid = -1; int mutex_locked = 0, ret = -1; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); pthread_mutex_lock(&cloexec_mutex); mutex_locked = 1; /* create pipe for reading the result */ if (pipe(respfds) != 0) goto Exit; fcntl(respfds[0], F_SETFD, O_CLOEXEC); /* spawn */ int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */ -1}; if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1) goto Exit; close(respfds[1]); respfds[1] = -1; pthread_mutex_unlock(&cloexec_mutex); mutex_locked = 0; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; if (r <= 0) break; (*resp)->size += r; } Exit: if (mutex_locked) pthread_mutex_unlock(&cloexec_mutex); if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); if (ret != 0) h2o_buffer_dispose(resp); return ret; }
static mrb_value send_chunked_method(mrb_state *mrb, mrb_value self) { h2o_mruby_generator_t *generator = h2o_mruby_current_generator; const char *s; mrb_int len; /* parse args */ mrb_get_args(mrb, "s", &s, &len); { /* precond check */ mrb_value exc = check_precond(mrb, generator); if (!mrb_nil_p(exc)) mrb_exc_raise(mrb, exc); } /* append to send buffer, and send out immediately if necessary */ if (len != 0) { h2o_mruby_chunked_t *chunked = generator->chunked; if (chunked->bytes_left != SIZE_MAX) { if (len > chunked->bytes_left) len = chunked->bytes_left; chunked->bytes_left -= len; } if (len != 0) { h2o_buffer_reserve(&chunked->callback.receiving, len); memcpy(chunked->callback.receiving->bytes + chunked->callback.receiving->size, s, len); chunked->callback.receiving->size += len; if (chunked->sending.bytes_inflight == 0) do_send(generator, &chunked->callback.receiving, 0); } } return mrb_nil_value(); }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; posix_spawn_file_actions_t file_actions; pid_t pid = -1; int ret = -1; extern char **environ; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); /* create pipe for reading the result */ if (pipe(respfds) != 0) goto Exit; /* spawn */ posix_spawn_file_actions_init(&file_actions); posix_spawn_file_actions_adddup2(&file_actions, respfds[1], 1); if ((errno = posix_spawnp(&pid, cmd, &file_actions, NULL, argv, environ)) != 0) { pid = -1; goto Exit; } close(respfds[1]); respfds[1] = -1; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; if (r <= 0) break; (*resp)->size += r; } Exit: if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); if (ret != 0) h2o_buffer_dispose(resp); return ret; }
static h2o_iovec_t *send_data_push(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_iovec_t *bufs, size_t bufcnt, int is_final) { ssize_t max_payload_size = 0, payload_size = 0; size_t data_header_offset = 0; for (; bufcnt != 0; ++bufs, --bufcnt) { while (bufs->len != 0) { size_t fill_size; /* encode the header, and allocate space for the next header */ if (payload_size == max_payload_size) { if (payload_size != 0) encode_data_header_and_consume_window(conn, stream, (uint8_t*)conn->_write.buf->bytes + data_header_offset, payload_size, 0); if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) goto Exit; h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE); data_header_offset = conn->_write.buf->size; conn->_write.buf->size += H2O_HTTP2_FRAME_HEADER_SIZE; payload_size = 0; } /* emit payload */ fill_size = sz_min(max_payload_size, bufs->len); memcpy(h2o_buffer_reserve(&conn->_write.buf, fill_size).base, bufs->base, fill_size); conn->_write.buf->size += fill_size; bufs->base += fill_size; bufs->len -= fill_size; payload_size += fill_size; } } /* all data have been emitted */ if (payload_size != 0) { encode_data_header_and_consume_window(conn, stream, (uint8_t*)conn->_write.buf->bytes + data_header_offset, payload_size, is_final); } else if (is_final) { encode_data_header_and_consume_window( conn, stream, (void*)h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE).base, 0, 1); conn->_write.buf->size += H2O_HTTP2_FRAME_HEADER_SIZE; } Exit: return bufs; }
static void post_error(struct st_h2o_mruby_http_request_context_t *ctx, const char *errstr) { static const struct phr_header headers_sorted[] = {{H2O_STRLIT("content-type"), H2O_STRLIT("text/plain; charset=utf-8")}}; ctx->client = NULL; size_t errstr_len = strlen(errstr); h2o_buffer_reserve(&ctx->resp.after_closed, errstr_len); memcpy(ctx->resp.after_closed->bytes + ctx->resp.after_closed->size, errstr, errstr_len); ctx->resp.after_closed->size += errstr_len; ctx->resp.has_content = 1; post_response(ctx, 500, headers_sorted, sizeof(headers_sorted) / sizeof(headers_sorted[0])); }
static h2o_iovec_t *send_data_push(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t send_state) { h2o_iovec_t dst; size_t max_payload_size; if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) goto Exit; /* reserve buffer and point dst to the payload */ dst.base = h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size).base + H2O_HTTP2_FRAME_HEADER_SIZE; dst.len = max_payload_size; /* emit data */ while (bufcnt != 0) { if (bufs->len != 0) break; ++bufs; --bufcnt; } while (bufcnt != 0) { size_t fill_size = sz_min(dst.len, bufs->len); memcpy(dst.base, bufs->base, fill_size); dst.base += fill_size; dst.len -= fill_size; bufs->base += fill_size; bufs->len -= fill_size; while (bufs->len == 0) { ++bufs; --bufcnt; if (bufcnt == 0) break; } if (dst.len == 0) break; } /* commit the DATA frame if we have actually emitted payload */ if (dst.len != max_payload_size || !h2o_send_state_is_in_progress(send_state)) { size_t payload_len = max_payload_size - dst.len; if (bufcnt != 0) { send_state = H2O_SEND_STATE_IN_PROGRESS; } commit_data_header(conn, stream, &conn->_write.buf, payload_len, send_state); } Exit: return bufs; }
static h2o_iovec_t *send_data_push(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_iovec_t *bufs, size_t bufcnt, int is_final) { h2o_iovec_t dst; size_t max_payload_size; if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) goto Exit; /* reserve buffer and point dst to the payload */ dst.base = h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size).base + H2O_HTTP2_FRAME_HEADER_SIZE; dst.len = max_payload_size; /* emit data */ while (bufcnt != 0) { if (bufs->len != 0) break; ++bufs; --bufcnt; } while (bufcnt != 0) { size_t fill_size = sz_min(dst.len, bufs->len); memcpy(dst.base, bufs->base, fill_size); dst.base += fill_size; dst.len -= fill_size; bufs->base += fill_size; bufs->len -= fill_size; while (bufs->len == 0) { ++bufs; --bufcnt; if (bufcnt == 0) break; } if (dst.len == 0) break; } /* commit the DATA frame if we have actually emitted payload */ if (dst.len != max_payload_size || is_final) { size_t payload_len = max_payload_size - dst.len; encode_data_header_and_consume_window(conn, stream, (uint8_t *)conn->_write.buf->bytes + conn->_write.buf->size, payload_len, is_final && bufcnt == 0); conn->_write.buf->size += H2O_HTTP2_FRAME_HEADER_SIZE + payload_len; } Exit: return bufs; }
static h2o_send_state_t send_data_pull(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { size_t max_payload_size; h2o_iovec_t cbuf; h2o_send_state_t send_state = H2O_SEND_STATE_IN_PROGRESS; if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) goto Exit; /* reserve buffer */ h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size); /* obtain content */ cbuf.base = conn->_write.buf->bytes + conn->_write.buf->size + H2O_HTTP2_FRAME_HEADER_SIZE; cbuf.len = max_payload_size; send_state = h2o_pull(&stream->req, stream->_pull_cb, &cbuf); /* write the header */ commit_data_header(conn, stream, &conn->_write.buf, cbuf.len, send_state); Exit: return send_state; }
static int collect_req_status(h2o_req_t *req, void *_cbdata) { struct st_collect_req_status_cbdata_t *cbdata = _cbdata; /* collect log */ char buf[4096]; size_t len = sizeof(buf); char *logline = h2o_log_request(cbdata->logconf, req, &len, buf); assert(len != 0); --len; /* omit trailing LF */ /* append to buffer */ h2o_buffer_reserve(&cbdata->buffer, len + 3); memcpy(cbdata->buffer->bytes + cbdata->buffer->size, logline, len); cbdata->buffer->size += len; if (logline != buf) free(logline); return 0; }
static int flatten_request_header(h2o_mruby_context_t *handler_ctx, h2o_iovec_t name, h2o_iovec_t value, void *_ctx) { struct st_h2o_mruby_http_request_context_t *ctx = _ctx; /* ignore certain headers */ if (h2o_lcstris(name.base, name.len, H2O_STRLIT("content-length")) || h2o_lcstris(name.base, name.len, H2O_STRLIT("connection")) || h2o_lcstris(name.base, name.len, H2O_STRLIT("host"))) return 0; /* mark the existence of transfer-encoding in order to prevent us from adding content-length header */ if (h2o_lcstris(name.base, name.len, H2O_STRLIT("transfer-encoding"))) ctx->req.has_transfer_encoding = 1; h2o_buffer_reserve(&ctx->req.buf, name.len + value.len + sizeof(": \r\n") - 1); append_to_buffer(&ctx->req.buf, name.base, name.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(": ")); append_to_buffer(&ctx->req.buf, value.base, value.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); return 0; }
static int send_data_pull(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream) { size_t max_payload_size; h2o_iovec_t cbuf; int is_final = 0; do { if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) break; /* reserve buffer */ h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size); /* obtain content */ cbuf.base = conn->_write.buf->bytes + conn->_write.buf->size + H2O_HTTP2_FRAME_HEADER_SIZE; cbuf.len = max_payload_size; is_final = h2o_pull(&stream->req, stream->_pull_cb, &cbuf); /* write the header */ encode_data_header_and_consume_window(conn, stream, (void*)(conn->_write.buf->bytes + conn->_write.buf->size), cbuf.len, is_final); /* adjust the write buf size */ conn->_write.buf->size += H2O_HTTP2_FRAME_HEADER_SIZE + cbuf.len; } while (! is_final); return is_final; }
static void proceed_handshake(h2o_socket_t *sock, const char *err) { h2o_iovec_t first_input = {NULL}; int ret; sock->_cb.write = NULL; if (err != NULL) { goto Complete; } if (sock->ssl->handshake.server.async_resumption.state == ASYNC_RESUMPTION_STATE_RECORD) { if (sock->ssl->input.encrypted->size <= 1024) { /* retain a copy of input if performing async resumption */ first_input = h2o_iovec_init(alloca(sock->ssl->input.encrypted->size), sock->ssl->input.encrypted->size); memcpy(first_input.base, sock->ssl->input.encrypted->bytes, first_input.len); } else { sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; } } Redo: if (SSL_is_server(sock->ssl->ssl)) { ret = SSL_accept(sock->ssl->ssl); } else { ret = SSL_connect(sock->ssl->ssl); } switch (sock->ssl->handshake.server.async_resumption.state) { case ASYNC_RESUMPTION_STATE_RECORD: /* async resumption has not been triggered; proceed the state to complete */ sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_COMPLETE; break; case ASYNC_RESUMPTION_STATE_REQUEST_SENT: { /* sent async request, reset the ssl state, and wait for async response */ assert(ret < 0); SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(sock->ssl->ssl); SSL_free(sock->ssl->ssl); create_ssl(sock, ssl_ctx); clear_output_buffer(sock->ssl); h2o_buffer_consume(&sock->ssl->input.encrypted, sock->ssl->input.encrypted->size); h2o_buffer_reserve(&sock->ssl->input.encrypted, first_input.len); memcpy(sock->ssl->input.encrypted->bytes, first_input.base, first_input.len); sock->ssl->input.encrypted->size = first_input.len; h2o_socket_read_stop(sock); return; } default: break; } if (ret == 0 || (ret < 0 && SSL_get_error(sock->ssl->ssl, ret) != SSL_ERROR_WANT_READ)) { /* failed */ long verify_result = SSL_get_verify_result(sock->ssl->ssl); if (verify_result != X509_V_OK) { err = X509_verify_cert_error_string(verify_result); } else { err = "ssl handshake failure"; } goto Complete; } if (sock->ssl->output.bufs.size != 0) { h2o_socket_read_stop(sock); flush_pending_ssl(sock, ret == 1 ? on_handshake_complete : proceed_handshake); } else { if (ret == 1) { if (!SSL_is_server(sock->ssl->ssl)) { X509 *cert = SSL_get_peer_certificate(sock->ssl->ssl); if (cert != NULL) { switch (validate_hostname(sock->ssl->handshake.client.server_name, cert)) { case MatchFound: /* ok */ break; case MatchNotFound: err = h2o_socket_error_ssl_cert_name_mismatch; break; default: err = h2o_socket_error_ssl_cert_invalid; break; } X509_free(cert); } else { err = h2o_socket_error_ssl_no_cert; } } goto Complete; } if (sock->ssl->input.encrypted->size != 0) goto Redo; h2o_socket_read_start(sock, proceed_handshake); } return; Complete: h2o_socket_read_stop(sock); on_handshake_complete(sock, err); }
int h2o_read_command(const char *cmd, char **argv, h2o_buffer_t **resp, int *child_status) { int respfds[2] = {-1, -1}; pid_t pid = -1; int mutex_locked = 0, ret = -1; h2o_buffer_init(resp, &h2o_socket_buffer_prototype); #ifndef _MSC_VER pthread_mutex_lock(&cloexec_mutex); mutex_locked = 1; #else uv_mutex_lock(&cloexec_mutex); mutex_locked = 1; #endif /* create pipe for reading the result */ #ifdef _MSC_VER if (_pipe(respfds, 4096, O_BINARY) == -1) //on fail //-- : Debug{ //printf("Pipe Failed \n"); goto Exit; #else if (pipe(respfds) != 0) //on fail goto Exit; #endif #ifndef _MSC_VER fcntl(respfds[0], F_SETFD, O_CLOEXEC); #endif /* spawn */ int mapped_fds[] = {respfds[1], 1, /* stdout of the child process is read from the pipe */ -1}; if ((pid = h2o_spawnp(cmd, argv, mapped_fds, 1)) == -1) goto Exit; close(respfds[1]); respfds[1] = -1; #ifndef _MSC_VER pthread_mutex_unlock(&cloexec_mutex); #else uv_mutex_unlock(&cloexec_mutex); #endif mutex_locked = 0; /* read the response from pipe */ while (1) { h2o_iovec_t buf = h2o_buffer_reserve(resp, 8192); ssize_t r; #ifndef _MSC_VER while ((r = read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; #else while ((r = _read(respfds[0], buf.base, buf.len)) == -1 && errno == EINTR) ; #endif if (r <= 0) break; (*resp)->size += r; } Exit: if (mutex_locked) #ifndef _MSC_VER pthread_mutex_unlock(&cloexec_mutex); #else uv_mutex_unlock(&cloexec_mutex); #endif //Child _ waiting doesn't work same way in Windows so #ifndef _MSC_VER if (pid != -1) { /* wait for the child to complete */ pid_t r; while ((r = waitpid(pid, child_status, 0)) == -1 && errno == EINTR) ; if (r == pid) { /* success */ ret = 0; } } #else //If you can come up with a way to wait for a child to exist in Windows put here.s #endif #ifndef _MSC_VER if (respfds[0] != -1) close(respfds[0]); if (respfds[1] != -1) close(respfds[1]); #else if (respfds[0] != -1) _close(respfds[0]); if (respfds[1] != -1) _close(respfds[1]); #endif if (ret != 0) h2o_buffer_dispose(resp); return ret; }
static uint8_t *allocate_frame(h2o_buffer_t **buf, size_t length, uint8_t type, uint8_t flags, int32_t stream_id) { h2o_iovec_t alloced = h2o_buffer_reserve(buf, H2O_HTTP2_FRAME_HEADER_SIZE + length); (*buf)->size += H2O_HTTP2_FRAME_HEADER_SIZE + length; return h2o_http2_encode_frame_header((uint8_t*)alloced.base, length, type, flags, stream_id); }
static mrb_value http_request_method(mrb_state *mrb, mrb_value self) { h2o_mruby_generator_t *generator; struct st_h2o_mruby_http_request_context_t *ctx; const char *arg_url; mrb_int arg_url_len; mrb_value arg_hash; h2o_iovec_t method; h2o_url_t url; /* parse args */ arg_hash = mrb_nil_value(); mrb_get_args(mrb, "s|H", &arg_url, &arg_url_len, &arg_hash); /* precond check */ if ((generator = h2o_mruby_current_generator) == NULL || generator->req == NULL) mrb_exc_raise(mrb, create_downstream_closed_exception(mrb)); /* allocate context and initialize */ ctx = h2o_mem_alloc_shared(&generator->req->pool, sizeof(*ctx), on_dispose); memset(ctx, 0, sizeof(*ctx)); ctx->generator = generator; ctx->receiver = mrb_nil_value(); h2o_buffer_init(&ctx->req.buf, &h2o_socket_buffer_prototype); h2o_buffer_init(&ctx->resp.after_closed, &h2o_socket_buffer_prototype); ctx->refs.request = mrb_nil_value(); ctx->refs.input_stream = mrb_nil_value(); /* uri */ if (h2o_url_parse(arg_url, arg_url_len, &url) != 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "invaild URL"); /* method */ method = h2o_iovec_init(H2O_STRLIT("GET")); if (mrb_hash_p(arg_hash)) { mrb_value t = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_method)); if (!mrb_nil_p(t)) { t = mrb_str_to_str(mrb, t); method = h2o_iovec_init(RSTRING_PTR(t), RSTRING_LEN(t)); } } /* start building the request */ h2o_buffer_reserve(&ctx->req.buf, method.len + 1); append_to_buffer(&ctx->req.buf, method.base, method.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" ")); h2o_buffer_reserve(&ctx->req.buf, url.path.len + url.authority.len + sizeof(" HTTP/1.1\r\nConnection: close\r\nHost: \r\n") - 1); append_to_buffer(&ctx->req.buf, url.path.base, url.path.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" HTTP/1.1\r\nConnection: close\r\nHost: ")); append_to_buffer(&ctx->req.buf, url.authority.base, url.authority.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* headers */ if (mrb_hash_p(arg_hash)) { mrb_value headers = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_headers)); if (!mrb_nil_p(headers)) { if (h2o_mruby_iterate_headers(generator->ctx, headers, flatten_request_header, ctx) != 0) { mrb_value exc = mrb_obj_value(mrb->exc); mrb->exc = NULL; mrb_exc_raise(mrb, exc); } } } /* body */ if (mrb_hash_p(arg_hash)) { mrb_value body = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->symbols.sym_body)); if (!mrb_nil_p(body)) { if (mrb_obj_eq(mrb, body, generator->rack_input)) { /* fast path */ mrb_int pos; mrb_input_stream_get_data(mrb, body, NULL, NULL, &pos, NULL, NULL); ctx->req.body = generator->req->entity; ctx->req.body.base += pos; ctx->req.body.len -= pos; } else { if (!mrb_string_p(body)) { body = mrb_funcall(mrb, body, "read", 0); if (!mrb_string_p(body)) mrb_raise(mrb, E_ARGUMENT_ERROR, "body.read did not return string"); } ctx->req.body = h2o_strdup(&ctx->generator->req->pool, RSTRING_PTR(body), RSTRING_LEN(body)); } if (!ctx->req.has_transfer_encoding) { char buf[64]; size_t l = (size_t)sprintf(buf, "content-length: %zu\r\n", ctx->req.body.len); h2o_buffer_reserve(&ctx->req.buf, l); append_to_buffer(&ctx->req.buf, buf, l); } } } h2o_buffer_reserve(&ctx->req.buf, 2); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* build request and connect */ h2o_http1client_connect(&ctx->client, ctx, &generator->req->conn->ctx->proxy.client_ctx, url.host, h2o_url_get_port(&url), on_connect); ctx->refs.request = h2o_mruby_create_data_instance(mrb, mrb_ary_entry(generator->ctx->constants, H2O_MRUBY_HTTP_REQUEST_CLASS), ctx, &request_type); return ctx->refs.request; }