Exemple #1
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;
}
Exemple #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_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_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;
}
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);
}
Exemple #5
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;
}
Exemple #6
0
/* When the handle is called, the net_vc is returned. */
static int
accept_handler(TSCont contp, TSEvent event, void *edata)
{
  TSCont txn_sm;
  TSMutex pmutex;

  switch (event) {
  case TS_EVENT_NET_ACCEPT:
    /* Create a new mutex for the TxnSM, which is going
       to handle the incoming request. */
    pmutex = (TSMutex)TSMutexCreate();
    txn_sm = (TSCont)TxnSMCreate(pmutex, (TSVConn)edata, server_port);

    /* This is no reason for not grabbing the lock.
       So skip the routine which handle LockTry failure case. */
    TSMutexLockTry(pmutex); // TODO: why should it not check if we got the lock??
    TSContCall(txn_sm, 0, NULL);
    TSMutexUnlock(pmutex);
    break;

  default:
    /* Something wrong with the network, if there are any
       pending NetAccept, cancel them. */
    if (pending_action && !TSActionDone(pending_action))
      TSActionCancel(pending_action);

    TSContDestroy(contp);
    break;
  }

  return TS_EVENT_NONE;
}
Exemple #7
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;
}
Exemple #8
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);
    }
  }
}
Exemple #9
0
int
get_nbelem_queue(Queue *q)
{
  int nb;
  TSMutexLock(q->mutex);
  nb = q->nb_elem;
  TSMutexUnlock(q->mutex);

  return nb;
}
Exemple #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;
}
Exemple #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);
}
}
Exemple #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 void
read_blacklist(TSCont contp)
{
  char blacklist_file[1024];
  TSFile file;

  sprintf(blacklist_file, "%s/blacklist.txt", TSPluginDirGet());
  file   = TSfopen(blacklist_file, "r");
  nsites = 0;

  /* If the Mutext lock is not successful try again in RETRY_TIME */
  if (TSMutexLockTry(sites_mutex) != TS_SUCCESS) {
    if (file != NULL) {
      TSfclose(file);
    }
    TSContSchedule(contp, RETRY_TIME, TS_THREAD_POOL_DEFAULT);
    return;
  }

  if (file != NULL) {
    char buffer[1024];

    while (TSfgets(file, buffer, sizeof(buffer) - 1) != NULL && nsites < MAX_NSITES) {
      char *eol;
      if ((eol = strstr(buffer, "\r\n")) != NULL) {
        /* To handle newlines on Windows */
        *eol = '\0';
      } else if ((eol = strchr(buffer, '\n')) != NULL) {
        *eol = '\0';
      } else {
        /* Not a valid line, skip it */
        continue;
      }
      if (sites[nsites] != NULL) {
        TSfree(sites[nsites]);
      }
      sites[nsites] = TSstrdup(buffer);
      nsites++;
    }

    TSfclose(file);
  } else {
    TSError("[%s] Unable to open %s", PLUGIN_NAME, blacklist_file);
    TSError("[%s] All sites will be allowed", PLUGIN_NAME);
  }

  TSMutexUnlock(sites_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;
}
Exemple #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;
}
Exemple #16
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;
}
/* 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);
}
Exemple #18
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 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;
}
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);

}
Exemple #22
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;
}
Exemple #23
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;
}
Exemple #24
0
/*-------------------------------------------------------------------------
  transform_handler
  Handler for all events received during the transformation process

  Input:
    contp      continuation for the current transaction
    event      event received
    data       pointer on optional data
  Output :
  Return Value:
  -------------------------------------------------------------------------*/
static int
transform_handler(TSCont contp, TSEvent event, void *edata)
{
  TSVIO input_vio;
  ContData *data;
  int state, retval;

  /* This section will be called by both TS internal
     and the thread. Protect it with a mutex to avoid
     concurrent calls. */

  /* Handle TryLock result */
  if (TSMutexLockTry(TSContMutexGet(contp)) != TS_SUCCESS) {
    TSCont c = TSContCreate(trylock_handler, NULL);
    TryLockData *d = TSmalloc(sizeof(TryLockData));

    d->contp = contp;
    d->event = event;
    TSContDataSet(c, d);
    TSContSchedule(c, 10, TS_THREAD_POOL_DEFAULT);
    return 1;
  }

  data = TSContDataGet(contp);
  TSAssert(data->magic == MAGIC_ALIVE);

  state = data->state;

  /* Check to see if the transformation has been closed */
  retval = TSVConnClosedGet(contp);
  if (retval) {
    /* If the thread is still executing its job, we don't want to destroy
       the continuation right away as the thread will call us back
       on this continuation. */
    if (state == STATE_READ_PSI) {
      TSContSchedule(contp, 10, TS_THREAD_POOL_DEFAULT);
    } else {
      TSMutexUnlock(TSContMutexGet(contp));
      cont_data_destroy(TSContDataGet(contp));
      TSContDestroy(contp);
      return 1;
    }
  } else {
    switch (event) {
    case TS_EVENT_ERROR:
      input_vio = TSVConnWriteVIOGet(contp);
      TSContCall(TSVIOContGet(input_vio), TS_EVENT_ERROR, input_vio);
      break;

    case TS_EVENT_VCONN_WRITE_COMPLETE:
      TSVConnShutdown(TSTransformOutputVConnGet(contp), 0, 1);
      break;

    case TS_EVENT_VCONN_WRITE_READY:
      /* downstream vconnection is done reading data we've write into it.
         let's read some more data from upstream if we're in read state. */
      if (state == STATE_READ_DATA) {
        handle_transform(contp);
      }
      break;

    case TS_EVENT_IMMEDIATE:
      if (state == STATE_READ_DATA) {
        /* upstream vconnection signals some more data ready to be read
           let's try to transform some more data */
        handle_transform(contp);
      } else if (state == STATE_DUMP_PSI) {
        /* The thread scheduled an event on our continuation to let us
           know it has completed its job
           Let's dump the include content to the output vconnection */
        dump_psi(contp);
        wake_up_streams(contp);
      }
      break;

    default:
      TSAssert(!"Unexpected event");
      break;
    }
  }

  TSMutexUnlock(TSContMutexGet(contp));
  return 1;
}
static void
handle_dns(TSHttpTxn txnp, TSCont contp)
{
  TSMBuffer bufp;
  TSMLoc hdr_loc;
  TSMLoc url_loc;
  const char *host;
  int i;
  int host_length;

  if (TSHttpTxnClientReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
    TSError("[%s] Couldn't retrieve client request header", PLUGIN_NAME);
    goto done;
  }

  if (TSHttpHdrUrlGet(bufp, hdr_loc, &url_loc) != TS_SUCCESS) {
    TSError("[%s] Couldn't retrieve request url", PLUGIN_NAME);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  host = TSUrlHostGet(bufp, url_loc, &host_length);
  if (!host) {
    TSError("[%s] Couldn't retrieve request hostname", PLUGIN_NAME);
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    goto done;
  }

  /* We need to lock the sites_mutex as that is the mutex that is
     protecting the global list of all blacklisted sites. */
  if (TSMutexLockTry(sites_mutex) != TS_SUCCESS) {
    TSDebug(PLUGIN_NAME, "Unable to get lock. Will retry after some time");
    TSHandleMLocRelease(bufp, hdr_loc, url_loc);
    TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
    TSContSchedule(contp, RETRY_TIME, TS_THREAD_POOL_DEFAULT);
    return;
  }

  for (i = 0; i < nsites; i++) {
    if (strncmp(host, sites[i], host_length) == 0) {
      if (log) {
        TSTextLogObjectWrite(log, "blacklisting site: %s", sites[i]);
      } else {
        TSDebug(PLUGIN_NAME, "blacklisting site: %s", sites[i]);
      }
      TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp);
      TSHandleMLocRelease(bufp, hdr_loc, url_loc);
      TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
      TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR);
      TSMutexUnlock(sites_mutex);
      return;
    }
  }

  TSMutexUnlock(sites_mutex);
  TSHandleMLocRelease(bufp, hdr_loc, url_loc);
  TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);

done:
  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
}
Exemple #26
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;
}
Exemple #27
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;
}
Exemple #28
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;
}
Exemple #29
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;
}
Exemple #30
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;
}