static mrb_value ngx_http_mruby_variable_get(mrb_state *mrb, mrb_value self, const char *c_name) { ngx_http_request_t *r; ngx_http_variable_value_t *var; ngx_str_t ngx_name; u_char *low; size_t len; ngx_uint_t key; r = ngx_http_mruby_get_request(); ngx_name.len = ngx_strlen(c_name); ngx_name.data = (u_char *)c_name; len = ngx_name.len; if (len) { low = ngx_pnalloc(r->pool, len); if (low == NULL) { return mrb_nil_value(); } } else { return mrb_nil_value(); } key = ngx_hash_strlow(low, ngx_name.data, len); var = ngx_http_get_variable(r, &ngx_name, key); if (var->not_found) { return mrb_nil_value(); } return mrb_str_new(mrb, (char *)var->data, var->len); }
static mrb_value ngx_http_mruby_return(mrb_state *mrb, mrb_value self) { ngx_http_mruby_rputs_chain_list_t *chain; ngx_http_mruby_ctx_t *ctx; ngx_http_request_t *r; mrb_int status; r = ngx_http_mruby_get_request(); status = NGX_HTTP_OK; mrb_get_args(mrb, "i", &status); r->headers_out.status = status; ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module); chain = ctx->rputs_chain; if (chain != NULL) { (*chain->last)->buf->last_buf = 1; } if (r->headers_out.status == NGX_HTTP_OK && chain == NULL) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s: Nginx.rputs is required in advance of Nginx.return(200)" , MODULE_NAME , __FUNCTION__ ); r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR; } return self; }
static mrb_value ngx_http_mruby_rputs(mrb_state *mrb, mrb_value self) { mrb_value argv; ngx_buf_t *b; ngx_http_mruby_rputs_chain_list_t *chain; u_char *str; ngx_str_t ns; ngx_http_request_t *r; ngx_http_mruby_ctx_t *ctx; r = ngx_http_mruby_get_request(); ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module); mrb_get_args(mrb, "o", &argv); argv = mrb_obj_as_string(mrb, argv); ns.data = (u_char *)RSTRING_PTR(argv); ns.len = RSTRING_LEN(argv); if (ns.len == 0) { return self; } if (ctx->rputs_chain == NULL) { chain = ngx_pcalloc(r->pool, sizeof(ngx_http_mruby_rputs_chain_list_t)); chain->out = ngx_alloc_chain_link(r->pool); chain->last = &chain->out; } else { chain = ctx->rputs_chain; (*chain->last)->next = ngx_alloc_chain_link(r->pool); chain->last = &(*chain->last)->next; } b = ngx_calloc_buf(r->pool); (*chain->last)->buf = b; (*chain->last)->next = NULL; if ((str = ngx_pnalloc(r->pool, ns.len + 1)) == NULL) { return self; } ngx_memcpy(str, ns.data, ns.len); str[ns.len] = '\0'; (*chain->last)->buf->pos = str; (*chain->last)->buf->last = str + ns.len; (*chain->last)->buf->memory = 1; ctx->rputs_chain = chain; if (r->headers_out.content_length_n == -1) { r->headers_out.content_length_n += ns.len + 1; } else { r->headers_out.content_length_n += ns.len; } return self; }
static mrb_value ngx_http_mruby_log(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_value msg; mrb_int argc; mrb_int log_level; ngx_http_request_t *r; r = ngx_http_mruby_get_request(); mrb_get_args(mrb, "*", &argv, &argc); if (argc != 2) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s: argument is not 2" , MODULE_NAME , __FUNCTION__ ); return self; } if (mrb_type(argv[0]) != MRB_TT_FIXNUM) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s: argv[0] is not integer" , MODULE_NAME , __FUNCTION__ ); return self; } log_level = mrb_fixnum(argv[0]); if (log_level < 0) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s: log level is not positive number" , MODULE_NAME , __FUNCTION__ ); return self; } msg = mrb_obj_as_string(mrb, argv[1]); ngx_log_error((ngx_uint_t)log_level, r->connection->log, 0, "%s", RSTRING_PTR(msg)); return self; }
static mrb_value ngx_http_mruby_variable_set_internal(mrb_state *mrb, mrb_value self, char *k, mrb_value o) { ngx_http_request_t *r; ngx_http_variable_t *v; ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; ngx_str_t key; ngx_uint_t hash; u_char *val, *low; r = ngx_http_mruby_get_request(); val = (u_char *)RSTRING_PTR(o); key.data = (u_char *)k; key.len = ngx_strlen(k); if (key.len) { low = ngx_pnalloc(r->pool, key.len); if (low == NULL) { return mrb_nil_value(); } } else { return mrb_nil_value(); } hash = ngx_hash_strlow(low, key.data, key.len); cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); v = ngx_hash_find(&cmcf->variables_hash, hash, key.data, key.len); if (v) { if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s not changeable" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); } if (v->set_handler) { vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); if (vv == NULL) { ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: memory allocate failed" , MODULE_NAME , __FUNCTION__ , __LINE__ ); return mrb_nil_value(); } vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = RSTRING_LEN(o); v->set_handler(r, vv, v->data); return mrb_str_new_cstr(mrb, (char *)val); } if (v->flags & NGX_HTTP_VAR_INDEXED) { vv = &r->variables[v->index]; vv->valid = 1; vv->not_found = 0; vv->no_cacheable = 0; vv->data = val; vv->len = RSTRING_LEN(o); return mrb_str_new_cstr(mrb, (char *)val); } ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s is not assinged" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); } ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "%s ERROR %s:%d: %s is not found" , MODULE_NAME , __FUNCTION__ , __LINE__ , key.data ); return mrb_nil_value(); }
// like Nginx rewrite keywords // used like this: // => http code 3xx location in browser // => internal redirection in nginx static mrb_value ngx_http_mruby_redirect(mrb_state *mrb, mrb_value self) { int argc; u_char *str; ngx_int_t rc; mrb_value uri, code; ngx_str_t ns; ngx_http_request_t *r; ngx_http_mruby_ctx_t *ctx; r = ngx_http_mruby_get_request(); ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module); argc = mrb_get_args(mrb, "o|oo", &uri, &code); if (argc == 2) { rc = mrb_fixnum(code); } else { rc = NGX_HTTP_MOVED_TEMPORARILY; } uri = mrb_obj_as_string(mrb, uri); // save location uri to ns ns.data = (u_char *)RSTRING_PTR(uri); ns.len = RSTRING_LEN(uri); if (ns.len == 0) { return mrb_nil_value(); } // if uri start with scheme prefix // return 3xx for redirect // else generate a internal redirection and response to raw request // request.path is not changed if (ngx_strncmp(ns.data, "http://", sizeof("http://") - 1) == 0 || ngx_strncmp(ns.data, "https://", sizeof("https://") - 1) == 0 || ngx_strncmp(ns.data, "$scheme", sizeof("$scheme") - 1) == 0) { if ((str = ngx_pnalloc(r->pool, ns.len + 1)) == NULL) { return self; } ngx_memcpy(str, ns.data, ns.len); str[ns.len] = '\0'; // build redirect location r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return self; } r->headers_out.location->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash(ngx_hash( ngx_hash('l', 'o'), 'c'), 'a'), 't'), 'i'), 'o'), 'n'); r->headers_out.location->value.data = ns.data; r->headers_out.location->value.len = ns.len; ngx_str_set(&r->headers_out.location->key, "Location"); r->headers_out.status = rc; ctx->exited = 1; ctx->exit_code = rc; } else { ctx->exited = 1; ctx->exit_code = ngx_http_internal_redirect(r, &ns, &r->args); } return self; }