コード例 #1
0
ファイル: httptrap.c プロジェクト: maier/reconnoiter
static struct rest_json_payload *
rest_get_json_upload(mtev_http_rest_closure_t *restc,
                    int *mask, int *complete) {
  struct rest_json_payload *rxc;
  mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
  httptrap_closure_t *ccl = NULL;
  int content_length;
  char buffer[32768];

  content_length = mtev_http_request_content_length(req);
  rxc = restc->call_closure;
  rxc->check = noit_poller_lookup(rxc->check_id);
  if (!rxc->check) {
    *complete = 1;
    return NULL;
  }

  if(!strcmp(rxc->check->module, "httptrap")) ccl = rxc->check->closure;
  rxc->immediate = noit_httptrap_check_asynch(ccl ? ccl->self : NULL, rxc->check);
  while(!rxc->complete) {
    int len;
    len = mtev_http_session_req_consume(
            restc->http_ctx, buffer,
            MIN(content_length - rxc->len, sizeof(buffer)),
            sizeof(buffer),
            mask);
    if(len > 0) {
      yajl_status status;
      _YD("inbound payload chunk (%d bytes) continuing YAJL parse\n", len);
      status = yajl_parse(rxc->parser, (unsigned char *)buffer, len);
      if(status != yajl_status_ok) {
        unsigned char *err;
        *complete = 1;
        err = yajl_get_error(rxc->parser, 0, (unsigned char *)buffer, len);
        rxc->error = strdup((char *)err);
        yajl_free_error(rxc->parser, err);
        return rxc;
      }
      rxc->len += len;
    }
    if(len < 0 && errno == EAGAIN) return NULL;
    else if(len < 0) {
      *complete = 1;
      return NULL;
    }
    content_length = mtev_http_request_content_length(req);
    if((mtev_http_request_payload_chunked(req) && len == 0) ||
       (rxc->len == content_length)) {
      rxc->complete = 1;
      _YD("no more data, finishing YAJL parse\n");
      yajl_complete_parse(rxc->parser);
    }
  }

  *complete = 1;
  return rxc;
}
コード例 #2
0
ファイル: httptrap.c プロジェクト: edwardt/reconnoiter
static struct rest_json_payload *
rest_get_json_upload(mtev_http_rest_closure_t *restc,
                    int *mask, int *complete) {
  struct rest_json_payload *rxc;
  mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
  httptrap_closure_t *ccl;
  int content_length;
  char buffer[32768];

  content_length = mtev_http_request_content_length(req);
  rxc = restc->call_closure;
  ccl = rxc->check->closure;
  rxc->immediate = mtev_httptrap_check_aynsch(ccl->self, rxc->check);
  while(!rxc->complete) {
    int len;
    len = mtev_http_session_req_consume(
            restc->http_ctx, buffer,
            MIN(content_length - rxc->len, sizeof(buffer)),
            sizeof(buffer),
            mask);
    if(len > 0) {
      yajl_status status;
      status = yajl_parse(rxc->parser, (unsigned char *)buffer, len);
      if(status != yajl_status_ok) {
        unsigned char *err;
        *complete = 1;
        err = yajl_get_error(rxc->parser, 0, (unsigned char *)buffer, len);
        rxc->error = strdup((char *)err);
        yajl_free_error(rxc->parser, err);
        return rxc;
      }
      rxc->len += len;
    }
    if(len < 0 && errno == EAGAIN) return NULL;
    else if(len < 0) {
      *complete = 1;
      return NULL;
    }
    content_length = mtev_http_request_content_length(req);
    if((mtev_http_request_payload_chunked(req) && len == 0) ||
       (rxc->len == content_length)) {
      rxc->complete = 1;
      yajl_complete_parse(rxc->parser);
    }
  }

  *complete = 1;
  return rxc;
}
コード例 #3
0
ファイル: mtev_events_rest.c プロジェクト: adriancole/libmtev
int
mtev_rest_eventer_logs(mtev_http_rest_closure_t *restc, int n, char **p) {
  char *endptr = NULL;
  const char *since_s, *last_s;
  const char *jsonstr;
  char errbuf[128];
  unsigned long long since;
  int last = 0;
  struct json_object *doc;
  mtev_log_stream_t ls;
  mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
  since_s = mtev_http_request_querystring(req, "since");
  if(since_s) since = strtoull(since_s, &endptr, 10);
  last_s = mtev_http_request_querystring(req, "last");
  if(last_s) last = atoi(last_s);

  assert(n==1);
  ls = mtev_log_stream_find(p[0]);
  if(!ls || strcmp(mtev_log_stream_get_type(ls),"memory"))
    goto not_found;

  doc = json_object_new_array();
  if(endptr != since_s)
    mtev_log_memory_lines_since(ls, since, json_spit_log, doc);
  else
    mtev_log_memory_lines(ls, last, json_spit_log, doc);

  mtev_http_response_ok(restc->http_ctx, "application/json");
  jsonstr = json_object_to_json_string(doc);
  mtev_http_response_append(restc->http_ctx, jsonstr, strlen(jsonstr));
  mtev_http_response_append(restc->http_ctx, "\n", 1);
  json_object_put(doc);
  mtev_http_response_end(restc->http_ctx);
  return 0;
 not_found:
  doc = json_object_new_object();
  snprintf(errbuf, sizeof(errbuf), "log '%s' not found", p[0]);
  json_object_object_add(doc, "error", json_object_new_string(errbuf));
  jsonstr = json_object_to_json_string(doc);
  mtev_http_response_not_found(restc->http_ctx, "application/json");
  mtev_http_response_append(restc->http_ctx, jsonstr, strlen(jsonstr));
  mtev_http_response_append(restc->http_ctx, "\n", 1);
  json_object_put(doc);
  mtev_http_response_end(restc->http_ctx);
  return 0;
}
コード例 #4
0
ファイル: lua_mtev_http.c プロジェクト: adriancole/libmtev
static int
mtev_http_ctx_index_func(lua_State *L) {
  OO_LUA_DECL(L, mtev_http_session_ctx, http_ctx, k);
  switch(*k) {
    case 'C':
      if(!strcmp(k, "CHUNKED")) {
        lua_pushinteger(L, MTEV_HTTP_CHUNKED);
        return 1;
      }
      if(!strcmp(k, "CLOSE")) {
        lua_pushinteger(L, MTEV_HTTP_CLOSE);
        return 1;
      }
      break;
    case 'D':
      if(!strcmp(k, "DEFATE")) {
        lua_pushinteger(L, MTEV_HTTP_DEFLATE);
        return 1;
      }
      break;
    case 'G':
      if(!strcmp(k, "GZIP")) {
        lua_pushinteger(L, MTEV_HTTP_GZIP);
        return 1;
      }
      break;
    case 'f':
      if(!strcmp(k, "flush")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_flush, 1);
        return 1;
      }
      if(!strcmp(k, "flush_end")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_flush_and_end, 1);
        return 1;
      }
      break;
    case 'h':
      if(!strcmp(k, "htmlentities")) {
        lua_getglobal(L, "mtev");
        lua_getfield(L, -1, "utf8tohtml");
        lua_remove(L, -2);  /* pop mtev */
        return 1;
      }
      if(!strcmp(k, "header")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_header_set, 1);
        return 1;
      }
      break;
    case 'o':
      if(!strcmp(k, "option")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_option_set, 1);
        return 1;
      }
      break;
    case 'r':
      if(!strcmp(k, "request")) {
        lua_pushlightuserdata(L, mtev_http_session_request(http_ctx));
        lua_pushcclosure(L, mtev_lua_http_request_func, 1);
        return 1;
      }
      if(!strcmp(k, "response")) {
        return 0;
      }
      break;
    case 's':
      if(!strcmp(k, "status")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_status_set, 1);
        return 1;
      }
      if(!strcmp(k, "set_cookie")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_set_cookie, 1);
        return 1;
      }
      break;
    case 'u':
      if(!strcmp(k, "url_decode")) {
        lua_pushcclosure(L, mtev_lua_http_url_decode, 0);
        return 1;
      }
      if(!strcmp(k, "url_encode")) {
        lua_pushcclosure(L, mtev_lua_http_url_encode, 0);
        return 1;
      }
      break;
    case 'w':
      if(!strcmp(k, "write")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_write, 1);
        return 1;
      }
      if(!strcmp(k, "write_fd")) {
        lua_pushlightuserdata(L, http_ctx);
        lua_pushcclosure(L, mtev_lua_http_write_fd, 1);
        return 1;
      }
      break;
    default:
      break;
  }
  luaL_error(L, "mtev_http_session_ctx no such element: %s", k);
  return 0;
}
コード例 #5
0
ファイル: lua_web.c プロジェクト: adriancole/libmtev
static int
lua_web_handler(mtev_http_rest_closure_t *restc,
                int npats, char **pats) {
  int status, base, rv, mask = 0;
  int complete = 0;
  lua_web_conf_t *conf = the_one_conf;
  lua_module_closure_t *lmc = &conf->lmc;
  mtev_lua_resume_info_t *ri;
  mtev_lua_resume_rest_info_t *ctx = NULL;
  lua_State *L;
  eventer_t conne;
  mtev_http_request *req = mtev_http_session_request(restc->http_ctx);
  mtev_http_response *res = mtev_http_session_response(restc->http_ctx);

  if(!lmc || !conf || !conf->dispatch) {
    goto boom;
  }

  if(mtev_http_request_get_upload(req, NULL) == NULL &&
     mtev_http_request_has_payload(req)) {
    const void *payload = NULL;
    int payload_len = 0;
    payload = rest_get_raw_upload(restc, &mask, &complete, &payload_len);
    if(!complete) return mask;
    mtev_http_request_set_upload(req, (char *)payload, (int64_t)payload_len,
                                 req_payload_free, NULL);
    restc->call_closure_free(restc->call_closure);
    restc->call_closure = NULL;
  }

  if(restc->call_closure == NULL) {
    ri = calloc(1, sizeof(*ri));
    ri->bound_thread = pthread_self();
    ri->context_magic = LUA_REST_INFO_MAGIC;
    ctx = ri->context_data = calloc(1, sizeof(mtev_lua_resume_rest_info_t));
    ctx->restc = restc;
    ri->lmc = lmc;
    lua_getglobal(lmc->lua_state, "mtev_coros");
    ri->coro_state = lua_newthread(lmc->lua_state);
    ri->coro_state_ref = luaL_ref(lmc->lua_state, -2);

    mtev_lua_set_resume_info(lmc->lua_state, ri);

    lua_pop(lmc->lua_state, 1); /* pops mtev_coros */

    restc->call_closure = ri;
    restc->call_closure_free = rest_lua_ctx_free;
  }
  ri = restc->call_closure;
  ctx = ri->context_data;
  ctx->httpcode = 404;

  L = ri->coro_state;

  lua_getglobal(L, "require");
  lua_pushstring(L, conf->dispatch);
  rv = lua_pcall(L, 1, 1, 0);
  if(rv) {
    int i;
    mtevL(mtev_error, "lua: require %s failed\n", conf->dispatch);
    i = lua_gettop(L);
    if(i>0) {
      if(lua_isstring(L, i)) {
        const char *err;
        size_t len;
        err = lua_tolstring(L, i, &len);
        mtevL(mtev_error, "lua: %s\n", err);
      }
    }
    lua_pop(L,i);
    goto boom;
  }
  lua_pop(L, lua_gettop(L));

  mtev_lua_pushmodule(L, conf->dispatch);
  if(lua_isnil(L, -1)) {
    lua_pop(L, 1);
    ctx->err = strdup("no such module");
    goto boom;
  }
  lua_getfield(L, -1, "handler");
  lua_remove(L, -2);
  if(!lua_isfunction(L, -1)) {
    lua_pop(L, 1);
    ctx->err = strdup("no 'handler' function in module");
    goto boom;
  }
  mtev_lua_setup_restc(L, restc);
  mtev_lua_hash_to_table(L, restc->ac->config);

  conne = mtev_http_connection_event(mtev_http_session_connection(restc->http_ctx));
  eventer_remove(conne);
  restc->fastpath = lua_web_restc_fastpath;

  status = lmc->resume(ri, 2);
  if(status == 0) return 0;

  if(mtev_http_response_complete(res) != mtev_true) {
 boom:
    mtev_http_response_standard(restc->http_ctx,
                                (ctx && ctx->httpcode) ? ctx->httpcode : 500,
                                "ERROR", "text/plain");
    if(ctx && ctx->err) mtev_http_response_append(restc->http_ctx, ctx->err, strlen(ctx->err));
    mtev_http_response_end(restc->http_ctx);
  }
  return 0;
}
コード例 #6
0
ファイル: httptrap.c プロジェクト: maier/reconnoiter
static int
rest_httptrap_handler(mtev_http_rest_closure_t *restc,
                      int npats, char **pats) {
  int mask, complete = 0, cnt;
  struct rest_json_payload *rxc = NULL;
  const char *error = "internal error", *secret = NULL;
  mtev_http_session_ctx *ctx = restc->http_ctx;
  const unsigned int DEBUGDATA_OUT_SIZE=4096;
  const unsigned int JSON_OUT_SIZE=DEBUGDATA_OUT_SIZE+128;
  char json_out[JSON_OUT_SIZE];
  char debugdata_out[DEBUGDATA_OUT_SIZE];
  int debugflag=0;
  const char *debugchkflag;
  noit_check_t *check;
  uuid_t check_id;
  mtev_http_request *req;
  mtev_hash_table *hdrs;

  if(npats != 2) {
    error = "bad uri";
    goto error;
  }
  if(uuid_parse(pats[0], check_id)) {
    error = "uuid parse error";
    goto error;
  }

  if(restc->call_closure == NULL) {
    mtev_boolean allowed = mtev_false;
    httptrap_closure_t *ccl = NULL;
    const char *delimiter = NULL;
    rxc = restc->call_closure = calloc(1, sizeof(*rxc));
    rxc->delimiter = DEFAULT_HTTPTRAP_DELIMITER;
    check = noit_poller_lookup(check_id);
    if(!check) {
      error = "no such check";
      goto error;
    }
    if(!httptrap_surrogate && strcmp(check->module, "httptrap")) {
      error = "no such httptrap check";
      goto error;
    }
 
    /* check "secret" then "httptrap_secret" as a fallback */
    (void)mtev_hash_retr_str(check->config, "secret", strlen("secret"), &secret);
    if(!secret) (void)mtev_hash_retr_str(check->config, "httptrap_secret", strlen("httptrap_secret"), &secret);
    if(secret && !strcmp(pats[1], secret)) allowed = mtev_true;
    if(!allowed && cross_module_reverse_allowed(check, pats[1])) allowed = mtev_true;

    if(!allowed) {
      error = "secret mismatch";
      goto error;
    }

    /* check "delimiter" then "httptrap_delimiter" as a fallback */
    (void)mtev_hash_retr_str(check->config, "delimiter", strlen("delimiter"), &delimiter);
    if(!delimiter) (void)mtev_hash_retr_str(check->config, "httptrap_delimiter", strlen("httptrap_delimiter"), &delimiter);
    if(delimiter && *delimiter) rxc->delimiter = *delimiter;
    rxc->check = check;
    uuid_copy(rxc->check_id, check_id);
    rxc->parser = yajl_alloc(&httptrap_yajl_callbacks, NULL, rxc);
    rxc->depth = -1;
    yajl_config(rxc->parser, yajl_allow_comments, 1);
    yajl_config(rxc->parser, yajl_dont_validate_strings, 1);
    yajl_config(rxc->parser, yajl_allow_trailing_garbage, 1);
    yajl_config(rxc->parser, yajl_allow_partial_values, 1);
    restc->call_closure_free = rest_json_payload_free;
  }
  else rxc = restc->call_closure;

  /* flip threads */
  {
    mtev_http_connection *conn = mtev_http_session_connection(ctx);
    eventer_t e = mtev_http_connection_event(conn);
    if(e) {
      pthread_t tgt = CHOOSE_EVENTER_THREAD_FOR_CHECK(rxc->check);
      if(!pthread_equal(e->thr_owner, tgt)) {
        e->thr_owner = tgt;
        return EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
      }
    }
  }

  rxc = rest_get_json_upload(restc, &mask, &complete);
  if(rxc == NULL && !complete) return mask;

  if(!rxc) goto error;
  if(rxc->error) goto error;

  cnt = rxc->cnt;

  mtev_http_response_status_set(ctx, 200, "OK"); 
  mtev_http_response_header_set(ctx, "Content-Type", "application/json");
  mtev_http_response_option_set(ctx, MTEV_HTTP_CLOSE); 
  
  /*Examine headers for x-circonus-httptrap-debug flag*/
  req = mtev_http_session_request(ctx);
  hdrs = mtev_http_request_headers_table(req); 
    
  /*Check if debug header passed in. If present and set to true, set debugflag value to one.*/
  if(mtev_hash_retr_str(hdrs, "x-circonus-httptrap-debug", strlen("x-circonus-httptrap-debug"), &debugchkflag))
  {
    if (strcmp(debugchkflag,"true")==0)
    {
      debugflag=1;
    }
  }
   
  /*If debugflag remains zero, simply output the number of metrics.*/
  if (debugflag==0)
  {
    snprintf(json_out, sizeof(json_out),
           "{ \"stats\": %d }", cnt);    
  }
  
  /*Otherwise, if set to one, output current metrics in addition to number of current metrics.*/
  else if (debugflag==1)
  {        
      stats_t *c;
      mtev_hash_table *metrics;
        
      /*Retrieve check information.*/        
      check = noit_poller_lookup(check_id);
      c = noit_check_get_stats_current(check);
      metrics = noit_check_stats_metrics(c);
      mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
      const char *k;
      int klen;
      void *data;
      int written=0;
      int offset=0;
      memset(debugdata_out,'\0',sizeof(debugdata_out));
      
      /*Extract metrics*/
      while(mtev_hash_next(metrics, &iter, &k, &klen, &data))
      {
        char buff[256];
        int toWrite = DEBUGDATA_OUT_SIZE-offset;
        metric_t *tmp=(metric_t *)data;
        char *metric_name=tmp->metric_name;
        metric_type_t metric_type=tmp->metric_type;
        noit_stats_snprint_metric_value(buff, sizeof(buff), tmp);
        written = snprintf(debugdata_out + offset, toWrite, "\"%s\": {\"_type\":\"%c\",\"_value\":\"%s\"},", metric_name,metric_type,buff);
        if(toWrite < written) 
        {
            break;
        }
        offset += written;
      }
        
      /*Set last character to empty-don't want extra comma in output*/
      if (offset>1)
      {
        snprintf(debugdata_out + (offset-1), 1, "%s"," ");
      }
      
      /*Output stats and metrics.*/
      snprintf(json_out, sizeof(json_out)+strlen(debugdata_out),
             "{ \"stats\": %d, \"metrics\": {%s } }", cnt, debugdata_out);
  }

  mtev_http_response_append(ctx, json_out, strlen(json_out));
  mtev_http_response_end(ctx);
  return 0;

 error:
  mtev_http_response_server_error(ctx, "application/json");
  mtev_http_response_append(ctx, "{ \"error\": \"", 12);
  if(rxc && rxc->error) error = rxc->error;
  mtev_http_response_append(ctx, error, strlen(error));
  mtev_http_response_append(ctx, "\" }", 3);
  mtev_http_response_end(ctx);
  return 0;
}