예제 #1
0
static mrb_value ngx_mrb_send_header(mrb_state *mrb, mrb_value self)
{
  ngx_mrb_rputs_chain_list_t *chain = NULL;
  ngx_http_mruby_ctx_t *ctx;

  ngx_http_request_t *r = ngx_mrb_get_request();
  mrb_int 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);
  if (ctx == NULL) {
    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s ERROR %s: get mruby context failed.", MODULE_NAME, __func__);
    mrb_raise(mrb, E_RUNTIME_ERROR, "get mruby context failed");
  }
  chain = ctx->rputs_chain;
  if (chain) {
    (*chain->last)->buf->last_buf = 1;
  }

  if (r->headers_out.status == NGX_HTTP_OK) {
    if (chain == NULL) {
      r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
      ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s ERROR %s: status code is 200, but response body is empty."
                                                        "Return NGX_HTTP_INTERNAL_SERVER_ERROR",
                    MODULE_NAME, __func__);
    }
  }

  return self;
}
예제 #2
0
static mrb_value ngx_mrb_errlogger(mrb_state *mrb, mrb_value self)
{
  mrb_value *argv;
  mrb_value msg;
  mrb_int argc;
  mrb_int log_level;
  ngx_http_request_t *r = ngx_mrb_get_request();
  if (r == NULL) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "can't use logger at this phase. only use at request phase");
  }

  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, __func__);
    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, __func__);
    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,
                  __func__);
    return self;
  }
  if (mrb_type(argv[1]) != MRB_TT_STRING) {
    msg = mrb_funcall(mrb, argv[1], "to_s", 0, NULL);
  } else {
    msg = mrb_str_dup(mrb, argv[1]);
  }
  ngx_log_error((ngx_uint_t)log_level, r->connection->log, 0, "%s", mrb_str_to_cstr(mrb, msg));

  return self;
}
예제 #3
0
static mrb_value ngx_mrb_get_filter_body(mrb_state *mrb, mrb_value self)
{
  ngx_http_request_t *r = ngx_mrb_get_request();
  ngx_http_mruby_ctx_t *ctx = ngx_mrb_http_get_module_ctx(mrb, r);

  return mrb_str_new(mrb, (char *)ctx->body, ctx->body_length);
}
예제 #4
0
static mrb_value ngx_mrb_var_method_missing(mrb_state *mrb, mrb_value self)
{
  mrb_value name, *a;
  int alen, c_len;
  mrb_value s_name;
  char *c_name;
  ngx_http_request_t *r;

  r = ngx_mrb_get_request();

  // get var symble from method_missing(sym, *args)
  mrb_get_args(mrb, "n*", &name, &a, &alen);

  // name is a symble obj
  // first init name with mrb_symbol
  // second get mrb_string with mrb_sym2str
  s_name = mrb_sym2str(mrb, mrb_symbol(name));
  c_name = mrb_str_to_cstr(mrb, s_name);
  c_len = RSTRING_LEN(s_name);

  if (c_name[c_len-1] == '=') {
    return ngx_mrb_var_set(mrb, self, strtok(c_name, "="), a[0], r);
  }
  else {
    return ngx_mrb_var_get(mrb, self, c_name, c_len, r);
  }
}
예제 #5
0
static mrb_value ngx_mrb_set_request_headers_out(mrb_state *mrb, mrb_value self)
{
    ngx_http_request_t *r;
    r = ngx_mrb_get_request();
    ngx_mrb_set_request_header(mrb, &r->headers_out.headers, 1);
    return self;
}
예제 #6
0
static mrb_value ngx_mrb_send_header(mrb_state *mrb, mrb_value self)
{
    rputs_chain_list_t *chain;
    ngx_mruby_ctx_t *ctx;

    ngx_http_request_t *r = ngx_mrb_get_request();
    mrb_int 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);
    if (ctx == NULL) {
        ngx_log_error(NGX_LOG_ERR
            , r->connection->log
            , 0
            , "get mruby context failed."
        );
    }
    chain = ctx->rputs_chain;
    (*chain->last)->buf->last_buf = 1;

    if (r->headers_out.status == NGX_HTTP_OK) {
        ngx_http_send_header(r);
        ngx_http_output_filter(r, chain->out);
        ngx_http_set_ctx(r, NULL, ngx_http_mruby_module);
    }

    return self;
}
예제 #7
0
static mrb_value ngx_mrb_set_request_uri(mrb_state *mrb, mrb_value self)
{
    mrb_value arg;
    u_char *str;

    ngx_http_request_t *r = ngx_mrb_get_request();
    mrb_get_args(mrb, "o", &arg);
    str = (u_char *)RSTRING_PTR(arg);
    ngx_str_set(&r->uri, str);

    return self;
}
예제 #8
0
static mrb_value ngx_mrb_rputs(mrb_state *mrb, mrb_value self)
{
    mrb_value argv;
    ngx_buf_t *b;
    ngx_mrb_rputs_chain_list_t *chain;
    u_char *str;
    ngx_str_t ns;

    ngx_http_request_t *r = ngx_mrb_get_request();
    ngx_http_mruby_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);

    mrb_get_args(mrb, "o", &argv);

    if (mrb_type(argv) != MRB_TT_STRING) {
        argv = mrb_funcall(mrb, argv, "to_s", 0, NULL);
    }

    ns.data     = (u_char *)RSTRING_PTR(argv);
    ns.len      = ngx_strlen(ns.data);
    if (ns.len == 0) {
        return self;
    }

    if (ctx->rputs_chain == NULL) {
        chain       = ngx_pcalloc(r->pool, sizeof(ngx_mrb_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;

    str         = ngx_pstrdup(r->pool, &ns);
    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;
    ngx_http_set_ctx(r, ctx, ngx_http_mruby_module);

    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;
}
예제 #9
0
static mrb_value ngx_mrb_set_filter_body(mrb_state *mrb, mrb_value self)
{
  ngx_http_request_t *r = ngx_mrb_get_request();
  ngx_http_mruby_ctx_t *ctx = ngx_mrb_http_get_module_ctx(mrb, r);
  mrb_value body;

  mrb_get_args(mrb, "o", &body);
  if (mrb_type(body) != MRB_TT_STRING) {
    body = mrb_funcall(mrb, body, "to_s", 0, NULL);
  }

  ctx->body_length = RSTRING_LEN(body);
  ctx->body = ngx_palloc(r->pool, ctx->body_length);
  ngx_memcpy(ctx->body, RSTRING_PTR(body), ctx->body_length);

  return mrb_fixnum_value(ctx->body_length);
}
예제 #10
0
static mrb_value ngx_mrb_set_content_type(mrb_state *mrb, mrb_value self) 
{
    mrb_value arg;
    u_char *str;

    ngx_http_request_t *r = ngx_mrb_get_request();
    mrb_get_args(mrb, "o", &arg);
    
    if (mrb_nil_p(arg))
        return self;

    str = (u_char *)RSTRING_PTR(arg);
    //ngx_str_set(&r->headers_out.content_type, str);
    r->headers_out.content_type.len = ngx_strlen(str) + 1;
    r->headers_out.content_type.data = (u_char *)str;

    return self;
}
예제 #11
0
// like Nginx rewrite keywords
// used like this:
// => http code 3xx location in browser
// => internal redirection in nginx
static mrb_value ngx_mrb_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_table_elt_t *location;

  ngx_http_request_t *r = ngx_mrb_get_request();
  argc = mrb_get_args(mrb, "o|oo", &uri, &code);

  // get status code from args
  if (argc == 2) {
    rc = mrb_fixnum(code);
  } else {
    rc = NGX_HTTP_MOVED_TEMPORARILY;
  }

  // get redirect uri from args
  if (mrb_type(uri) != MRB_TT_STRING) {
    uri = mrb_funcall(mrb, uri, "to_s", 0, NULL);
  }

  // save location uri to ns
  ns.len = RSTRING_LEN(uri);
  if (ns.len == 0) {
    return mrb_nil_value();
  }
  ns.data = ngx_palloc(r->pool, ns.len);
  ngx_memcpy(ns.data, RSTRING_PTR(uri), ns.len);

  // 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) {

    str = ngx_pstrdup(r->pool, &ns);
    if (str == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    str[ns.len] = '\0';

    // build redirect location
    location = ngx_list_push(&r->headers_out.headers);
    if (location == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    location->hash = 1;
    ngx_str_set(&location->key, "Location");
    location->value = ns;
    location->lowcase_key = ngx_pnalloc(r->pool, location->value.len);
    if (location->lowcase_key == NULL) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "failed to allocate memory");
    }
    ngx_strlow(location->lowcase_key, location->value.data, location->value.len);

    // set location and response code for hreaders
    r->headers_out.location = location;
    r->headers_out.status = rc;
  } else {
    ngx_http_internal_redirect(r, &ns, &r->args);
    ngx_http_finalize_request(r, NGX_DONE);
  }

  return self;
}
예제 #12
0
static mrb_value ngx_mrb_get_request_headers_in(mrb_state *mrb, mrb_value self)
{
    ngx_http_request_t *r;
    r = ngx_mrb_get_request();
    return ngx_mrb_get_request_header(mrb, &r->headers_in.headers);
}
예제 #13
0
static mrb_value ngx_mrb_get_request_uri(mrb_state *mrb, mrb_value self)
{
    ngx_http_request_t *r = ngx_mrb_get_request();
    return mrb_str_new_cstr(mrb, (const char *)r->uri.data);
}
예제 #14
0
static mrb_value ngx_mrb_get_content_type(mrb_state *mrb, mrb_value self) 
{
    ngx_http_request_t *r = ngx_mrb_get_request();
    return mrb_str_new_cstr(mrb, (char *)r->headers_out.content_type.data);
}
예제 #15
0
static mrb_value ngx_mrb_var_set_func(mrb_state *mrb, mrb_value self)
{
  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, val;
  ngx_uint_t hash;
  mrb_value k;
  mrb_value o;
  u_char *keyp, *valp;

  mrb_get_args(mrb, "oo", &k, &o);
  if (mrb_type(k) != MRB_TT_STRING) {
    k = mrb_funcall(mrb, k, "to_s", 0, NULL);
  }
  if (mrb_type(o) != MRB_TT_STRING) {
    o = mrb_funcall(mrb, o, "to_s", 0, NULL);
  }

  r = ngx_mrb_get_request();

  key.data = (u_char *)RSTRING_PTR(k);
  key.len  = RSTRING_LEN(k);
  val.data = (u_char *)RSTRING_PTR(o);
  val.len  = RSTRING_LEN(o);

  /* RSTRING_PTR(k) is not always null-terminated */
  keyp = ngx_palloc(r->pool, key.len + 1);
  if (keyp == NULL) {
    ngx_log_error(NGX_LOG_ERR
      , r->connection->log
      , 0
      , "%s ERROR %s:%d: memory allocate failed"
      , MODULE_NAME
      , __func__
      , __LINE__
    );
    goto ARENA_RESTOR_AND_ERROR;
  }

  /* RSTRING_PTR(o) is not always null-terminated */
  valp = ngx_palloc(r->pool, val.len + 1);
  if (valp == NULL) {
    ngx_log_error(NGX_LOG_ERR
      , r->connection->log
      , 0
      , "%s ERROR %s:%d: memory allocate failed"
      , MODULE_NAME
      , __func__
      , __LINE__
    );
    goto ARENA_RESTOR_AND_ERROR;
  }

  ngx_cpystrn(keyp, key.data, key.len + 1);
  ngx_cpystrn(valp, val.data, val.len + 1);

  hash = ngx_hash_strlow(key.data, 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
        , __func__
        , __LINE__
        , keyp
      );
      goto ARENA_RESTOR_AND_ERROR;
    }
    else 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
          , __func__
          , __LINE__
        );
        goto ARENA_RESTOR_AND_ERROR;
      }
      v->set_handler(r, vv, v->data);
    }
    else if (v->flags & NGX_HTTP_VAR_INDEXED) {
      vv = &r->variables[v->index];
    }
    else {
      ngx_log_error(NGX_LOG_ERR
        , r->connection->log
        , 0
        , "%s ERROR %s:%d: %s is not assinged"
        , MODULE_NAME
        , __func__
        , __LINE__
        , keyp
      );
      goto ARENA_RESTOR_AND_ERROR;
    }
    vv->valid = 1;
    vv->not_found = 0;
    vv->no_cacheable = 0;
    vv->data = val.data;
    vv->len = val.len;
    ngx_log_error(NGX_LOG_INFO
      , r->connection->log
      , 0
      , "%s INFO %s:%d: set variable key:%s val:%s"
      , MODULE_NAME
      , __func__
      , __LINE__
      , keyp
      , valp
    );
    return mrb_str_new(mrb, (char *)vv->data, vv->len);
  }

  ngx_log_error(NGX_LOG_ERR
    , r->connection->log
    , 0
    , "%s ERROR %s:%d: %s is not found"
    , MODULE_NAME
    , __func__
    , __LINE__
    , keyp
  );

ARENA_RESTOR_AND_ERROR:
  return mrb_nil_value();
}
예제 #16
0
// like Nginx rewrite keywords
// used like this:
// => http code 3xx location in browser
// => internal redirection in nginx
static mrb_value ngx_mrb_redirect(mrb_state *mrb, mrb_value self)
{
    int                     argc;
    u_char                  *str;
    ngx_buf_t               *b;
    ngx_int_t               rc;
    mrb_value               uri, code;
    ngx_str_t               ns;
    ngx_http_mruby_ctx_t         *ctx;
    ngx_table_elt_t         *location;
    ngx_mrb_rputs_chain_list_t      *chain;

    ngx_http_request_t *r = ngx_mrb_get_request();
    argc = mrb_get_args(mrb, "o|oo", &uri, &code);

    // get status code from args
    if (argc == 2) {
        rc = mrb_fixnum(code);
    } else {
        rc = NGX_HTTP_MOVED_TEMPORARILY;
    }

    // get redirect uri from args
    if (mrb_type(uri) != MRB_TT_STRING) {
        uri = mrb_funcall(mrb, uri, "to_s", 0, NULL);
    }

    // save location uri to ns
    ns.data     = (u_char *)RSTRING_PTR(uri);
    ns.len      = ngx_strlen(ns.data);
    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) {    
        ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);
        if (ctx == NULL) {
            ngx_log_error(NGX_LOG_ERR
                , r->connection->log
                , 0
                , "get mruby context failed."
            );
        }

        if (ctx->rputs_chain == NULL) {
            chain       = ngx_pcalloc(r->pool, sizeof(ngx_mrb_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;
        }

        // allocate space for body
        b = ngx_calloc_buf(r->pool);
        (*chain->last)->buf = b;
        (*chain->last)->next = NULL;

        str         = ngx_pstrdup(r->pool, &ns);
        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;
        ngx_http_set_ctx(r, ctx, ngx_http_mruby_module);

        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;
        }

        // build redirect location
        location = ngx_list_push(&r->headers_out.headers);
        location->hash = 1;
        ngx_str_set(&location->key, "Location");
        location->value = ns;
        location->lowcase_key = ngx_pnalloc(r->pool, location->value.len);
        ngx_strlow(location->lowcase_key, location->value.data, location->value.len);

        // set location and response code for hreaders
        r->headers_out.location = location;
        r->headers_out.status = rc;

        ngx_http_send_header(r);
        ngx_http_output_filter(r, chain->out);
    } else {
        ngx_http_internal_redirect(r, &ns, &r->args);
    }

    return self;
}