nghttpx: Rewrite API; introduce Env object

This commit is contained in:
Tatsuhiro Tsujikawa 2015-09-04 23:56:07 +09:00
parent a9338f1c0e
commit bddc4a0a04
9 changed files with 218 additions and 22 deletions

View File

@ -134,6 +134,7 @@ if HAVE_MRUBY
NGHTTPX_SRCS += \
shrpx_mruby.cc shrpx_mruby.h \
shrpx_mruby_module.cc shrpx_mruby_module.h \
shrpx_mruby_module_env.cc shrpx_mruby_module_env.h \
shrpx_mruby_module_request.cc shrpx_mruby_module_request.h \
shrpx_mruby_module_response.cc shrpx_mruby_module_response.h
endif # HAVE_MRUBY

View File

@ -34,6 +34,11 @@
#include "shrpx_error.h"
#include "shrpx_downstream_connection.h"
#include "shrpx_downstream_queue.h"
#include "shrpx_worker.h"
#include "shrpx_http2_session.h"
#ifdef HAVE_MRUBY
#include "shrpx_mruby.h"
#endif // HAVE_MRUBY
#include "util.h"
#include "http2.h"
@ -160,6 +165,12 @@ Downstream::~Downstream() {
ev_timer_stop(loop, &upstream_wtimer_);
ev_timer_stop(loop, &downstream_rtimer_);
ev_timer_stop(loop, &downstream_wtimer_);
auto handler = upstream_->get_client_handler();
auto worker = handler->get_worker();
auto mruby_ctx = worker->get_mruby_context();
mruby_ctx->delete_downstream(this);
}
// DownstreamConnection may refer to this object. Delete it now

View File

@ -99,6 +99,10 @@ int MRubyContext::run_on_response_proc(Downstream *downstream) {
return run_request_proc(downstream, on_response_proc_);
}
void MRubyContext::delete_downstream(Downstream *downstream) {
delete_downstream_from_module(mrb_, downstream);
}
// Based on
// https://github.com/h2o/h2o/blob/master/lib/handler/mruby.c. It is
// very hard to write these kind of code because mruby has almost no
@ -144,6 +148,13 @@ RProc *compile(mrb_state *mrb, const char *filename) {
}
std::unique_ptr<MRubyContext> create_mruby_context() {
auto req_file = get_config()->request_phase_file.get();
auto res_file = get_config()->response_phase_file.get();
if (!req_file && !res_file) {
return make_unique<MRubyContext>(nullptr, nullptr, nullptr);
}
auto mrb = mrb_open();
if (mrb == nullptr) {
LOG(ERROR) << "mrb_open failed";
@ -152,9 +163,6 @@ std::unique_ptr<MRubyContext> create_mruby_context() {
init_module(mrb);
auto req_file = get_config()->request_phase_file.get();
auto res_file = get_config()->response_phase_file.get();
auto req_proc = compile(mrb, req_file);
if (req_file && !req_proc) {
@ -174,6 +182,12 @@ std::unique_ptr<MRubyContext> create_mruby_context() {
return make_unique<MRubyContext>(mrb, req_proc, res_proc);
}
mrb_sym intern_ptr(mrb_state *mrb, void *ptr) {
auto p = reinterpret_cast<uintptr_t>(ptr);
return mrb_intern(mrb, reinterpret_cast<const char *>(&p), sizeof(p));
}
} // namespace mruby
} // namespace shrpx

View File

@ -48,6 +48,8 @@ public:
int run_request_proc(Downstream *downstream, RProc *proc);
void delete_downstream(Downstream *downstream);
private:
mrb_state *mrb_;
RProc *on_request_proc_;
@ -65,6 +67,9 @@ RProc *compile(mrb_state *mrb, const char *filename);
std::unique_ptr<MRubyContext> create_mruby_context();
// Return interned |ptr|.
mrb_sym intern_ptr(mrb_state *mrb, void *ptr);
} // namespace mruby
} // namespace shrpx

View File

@ -32,6 +32,7 @@
#include <mruby/array.h>
#include "shrpx_mruby.h"
#include "shrpx_mruby_module_env.h"
#include "shrpx_mruby_module_request.h"
#include "shrpx_mruby_module_response.h"
@ -49,21 +50,48 @@ mrb_value run(mrb_state *mrb, mrb_value self) {
}
auto module = mrb_module_get(mrb, "Nghttpx");
auto env_sym = mrb_intern_lit(mrb, "env");
auto env = mrb_obj_iv_get(mrb, reinterpret_cast<RObject *>(module), env_sym);
if (mrb_nil_p(env)) {
auto env_class = mrb_class_get_under(mrb, module, "Env");
auto request_class = mrb_class_get_under(mrb, module, "Request");
auto response_class = mrb_class_get_under(mrb, module, "Response");
std::array<mrb_value, 2> args{{mrb_obj_new(mrb, response_class, 0, nullptr),
mrb_obj_new(mrb, request_class, 0, nullptr)}};
env = mrb_obj_new(mrb, env_class, 0, nullptr);
auto req = mrb_obj_new(mrb, request_class, 0, nullptr);
auto resp = mrb_obj_new(mrb, response_class, 0, nullptr);
mrb_iv_set(mrb, env, mrb_intern_lit(mrb, "req"), req);
mrb_iv_set(mrb, env, mrb_intern_lit(mrb, "resp"), resp);
mrb_obj_iv_set(mrb, reinterpret_cast<RObject *>(module), env_sym, env);
}
std::array<mrb_value, 1> args{{env}};
return mrb_yield_argv(mrb, b, args.size(), args.data());
}
} // namespace
void delete_downstream_from_module(mrb_state *mrb, Downstream *downstream) {
auto module = mrb_module_get(mrb, "Nghttpx");
auto env = mrb_obj_iv_get(mrb, reinterpret_cast<RObject *>(module),
mrb_intern_lit(mrb, "env"));
if (mrb_nil_p(env)) {
return;
}
mrb_iv_remove(mrb, env, intern_ptr(mrb, downstream));
}
void init_module(mrb_state *mrb) {
auto module = mrb_define_module(mrb, "Nghttpx");
mrb_define_class_method(mrb, module, "run", run,
MRB_ARGS_REQ(1) | MRB_ARGS_BLOCK());
init_env_class(mrb, module);
init_request_class(mrb, module);
init_response_class(mrb, module);
}

View File

@ -35,10 +35,14 @@ using namespace nghttp2;
namespace shrpx {
class Downstream;
namespace mruby {
void init_module(mrb_state *mrb);
void delete_downstream_from_module(mrb_state *mrb, Downstream *downstream);
mrb_value create_headers_hash(mrb_state *mrb, const Headers &headers);
} // namespace mruby

View File

@ -0,0 +1,104 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "shrpx_mruby_module_env.h"
#include <mruby/variable.h>
#include <mruby/string.h>
#include <mruby/hash.h>
#include <mruby/array.h>
#include "shrpx_downstream.h"
#include "shrpx_upstream.h"
#include "shrpx_client_handler.h"
#include "shrpx_mruby.h"
#include "shrpx_mruby_module.h"
#include "util.h"
#include "http2.h"
namespace shrpx {
namespace mruby {
namespace {
mrb_value env_init(mrb_state *mrb, mrb_value self) { return self; }
} // namespace
namespace {
mrb_value env_get_req(mrb_state *mrb, mrb_value self) {
return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "req"));
}
} // namespace
namespace {
mrb_value env_get_resp(mrb_state *mrb, mrb_value self) {
return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "resp"));
}
} // namespace
namespace {
mrb_value env_get_ctx(mrb_state *mrb, mrb_value self) {
auto data = reinterpret_cast<MRubyAssocData *>(mrb->ud);
auto downstream = data->downstream;
auto dsym = intern_ptr(mrb, downstream);
auto ctx = mrb_iv_get(mrb, self, dsym);
if (mrb_nil_p(ctx)) {
ctx = mrb_hash_new(mrb);
mrb_iv_set(mrb, self, dsym, ctx);
}
return ctx;
}
} // namespace
namespace {
mrb_value env_get_remote_addr(mrb_state *mrb, mrb_value self) {
auto data = static_cast<MRubyAssocData *>(mrb->ud);
auto downstream = data->downstream;
auto upstream = downstream->get_upstream();
auto handler = upstream->get_client_handler();
auto &ipaddr = handler->get_ipaddr();
return mrb_str_new(mrb, ipaddr.c_str(), ipaddr.size());
}
} // namespace
void init_env_class(mrb_state *mrb, RClass *module) {
auto env_class =
mrb_define_class_under(mrb, module, "Env", mrb->object_class);
mrb_define_method(mrb, env_class, "initialize", env_init, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "req", env_get_req, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "resp", env_get_resp, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "ctx", env_get_ctx, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "remote_addr", env_get_remote_addr,
MRB_ARGS_NONE());
}
} // namespace mruby
} // namespace shrpx

View File

@ -0,0 +1,44 @@
/*
* nghttp2 - HTTP/2 C Library
*
* Copyright (c) 2015 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SHRPX_MRUBY_MODULE_ENV_H
#define SHRPX_MRUBY_MODULE_ENV_H
#include "shrpx.h"
#include <mruby.h>
using namespace nghttp2;
namespace shrpx {
namespace mruby {
void init_env_class(mrb_state *mrb, RClass *module);
} // namespace mruby
} // namespace shrpx
#endif // SHRPX_MRUBY_MODULE_ENV_H

View File

@ -250,19 +250,6 @@ mrb_value request_clear_headers(mrb_state *mrb, mrb_value self) {
}
} // namespace
namespace {
mrb_value request_get_remote_addr(mrb_state *mrb, mrb_value self) {
auto data = static_cast<MRubyAssocData *>(mrb->ud);
auto downstream = data->downstream;
auto upstream = downstream->get_upstream();
auto handler = upstream->get_client_handler();
auto &ipaddr = handler->get_ipaddr();
return mrb_str_new(mrb, ipaddr.c_str(), ipaddr.size());
}
} // namespace
void init_request_class(mrb_state *mrb, RClass *module) {
auto request_class =
mrb_define_class_under(mrb, module, "Request", mrb->object_class);
@ -297,8 +284,6 @@ void init_request_class(mrb_state *mrb, RClass *module) {
MRB_ARGS_REQ(2));
mrb_define_method(mrb, request_class, "clear_headers", request_clear_headers,
MRB_ARGS_NONE());
mrb_define_method(mrb, request_class, "remote_addr", request_get_remote_addr,
MRB_ARGS_NONE());
}
} // namespace mruby