Пример #1
0
void
add_to_queue(Queue *q, void *data)
{
  Cell *new_cell;
  int n;

  if (data != NULL) {
    TSMutexLock(q->mutex);
    /* Init the new cell */
    new_cell = TSmalloc(sizeof(Cell));
    new_cell->magic = MAGIC_ALIVE;
    new_cell->ptr_data = data;
    new_cell->ptr_next = q->tail;
    new_cell->ptr_prev = NULL;

    /* Add this new cell to the queue */
    if (q->tail == NULL) {
      TSAssert(q->head == NULL);
      TSAssert(q->nb_elem == 0);
      q->tail = new_cell;
      q->head = new_cell;
    } else {
      TSAssert(q->tail->magic == MAGIC_ALIVE);
      q->tail->ptr_prev = new_cell;
      q->tail = new_cell;
    }
    n = q->nb_elem++;
    TSMutexUnlock(q->mutex);

    if (n > MAX_JOBS_ALARM) {
      TSError("[thread_pool] Warning:Too many jobs in plugin thread pool queue (%d). Maximum allowed is %d", n, MAX_JOBS_ALARM);
    }
  }
}
Пример #2
0
TSRemapStatus
TSRemapDoRemap(void* ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
{
    int                         ret;
    uint64_t                    req_id;
    TSCont                      contp;
    lua_State                   *L;
    ts_lua_main_ctx             *main_ctx;
    ts_lua_http_ctx             *http_ctx;
    ts_lua_cont_info            *ci;
    ts_lua_instance_conf        *instance_conf;

    instance_conf = (ts_lua_instance_conf*)ih;
    req_id = __sync_fetch_and_add(&ts_lua_http_next_id, 1);

    main_ctx = &ts_lua_main_ctx_array[req_id%TS_LUA_MAX_STATE_COUNT];

    TSMutexLock(main_ctx->mutexp);

    http_ctx = ts_lua_create_http_ctx(main_ctx, instance_conf);

    http_ctx->txnp = rh;
    http_ctx->client_request_bufp = rri->requestBufp;
    http_ctx->client_request_hdrp = rri->requestHdrp;
    http_ctx->client_request_url = rri->requestUrl;
    http_ctx->rri = rri;

    ci = &http_ctx->cinfo;
    L = ci->routine.lua;

    contp = TSContCreate(ts_lua_http_cont_handler, NULL);
    TSContDataSet(contp, http_ctx);

    ci->contp = contp;
    ci->mutex = TSContMutexGet((TSCont)rh);

    // push do_remap function on the stack, and no async operation should exist here.
    lua_getglobal(L, TS_LUA_FUNCTION_REMAP);

    if (lua_pcall(L, 0, 1, 0) != 0) {
        ee("lua_pcall failed: %s", lua_tostring(L, -1));
        ret = TSREMAP_NO_REMAP;

    } else {
        ret = lua_tointeger(L, -1);
    }

    lua_pop(L, 1);      // pop the result

    if (http_ctx->hooks > 0) {
        TSMutexUnlock(main_ctx->mutexp);
        TSHttpTxnHookAdd(rh, TS_HTTP_TXN_CLOSE_HOOK, contp);

    } else {
        ts_lua_destroy_http_ctx(http_ctx);
        TSMutexUnlock(main_ctx->mutexp);
    }

    return ret;
}
Пример #3
0
int
ts_http_fetcher_callback_sm(http_fetcher *fch, TSEvent event)
{
    if (fch->deleted && !fch->ref) {
        ts_http_fetcher_release(fch);
        return -1;
    }

    if (event == TS_FETCH_EVENT_BODY_QUIET)
        return 0;

    fch->ref++;

    if (fch->flags & TS_FETCH_FLAG_USE_NEW_LOCK)
        TSMutexLock(TSContMutexGet(fch->contp));

    TSContCall(fch->contp, event, fch);

    if (fch->flags & TS_FETCH_FLAG_USE_NEW_LOCK)
        TSMutexUnlock(TSContMutexGet(fch->contp));

    fch->ref--;

    if (fch->deleted && !fch->ref) {
        ts_http_fetcher_release(fch);
        return -1;
    }

    return 0;
}
Пример #4
0
void *
remove_from_queue(Queue *q)
{
  void *data = NULL;
  Cell *remove_cell;

  TSMutexLock(q->mutex);
  if (q->nb_elem > 0) {
    remove_cell = q->head;
    TSAssert(remove_cell->magic == MAGIC_ALIVE);

    data = remove_cell->ptr_data;
    q->head = remove_cell->ptr_prev;
    if (q->head == NULL) {
      TSAssert(q->nb_elem == 1);
      q->tail = NULL;
    } else {
      TSAssert(q->head->magic == MAGIC_ALIVE);
      q->head->ptr_next = NULL;
    }

    remove_cell->magic = MAGIC_DEAD;
    TSfree(remove_cell);
    q->nb_elem--;
  }
  TSMutexUnlock(q->mutex);
  return data;
}
static void
free_request_state(StateInfo *state)
{
#if defined(DEBUG)
  int verify = 1;
#else
  int verify = TSIsDebugTagSet(PLUGIN_NAME);
#endif

  // Verify that the effective URL of this state object has been removed before we delete the state.
  if (verify) {
    void *ptr;

    TSMutexLock(state->plugin_config->troot_mutex);
    ptr = tfind(state->req_info->effective_url, &(state->plugin_config->troot), xstrcmp);
    TSMutexUnlock(state->plugin_config->troot_mutex);

    if (ptr) {
      TSReleaseAssert(ptr != state->req_info->effective_url);
    }
  }

  if (state->resp_info) {
    free_response_info(state->resp_info);
  }

  free_request_info(state->req_info);
  TSfree(state);
}
Пример #6
0
int
get_nbelem_queue(Queue *q)
{
  int nb;
  TSMutexLock(q->mutex);
  nb = q->nb_elem;
  TSMutexUnlock(q->mutex);

  return nb;
}
Пример #7
0
TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * rri)
{
  int ret;
  uint64_t req_id;

  TSCont contp;
  lua_State *l;

  ts_lua_main_ctx *main_ctx;
  ts_lua_http_ctx *http_ctx;

  ts_lua_instance_conf *instance_conf;

  instance_conf = (ts_lua_instance_conf *) ih;
  req_id = __sync_fetch_and_add(&ts_lua_http_next_id, 1);


  main_ctx = &ts_lua_main_ctx_array[req_id % TS_LUA_MAX_STATE_COUNT];

  TSMutexLock(main_ctx->mutexp);

  http_ctx = ts_lua_create_http_ctx(main_ctx, instance_conf);

  http_ctx->txnp = rh;
  http_ctx->client_request_bufp = rri->requestBufp;
  http_ctx->client_request_hdrp = rri->requestHdrp;
  http_ctx->client_request_url = rri->requestUrl;
  http_ctx->remap = 1;
  l = http_ctx->lua;

  lua_getglobal(l, TS_LUA_FUNCTION_REMAP);
  if (lua_type(l, -1) != LUA_TFUNCTION) {
    TSMutexUnlock(main_ctx->mutexp);
    return TSREMAP_NO_REMAP;
  }

  contp = TSContCreate(ts_lua_http_cont_handler, NULL);
  TSContDataSet(contp, http_ctx);
  http_ctx->main_contp = contp;

  if (lua_pcall(l, 0, 1, 0) != 0) {
    fprintf(stderr, "lua_pcall failed: %s\n", lua_tostring(l, -1));
  }

  ret = lua_tointeger(l, -1);
  lua_pop(l, 1);

  TSHttpTxnHookAdd(rh, TS_HTTP_TXN_CLOSE_HOOK, contp);

  TSMutexUnlock(main_ctx->mutexp);

  return ret;
}
static int
ts_lua_http_intercept_handler(TSCont contp, TSEvent event, void *edata)
{
  int ret, n;
  TSMutex mtxp;
  ts_lua_http_intercept_ctx *ictx;

  ictx = (ts_lua_http_intercept_ctx *) TSContDataGet(contp);
  mtxp = NULL;

  if (edata == ictx->input.vio) {
    ret = ts_lua_http_intercept_process_read(event, ictx);

  } else if (edata == ictx->output.vio) {
    ret = ts_lua_http_intercept_process_write(event, ictx);

  } else {
    mtxp = ictx->mctx->mutexp;
    n = (int64_t) edata & 0xFFFF;
    TSMutexLock(mtxp);
    ret = ts_lua_http_intercept_run_coroutine(ictx, n);
  }

  if (ret || (ictx->send_complete && ictx->recv_complete)) {

    TSContDestroy(contp);

    if (!mtxp) {
      mtxp = ictx->mctx->mutexp;
      TSMutexLock(mtxp);
    }

    ts_lua_destroy_http_intercept_ctx(ictx);
  }

  if (mtxp)
    TSMutexUnlock(mtxp);

  return 0;
}
Пример #9
0
static int
ts_lua_schedule_handler(TSCont contp, TSEvent ev, void *edata)
{
  lua_State *L;
  ts_lua_cont_info *ci;
  ts_lua_coroutine *crt;
  int event, n, ret;
  ts_lua_http_ctx *actx;
  ts_lua_main_ctx *main_ctx;

  event = (int)ev;
  TSDebug(TS_LUA_DEBUG_TAG, "getting actx and other info");
  actx = (ts_lua_http_ctx *)TSContDataGet(contp);

  TSDebug(TS_LUA_DEBUG_TAG, "getting http_Ctx");
  ci = &actx->cinfo;
  crt = &ci->routine;

  main_ctx = crt->mctx;
  L = crt->lua;

  ret = 0;

  TSMutexLock(main_ctx->mutexp);
  ts_lua_set_cont_info(L, ci);

  if (event == TS_LUA_EVENT_COROUTINE_CONT) {
    TSDebug(TS_LUA_DEBUG_TAG, "event is coroutine_cont");
    n = (intptr_t)edata;
    ret = lua_resume(L, n);
  } else {
    TSDebug(TS_LUA_DEBUG_TAG, "event is not coroutine_cont");
    n = lua_gettop(L);
    ret = lua_resume(L, n - 1);
  }

  if (ret == LUA_YIELD) {
    TSMutexUnlock(main_ctx->mutexp);
    goto done;
  }

  if (ret != 0) {
    TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
  }

  lua_pop(L, lua_gettop(L));
  TSMutexUnlock(main_ctx->mutexp);
  ts_lua_destroy_async_ctx(actx);

done:
  return 0;
}
Пример #10
0
static int
ts_lua_cache_handle_write(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State               *L;
    TSMutex                 mtx;
    int64_t                 avail, done, n;

    n = 0;

    switch (event) {

        case TS_EVENT_VCONN_WRITE_READY:
            done = TSVIONDoneGet(info->ioh.vio);
            if (done < info->need) {
                TSVIOReenable(info->ioh.vio);

            } else {
                n = info->need - info->already;
                avail = TSIOBufferReaderAvail(info->ioh.reader);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            break;

        default:
            info->err = 1;
            break;
    }

    if (info->wait && (n > 0 || info->err)) {           // resume
        L = ci->routine.lua;
        mtx = ci->routine.mctx->mutexp;

        TSMutexLock(mtx);

        if (n > 0) {
            lua_pushnumber(L, n);
            info->already = info->need;

        } else {
            lua_pushnumber(L, 0);
        }

        info->wait = 0;
        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);
        TSMutexUnlock(mtx);
    }

    return 0;
}
Пример #11
0
static void
stat_add(char *name, TSMgmtInt amount, TSStatPersistence persist_type, TSMutex create_mutex)
{
int stat_id = -1;
ENTRY search, *result = NULL;
static __thread struct hsearch_data stat_cache;
static __thread bool hash_init = false;

if (unlikely(!hash_init)) {
    hcreate_r(TS_MAX_API_STATS << 1, &stat_cache);
    hash_init = true;
    TSDebug(DEBUG_TAG, "stat cache hash init");
}

search.key  = name;
search.data = 0;
hsearch_r(search, FIND, &result, &stat_cache);

if (unlikely(result == NULL)) {
    // This is an unlikely path because we most likely have the stat cached
    // so this mutex won't be much overhead and it fixes a race condition
    // in the RecCore. Hopefully this can be removed in the future.
    TSMutexLock(create_mutex);
    if (TS_ERROR == TSStatFindName((const char *)name, &stat_id)) {
        stat_id = TSStatCreate((const char *)name, TS_RECORDDATATYPE_INT, persist_type, TS_STAT_SYNC_SUM);
        if (stat_id == TS_ERROR) {
            TSDebug(DEBUG_TAG, "Error creating stat_name: %s", name);
        } else {
            TSDebug(DEBUG_TAG, "Created stat_name: %s stat_id: %d", name, stat_id);
        }
    }
    TSMutexUnlock(create_mutex);

    if (stat_id >= 0) {
        search.key  = TSstrdup(name);
        search.data = (void *)((intptr_t)stat_id);
        hsearch_r(search, ENTER, &result, &stat_cache);
        TSDebug(DEBUG_TAG, "Cached stat_name: %s stat_id: %d", name, stat_id);
    }
} else {
    stat_id = (int)((intptr_t)result->data);
}

if (likely(stat_id >= 0)) {
    TSStatIntIncrement(stat_id, amount);
} else {
    TSDebug(DEBUG_TAG, "stat error! stat_name: %s stat_id: %d", name, stat_id);
}
}
Пример #12
0
  void RateLimiter::Release(int counter_index, const char * key, uint64_t amount) {
    TSReleaseAssert(!pthread_rwlock_rdlock(&rwlock_keymap_));

    std::map<const char *,LimiterState *>::iterator it = keymap_.find(key);

    TSReleaseAssert(!pthread_rwlock_unlock(&rwlock_keymap_));
    TSReleaseAssert( it != keymap_.end() );
    LimiterState * state = it->second;


    TSMutexLock(update_mutex_);
    state->set_taken(counter_index, state->taken(counter_index) - amount);
    dbg("released amount, currently taken %f", state->taken(counter_index));
    TSMutexUnlock(update_mutex_);
  }
static int
config_handler(TSCont cont, TSEvent event, void *edata)
{
  plugin_state_t *pstate;
  invalidate_t *i, *iptr;
  TSCont free_cont;
  bool updated;
  TSMutex mutex;

  mutex = TSContMutexGet(cont);
  TSMutexLock(mutex);

  TSDebug(LOG_PREFIX, "In config Handler");
  pstate = (plugin_state_t *)TSContDataGet(cont);
  i      = copy_config(pstate->invalidate_list);

  updated = prune_config(&i);
  updated = load_config(pstate, &i) || updated;

  if (updated) {
    list_config(pstate, i);
    iptr = __sync_val_compare_and_swap(&(pstate->invalidate_list), pstate->invalidate_list, i);

    if (iptr) {
      free_cont = TSContCreate(free_handler, TSMutexCreate());
      TSContDataSet(free_cont, (void *)iptr);
      TSContScheduleOnPool(free_cont, FREE_TMOUT, TS_THREAD_POOL_TASK);
    }
  } else {
    TSDebug(LOG_PREFIX, "No Changes");
    if (i) {
      free_invalidate_t_list(i);
    }
  }

  TSMutexUnlock(mutex);

  // Don't reschedule for TS_EVENT_MGMT_UPDATE
  if (event == TS_EVENT_TIMEOUT) {
    TSContScheduleOnPool(cont, CONFIG_TMOUT, TS_THREAD_POOL_TASK);
  }
  return 0;
}
Пример #14
0
static int
ts_lua_cache_open_write(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State       *L;
    TSMutex         mtx;
    TSVConn         vc;

    L = ci->routine.lua;
    mtx = ci->routine.mctx->mutexp;

    switch (event) {

        case TS_EVENT_CACHE_OPEN_WRITE:
            vc = (TSVConn)edata;
            info->cache_vc = vc;
            break;

        default:                // error
            info->err = 1;
            break;
    }

    TSMutexLock(mtx);

    // result table
    lua_newtable(L);
    lua_pushlstring(L, "info", sizeof("info") - 1);
    lua_pushlightuserdata(L, info);
    lua_rawset(L, -3);

    if (info->cache_action) {
        info->cache_action = NULL;
        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);

    } else {
        // return to the ts.cache_open synchronized
    }

    TSMutexUnlock(mtx);

    return 0;
}
Пример #15
0
static int
ts_lua_shared_dict_get_keys(lua_State *L)
{
    int                         n, max;
    ts_lua_shared_dict          *dct;
    ts_lua_shared_dict_keys_ctx ctx;

    n = lua_gettop(L);

    if (n < 1) {
        return luaL_error(L, "invalid param for xx:get_keys()");
    }

    dct = (ts_lua_shared_dict*)lua_touserdata(L, 1);
    if (dct == NULL) {
        return luaL_error(L, "userdata is required for xx:get_keys()");
    }

    if (n == 2) {
        max = lua_tonumber(L, 2);

    } else {
        max = 0;
    }

    ctx.l = L;
    ctx.dct = dct;
    ctx.max = max;
    ctx.n = 0;

    lua_newtable(L);

    if (!(dct->flags & TS_LUA_SHDICT_FLAG_STATIC))
        TSMutexLock(dct->map.mutexp);

    ts_lua_hash_table_iterate(&dct->map.t, dump_entry_key, &ctx);

    if (!(dct->flags & TS_LUA_SHDICT_FLAG_STATIC))
        TSMutexUnlock(dct->map.mutexp);
 
    return 1;
}
Пример #16
0
/* This is where we start the PURGE events, setting up the transaction to fail,
   and bump the generation ID, and finally save the state. */
static void
update_purge_state(PurgeInstance *purge)
{
  FILE *file;

  TSMutexLock(purge->lock);

  ++purge->gen_id;
  TSDebug(PLUGIN_NAME, "Bumping the Generation ID to %" PRId64 " for %s", purge->gen_id, purge->id);

  if ((file = fopen(purge->state_file, "w"))) {
    TSDebug(PLUGIN_NAME, "\tsaving state to %s", purge->state_file);
    fprintf(file, "%" PRId64 "", purge->gen_id);
    fclose(file);
  } else {
    TSError("[%s] Unable to save state to file %s: errno=%d", PLUGIN_NAME, purge->state_file, errno);
  }

  TSMutexUnlock(purge->lock);
}
Пример #17
0
int
ts_lua_del_module(ts_lua_instance_conf * conf, ts_lua_main_ctx * arr, int n)
{
  int i;
  lua_State *L;

  for (i = 0; i < n; i++) {

    TSMutexLock(arr[i].mutexp);

    L = arr[i].lua;

    /* call "__clean__", to clean resources */
    lua_pushlightuserdata(L, conf);
    lua_rawget(L, LUA_REGISTRYINDEX);
    lua_replace(L, LUA_GLOBALSINDEX);   /* L[GLOBAL] = L[REG][conf] */

    lua_getglobal(L, "__clean__");      /* get __clean__ function */

    if (lua_type(L, -1) == LUA_TFUNCTION) {

      if (lua_pcall(L, 0, 0, 0)) {
        TSError("[%s] lua_pcall %s failed: %s", __FUNCTION__, conf->script, lua_tostring(L, -1));
      }

    } else {
      lua_pop(L, 1);            /* pop nil */
    }

    lua_pushlightuserdata(L, conf);
    lua_pushnil(L);
    lua_rawset(L, LUA_REGISTRYINDEX);   /* L[REG][conf] = nil */

    lua_newtable(L);
    lua_replace(L, LUA_GLOBALSINDEX);   /* L[GLOBAL] = EMPTY  */

    TSMutexUnlock(arr[i].mutexp);
  }

  return 0;
}
  uint64_t RateLimiter::GetMaxUnits(uint64_t amount,LimiterState * state) {
    timeval timev;
    gettimeofday(&timev,NULL);
    time_t t = time(NULL);
	struct tm * p = localtime(&t); 
    int counter_index = p->tm_hour;
    LimiterEntry * limiter_entry = counters_[counter_index];

    if (!state) {
      return limiter_entry->max_rate();
    }

	TSMutexLock(update_mutex_);
    timeval elapsed;
    timeval stime = state->time(counter_index);
    timersub(&timev, &stime, &elapsed);

    float elapsed_ms = (elapsed.tv_sec * 1000.0f) + ( elapsed.tv_usec/1000.0f );
    float rate_timeslice = 1.0f - (limiter_entry->milliseconds() - elapsed_ms) / limiter_entry->milliseconds();
    if (rate_timeslice<0) rate_timeslice=0;

    float replenishment  = rate_timeslice * limiter_entry->max_rate();
    float newallowance   = state->allowance(counter_index) + replenishment;

    newallowance = newallowance > limiter_entry->max_rate() ? limiter_entry->max_rate() : newallowance;

    int rv = amount;

    if (amount > newallowance) {
      amount = rv = newallowance;
    }
	
    newallowance -= amount;
    
    if (newallowance >= 0.0f  ) {
      state->set_allowance(counter_index, newallowance);
      state->set_time(counter_index, timev);
    }
	TSMutexUnlock(update_mutex_);
    return rv;
  }
static void
ts_lua_http_intercept_process(ts_lua_http_ctx * http_ctx, TSVConn conn)
{
  TSCont contp;
  lua_State *l;
  TSMutex mtxp;
  ts_lua_http_intercept_ctx *ictx;

  mtxp = http_ctx->mctx->mutexp;
  TSMutexLock(mtxp);

  ictx = ts_lua_create_http_intercept_ctx(http_ctx);

  contp = TSContCreate(ts_lua_http_intercept_handler, TSMutexCreate());
  TSContDataSet(contp, ictx);

  ictx->contp = contp;
  ictx->net_vc = conn;

  l = ictx->lua;

  // set up read.
  ts_lua_http_intercept_setup_read(ictx);

  // set up write.
  ts_lua_http_intercept_setup_write(ictx);

  // invoke function here
  if (http_ctx->intercept_type == TS_LUA_TYPE_HTTP_INTERCEPT) {
    lua_getglobal(l, TS_LUA_FUNCTION_HTTP_INTERCEPT);
  } else {
    lua_getglobal(l, TS_LUA_FUNCTION_HTTP_SERVER_INTERCEPT);
  }

  ts_lua_http_intercept_run_coroutine(ictx, 0);

  TSMutexUnlock(mtxp);

}
Пример #20
0
/* This is where we start the PURGE events, setting up the transactino to fail,
   and bump the generation ID, and finally save the state. */
static int
on_http_cache_lookup_complete(TSHttpTxn txnp, TSCont contp, PurgeInstance *purge)
{
  FILE *file;

  TSMutexLock(purge->lock);

  ++purge->gen_id;
  TSDebug(PLUGIN_NAME, "Bumping the Generation ID to %" PRId64 " for %s", purge->gen_id, purge->id);

  if ((file = fopen(purge->state_file, "w"))) {
    TSDebug(PLUGIN_NAME, "\tsaving state to %s", purge->state_file);
    fprintf(file, "%" PRId64 "", purge->gen_id);
    fclose(file);
  } else {
    TSError("[%s] Unable to save state to file %s: errno=%d", PLUGIN_NAME, purge->state_file, errno);
  }

  TSMutexUnlock(purge->lock);

  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
  return TS_SUCCESS;
}
Пример #21
0
int
ts_http_fetcher_callback_sm(http_fetcher *fch, TSEvent event)
{
    if (fch->deleted && !fch->ref) {
        ts_http_fetcher_release(fch);
        return -1;
    }

    if (event == TS_EVENT_FETCH_BODY_QUIET || fch->stopped) {
        return 0;

    } else if (event != TS_EVENT_FETCH_HEADER_DONE &&
               event != TS_EVENT_FETCH_BODY_READY &&
               event != TS_EVENT_FETCH_BODY_QUIET) {

        fch->stopped = 1;
    }

    fch->ref++;

    if (fch->flags & TS_FLAG_FETCH_USE_NEW_LOCK)
        TSMutexLock(TSContMutexGet(fch->contp));

    TSContCall(fch->contp, event, fch);

    if (fch->flags & TS_FLAG_FETCH_USE_NEW_LOCK)
        TSMutexUnlock(TSContMutexGet(fch->contp));

    fch->ref--;

    if (fch->deleted && !fch->ref) {
        ts_http_fetcher_release(fch);
        return -1;
    }

    return 0;
}
Пример #22
0
static int
ts_lua_shared_dict_get(lua_State *L)
{
    int                     n, type;
    int64_t                 nkey;
    const char              *key;
    void                    *val;
    size_t                  key_len;
    void                    *hKey;
    ts_lua_shared_dict      *dct;
    ts_lua_shared_dict_item *item;

    n = lua_gettop(L);

    if (n != 2) {
        return luaL_error(L, "invalid param for xx:get(key)");
    }

    dct = (ts_lua_shared_dict*)lua_touserdata(L, 1);
    if (dct == NULL) {
        return luaL_error(L, "userdata is required for xx:get()");
    }

    type = lua_type(L, 2);

    if (dct->flags & TS_LUA_SHDICT_FLAG_INTKEY) {

        if (type != LUA_TNUMBER) {
            return luaL_error(L, "key for xx:get() is not number.");
        }

        nkey = lua_tonumber(L, 2);
        hKey = (void*)nkey;

    } else if (type != LUA_TSTRING) {
        return luaL_error(L, "key for xx:get() is not string.");

    } else {
        key = lua_tolstring(L, 2, &key_len);
        hKey = (void*)key;
    }

    if (!(dct->flags & TS_LUA_SHDICT_FLAG_STATIC))
         TSMutexLock(dct->map.mutexp);

    if (ts_lua_hash_table_lookup(&dct->map.t, hKey, &val)) {        // found

        item = (ts_lua_shared_dict_item*)val;
        switch (item->vtype) {

            case LUA_TNUMBER:
                lua_pushnumber(L, item->v.n);
                break;

            case LUA_TBOOLEAN:
                lua_pushboolean(L, item->v.n);
                break;

            case LUA_TSTRING:
                lua_pushlstring(L, item->v.s, item->vsize);
                break;

            case LUA_TNIL:
            default:
                lua_pushnil(L);
        }

    } else {                                                        // not found
        lua_pushnil(L);
    }

    if (!(dct->flags & TS_LUA_SHDICT_FLAG_STATIC))
         TSMutexUnlock(dct->map.mutexp);

    return 1;
}
static int
ts_lua_transform_handler(TSCont contp, ts_lua_http_transform_ctx *transform_ctx, TSEvent event, int n)
{
  TSVConn output_conn;
  TSVIO input_vio;
  TSIOBufferReader input_reader;
  TSIOBufferBlock blk;
  int64_t toread, towrite, blk_len, upstream_done, input_avail, input_wm_bytes, l;
  const char *start;
  const char *res;
  size_t res_len;
  int ret, eos, write_down, rc, top, empty_input;
  ts_lua_coroutine *crt;
  ts_lua_cont_info *ci;

  lua_State *L;
  TSMutex mtxp;

  ci  = &transform_ctx->cinfo;
  crt = &ci->routine;

  mtxp = crt->mctx->mutexp;
  L    = crt->lua;

  output_conn = TSTransformOutputVConnGet(contp);
  input_vio   = TSVConnWriteVIOGet(contp);

  empty_input = 0;
  if (!TSVIOBufferGet(input_vio)) {
    if (transform_ctx->output.vio) {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] reenabling output VIO after input VIO does not exist", __FUNCTION__);
      TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
      TSVIOReenable(transform_ctx->output.vio);
      return 0;
    } else {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] no input VIO and output VIO", __FUNCTION__);
      empty_input = 1;
    }
  } else { // input VIO exists
    input_wm_bytes = TSIOBufferWaterMarkGet(TSVIOBufferGet(input_vio));
    if (transform_ctx->upstream_watermark_bytes >= 0 && transform_ctx->upstream_watermark_bytes != input_wm_bytes) {
      TSDebug(TS_LUA_DEBUG_TAG, "[%s] Setting input_vio watermark to %" PRId64 " bytes", __FUNCTION__,
              transform_ctx->upstream_watermark_bytes);
      TSIOBufferWaterMarkSet(TSVIOBufferGet(input_vio), transform_ctx->upstream_watermark_bytes);
    }
  }

  if (empty_input == 0) {
    input_reader = TSVIOReaderGet(input_vio);
  }

  if (!transform_ctx->output.buffer) {
    transform_ctx->output.buffer = TSIOBufferCreate();
    transform_ctx->output.reader = TSIOBufferReaderAlloc(transform_ctx->output.buffer);

    transform_ctx->reserved.buffer = TSIOBufferCreate();
    transform_ctx->reserved.reader = TSIOBufferReaderAlloc(transform_ctx->reserved.buffer);

    if (empty_input == 0) {
      transform_ctx->upstream_bytes = TSVIONBytesGet(input_vio);
    } else {
      transform_ctx->upstream_bytes = 0;
    }

    transform_ctx->downstream_bytes = INT64_MAX;
  }

  if (empty_input == 0) {
    input_avail   = TSIOBufferReaderAvail(input_reader);
    upstream_done = TSVIONDoneGet(input_vio);
    toread        = TSVIONTodoGet(input_vio);

    if (toread <= input_avail) { // upstream finished
      eos = 1;
    } else {
      eos = 0;
    }
  } else {
    input_avail = 0;
    toread      = 0;
    eos         = 1;
  }

  if (input_avail > 0) {
    // move to the reserved.buffer
    TSIOBufferCopy(transform_ctx->reserved.buffer, input_reader, input_avail, 0);

    // reset input
    TSIOBufferReaderConsume(input_reader, input_avail);
    TSVIONDoneSet(input_vio, upstream_done + input_avail);
  }

  write_down = 0;
  if (empty_input == 0) {
    towrite = TSIOBufferReaderAvail(transform_ctx->reserved.reader);
  } else {
    towrite = 0;
  }

  TSMutexLock(mtxp);
  ts_lua_set_cont_info(L, ci);

  do {
    if (event == TS_LUA_EVENT_COROUTINE_CONT) {
      event = 0;
      goto launch;
    } else {
      n = 2;
    }

    if (towrite == 0 && empty_input == 0) {
      break;
    }

    if (empty_input == 0) {
      blk   = TSIOBufferReaderStart(transform_ctx->reserved.reader);
      start = TSIOBufferBlockReadStart(blk, transform_ctx->reserved.reader, &blk_len);

      lua_pushlightuserdata(L, transform_ctx);
      lua_rawget(L, LUA_GLOBALSINDEX); /* push function */

      if (towrite > blk_len) {
        lua_pushlstring(L, start, (size_t)blk_len);
        towrite -= blk_len;
        TSIOBufferReaderConsume(transform_ctx->reserved.reader, blk_len);
      } else {
        lua_pushlstring(L, start, (size_t)towrite);
        TSIOBufferReaderConsume(transform_ctx->reserved.reader, towrite);
        towrite = 0;
      }

      if (!towrite && eos) {
        lua_pushinteger(L, 1); /* second param, data finished */
      } else {
        lua_pushinteger(L, 0); /* second param, data not finish */
      }
    } else {
      lua_pushlightuserdata(L, transform_ctx);
      lua_rawget(L, LUA_GLOBALSINDEX); /* push function */

      lua_pushlstring(L, "", 0);
      lua_pushinteger(L, 1); /* second param, data finished */
    }

  launch:
    rc  = lua_resume(L, n);
    top = lua_gettop(L);

    switch (rc) {
    case LUA_YIELD: // coroutine yield
      TSMutexUnlock(mtxp);
      return 0;

    case 0: // coroutine success
      if (top == 2) {
        ret = lua_tointeger(L, -1); /* 0 is not finished, 1 is finished */
        res = lua_tolstring(L, -2, &res_len);
      } else { // what hells code are you writing ?
        ret     = 0;
        res     = NULL;
        res_len = 0;
      }
      break;

    default: // coroutine failed
      TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
      ret     = 1;
      res     = NULL;
      res_len = 0;
      break;
    }

    if (res && res_len > 0) {
      if (!transform_ctx->output.vio) {
        l = transform_ctx->downstream_bytes;
        if (ret) {
          l = res_len;
        }

        transform_ctx->output.vio = TSVConnWrite(output_conn, contp, transform_ctx->output.reader, l); // HttpSM go on
      }

      TSIOBufferWrite(transform_ctx->output.buffer, res, res_len);
      transform_ctx->total += res_len;
      write_down = 1;
    }

    lua_pop(L, top);

    if (ret || (eos && !towrite)) { // EOS
      eos = 1;
      break;
    }

  } while (towrite > 0);

  TSMutexUnlock(mtxp);

  if (eos && !transform_ctx->output.vio) {
    transform_ctx->output.vio = TSVConnWrite(output_conn, contp, transform_ctx->output.reader, 0);
  }

  if (write_down || eos) {
    TSVIOReenable(transform_ctx->output.vio);
  }

  if (toread > input_avail) { // upstream not finished.
    if (eos) {
      TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
      if (empty_input == 0) {
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_EOS, input_vio);
      }
    } else {
      if (empty_input == 0) {
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
      }
    }
  } else { // upstream is finished.
    TSVIONBytesSet(transform_ctx->output.vio, transform_ctx->total);
    if (empty_input == 0) {
      TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    }
  }

  return 0;
}
Пример #24
0
static int
ts_lua_cache_handle_read(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State               *L;
    TSMutex                 mtx;
    char                    *dst;
    int64_t                 avail, n;

    n = 0;

    switch (event) {

        case TS_EVENT_VCONN_READ_READY:
            avail = TSIOBufferReaderAvail(info->ioh.reader);
            if (avail > 0) {
                TSIOBufferCopy(info->reserved.buffer, info->ioh.reader, avail, 0);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            avail = TSIOBufferReaderAvail(info->reserved.reader);
            if (avail + info->already >= info->need) {
                n = info->need - info->already;

            } else {
                TSVIOReenable(info->ioh.vio);
            }

            break;

        case TS_EVENT_VCONN_READ_COMPLETE:
        case TS_EVENT_VCONN_EOS:
            avail = TSIOBufferReaderAvail(info->ioh.reader);
            if (avail > 0) {
                TSIOBufferCopy(info->reserved.buffer, info->ioh.reader, avail, 0);
                TSIOBufferReaderConsume(info->ioh.reader, avail);
            }

            n = TSIOBufferReaderAvail(info->reserved.reader);

            info->eof = 1;
            break;

        default:                                // error
            info->err = 1;
            break;
    }

    if (info->wait && (n > 0 || info->eof || info->err)) {      // resume
        L = ci->routine.lua;
        mtx = ci->routine.mctx->mutexp;

        TSMutexLock(mtx);

        if (n > 0) {
            dst = TSmalloc(n);
            IOBufferReaderCopy(info->reserved.reader, dst, n);
            lua_pushlstring(L, (char*)dst, n);
            TSfree(dst);

            info->already += n;
            TSIOBufferReaderConsume(info->reserved.reader, n);

        } else {
            lua_pushnil(L);
        }

        info->wait = 0;

        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);
        TSMutexUnlock(mtx);
    }

    return 0;
}
Пример #25
0
static int
ts_lua_shared_dict_del(lua_State *L)
{
    int                     n, type;
    int64_t                 nkey;
    const char              *key;
    size_t                  key_len;
    void                    *hKey;
    Tcl_HashEntry           *entry;
    ts_lua_shared_dict_item *item;
    ts_lua_shared_dict      *dct;

    n = lua_gettop(L);

    if (n != 2) {
        return luaL_error(L, "invalid param for xx:del(key)");
    }

    dct = (ts_lua_shared_dict*)lua_touserdata(L, 1);
    if (dct == NULL) {
        return luaL_error(L, "userdata is required for xx:del()");
    }

    type = lua_type(L, 2);

    if (dct->flags & TS_LUA_SHDICT_FLAG_INTKEY) {

        if (type != LUA_TNUMBER) {
            return luaL_error(L, "key for xx:del() is not number.");
        }

        nkey = lua_tonumber(L, 2);
        hKey = (void*)nkey;

    } else if (type != LUA_TSTRING) {
        return luaL_error(L, "key for xx:del() is not string.");

    } else {
        key = lua_tolstring(L, 2, &key_len);
        hKey = (void*)key;
    }

    item = NULL;

    TSMutexLock(dct->map.mutexp);

    entry = ts_lua_hash_table_lookup_entry(&dct->map.t, hKey);

    if (entry) {
        item = ts_lua_hash_table_entry_value(&dct->map.t, entry);
        Tcl_DeleteHashEntry(entry);

        dct->used -= item->ksize + item->vsize + sizeof(ts_lua_shared_dict_item);
    }

    TSMutexUnlock(dct->map.mutexp);

    if (item) {
        TSfree(item);
    }
 
    return 0;
}
Пример #26
0
static int
ts_lua_transform_handler(TSCont contp, ts_lua_transform_ctx *transform_ctx)
{
    TSVConn             output_conn;
    TSVIO               input_vio;
    TSIOBufferReader    input_reader;
    TSIOBufferBlock     blk;
    int64_t             towrite, blk_len, upstream_done, avail, left;
    const char          *start;
    const char          *res;
    size_t              res_len;
    int                 ret, eos;

    lua_State           *L;
    TSMutex             mtxp;

    L = transform_ctx->hctx->lua;
    mtxp = transform_ctx->hctx->mctx->mutexp;

    output_conn = TSTransformOutputVConnGet(contp);
    input_vio = TSVConnWriteVIOGet(contp);
    input_reader = TSVIOReaderGet(input_vio);

    if (!transform_ctx->output_buffer) {
        transform_ctx->output_buffer = TSIOBufferCreate();
        transform_ctx->output_reader = TSIOBufferReaderAlloc(transform_ctx->output_buffer);
        transform_ctx->output_vio = TSVConnWrite(output_conn, contp, transform_ctx->output_reader, INT64_MAX);
    }

    if (!TSVIOBufferGet(input_vio)) {
        TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total);
        TSVIOReenable(transform_ctx->output_vio);
        return 1;
    }

    if (transform_ctx->eos) {
        return 1;
    }

    left = towrite = TSVIONTodoGet(input_vio);
    upstream_done = TSVIONDoneGet(input_vio);
    avail = TSIOBufferReaderAvail(input_reader);
    eos = 0;

    if (left <= avail)
        eos = 1;

    if (towrite > avail)
        towrite = avail;

    TSMutexLock(mtxp);

    blk = TSIOBufferReaderStart(input_reader);

    do {
        start = TSIOBufferBlockReadStart(blk, input_reader, &blk_len);

        lua_pushlightuserdata(L, transform_ctx);
        lua_rawget(L, LUA_GLOBALSINDEX);                /* push function */

        if (towrite > blk_len) {
            lua_pushlstring(L, start, (size_t)blk_len);
            towrite -= blk_len;
        } else {
            lua_pushlstring(L, start, (size_t)towrite);
            towrite = 0;
        }

        if (!towrite && eos) {
            lua_pushinteger(L, 1);                          /* second param, not finish */ 
        } else {
            lua_pushinteger(L, 0);                          /* second param, not finish */ 
        }

        if (lua_pcall(L, 2, 2, 0)) {
            fprintf(stderr, "lua_pcall failed: %s\n", lua_tostring(L, -1));
        }

        ret = lua_tointeger(L, -1);                         /* 0 is not finished, 1 is finished */
        res = lua_tolstring(L, -2, &res_len);

        if (res && res_len) {
            TSIOBufferWrite(transform_ctx->output_buffer, res, res_len);
            transform_ctx->total += res_len;
        }

        lua_pop(L, 2);

        if (ret || (eos && !towrite)) {            // EOS
            eos = 1;
            break;
        }

        blk = TSIOBufferBlockNext(blk);

    } while (blk && towrite > 0);

    TSMutexUnlock(mtxp);

    TSIOBufferReaderConsume(input_reader, avail);
    TSVIONDoneSet(input_vio, upstream_done + avail);

    if (eos) {
        transform_ctx->eos = 1;
        TSVIONBytesSet(transform_ctx->output_vio, transform_ctx->total);
        TSVIOReenable(transform_ctx->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_COMPLETE, input_vio);
    } else {
        TSVIOReenable(transform_ctx->output_vio);
        TSContCall(TSVIOContGet(input_vio), TS_EVENT_VCONN_WRITE_READY, input_vio);
    }

    return 1;
}
Пример #27
0
TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * rri)
{
  int ret;
  uint64_t req_id;

  TSCont contp;
  lua_State *l;

  ts_lua_main_ctx *main_ctx;
  ts_lua_http_ctx *http_ctx;

  ts_lua_instance_conf *instance_conf;

  instance_conf = (ts_lua_instance_conf *) ih;
  req_id = __sync_fetch_and_add(&ts_lua_http_next_id, 1);


  main_ctx = &ts_lua_main_ctx_array[req_id % TS_LUA_MAX_STATE_COUNT];

  TSMutexLock(main_ctx->mutexp);

  http_ctx = ts_lua_create_http_ctx(main_ctx, instance_conf);

  http_ctx->txnp = rh;
  http_ctx->client_request_bufp = rri->requestBufp;
  http_ctx->client_request_hdrp = rri->requestHdrp;
  http_ctx->client_request_url = rri->requestUrl;
  http_ctx->remap = 1;
  http_ctx->has_hook = 0;

  contp = TSContCreate(ts_lua_http_cont_handler, NULL);
  TSContDataSet(contp, http_ctx);
  http_ctx->main_contp = contp;

  l = http_ctx->lua;

  lua_getglobal(l, TS_LUA_FUNCTION_REMAP);
  if (lua_type(l, -1) != LUA_TFUNCTION) {
    TSMutexUnlock(main_ctx->mutexp);
    return TSREMAP_NO_REMAP;
  }

  if (lua_pcall(l, 0, 1, 0) != 0) {
    TSError("lua_pcall failed: %s", lua_tostring(l, -1));
  }

  ret = lua_tointeger(l, -1);
  lua_pop(l, 1);

  if(http_ctx->has_hook) {
    TSDebug(TS_LUA_DEBUG_TAG, "[%s] has txn hook -> adding txn close hook handler to release resources", __FUNCTION__);
    TSHttpTxnHookAdd(rh, TS_HTTP_TXN_CLOSE_HOOK, contp);
  } else {
    TSDebug(TS_LUA_DEBUG_TAG, "[%s] no txn hook -> release resources now", __FUNCTION__);
    ts_lua_destroy_http_ctx(http_ctx);
    TSContDestroy(contp);
  }

  TSMutexUnlock(main_ctx->mutexp);

  return ret;
}
Пример #28
0
static int
ts_lua_cache_open_read(ts_lua_cont_info *ci, ts_lua_cache_info *info, TSEvent event, void *edata)
{
    lua_State       *L;
    TSMutex         mtx;
    TSVConn         vc;
    int64_t         sz;

    L = ci->routine.lua;
    mtx = ci->routine.mctx->mutexp;

    TSMutexLock(mtx);

    // result table
    lua_newtable(L);

    switch (event) {

        case TS_EVENT_CACHE_OPEN_READ:
            vc = (TSVConn)edata;
            sz = TSVConnCacheObjectSizeGet(vc);

            info->cache_vc = vc;
            info->hit = 1;
            info->sz = sz;

            lua_pushlstring(L, "hit", sizeof("hit") - 1);
            lua_pushboolean(L, 1);
            lua_rawset(L, -3);

            lua_pushlstring(L, "size", sizeof("size") - 1);
            lua_pushnumber(L, sz);
            lua_rawset(L, -3);

            break;

        case TS_EVENT_CACHE_OPEN_READ_FAILED:               // miss
        default:                                            // error
            lua_pushlstring(L, "hit", sizeof("hit") - 1);
            lua_pushboolean(L, 0);
            lua_rawset(L, -3);

            lua_pushlstring(L, "size", sizeof("size") - 1);
            lua_pushnumber(L, -1);
            lua_rawset(L, -3);

            if (event != TS_EVENT_CACHE_OPEN_READ_FAILED) {
                info->err = 1;
            }

            break;
    }

    lua_pushlstring(L, "info", sizeof("info") - 1);
    lua_pushlightuserdata(L, info);
    lua_rawset(L, -3);

    if (info->cache_action) {
        info->cache_action = NULL;
        TSContCall(ci->contp, TS_LUA_EVENT_COROUTINE_CONT, (void*)1);

    } else {
        // return to the ts.cache_open synchronized
    }

    TSMutexUnlock(mtx);
    return 0;
}
Пример #29
0
static int
globalHookHandler(TSCont contp, TSEvent event ATS_UNUSED, void *edata)
{
  TSHttpTxn txnp = (TSHttpTxn) edata;

  TSMBuffer bufp;
  TSMLoc hdr_loc;
  TSMLoc url_loc;

  int ret;
  uint64_t req_id;
  TSCont txn_contp;

  lua_State *l;

  ts_lua_main_ctx *main_ctx;
  ts_lua_http_ctx *http_ctx;

  ts_lua_instance_conf *conf = (ts_lua_instance_conf *) TSContDataGet(contp);

  req_id = __sync_fetch_and_add(&ts_lua_g_http_next_id, 1);

  main_ctx = &ts_lua_g_main_ctx_array[req_id % TS_LUA_MAX_STATE_COUNT];

  TSDebug(TS_LUA_DEBUG_TAG, "[%s] req_id: %" PRId64, __FUNCTION__, req_id);
  TSMutexLock(main_ctx->mutexp);

  http_ctx = ts_lua_create_http_ctx(main_ctx, conf);
  http_ctx->txnp = txnp;
  http_ctx->remap = 0;
  http_ctx->has_hook = 0;

  if (!http_ctx->client_request_bufp) {
    if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) == TS_SUCCESS) {
      http_ctx->client_request_bufp = bufp;
      http_ctx->client_request_hdrp = hdr_loc;

      if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) == TS_SUCCESS) {
        http_ctx->client_request_url = url_loc;
      }
    }
  }

  if (!http_ctx->client_request_hdrp) {
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    return 0;
  }

  txn_contp = TSContCreate(ts_lua_http_cont_handler, NULL);
  TSContDataSet(txn_contp, http_ctx);
  http_ctx->main_contp = txn_contp;

  l = http_ctx->lua;

  switch (event) {
  case TS_EVENT_HTTP_READ_REQUEST_HDR:
    lua_getglobal(l, TS_LUA_FUNCTION_G_READ_REQUEST);
    break;

  case TS_EVENT_HTTP_SEND_REQUEST_HDR:
    lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_REQUEST);
    break;

  case TS_EVENT_HTTP_READ_RESPONSE_HDR:
    lua_getglobal(l, TS_LUA_FUNCTION_G_READ_RESPONSE);
    break;

  case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
    lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_RESPONSE);
    break;

  case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
    lua_getglobal(l, TS_LUA_FUNCTION_G_CACHE_LOOKUP_COMPLETE);
    break;

  case TS_EVENT_HTTP_TXN_START:
    lua_getglobal(l, TS_LUA_FUNCTION_G_TXN_START);
    break;

  case TS_EVENT_HTTP_PRE_REMAP:
    lua_getglobal(l, TS_LUA_FUNCTION_G_PRE_REMAP);
    break;

  case TS_EVENT_HTTP_POST_REMAP:
    lua_getglobal(l, TS_LUA_FUNCTION_G_POST_REMAP);
    break;

  case TS_EVENT_HTTP_SELECT_ALT:
    lua_getglobal(l, TS_LUA_FUNCTION_G_SELECT_ALT);
    break;

  case TS_EVENT_HTTP_OS_DNS:
    lua_getglobal(l, TS_LUA_FUNCTION_G_OS_DNS);
    break;

  case TS_EVENT_HTTP_READ_CACHE_HDR:
    lua_getglobal(l, TS_LUA_FUNCTION_G_READ_CACHE);
    break;

  case TS_EVENT_HTTP_TXN_CLOSE:
    lua_getglobal(l, TS_LUA_FUNCTION_G_TXN_CLOSE);
    break;

  default:
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    return 0;
    break;
  }

  if (lua_type(l, -1) != LUA_TFUNCTION) {
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
    lua_pop(l, 1);
    return 0;
  }

  if (lua_pcall(l, 0, 1, 0) != 0) {
    TSError("lua_pcall failed: %s", lua_tostring(l, -1));
  }

  ret = lua_tointeger(l, -1);
  lua_pop(l, 1);

  if(http_ctx->has_hook) {
    // add a hook to release resources for context
    TSDebug(TS_LUA_DEBUG_TAG, "[%s] has txn hook -> adding txn close hook handler to release resources", __FUNCTION__);
    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);
  } else {
    TSDebug(TS_LUA_DEBUG_TAG, "[%s] no txn hook -> release resources now", __FUNCTION__);
    ts_lua_destroy_http_ctx(http_ctx);
    TSContDestroy(txn_contp);
  }

  TSMutexUnlock(main_ctx->mutexp);

  if(ret) {
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
  } else {
    TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
  }

  return 0;
}
Пример #30
0
/*-------------------------------------------------------------------------
  psi_include
  Read file to include. Copy its content into an iobuffer.

  This is the function doing blocking calls and called by the plugin's threads

  Input:
    data      continuation for the current transaction
  Output :
    data->psi_buffer  contains the file content
    data->psi_sucess  0 if include failed, 1 if success
  Return Value:
    0  if failure
    1  if success
  -------------------------------------------------------------------------*/
static int
psi_include(TSCont contp, void *edata)
{
#define BUFFER_SIZE 1024
  ContData *data;
  TSFile filep;
  char buf[BUFFER_SIZE];
  char inc_file[PSI_PATH_MAX_SIZE + PSI_FILENAME_MAX_SIZE];

  /* We manipulate plugin continuation data from a separate thread.
     Grab mutex to avoid concurrent access */
  TSMutexLock(TSContMutexGet(contp));
  data = TSContDataGet(contp);
  TSAssert(data->magic == MAGIC_ALIVE);

  if (!data->psi_buffer) {
    data->psi_buffer = TSIOBufferCreate();
    data->psi_reader = TSIOBufferReaderAlloc(data->psi_buffer);
  }

  /* For security reason, we do not allow to include files that are
     not in the directory <plugin_path>/include.
     Also include file cannot contain any path. */
  sprintf(inc_file, "%s/%s", psi_directory, _basename(data->psi_filename));

  /* Read the include file and copy content into iobuffer */
  if ((filep = TSfopen(inc_file, "r")) != NULL) {
    TSDebug(DBG_TAG, "Reading include file %s", inc_file);

    while (TSfgets(filep, buf, BUFFER_SIZE) != NULL) {
      TSIOBufferBlock block;
      int64_t len, avail, ndone, ntodo, towrite;
      char *ptr_block;

      len = strlen(buf);
      ndone = 0;
      ntodo = len;
      while (ntodo > 0) {
        /* TSIOBufferStart allocates more blocks if required */
        block = TSIOBufferStart(data->psi_buffer);
        ptr_block = TSIOBufferBlockWriteStart(block, &avail);
        towrite = MIN(ntodo, avail);

        memcpy(ptr_block, buf + ndone, towrite);
        TSIOBufferProduce(data->psi_buffer, towrite);
        ntodo -= towrite;
        ndone += towrite;
      }
    }
    TSfclose(filep);
    data->psi_success = 1;
    if (log) {
      TSTextLogObjectWrite(log, "Successfully included file: %s", inc_file);
    }
  } else {
    data->psi_success = 0;
    if (log) {
      TSTextLogObjectWrite(log, "Failed to include file: %s", inc_file);
    }
  }

  /* Change state and schedule an event EVENT_IMMEDIATE on the plugin continuation
     to let it know we're done. */

  /* Note: if the blocking call was not in the transformation state (i.e. in
     TS_HTTP_READ_REQUEST_HDR, TS_HTTP_OS_DNS and so on...) we could
     use TSHttpTxnReenable to wake up the transaction instead of sending an event. */

  TSContSchedule(contp, 0, TS_THREAD_POOL_DEFAULT);
  data->psi_success = 0;
  data->state = STATE_READ_DATA;
  TSMutexUnlock(TSContMutexGet(contp));

  return 0;
}